From: Greg Kroah-Hartman Date: Fri, 6 Dec 2013 19:40:51 +0000 (-0800) Subject: 3.4-stable patches X-Git-Tag: v3.4.73~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4dd94005364eee3cb7fa19271d105f7094d6750e;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: blk-core-fix-memory-corruption-if-blkcg_init_queue-fails.patch dm-fix-truncated-status-strings.patch --- diff --git a/queue-3.4/blk-core-fix-memory-corruption-if-blkcg_init_queue-fails.patch b/queue-3.4/blk-core-fix-memory-corruption-if-blkcg_init_queue-fails.patch new file mode 100644 index 00000000000..9f8c6fb2638 --- /dev/null +++ b/queue-3.4/blk-core-fix-memory-corruption-if-blkcg_init_queue-fails.patch @@ -0,0 +1,80 @@ +From fff4996b7db7955414ac74386efa5e07fd766b50 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 14 Oct 2013 12:11:36 -0400 +Subject: blk-core: Fix memory corruption if blkcg_init_queue fails + +From: Mikulas Patocka + +commit fff4996b7db7955414ac74386efa5e07fd766b50 upstream. + +If blkcg_init_queue fails, blk_alloc_queue_node doesn't call bdi_destroy +to clean up structures allocated by the backing dev. + +------------[ cut here ]------------ +WARNING: at lib/debugobjects.c:260 debug_print_object+0x85/0xa0() +ODEBUG: free active (active state 0) object type: percpu_counter hint: (null) +Modules linked in: dm_loop dm_mod ip6table_filter ip6_tables uvesafb cfbcopyarea cfbimgblt cfbfillrect fbcon font bitblit fbcon_rotate fbcon_cw fbcon_ud fbcon_ccw softcursor fb fbdev ipt_MASQUERADE iptable_nat nf_nat_ipv4 msr nf_conntrack_ipv4 nf_defrag_ipv4 xt_state ipt_REJECT xt_tcpudp iptable_filter ip_tables x_tables bridge stp llc tun ipv6 cpufreq_userspace cpufreq_stats cpufreq_powersave cpufreq_ondemand cpufreq_conservative spadfs fuse hid_generic usbhid hid raid0 md_mod dmi_sysfs nf_nat_ftp nf_nat nf_conntrack_ftp nf_conntrack lm85 hwmon_vid snd_usb_audio snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_page_alloc snd_hwdep snd_usbmidi_lib snd_rawmidi snd soundcore acpi_cpufreq freq_table mperf sata_svw serverworks kvm_amd ide_core ehci_pci ohci_hcd libata ehci_hcd kvm usbcore tg3 usb_common libphy k10temp pcspkr ptp i2c_piix4 i2c_core evdev microcode hwmon rtc_cmos pps_core e100 skge floppy mii processor button unix +CPU: 0 PID: 2739 Comm: lvchange Tainted: G W +3.10.15-devel #14 +Hardware name: empty empty/S3992-E, BIOS 'V1.06 ' 06/09/2009 + 0000000000000009 ffff88023c3c1ae8 ffffffff813c8fd4 ffff88023c3c1b20 + ffffffff810399eb ffff88043d35cd58 ffffffff81651940 ffff88023c3c1bf8 + ffffffff82479d90 0000000000000005 ffff88023c3c1b80 ffffffff81039a67 +Call Trace: + [] dump_stack+0x19/0x1b + [] warn_slowpath_common+0x6b/0xa0 + [] warn_slowpath_fmt+0x47/0x50 + [] ? debug_check_no_obj_freed+0xcf/0x250 + [] debug_print_object+0x85/0xa0 + [] debug_check_no_obj_freed+0x203/0x250 + [] kmem_cache_free+0x20c/0x3a0 + [] blk_alloc_queue_node+0x2a9/0x2c0 + [] blk_alloc_queue+0xe/0x10 + [] dm_create+0x1a3/0x530 [dm_mod] + [] ? list_version_get_info+0xe0/0xe0 [dm_mod] + [] dev_create+0x57/0x2b0 [dm_mod] + [] ? list_version_get_info+0xe0/0xe0 [dm_mod] + [] ? list_version_get_info+0xe0/0xe0 [dm_mod] + [] ctl_ioctl+0x268/0x500 [dm_mod] + [] ? get_lock_stats+0x22/0x70 + [] dm_ctl_ioctl+0xe/0x20 [dm_mod] + [] do_vfs_ioctl+0x2ed/0x520 + [] ? fget_light+0x377/0x4e0 + [] SyS_ioctl+0x4b/0x90 + [] system_call_fastpath+0x1a/0x1f +---[ end trace 4b5ff0d55673d986 ]--- +------------[ cut here ]------------ + +This fix should be backported to stable kernels starting with 2.6.37. Note +that in the kernels prior to 3.5 the affected code is different, but the +bug is still there - bdi_init is called and bdi_destroy isn't. + +Signed-off-by: Mikulas Patocka +Acked-by: Tejun Heo +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman + +--- + block/blk-core.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/block/blk-core.c ++++ b/block/blk-core.c +@@ -499,7 +499,7 @@ struct request_queue *blk_alloc_queue_no + goto fail_id; + + if (blk_throtl_init(q)) +- goto fail_id; ++ goto fail_bdi; + + setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, + laptop_mode_timer_fn, (unsigned long) q); +@@ -524,6 +524,8 @@ struct request_queue *blk_alloc_queue_no + + return q; + ++fail_bdi: ++ bdi_destroy(&q->backing_dev_info); + fail_id: + ida_simple_remove(&blk_queue_ida, q->id); + fail_q: diff --git a/queue-3.4/dm-fix-truncated-status-strings.patch b/queue-3.4/dm-fix-truncated-status-strings.patch new file mode 100644 index 00000000000..d6c5849308c --- /dev/null +++ b/queue-3.4/dm-fix-truncated-status-strings.patch @@ -0,0 +1,522 @@ +From fd7c092e711ebab55b2688d3859d95dfd0301f73 Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Fri, 1 Mar 2013 22:45:44 +0000 +Subject: dm: fix truncated status strings + +From: Mikulas Patocka + +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 +Signed-off-by: Alasdair G Kergon +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/md/dm-crypt.c | 37 ++++---------------- + drivers/md/dm-delay.c | 6 +-- + drivers/md/dm-flakey.c | 5 +- + drivers/md/dm-ioctl.c | 18 ++++++--- + drivers/md/dm-linear.c | 5 +- + drivers/md/dm-mpath.c | 6 +-- + drivers/md/dm-raid.c | 6 +-- + drivers/md/dm-raid1.c | 6 +-- + drivers/md/dm-snap.c | 12 ++---- + drivers/md/dm-stripe.c | 5 +- + drivers/md/dm-thin.c | 76 +++++++++++++++++++++++++----------------- + drivers/md/dm-verity.c | 6 +-- + include/linux/device-mapper.h | 4 +- + 13 files changed, 88 insertions(+), 104 deletions(-) + +--- a/drivers/md/dm-crypt.c ++++ b/drivers/md/dm-crypt.c +@@ -1262,20 +1262,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, int cpu) + { + struct crypt_cpu *cpu_cc = per_cpu_ptr(cc->cpu, cpu); +@@ -1741,11 +1727,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, +- char *result, unsigned int maxlen) ++static void crypt_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned int maxlen) + { + struct crypt_config *cc = ti->private; +- unsigned int sz = 0; ++ unsigned i, sz = 0; + + switch (type) { + case STATUSTYPE_INFO: +@@ -1755,17 +1741,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); +@@ -1775,7 +1755,6 @@ static int crypt_status(struct dm_target + + break; + } +- return 0; + } + + static void crypt_postsuspend(struct dm_target *ti) +--- a/drivers/md/dm-delay.c ++++ b/drivers/md/dm-delay.c +@@ -294,8 +294,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, +- char *result, unsigned maxlen) ++static void delay_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned maxlen) + { + struct delay_c *dc = ti->private; + int sz = 0; +@@ -315,8 +315,6 @@ static int delay_status(struct dm_target + dc->write_delay); + break; + } +- +- return 0; + } + + static int delay_iterate_devices(struct dm_target *ti, +--- a/drivers/md/dm-flakey.c ++++ b/drivers/md/dm-flakey.c +@@ -332,8 +332,8 @@ static int flakey_end_io(struct dm_targe + return error; + } + +-static int flakey_status(struct dm_target *ti, status_type_t type, +- char *result, unsigned int maxlen) ++static void flakey_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned int maxlen) + { + unsigned sz = 0; + struct flakey_c *fc = ti->private; +@@ -363,7 +363,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) +--- a/drivers/md/dm-ioctl.c ++++ b/drivers/md/dm-ioctl.c +@@ -1066,6 +1066,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)) { +@@ -1089,15 +1090,18 @@ static void retrieve_status(struct dm_ta + } + + /* Get the status/table string from the target driver */ +- if (ti->type->status) { +- if (ti->type->status(ti, type, outptr, remaining)) { +- param->flags |= DM_BUFFER_FULL_FLAG; +- break; +- } +- } else ++ if (ti->type->status) ++ ti->type->status(ti, type, 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, +- char *result, unsigned int maxlen) ++static void linear_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned int 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, +--- a/drivers/md/dm-mpath.c ++++ b/drivers/md/dm-mpath.c +@@ -1343,8 +1343,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, +- char *result, unsigned int maxlen) ++static void multipath_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned int maxlen) + { + int sz = 0; + unsigned long flags; +@@ -1447,8 +1447,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) +--- a/drivers/md/dm-raid.c ++++ b/drivers/md/dm-raid.c +@@ -1067,8 +1067,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, +- char *result, unsigned maxlen) ++static void raid_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned maxlen) + { + struct raid_set *rs = ti->private; + unsigned raid_param_cnt = 1; /* at least 1 for chunksize */ +@@ -1203,8 +1203,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) +--- a/drivers/md/dm-raid1.c ++++ b/drivers/md/dm-raid1.c +@@ -1362,8 +1362,8 @@ static char device_status_char(struct mi + } + + +-static int mirror_status(struct dm_target *ti, status_type_t type, +- char *result, unsigned int maxlen) ++static void mirror_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned int maxlen) + { + unsigned int m, sz = 0; + struct mirror_set *ms = (struct mirror_set *) ti->private; +@@ -1398,8 +1398,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, +--- a/drivers/md/dm-snap.c ++++ b/drivers/md/dm-snap.c +@@ -1845,8 +1845,8 @@ static void snapshot_merge_resume(struct + start_merge(s); + } + +-static int snapshot_status(struct dm_target *ti, status_type_t type, +- char *result, unsigned int maxlen) ++static void snapshot_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned int maxlen) + { + unsigned sz = 0; + struct dm_snapshot *snap = ti->private; +@@ -1892,8 +1892,6 @@ static int snapshot_status(struct dm_tar + maxlen - sz); + break; + } +- +- return 0; + } + + static int snapshot_iterate_devices(struct dm_target *ti, +@@ -2148,8 +2146,8 @@ static void origin_resume(struct dm_targ + ti->split_io = get_origin_minimum_chunksize(dev->bdev); + } + +-static int origin_status(struct dm_target *ti, status_type_t type, char *result, +- unsigned int maxlen) ++static void origin_status(struct dm_target *ti, status_type_t type, char *result, ++ unsigned int maxlen) + { + struct dm_dev *dev = ti->private; + +@@ -2162,8 +2160,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, +--- a/drivers/md/dm-stripe.c ++++ b/drivers/md/dm-stripe.c +@@ -302,8 +302,8 @@ static int stripe_map(struct dm_target * + * + */ + +-static int stripe_status(struct dm_target *ti, +- status_type_t type, char *result, unsigned int maxlen) ++static void stripe_status(struct dm_target *ti, ++ status_type_t type, char *result, unsigned int maxlen) + { + struct stripe_c *sc = (struct stripe_c *) ti->private; + char buffer[sc->stripes + 1]; +@@ -330,7 +330,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, +--- a/drivers/md/dm-thin.c ++++ b/drivers/md/dm-thin.c +@@ -2325,8 +2325,8 @@ static int pool_message(struct dm_target + * / + * / + */ +-static int pool_status(struct dm_target *ti, status_type_t type, +- char *result, unsigned maxlen) ++static void pool_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned maxlen) + { + int r, count; + unsigned sz = 0; +@@ -2343,32 +2343,41 @@ static int pool_status(struct dm_target + + switch (type) { + case STATUSTYPE_INFO: +- 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_held_metadata_root(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, +@@ -2406,8 +2415,10 @@ static int pool_status(struct dm_target + + break; + } ++ return; + +- return 0; ++err: ++ DMEMIT("Error"); + } + + static int pool_iterate_devices(struct dm_target *ti, +@@ -2659,8 +2670,8 @@ static void thin_postsuspend(struct dm_t + /* + * + */ +-static int thin_status(struct dm_target *ti, status_type_t type, +- char *result, unsigned maxlen) ++static void thin_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned maxlen) + { + int r; + ssize_t sz = 0; +@@ -2674,12 +2685,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) +@@ -2699,7 +2714,10 @@ static int thin_status(struct dm_target + } + } + +- return 0; ++ return; ++ ++err: ++ DMEMIT("Error"); + } + + static int thin_iterate_devices(struct dm_target *ti, +--- a/drivers/md/dm-verity.c ++++ b/drivers/md/dm-verity.c +@@ -514,8 +514,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, +- char *result, unsigned maxlen) ++static void verity_status(struct dm_target *ti, status_type_t type, ++ char *result, unsigned maxlen) + { + struct dm_verity *v = ti->private; + unsigned sz = 0; +@@ -546,8 +546,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, +--- a/include/linux/device-mapper.h ++++ b/include/linux/device-mapper.h +@@ -72,8 +72,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, +- char *result, unsigned int maxlen); ++typedef void (*dm_status_fn) (struct dm_target *ti, status_type_t status_type, ++ char *result, unsigned int maxlen); + + typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv); + diff --git a/queue-3.4/series b/queue-3.4/series index de8a20a81f3..2ff4c0e6850 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -28,3 +28,5 @@ nfsd-use-init_net-for-portmapper.patch video-kyro-fix-incorrect-sizes-when-copying-to-userspace.patch iommu-vt-d-fixed-interaction-of-vfio_iommu_map_dma-with-iommu-address-limits.patch elevator-acquire-q-sysfs_lock-in-elevator_change.patch +dm-fix-truncated-status-strings.patch +blk-core-fix-memory-corruption-if-blkcg_init_queue-fails.patch