mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-10-01 13:44:40 +00:00
SPA POD parser: fix several integer overflows
This fixes several integer overflow problems in the POD parser, as well as fixing a returns-twice warning from GCC and integer truncation problems in SPA_FLAG_CLEAR and SPA_ROUND_DOWN_N. The integer overflows can result in a tiny POD being treated as a huge one, causing out-of-bounds reads.
This commit is contained in:
parent
0e4df09e53
commit
1e848fc299
|
@ -3,7 +3,7 @@ project('pipewire', ['c' ],
|
|||
license : [ 'MIT', 'LGPL-2.1-or-later', 'GPL-2.0-only' ],
|
||||
meson_version : '>= 0.59.0',
|
||||
default_options : [ 'warning_level=3',
|
||||
'c_std=gnu99',
|
||||
'c_std=gnu11',
|
||||
'cpp_std=c++17',
|
||||
'b_pie=true',
|
||||
#'b_sanitize=address,undefined',
|
||||
|
|
|
@ -161,8 +161,9 @@ static inline int spa_buffer_alloc_fill_info(struct spa_buffer_alloc_info *info,
|
|||
*target += info->chunk_size;
|
||||
|
||||
for (i = 0, size = 0; i < n_datas; i++) {
|
||||
int64_t align = data_aligns[i];
|
||||
info->max_align = SPA_MAX(info->max_align, data_aligns[i]);
|
||||
size = SPA_ROUND_UP_N(size, data_aligns[i]);
|
||||
size = SPA_ROUND_UP_N(size, align);
|
||||
size += datas[i].maxsize;
|
||||
}
|
||||
info->data_size = size;
|
||||
|
|
|
@ -82,12 +82,20 @@ spa_pod_parser_reset(struct spa_pod_parser *parser, struct spa_pod_parser_state
|
|||
static inline struct spa_pod *
|
||||
spa_pod_parser_deref(struct spa_pod_parser *parser, uint32_t offset, uint32_t size)
|
||||
{
|
||||
if (offset + 8 <= size) {
|
||||
struct spa_pod *pod = SPA_PTROFF(parser->data, offset, struct spa_pod);
|
||||
if (offset + SPA_POD_SIZE(pod) <= size)
|
||||
return pod;
|
||||
/* Cast to uint64_t to avoid wraparound. Add 8 for the pod itself. */
|
||||
const uint64_t long_offset = (uint64_t)offset + 8;
|
||||
if (long_offset <= size && (offset & 7) == 0) {
|
||||
/* Use void* because creating a misaligned pointer is undefined. */
|
||||
void *pod = SPA_PTROFF(parser->data, offset, void);
|
||||
/*
|
||||
* Check that the pointer is aligned and that the size (rounded
|
||||
* to the next multiple of 8) is in bounds.
|
||||
*/
|
||||
if (SPA_IS_ALIGNED(pod, 8) &&
|
||||
long_offset + SPA_ROUND_UP_N((uint64_t)SPA_POD_BODY_SIZE(pod), 8) <= size)
|
||||
return (struct spa_pod *)pod;
|
||||
}
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct spa_pod *spa_pod_parser_frame(struct spa_pod_parser *parser, struct spa_pod_frame *frame)
|
||||
|
|
|
@ -39,7 +39,7 @@ extern "C" {
|
|||
|
||||
#define SPA_POD_BODY_SIZE(pod) (((struct spa_pod*)(pod))->size)
|
||||
#define SPA_POD_TYPE(pod) (((struct spa_pod*)(pod))->type)
|
||||
#define SPA_POD_SIZE(pod) (sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod))
|
||||
#define SPA_POD_SIZE(pod) ((uint64_t)sizeof(struct spa_pod) + SPA_POD_BODY_SIZE(pod))
|
||||
#define SPA_POD_CONTENTS_SIZE(type,pod) (SPA_POD_SIZE(pod)-sizeof(type))
|
||||
|
||||
#define SPA_POD_CONTENTS(type,pod) SPA_PTROFF((pod),sizeof(type),void)
|
||||
|
|
|
@ -119,7 +119,7 @@ struct spa_system_methods {
|
|||
|
||||
#define spa_system_method_r(o,method,version,...) \
|
||||
({ \
|
||||
int _res = -ENOTSUP; \
|
||||
volatile int _res = -ENOTSUP; \
|
||||
struct spa_system *_o = o; \
|
||||
spa_interface_call_res(&_o->iface, \
|
||||
struct spa_system_methods, _res, \
|
||||
|
|
|
@ -27,8 +27,18 @@
|
|||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
# if __cplusplus >= 201103L
|
||||
# define SPA_STATIC_ASSERT static_assert
|
||||
# endif
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
# include <stdbool.h>
|
||||
# if __STDC_VERSION__ >= 201112L
|
||||
# define SPA_STATIC_ASSERT _Static_assert
|
||||
# endif
|
||||
#endif
|
||||
#ifndef SPA_STATIC_ASSERT
|
||||
#define SPA_STATIC_ASSERT(a, b) \
|
||||
((void)sizeof(struct { int spa_static_assertion_failed : 2 * !!(a) - 1; }))
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
|
@ -74,8 +84,16 @@ extern "C" {
|
|||
#define SPA_FLAG_MASK(field,mask,flag) (((field) & (mask)) == (flag))
|
||||
#define SPA_FLAG_IS_SET(field,flag) SPA_FLAG_MASK(field,flag,flag)
|
||||
#define SPA_FLAG_SET(field,flag) ((field) |= (flag))
|
||||
#define SPA_FLAG_CLEAR(field,flag) ((field) &= ~(flag))
|
||||
#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET(field,flag) : SPA_FLAG_CLEAR(field,flag))
|
||||
#define SPA_FLAG_CLEAR(field, flag) \
|
||||
({ \
|
||||
SPA_STATIC_ASSERT(__builtin_constant_p(flag) ? \
|
||||
(__typeof__(flag))(__typeof__(field))(__typeof__(flag))(flag) == (flag) : \
|
||||
sizeof(field) >= sizeof(flag), \
|
||||
"truncation problem when masking " #field \
|
||||
" with ~" #flag); \
|
||||
((field) &= ~(__typeof__(field))(flag)); \
|
||||
})
|
||||
#define SPA_FLAG_UPDATE(field,flag,val) ((val) ? SPA_FLAG_SET((field),(flag)) : SPA_FLAG_CLEAR((field),(flag)))
|
||||
|
||||
enum spa_direction {
|
||||
SPA_DIRECTION_INPUT = 0,
|
||||
|
@ -239,7 +257,17 @@ struct spa_fraction {
|
|||
#define SPA_ROUND_DOWN(num,value) ((num) - ((num) % (value)))
|
||||
#define SPA_ROUND_UP(num,value) ((((num) + (value) - 1) / (value)) * (value))
|
||||
|
||||
#define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1))
|
||||
#define SPA_MASK_NEGATED(num1, num2) \
|
||||
({ \
|
||||
SPA_STATIC_ASSERT(__builtin_constant_p(num2) ? \
|
||||
(__typeof__(num2))(__typeof__(num1))(__typeof__(num2))(num2) == (num2) : \
|
||||
sizeof(num1) >= sizeof(num2), \
|
||||
"truncation problem when masking " #num1 \
|
||||
" with ~" #num2); \
|
||||
((num1) & ~(__typeof__(num1))(num2)); \
|
||||
})
|
||||
|
||||
#define SPA_ROUND_DOWN_N(num,align) SPA_MASK_NEGATED((num), (align) - 1)
|
||||
#define SPA_ROUND_UP_N(num,align) SPA_ROUND_DOWN_N((num) + ((align) - 1),align)
|
||||
|
||||
#define SPA_PTR_ALIGNMENT(p,align) ((intptr_t)(p) & ((align)-1))
|
||||
|
|
|
@ -31,13 +31,19 @@ int pw_protocol_native_connect_portal_screencast(struct pw_protocol_client *clie
|
|||
void (*done_callback) (void *data, int res),
|
||||
void *data);
|
||||
|
||||
static inline void *get_first_pod_from_data(void *data, size_t maxsize, off_t offset)
|
||||
static inline void *get_first_pod_from_data(void *data, uint32_t maxsize, uint64_t offset)
|
||||
{
|
||||
void *pod;
|
||||
if (offset + sizeof(struct spa_pod) > maxsize)
|
||||
if (maxsize <= offset)
|
||||
return NULL;
|
||||
|
||||
/* spa_pod_parser_advance() rounds up, so round down here to compensate */
|
||||
maxsize = SPA_ROUND_DOWN_N(maxsize - offset, 8);
|
||||
if (maxsize < sizeof(struct spa_pod))
|
||||
return NULL;
|
||||
|
||||
pod = SPA_PTROFF(data, offset, void);
|
||||
if (offset + SPA_POD_SIZE(pod) > maxsize)
|
||||
if (SPA_POD_BODY_SIZE(pod) > maxsize - sizeof(struct spa_pod))
|
||||
return NULL;
|
||||
return pod;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue