lkml.org 
[lkml]   [2013]   [Mar]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 022/100] dm: fix truncated status strings
    Date
    3.8-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Mikulas Patocka <mpatocka@redhat.com>

    commit fd7c092e711ebab55b2688d3859d95dfd0301f73 upstream.

    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.

    Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
    Signed-off-by: Alasdair G Kergon <agk@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/md/dm-crypt.c | 39 ++++---------------
    drivers/md/dm-delay.c | 8 +---
    drivers/md/dm-flakey.c | 7 +--
    drivers/md/dm-ioctl.c | 14 ++++---
    drivers/md/dm-linear.c | 7 +--
    drivers/md/dm-mpath.c | 8 +---
    drivers/md/dm-raid.c | 8 +---
    drivers/md/dm-raid1.c | 8 +---
    drivers/md/dm-snap.c | 16 +++-----
    drivers/md/dm-stripe.c | 7 +--
    drivers/md/dm-thin.c | 82 +++++++++++++++++++++++++-----------------
    drivers/md/dm-verity.c | 8 +---
    include/linux/device-mapper.h | 4 +-
    13 files changed, 100 insertions(+), 116 deletions(-)

    --- a/drivers/md/dm-crypt.c
    +++ b/drivers/md/dm-crypt.c
    @@ -1234,20 +1234,6 @@ static int crypt_decode_key(u8 *key, cha
    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;
    @@ -1717,11 +1703,11 @@ static int crypt_map(struct dm_target *t
    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:
    @@ -1731,17 +1717,11 @@ static int crypt_status(struct dm_target
    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);
    @@ -1751,7 +1731,6 @@ static int crypt_status(struct dm_target

    break;
    }
    - return 0;
    }

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

    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,
    --- a/drivers/md/dm-delay.c
    +++ b/drivers/md/dm-delay.c
    @@ -293,8 +293,8 @@ static int delay_map(struct dm_target *t
    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;
    @@ -314,8 +314,6 @@ static int delay_status(struct dm_target
    dc->write_delay);
    break;
    }
    -
    - return 0;
    }

    static int delay_iterate_devices(struct dm_target *ti,
    @@ -337,7 +335,7 @@ out:

    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,
    --- a/drivers/md/dm-flakey.c
    +++ b/drivers/md/dm-flakey.c
    @@ -337,8 +337,8 @@ static int flakey_end_io(struct dm_targe
    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;
    @@ -368,7 +368,6 @@ static int flakey_status(struct dm_targe

    break;
    }
    - return 0;
    }

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

    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,
    --- a/drivers/md/dm-ioctl.c
    +++ b/drivers/md/dm-ioctl.c
    @@ -1067,6 +1067,7 @@ static void retrieve_status(struct dm_ta
    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)) {
    @@ -1093,14 +1094,17 @@ static void retrieve_status(struct dm_ta
    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);
    --- a/drivers/md/dm-linear.c
    +++ b/drivers/md/dm-linear.c
    @@ -95,8 +95,8 @@ static int linear_map(struct dm_target *
    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;

    @@ -110,7 +110,6 @@ static int linear_status(struct dm_targe
    (unsigned long long)lc->start);
    break;
    }
    - return 0;
    }

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

    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,
    --- a/drivers/md/dm-mpath.c
    +++ b/drivers/md/dm-mpath.c
    @@ -1378,8 +1378,8 @@ static void multipath_resume(struct dm_t
    * [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;
    @@ -1485,8 +1485,6 @@ static int multipath_status(struct dm_ta
    }

    spin_unlock_irqrestore(&m->lock, flags);
    -
    - return 0;
    }

    static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
    @@ -1695,7 +1693,7 @@ out:
    *---------------------------------------------------------------*/
    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,
    --- a/drivers/md/dm-raid.c
    +++ b/drivers/md/dm-raid.c
    @@ -1201,8 +1201,8 @@ static int raid_map(struct dm_target *ti
    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 */
    @@ -1344,8 +1344,6 @@ static int raid_status(struct dm_target
    DMEMIT(" -");
    }
    }
    -
    - return 0;
    }

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

    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,
    --- a/drivers/md/dm-raid1.c
    +++ b/drivers/md/dm-raid1.c
    @@ -1347,8 +1347,8 @@ static char device_status_char(struct mi
    }


    -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;
    @@ -1383,8 +1383,6 @@ static int mirror_status(struct dm_targe
    if (ms->features & DM_RAID1_HANDLE_ERRORS)
    DMEMIT(" 1 handle_errors");
    }
    -
    - return 0;
    }

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

    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,
    --- a/drivers/md/dm-snap.c
    +++ b/drivers/md/dm-snap.c
    @@ -1837,8 +1837,8 @@ static void snapshot_merge_resume(struct
    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;
    @@ -1884,8 +1884,6 @@ static int snapshot_status(struct dm_tar
    maxlen - sz);
    break;
    }
    -
    - return 0;
    }

    static int snapshot_iterate_devices(struct dm_target *ti,
    @@ -2139,8 +2137,8 @@ static void origin_resume(struct dm_targ
    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;

    @@ -2153,8 +2151,6 @@ static int origin_status(struct dm_targe
    snprintf(result, maxlen, "%s", dev->name);
    break;
    }
    -
    - return 0;
    }

    static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
    @@ -2181,7 +2177,7 @@ static int origin_iterate_devices(struct

    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,
    @@ -2194,7 +2190,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,
    --- a/drivers/md/dm-stripe.c
    +++ b/drivers/md/dm-stripe.c
    @@ -312,8 +312,8 @@ static int stripe_map(struct dm_target *
    *
    */

    -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];
    @@ -340,7 +340,6 @@ static int stripe_status(struct dm_targe
    (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)
    @@ -428,7 +427,7 @@ static int stripe_merge(struct dm_target

    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,
    --- a/drivers/md/dm-thin.c
    +++ b/drivers/md/dm-thin.c
    @@ -2299,8 +2299,8 @@ static void emit_flags(struct pool_featu
    * <transaction id> <used metadata sectors>/<total metadata sectors>
    * <used data sectors>/<total data sectors> <held metadata root>
    */
    -static int pool_status(struct dm_target *ti, status_type_t type,
    - unsigned status_flags, char *result, unsigned maxlen)
    +static void pool_status(struct dm_target *ti, status_type_t type,
    + unsigned status_flags, char *result, unsigned maxlen)
    {
    int r;
    unsigned sz = 0;
    @@ -2326,32 +2326,41 @@ static int pool_status(struct dm_target
    if (!(status_flags & DM_STATUS_NOFLUSH_FLAG) && !dm_suspended(ti))
    (void) commit_or_fallback(pool);

    - r = dm_pool_get_metadata_transaction_id(pool->pmd,
    - &transaction_id);
    - if (r)
    - return r;
    -
    - r = dm_pool_get_free_metadata_block_count(pool->pmd,
    - &nr_free_blocks_metadata);
    - if (r)
    - return r;
    + r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id);
    + if (r) {
    + DMERR("dm_pool_get_metadata_transaction_id returned %d", r);
    + goto err;
    + }
    +
    + r = dm_pool_get_free_metadata_block_count(pool->pmd, &nr_free_blocks_metadata);
    + if (r) {
    + DMERR("dm_pool_get_free_metadata_block_count returned %d", r);
    + goto err;
    + }

    r = dm_pool_get_metadata_dev_size(pool->pmd, &nr_blocks_metadata);
    - if (r)
    - return r;
    + if (r) {
    + DMERR("dm_pool_get_metadata_dev_size returned %d", r);
    + goto err;
    + }

    - r = dm_pool_get_free_block_count(pool->pmd,
    - &nr_free_blocks_data);
    - if (r)
    - return r;
    + r = dm_pool_get_free_block_count(pool->pmd, &nr_free_blocks_data);
    + if (r) {
    + DMERR("dm_pool_get_free_block_count returned %d", r);
    + goto err;
    + }

    r = dm_pool_get_data_dev_size(pool->pmd, &nr_blocks_data);
    - if (r)
    - return r;
    + if (r) {
    + DMERR("dm_pool_get_data_dev_size returned %d", r);
    + goto err;
    + }

    r = dm_pool_get_metadata_snap(pool->pmd, &held_root);
    - if (r)
    - return r;
    + if (r) {
    + DMERR("dm_pool_get_metadata_snap returned %d", r);
    + goto err;
    + }

    DMEMIT("%llu %llu/%llu %llu/%llu ",
    (unsigned long long)transaction_id,
    @@ -2388,8 +2397,10 @@ static int pool_status(struct dm_target
    emit_flags(&pt->requested_pf, result, sz, maxlen);
    break;
    }
    + return;

    - return 0;
    +err:
    + DMEMIT("Error");
    }

    static int pool_iterate_devices(struct dm_target *ti,
    @@ -2468,7 +2479,7 @@ static struct target_type pool_target =
    .name = "thin-pool",
    .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
    DM_TARGET_IMMUTABLE,
    - .version = {1, 6, 0},
    + .version = {1, 6, 1},
    .module = THIS_MODULE,
    .ctr = pool_ctr,
    .dtr = pool_dtr,
    @@ -2676,8 +2687,8 @@ static void thin_postsuspend(struct dm_t
    /*
    * <nr mapped sectors> <highest mapped sector>
    */
    -static int thin_status(struct dm_target *ti, status_type_t type,
    - unsigned status_flags, char *result, unsigned maxlen)
    +static void thin_status(struct dm_target *ti, status_type_t type,
    + unsigned status_flags, char *result, unsigned maxlen)
    {
    int r;
    ssize_t sz = 0;
    @@ -2687,7 +2698,7 @@ static int thin_status(struct dm_target

    if (get_pool_mode(tc->pool) == PM_FAIL) {
    DMEMIT("Fail");
    - return 0;
    + return;
    }

    if (!tc->td)
    @@ -2696,12 +2707,16 @@ static int thin_status(struct dm_target
    switch (type) {
    case STATUSTYPE_INFO:
    r = dm_thin_get_mapped_count(tc->td, &mapped);
    - if (r)
    - return r;
    + if (r) {
    + DMERR("dm_thin_get_mapped_count returned %d", r);
    + goto err;
    + }

    r = dm_thin_get_highest_mapped_block(tc->td, &highest);
    - if (r < 0)
    - return r;
    + if (r < 0) {
    + DMERR("dm_thin_get_highest_mapped_block returned %d", r);
    + goto err;
    + }

    DMEMIT("%llu ", mapped * tc->pool->sectors_per_block);
    if (r)
    @@ -2721,7 +2736,10 @@ static int thin_status(struct dm_target
    }
    }

    - return 0;
    + return;
    +
    +err:
    + DMEMIT("Error");
    }

    static int thin_iterate_devices(struct dm_target *ti,
    @@ -2748,7 +2766,7 @@ static int thin_iterate_devices(struct d

    static struct target_type thin_target = {
    .name = "thin",
    - .version = {1, 7, 0},
    + .version = {1, 7, 1},
    .module = THIS_MODULE,
    .ctr = thin_ctr,
    .dtr = thin_dtr,
    --- a/drivers/md/dm-verity.c
    +++ b/drivers/md/dm-verity.c
    @@ -508,8 +508,8 @@ static int verity_map(struct dm_target *
    /*
    * Status: V (valid) or C (corruption found)
    */
    -static int verity_status(struct dm_target *ti, status_type_t type,
    - unsigned status_flags, char *result, unsigned maxlen)
    +static void verity_status(struct dm_target *ti, status_type_t type,
    + unsigned status_flags, char *result, unsigned maxlen)
    {
    struct dm_verity *v = ti->private;
    unsigned sz = 0;
    @@ -540,8 +540,6 @@ static int verity_status(struct dm_targe
    DMEMIT("%02x", v->salt[x]);
    break;
    }
    -
    - return 0;
    }

    static int verity_ioctl(struct dm_target *ti, unsigned cmd,
    @@ -860,7 +858,7 @@ bad:

    static struct target_type verity_target = {
    .name = "verity",
    - .version = {1, 1, 0},
    + .version = {1, 1, 1},
    .module = THIS_MODULE,
    .ctr = verity_ctr,
    .dtr = verity_dtr,
    --- a/include/linux/device-mapper.h
    +++ b/include/linux/device-mapper.h
    @@ -68,8 +68,8 @@ typedef void (*dm_postsuspend_fn) (struc
    typedef int (*dm_preresume_fn) (struct dm_target *ti);
    typedef void (*dm_resume_fn) (struct dm_target *ti);

    -typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
    - unsigned status_flags, char *result, unsigned maxlen);
    +typedef void (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
    + unsigned status_flags, char *result, unsigned maxlen);

    typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);




    \
     
     \ /
      Last update: 2013-03-13 00:41    [W:4.349 / U:0.500 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site