Skip to content

Commit

Permalink
dm: fix truncated status strings
Browse files Browse the repository at this point in the history
Avoid returning a truncated table or status string instead of setting
the DM_BUFFER_FULL_FLAG when the last target of a table fills the
buffer.

When processing a table or status request, the function retrieve_status
calls ti->type->status. If ti->type->status returns non-zero,
retrieve_status assumes that the buffer overflowed and sets
DM_BUFFER_FULL_FLAG.

However, targets don't return non-zero values from their status method
on overflow. Most targets returns always zero.

If a buffer overflow happens in a target that is not the last in the
table, it gets noticed during the next iteration of the loop in
retrieve_status; but if a buffer overflow happens in the last target, it
goes unnoticed and erroneously truncated data is returned.

In the current code, the targets behave in the following way:
* dm-crypt returns -ENOMEM if there is not enough space to store the
  key, but it returns 0 on all other overflows.
* dm-thin returns errors from the status method if a disk error happened.
  This is incorrect because retrieve_status doesn't check the error
  code, it assumes that all non-zero values mean buffer overflow.
* all the other targets always return 0.

This patch changes the ti->type->status function to return void (because
most targets don't use the return code). Overflow is detected in
retrieve_status: if the status method fills up the remaining space
completely, it is assumed that buffer overflow happened.

Cc: stable@vger.kernel.org
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
  • Loading branch information
Mikulas Patocka authored and Alasdair G Kergon committed Mar 1, 2013
1 parent 16245bd commit fd7c092
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 115 deletions.
39 changes: 9 additions & 30 deletions drivers/md/dm-crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1234,20 +1234,6 @@ static int crypt_decode_key(u8 *key, char *hex, unsigned int size)
return 0;
}

/*
* Encode key into its hex representation
*/
static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
{
unsigned int i;

for (i = 0; i < size; i++) {
sprintf(hex, "%02x", *key);
hex += 2;
key++;
}
}

static void crypt_free_tfms(struct crypt_config *cc)
{
unsigned i;
Expand Down Expand Up @@ -1717,11 +1703,11 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_SUBMITTED;
}

static int crypt_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void crypt_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct crypt_config *cc = ti->private;
unsigned int sz = 0;
unsigned i, sz = 0;

switch (type) {
case STATUSTYPE_INFO:
Expand All @@ -1731,17 +1717,11 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
case STATUSTYPE_TABLE:
DMEMIT("%s ", cc->cipher_string);

if (cc->key_size > 0) {
if ((maxlen - sz) < ((cc->key_size << 1) + 1))
return -ENOMEM;

crypt_encode_key(result + sz, cc->key, cc->key_size);
sz += cc->key_size << 1;
} else {
if (sz >= maxlen)
return -ENOMEM;
result[sz++] = '-';
}
if (cc->key_size > 0)
for (i = 0; i < cc->key_size; i++)
DMEMIT("%02x", cc->key[i]);
else
DMEMIT("-");

DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
cc->dev->name, (unsigned long long)cc->start);
Expand All @@ -1751,7 +1731,6 @@ static int crypt_status(struct dm_target *ti, status_type_t type,

break;
}
return 0;
}

static void crypt_postsuspend(struct dm_target *ti)
Expand Down Expand Up @@ -1845,7 +1824,7 @@ static int crypt_iterate_devices(struct dm_target *ti,

static struct target_type crypt_target = {
.name = "crypt",
.version = {1, 12, 0},
.version = {1, 12, 1},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
Expand Down
8 changes: 3 additions & 5 deletions drivers/md/dm-delay.c
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ static int delay_map(struct dm_target *ti, struct bio *bio)
return delay_bio(dc, dc->read_delay, bio);
}

static int delay_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void delay_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct delay_c *dc = ti->private;
int sz = 0;
Expand All @@ -314,8 +314,6 @@ static int delay_status(struct dm_target *ti, status_type_t type,
dc->write_delay);
break;
}

return 0;
}

