Avoid integer overflows when computing buffer sizes.
If any field size would cause an overflow, fail to create the model. PiperOrigin-RevId: 460466485 Change-Id: Ic8b84f3b56f2617c04ba04604729f0f76c6d62ee
This commit is contained in:
committed by
Copybara-Service
parent
d5059f484d
commit
af12322e9d
+37
-6
@@ -351,6 +351,31 @@ static void mj_setPtrModel(mjModel* m) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// increases buffer size without causing integer overflow, returns 0 if
|
||||||
|
// operation would cause overflow
|
||||||
|
// performs the following operations:
|
||||||
|
// *nbuffer += SKIP(*offset) + type_size*nr*nc;
|
||||||
|
// *offset += SKIP(*offset) + type_size*nr*nc;
|
||||||
|
static int safeAddToBufferSize(intptr_t* offset, int* nbuffer, size_t type_size, int nr, int nc) {
|
||||||
|
#if defined(__has_builtin) \
|
||||||
|
&& __has_builtin(__builtin_add_overflow) && __has_builtin(__builtin_mul_overflow)
|
||||||
|
// supported by GCC and Clang
|
||||||
|
int to_add = 0;
|
||||||
|
if (__builtin_mul_overflow(nc, nr, &to_add)) return 0;
|
||||||
|
if (__builtin_mul_overflow(to_add, type_size, &to_add)) return 0;
|
||||||
|
if (__builtin_add_overflow(to_add, SKIP(*offset), &to_add)) return 0;
|
||||||
|
if (__builtin_add_overflow(*nbuffer, to_add, nbuffer)) return 0;
|
||||||
|
if (__builtin_add_overflow(*offset, to_add, offset)) return 0;
|
||||||
|
#else
|
||||||
|
// TODO: offer a safe implementation for MSVC or other compilers that don't have the builtins
|
||||||
|
*nbuffer += SKIP(*offset) + type_size*nr*nc;
|
||||||
|
*offset += SKIP(*offset) + type_size*nr*nc;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// allocate and initialize mjModel structure
|
// allocate and initialize mjModel structure
|
||||||
mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
||||||
@@ -435,9 +460,12 @@ mjModel* mj_makeModel(int nq, int nv, int nu, int na, int nbody, int njnt,
|
|||||||
|
|
||||||
// compute buffer size
|
// compute buffer size
|
||||||
m->nbuffer = 0;
|
m->nbuffer = 0;
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
m->nbuffer += SKIP(offset) + sizeof(type)*(m->nr)*(nc); \
|
if (!safeAddToBufferSize(&offset, &m->nbuffer, sizeof(type), m->nr, nc)) { \
|
||||||
offset += SKIP(offset) + sizeof(type)*(m->nr)*(nc);
|
mju_warning("Invalid model: " #name " too large."); \
|
||||||
|
mj_deleteModel(m); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
MJMODEL_POINTERS
|
MJMODEL_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
@@ -799,9 +827,12 @@ static mjData* _makeData(const mjModel* m) {
|
|||||||
|
|
||||||
// compute buffer size
|
// compute buffer size
|
||||||
d->nbuffer = 0;
|
d->nbuffer = 0;
|
||||||
#define X(type, name, nr, nc) \
|
#define X(type, name, nr, nc) \
|
||||||
d->nbuffer += SKIP(offset) + sizeof(type)*(m->nr)*(nc); \
|
if (!safeAddToBufferSize(&offset, &d->nbuffer, sizeof(type), m->nr, nc)) { \
|
||||||
offset += SKIP(offset) + sizeof(type)*(m->nr)*(nc);
|
mju_warning("Invalid data: " #name " too large."); \
|
||||||
|
mj_deleteData(d); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
MJDATA_POINTERS
|
MJDATA_POINTERS
|
||||||
#undef X
|
#undef X
|
||||||
|
|||||||
Reference in New Issue
Block a user