Skip to content

Commit 10655c7

Browse files
DemiMarieMike Snitzer
authored andcommitted
dm ioctl: structs and parameter strings must not overlap
The NUL terminator for each target parameter string must precede the following 'struct dm_target_spec'. Otherwise, dm_split_args() might corrupt this struct. Furthermore, the first 'struct dm_target_spec' must come after the 'struct dm_ioctl', as if it overlaps too much dm_split_args() could corrupt the 'struct dm_ioctl'. Signed-off-by: Demi Marie Obenour <[email protected]> Reviewed-by: Mikulas Patocka <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 13f4a69 commit 10655c7

File tree

1 file changed

+21
-7
lines changed

1 file changed

+21
-7
lines changed

drivers/md/dm-ioctl.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,7 +1391,7 @@ static inline blk_mode_t get_mode(struct dm_ioctl *param)
13911391
return mode;
13921392
}
13931393

1394-
static int next_target(struct dm_target_spec *last, uint32_t next, void *end,
1394+
static int next_target(struct dm_target_spec *last, uint32_t next, const char *end,
13951395
struct dm_target_spec **spec, char **target_params)
13961396
{
13971397
static_assert(__alignof__(struct dm_target_spec) <= 8,
@@ -1402,7 +1402,7 @@ static int next_target(struct dm_target_spec *last, uint32_t next, void *end,
14021402
* sizeof(struct dm_target_spec) or more, as otherwise *last was
14031403
* out of bounds already.
14041404
*/
1405-
size_t remaining = (char *)end - (char *)last;
1405+
size_t remaining = end - (char *)last;
14061406

14071407
/*
14081408
* There must be room for both the next target spec and the
@@ -1422,10 +1422,7 @@ static int next_target(struct dm_target_spec *last, uint32_t next, void *end,
14221422
*spec = (struct dm_target_spec *) ((unsigned char *) last + next);
14231423
*target_params = (char *) (*spec + 1);
14241424

1425-
if (*spec < (last + 1))
1426-
return -EINVAL;
1427-
1428-
return invalid_str(*target_params, end);
1425+
return 0;
14291426
}
14301427

14311428
static int populate_table(struct dm_table *table,
@@ -1435,22 +1432,39 @@ static int populate_table(struct dm_table *table,
14351432
unsigned int i = 0;
14361433
struct dm_target_spec *spec = (struct dm_target_spec *) param;
14371434
uint32_t next = param->data_start;
1438-
void *end = (void *) param + param_size;
1435+
const char *const end = (const char *) param + param_size;
14391436
char *target_params;
1437+
size_t min_size = sizeof(struct dm_ioctl);
14401438

14411439
if (!param->target_count) {
14421440
DMERR("%s: no targets specified", __func__);
14431441
return -EINVAL;
14441442
}
14451443

14461444
for (i = 0; i < param->target_count; i++) {
1445+
const char *nul_terminator;
1446+
1447+
if (next < min_size) {
1448+
DMERR("%s: next target spec (offset %u) overlaps %s",
1449+
__func__, next, i ? "previous target" : "'struct dm_ioctl'");
1450+
return -EINVAL;
1451+
}
14471452

14481453
r = next_target(spec, next, end, &spec, &target_params);
14491454
if (r) {
14501455
DMERR("unable to find target");
14511456
return r;
14521457
}
14531458

1459+
nul_terminator = memchr(target_params, 0, (size_t)(end - target_params));
1460+
if (nul_terminator == NULL) {
1461+
DMERR("%s: target parameters not NUL-terminated", __func__);
1462+
return -EINVAL;
1463+
}
1464+
1465+
/* Add 1 for NUL terminator */
1466+
min_size = (size_t)(nul_terminator - (const char *)spec) + 1;
1467+
14541468
r = dm_table_add_target(table, spec->target_type,
14551469
(sector_t) spec->sector_start,
14561470
(sector_t) spec->length,

0 commit comments

Comments
 (0)