static int delay_iterate_devices(struct dm_target *ti,
Expand All @@ -337,7 +335,7 @@ static int delay_iterate_devices(struct dm_target *ti,

static struct target_type delay_target = {
.name = "delay",
.version = {1, 2, 0},
.version = {1, 2, 1},
.module = THIS_MODULE,
.ctr = delay_ctr,
.dtr = delay_dtr,
Expand Down
7 changes: 3 additions & 4 deletions drivers/md/dm-flakey.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,8 @@ static int flakey_end_io(struct dm_target *ti, struct bio *bio, int error)
return error;
}

static int flakey_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void flakey_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
unsigned sz = 0;
struct flakey_c *fc = ti->private;
Expand Down Expand Up @@ -368,7 +368,6 @@ static int flakey_status(struct dm_target *ti, status_type_t type,

break;
}
return 0;
}

static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg)
Expand Down Expand Up @@ -411,7 +410,7 @@ static int flakey_iterate_devices(struct dm_target *ti, iterate_devices_callout_

static struct target_type flakey_target = {
.name = "flakey",
.version = {1, 3, 0},
.version = {1, 3, 1},
.module = THIS_MODULE,
.ctr = flakey_ctr,
.dtr = flakey_dtr,
Expand Down
14 changes: 9 additions & 5 deletions drivers/md/dm-ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@ static void retrieve_status(struct dm_table *table,
num_targets = dm_table_get_num_targets(table);
for (i = 0; i < num_targets; i++) {
struct dm_target *ti = dm_table_get_target(table, i);
size_t l;

remaining = len - (outptr - outbuf);
if (remaining <= sizeof(struct dm_target_spec)) {
Expand All @@ -1093,14 +1094,17 @@ static void retrieve_status(struct dm_table *table,
if (ti->type->status) {
if (param->flags & DM_NOFLUSH_FLAG)
status_flags |= DM_STATUS_NOFLUSH_FLAG;
if (ti->type->status(ti, type, status_flags, outptr, remaining)) {
param->flags |= DM_BUFFER_FULL_FLAG;
break;
}
ti->type->status(ti, type, status_flags, outptr, remaining);
} else
outptr[0] = '\0';

outptr += strlen(outptr) + 1;
l = strlen(outptr) + 1;
if (l == remaining) {
param->flags |= DM_BUFFER_FULL_FLAG;
break;
}

outptr += l;
used = param->data_start + (outptr - outbuf);

outptr = align_ptr(outptr);
Expand Down
7 changes: 3 additions & 4 deletions drivers/md/dm-linear.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ static int linear_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_REMAPPED;
}

static int linear_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void linear_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct linear_c *lc = (struct linear_c *) ti->private;

Expand All @@ -110,7 +110,6 @@ static int linear_status(struct dm_target *ti, status_type_t type,
(unsigned long long)lc->start);
break;
}
return 0;
}

static int linear_ioctl(struct dm_target *ti, unsigned int cmd,
Expand Down Expand Up @@ -155,7 +154,7 @@ static int linear_iterate_devices(struct dm_target *ti,

static struct target_type linear_target = {
.name = "linear",
.version = {1, 2, 0},
.version = {1, 2, 1},
.module = THIS_MODULE,
.ctr = linear_ctr,
.dtr = linear_dtr,
Expand Down
8 changes: 3 additions & 5 deletions drivers/md/dm-mpath.c
Original file line number Diff line number Diff line change
Expand Up @@ -1378,8 +1378,8 @@ static void multipath_resume(struct dm_target *ti)
* [priority selector-name num_ps_args [ps_args]*
* num_paths num_selector_args [path_dev [selector_args]* ]+ ]+
*/
static int multipath_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void multipath_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
int sz = 0;
unsigned long flags;
Expand Down Expand Up @@ -1485,8 +1485,6 @@ static int multipath_status(struct dm_target *ti, status_type_t type,
}

spin_unlock_irqrestore(&m->lock, flags);

return 0;
}

static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
Expand Down Expand Up @@ -1695,7 +1693,7 @@ static int multipath_busy(struct dm_target *ti)
*---------------------------------------------------------------*/
static struct target_type multipath_target = {
.name = "multipath",
.version = {1, 5, 0},
.version = {1, 5, 1},
.module = THIS_MODULE,
.ctr = multipath_ctr,
.dtr = multipath_dtr,
Expand Down
8 changes: 3 additions & 5 deletions drivers/md/dm-raid.c
Original file line number Diff line number Diff line change
Expand Up @@ -1201,8 +1201,8 @@ static int raid_map(struct dm_target *ti, struct bio *bio)
return DM_MAPIO_SUBMITTED;
}

static int raid_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void raid_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct raid_set *rs = ti->private;
unsigned raid_param_cnt = 1; /* at least 1 for chunksize */
Expand Down Expand Up @@ -1344,8 +1344,6 @@ static int raid_status(struct dm_target *ti, status_type_t type,
DMEMIT(" -");
}
}

return 0;
}

static int raid_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data)
Expand Down Expand Up @@ -1405,7 +1403,7 @@ static void raid_resume(struct dm_target *ti)

static struct target_type raid_target = {
.name = "raid",
.version = {1, 4, 1},
.version = {1, 4, 2},
.module = THIS_MODULE,
.ctr = raid_ctr,
.dtr = raid_dtr,
Expand Down
8 changes: 3 additions & 5 deletions drivers/md/dm-raid1.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,8 +1347,8 @@ static char device_status_char(struct mirror *m)
}


static int mirror_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void mirror_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
unsigned int m, sz = 0;
struct mirror_set *ms = (struct mirror_set *) ti->private;
Expand Down Expand Up @@ -1383,8 +1383,6 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
if (ms->features & DM_RAID1_HANDLE_ERRORS)
DMEMIT(" 1 handle_errors");
}

return 0;
}

static int mirror_iterate_devices(struct dm_target *ti,
Expand All @@ -1403,7 +1401,7 @@ static int mirror_iterate_devices(struct dm_target *ti,

static struct target_type mirror_target = {
.name = "mirror",
.version = {1, 13, 1},
.version = {1, 13, 2},
.module = THIS_MODULE,
.ctr = mirror_ctr,
.dtr = mirror_dtr,
Expand Down
16 changes: 6 additions & 10 deletions drivers/md/dm-snap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1836,8 +1836,8 @@ static void snapshot_merge_resume(struct dm_target *ti)
start_merge(s);
}

static int snapshot_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void snapshot_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
unsigned sz = 0;
struct dm_snapshot *snap = ti->private;
Expand Down Expand Up @@ -1883,8 +1883,6 @@ static int snapshot_status(struct dm_target *ti, status_type_t type,
maxlen - sz);
break;
}

return 0;
}

static int snapshot_iterate_devices(struct dm_target *ti,
Expand Down Expand Up @@ -2138,8 +2136,8 @@ static void origin_resume(struct dm_target *ti)
ti->max_io_len = get_origin_minimum_chunksize(dev->bdev);
}

static int origin_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void origin_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct dm_dev *dev = ti->private;

Expand All @@ -2152,8 +2150,6 @@ static int origin_status(struct dm_target *ti, status_type_t type,
snprintf(result, maxlen, "%s", dev->name);
break;
}

return 0;
}

static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
Expand All @@ -2180,7 +2176,7 @@ static int origin_iterate_devices(struct dm_target *ti,

static struct target_type origin_target = {
.name = "snapshot-origin",
.version = {1, 8, 0},
.version = {1, 8, 1},
.module = THIS_MODULE,
.ctr = origin_ctr,
.dtr = origin_dtr,
Expand All @@ -2193,7 +2189,7 @@ static struct target_type origin_target = {

static struct target_type snapshot_target = {
.name = "snapshot",
.version = {1, 11, 0},
.version = {1, 11, 1},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
Expand Down
7 changes: 3 additions & 4 deletions drivers/md/dm-stripe.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
*
*/

static int stripe_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
static void stripe_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct stripe_c *sc = (struct stripe_c *) ti->private;
char buffer[sc->stripes + 1];
Expand All @@ -340,7 +340,6 @@ static int stripe_status(struct dm_target *ti, status_type_t type,
(unsigned long long)sc->stripe[i].physical_start);
break;
}
return 0;
}

static int stripe_end_io(struct dm_target *ti, struct bio *bio, int error)
Expand Down Expand Up @@ -428,7 +427,7 @@ static int stripe_merge(struct dm_target *ti, struct bvec_merge_data *bvm,

static struct target_type stripe_target = {
.name = "striped",
.version = {1, 5, 0},
.version = {1, 5, 1},
.module = THIS_MODULE,
.ctr = stripe_ctr,
.dtr = stripe_dtr,
Expand Down
Loading

0 comments on commit fd7c092

Please sign in to comment.