From: Greg Kroah-Hartman Date: Fri, 28 Apr 2017 08:00:36 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v4.4.65~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c7d771e8dd5d2d9093e253fd0c8f8c93adef5634;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: mnt-add-a-per-mount-namespace-limit-on-the-number-of-mounts.patch netfilter-nfnetlink-correctly-validate-length-of-batch-messages.patch perf-core-fix-concurrent-sys_perf_event_open-vs.-move_group-race.patch ping-implement-proper-locking.patch staging-android-ion-fix-a-race-condition-in-the-ion-driver.patch tipc-check-minimum-bearer-mtu.patch vfio-pci-fix-integer-overflows-bitmask-check.patch xc2028-avoid-use-after-free.patch --- diff --git a/queue-4.4/mnt-add-a-per-mount-namespace-limit-on-the-number-of-mounts.patch b/queue-4.4/mnt-add-a-per-mount-namespace-limit-on-the-number-of-mounts.patch new file mode 100644 index 00000000000..f0c5f35b0a2 --- /dev/null +++ b/queue-4.4/mnt-add-a-per-mount-namespace-limit-on-the-number-of-mounts.patch @@ -0,0 +1,276 @@ +From d29216842a85c7970c536108e093963f02714498 Mon Sep 17 00:00:00 2001 +From: "Eric W. Biederman" +Date: Wed, 28 Sep 2016 00:27:17 -0500 +Subject: mnt: Add a per mount namespace limit on the number of mounts + +From: Eric W. Biederman + +commit d29216842a85c7970c536108e093963f02714498 upstream. + +CAI Qian pointed out that the semantics +of shared subtrees make it possible to create an exponentially +increasing number of mounts in a mount namespace. + + mkdir /tmp/1 /tmp/2 + mount --make-rshared / + for i in $(seq 1 20) ; do mount --bind /tmp/1 /tmp/2 ; done + +Will create create 2^20 or 1048576 mounts, which is a practical problem +as some people have managed to hit this by accident. + +As such CVE-2016-6213 was assigned. + +Ian Kent described the situation for autofs users +as follows: + +> The number of mounts for direct mount maps is usually not very large because of +> the way they are implemented, large direct mount maps can have performance +> problems. There can be anywhere from a few (likely case a few hundred) to less +> than 10000, plus mounts that have been triggered and not yet expired. +> +> Indirect mounts have one autofs mount at the root plus the number of mounts that +> have been triggered and not yet expired. +> +> The number of autofs indirect map entries can range from a few to the common +> case of several thousand and in rare cases up to between 30000 and 50000. I've +> not heard of people with maps larger than 50000 entries. +> +> The larger the number of map entries the greater the possibility for a large +> number of active mounts so it's not hard to expect cases of a 1000 or somewhat +> more active mounts. + +So I am setting the default number of mounts allowed per mount +namespace at 100,000. This is more than enough for any use case I +know of, but small enough to quickly stop an exponential increase +in mounts. Which should be perfect to catch misconfigurations and +malfunctioning programs. + +For anyone who needs a higher limit this can be changed by writing +to the new /proc/sys/fs/mount-max sysctl. + +Tested-by: CAI Qian +Signed-off-by: "Eric W. Biederman" +[bwh: Backported to 4.4: adjust context] +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + Documentation/sysctl/fs.txt | 7 ++++++ + fs/mount.h | 2 + + fs/namespace.c | 50 +++++++++++++++++++++++++++++++++++++++++++- + fs/pnode.c | 2 - + fs/pnode.h | 1 + include/linux/mount.h | 2 + + kernel/sysctl.c | 9 +++++++ + 7 files changed, 71 insertions(+), 2 deletions(-) + +--- a/Documentation/sysctl/fs.txt ++++ b/Documentation/sysctl/fs.txt +@@ -265,6 +265,13 @@ aio-nr can grow to. + + ============================================================== + ++mount-max: ++ ++This denotes the maximum number of mounts that may exist ++in a mount namespace. ++ ++============================================================== ++ + + 2. /proc/sys/fs/binfmt_misc + ---------------------------------------------------------- +--- a/fs/mount.h ++++ b/fs/mount.h +@@ -13,6 +13,8 @@ struct mnt_namespace { + u64 seq; /* Sequence number to prevent loops */ + wait_queue_head_t poll; + u64 event; ++ unsigned int mounts; /* # of mounts in the namespace */ ++ unsigned int pending_mounts; + }; + + struct mnt_pcp { +--- a/fs/namespace.c ++++ b/fs/namespace.c +@@ -27,6 +27,9 @@ + #include "pnode.h" + #include "internal.h" + ++/* Maximum number of mounts in a mount namespace */ ++unsigned int sysctl_mount_max __read_mostly = 100000; ++ + static unsigned int m_hash_mask __read_mostly; + static unsigned int m_hash_shift __read_mostly; + static unsigned int mp_hash_mask __read_mostly; +@@ -925,6 +928,9 @@ static void commit_tree(struct mount *mn + + list_splice(&head, n->list.prev); + ++ n->mounts += n->pending_mounts; ++ n->pending_mounts = 0; ++ + __attach_mnt(mnt, parent); + touch_mnt_namespace(n); + } +@@ -1445,11 +1451,16 @@ static void umount_tree(struct mount *mn + propagate_umount(&tmp_list); + + while (!list_empty(&tmp_list)) { ++ struct mnt_namespace *ns; + bool disconnect; + p = list_first_entry(&tmp_list, struct mount, mnt_list); + list_del_init(&p->mnt_expire); + list_del_init(&p->mnt_list); +- __touch_mnt_namespace(p->mnt_ns); ++ ns = p->mnt_ns; ++ if (ns) { ++ ns->mounts--; ++ __touch_mnt_namespace(ns); ++ } + p->mnt_ns = NULL; + if (how & UMOUNT_SYNC) + p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; +@@ -1850,6 +1861,28 @@ static int invent_group_ids(struct mount + return 0; + } + ++int count_mounts(struct mnt_namespace *ns, struct mount *mnt) ++{ ++ unsigned int max = READ_ONCE(sysctl_mount_max); ++ unsigned int mounts = 0, old, pending, sum; ++ struct mount *p; ++ ++ for (p = mnt; p; p = next_mnt(p, mnt)) ++ mounts++; ++ ++ old = ns->mounts; ++ pending = ns->pending_mounts; ++ sum = old + pending; ++ if ((old > sum) || ++ (pending > sum) || ++ (max < sum) || ++ (mounts > (max - sum))) ++ return -ENOSPC; ++ ++ ns->pending_mounts = pending + mounts; ++ return 0; ++} ++ + /* + * @source_mnt : mount tree to be attached + * @nd : place the mount tree @source_mnt is attached +@@ -1919,6 +1952,7 @@ static int attach_recursive_mnt(struct m + struct path *parent_path) + { + HLIST_HEAD(tree_list); ++ struct mnt_namespace *ns = dest_mnt->mnt_ns; + struct mountpoint *smp; + struct mount *child, *p; + struct hlist_node *n; +@@ -1931,6 +1965,13 @@ static int attach_recursive_mnt(struct m + if (IS_ERR(smp)) + return PTR_ERR(smp); + ++ /* Is there space to add these mounts to the mount namespace? */ ++ if (!parent_path) { ++ err = count_mounts(ns, source_mnt); ++ if (err) ++ goto out; ++ } ++ + if (IS_MNT_SHARED(dest_mnt)) { + err = invent_group_ids(source_mnt, true); + if (err) +@@ -1970,11 +2011,14 @@ static int attach_recursive_mnt(struct m + out_cleanup_ids: + while (!hlist_empty(&tree_list)) { + child = hlist_entry(tree_list.first, struct mount, mnt_hash); ++ child->mnt_parent->mnt_ns->pending_mounts = 0; + umount_tree(child, UMOUNT_SYNC); + } + unlock_mount_hash(); + cleanup_group_ids(source_mnt, NULL); + out: ++ ns->pending_mounts = 0; ++ + read_seqlock_excl(&mount_lock); + put_mountpoint(smp); + read_sequnlock_excl(&mount_lock); +@@ -2804,6 +2848,8 @@ static struct mnt_namespace *alloc_mnt_n + init_waitqueue_head(&new_ns->poll); + new_ns->event = 0; + new_ns->user_ns = get_user_ns(user_ns); ++ new_ns->mounts = 0; ++ new_ns->pending_mounts = 0; + return new_ns; + } + +@@ -2853,6 +2899,7 @@ struct mnt_namespace *copy_mnt_ns(unsign + q = new; + while (p) { + q->mnt_ns = new_ns; ++ new_ns->mounts++; + if (new_fs) { + if (&p->mnt == new_fs->root.mnt) { + new_fs->root.mnt = mntget(&q->mnt); +@@ -2891,6 +2938,7 @@ static struct mnt_namespace *create_mnt_ + struct mount *mnt = real_mount(m); + mnt->mnt_ns = new_ns; + new_ns->root = mnt; ++ new_ns->mounts++; + list_add(&mnt->mnt_list, &new_ns->list); + } else { + mntput(m); +--- a/fs/pnode.c ++++ b/fs/pnode.c +@@ -259,7 +259,7 @@ static int propagate_one(struct mount *m + read_sequnlock_excl(&mount_lock); + } + hlist_add_head(&child->mnt_hash, list); +- return 0; ++ return count_mounts(m->mnt_ns, child); + } + + /* +--- a/fs/pnode.h ++++ b/fs/pnode.h +@@ -54,4 +54,5 @@ void mnt_change_mountpoint(struct mount + struct mount *copy_tree(struct mount *, struct dentry *, int); + bool is_path_reachable(struct mount *, struct dentry *, + const struct path *root); ++int count_mounts(struct mnt_namespace *ns, struct mount *mnt); + #endif /* _LINUX_PNODE_H */ +--- a/include/linux/mount.h ++++ b/include/linux/mount.h +@@ -95,4 +95,6 @@ extern void mark_mounts_for_expiry(struc + + extern dev_t name_to_dev_t(const char *name); + ++extern unsigned int sysctl_mount_max; ++ + #endif /* _LINUX_MOUNT_H */ +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -65,6 +65,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1749,6 +1750,14 @@ static struct ctl_table fs_table[] = { + .mode = 0644, + .proc_handler = proc_doulongvec_minmax, + }, ++ { ++ .procname = "mount-max", ++ .data = &sysctl_mount_max, ++ .maxlen = sizeof(unsigned int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = &one, ++ }, + { } + }; + diff --git a/queue-4.4/netfilter-nfnetlink-correctly-validate-length-of-batch-messages.patch b/queue-4.4/netfilter-nfnetlink-correctly-validate-length-of-batch-messages.patch new file mode 100644 index 00000000000..8be7da7fafb --- /dev/null +++ b/queue-4.4/netfilter-nfnetlink-correctly-validate-length-of-batch-messages.patch @@ -0,0 +1,78 @@ +From c58d6c93680f28ac58984af61d0a7ebf4319c241 Mon Sep 17 00:00:00 2001 +From: Phil Turnbull +Date: Tue, 2 Feb 2016 13:36:45 -0500 +Subject: netfilter: nfnetlink: correctly validate length of batch messages + +From: Phil Turnbull + +commit c58d6c93680f28ac58984af61d0a7ebf4319c241 upstream. + +If nlh->nlmsg_len is zero then an infinite loop is triggered because +'skb_pull(skb, msglen);' pulls zero bytes. + +The calculation in nlmsg_len() underflows if 'nlh->nlmsg_len < +NLMSG_HDRLEN' which bypasses the length validation and will later +trigger an out-of-bound read. + +If the length validation does fail then the malformed batch message is +copied back to userspace. However, we cannot do this because the +nlh->nlmsg_len can be invalid. This leads to an out-of-bounds read in +netlink_ack: + + [ 41.455421] ================================================================== + [ 41.456431] BUG: KASAN: slab-out-of-bounds in memcpy+0x1d/0x40 at addr ffff880119e79340 + [ 41.456431] Read of size 4294967280 by task a.out/987 + [ 41.456431] ============================================================================= + [ 41.456431] BUG kmalloc-512 (Not tainted): kasan: bad access detected + [ 41.456431] ----------------------------------------------------------------------------- + ... + [ 41.456431] Bytes b4 ffff880119e79310: 00 00 00 00 d5 03 00 00 b0 fb fe ff 00 00 00 00 ................ + [ 41.456431] Object ffff880119e79320: 20 00 00 00 10 00 05 00 00 00 00 00 00 00 00 00 ............... + [ 41.456431] Object ffff880119e79330: 14 00 0a 00 01 03 fc 40 45 56 11 22 33 10 00 05 .......@EV."3... + [ 41.456431] Object ffff880119e79340: f0 ff ff ff 88 99 aa bb 00 14 00 0a 00 06 fe fb ................ + ^^ start of batch nlmsg with + nlmsg_len=4294967280 + ... + [ 41.456431] Memory state around the buggy address: + [ 41.456431] ffff880119e79400: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + [ 41.456431] ffff880119e79480: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + [ 41.456431] >ffff880119e79500: 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc fc + [ 41.456431] ^ + [ 41.456431] ffff880119e79580: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc + [ 41.456431] ffff880119e79600: fc fc fc fc fc fc fc fc fc fc fb fb fb fb fb fb + [ 41.456431] ================================================================== + +Fix this with better validation of nlh->nlmsg_len and by setting +NFNL_BATCH_FAILURE if any batch message fails length validation. + +CAP_NET_ADMIN is required to trigger the bugs. + +Fixes: 9ea2aa8b7dba ("netfilter: nfnetlink: validate nfnetlink header from batch") +Signed-off-by: Phil Turnbull +Signed-off-by: Pablo Neira Ayuso +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman + +--- + net/netfilter/nfnetlink.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/net/netfilter/nfnetlink.c ++++ b/net/netfilter/nfnetlink.c +@@ -326,10 +326,12 @@ replay: + nlh = nlmsg_hdr(skb); + err = 0; + +- if (nlmsg_len(nlh) < sizeof(struct nfgenmsg) || +- skb->len < nlh->nlmsg_len) { +- err = -EINVAL; +- goto ack; ++ if (nlh->nlmsg_len < NLMSG_HDRLEN || ++ skb->len < nlh->nlmsg_len || ++ nlmsg_len(nlh) < sizeof(struct nfgenmsg)) { ++ nfnl_err_reset(&err_list); ++ status |= NFNL_BATCH_FAILURE; ++ goto done; + } + + /* Only requests are handled by the kernel */ diff --git a/queue-4.4/perf-core-fix-concurrent-sys_perf_event_open-vs.-move_group-race.patch b/queue-4.4/perf-core-fix-concurrent-sys_perf_event_open-vs.-move_group-race.patch new file mode 100644 index 00000000000..25bac9a658d --- /dev/null +++ b/queue-4.4/perf-core-fix-concurrent-sys_perf_event_open-vs.-move_group-race.patch @@ -0,0 +1,146 @@ +From 321027c1fe77f892f4ea07846aeae08cefbbb290 Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra +Date: Wed, 11 Jan 2017 21:09:50 +0100 +Subject: perf/core: Fix concurrent sys_perf_event_open() vs. 'move_group' race + +From: Peter Zijlstra + +commit 321027c1fe77f892f4ea07846aeae08cefbbb290 upstream. + +Di Shen reported a race between two concurrent sys_perf_event_open() +calls where both try and move the same pre-existing software group +into a hardware context. + +The problem is exactly that described in commit: + + f63a8daa5812 ("perf: Fix event->ctx locking") + +... where, while we wait for a ctx->mutex acquisition, the event->ctx +relation can have changed under us. + +That very same commit failed to recognise sys_perf_event_context() as an +external access vector to the events and thereby didn't apply the +established locking rules correctly. + +So while one sys_perf_event_open() call is stuck waiting on +mutex_lock_double(), the other (which owns said locks) moves the group +about. So by the time the former sys_perf_event_open() acquires the +locks, the context we've acquired is stale (and possibly dead). + +Apply the established locking rules as per perf_event_ctx_lock_nested() +to the mutex_lock_double() for the 'move_group' case. This obviously means +we need to validate state after we acquire the locks. + +Reported-by: Di Shen (Keen Lab) +Tested-by: John Dias +Signed-off-by: Peter Zijlstra (Intel) +Cc: Alexander Shishkin +Cc: Arnaldo Carvalho de Melo +Cc: Arnaldo Carvalho de Melo +Cc: Jiri Olsa +Cc: Kees Cook +Cc: Linus Torvalds +Cc: Min Chong +Cc: Peter Zijlstra +Cc: Stephane Eranian +Cc: Thomas Gleixner +Cc: Vince Weaver +Fixes: f63a8daa5812 ("perf: Fix event->ctx locking") +Link: http://lkml.kernel.org/r/20170106131444.GZ3174@twins.programming.kicks-ass.net +Signed-off-by: Ingo Molnar +[bwh: Backported to 4.4: + - Test perf_event::group_flags instead of group_caps + - Adjust context] +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + kernel/events/core.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 53 insertions(+), 4 deletions(-) + +--- a/kernel/events/core.c ++++ b/kernel/events/core.c +@@ -8250,6 +8250,37 @@ static int perf_event_set_clock(struct p + return 0; + } + ++/* ++ * Variation on perf_event_ctx_lock_nested(), except we take two context ++ * mutexes. ++ */ ++static struct perf_event_context * ++__perf_event_ctx_lock_double(struct perf_event *group_leader, ++ struct perf_event_context *ctx) ++{ ++ struct perf_event_context *gctx; ++ ++again: ++ rcu_read_lock(); ++ gctx = READ_ONCE(group_leader->ctx); ++ if (!atomic_inc_not_zero(&gctx->refcount)) { ++ rcu_read_unlock(); ++ goto again; ++ } ++ rcu_read_unlock(); ++ ++ mutex_lock_double(&gctx->mutex, &ctx->mutex); ++ ++ if (group_leader->ctx != gctx) { ++ mutex_unlock(&ctx->mutex); ++ mutex_unlock(&gctx->mutex); ++ put_ctx(gctx); ++ goto again; ++ } ++ ++ return gctx; ++} ++ + /** + * sys_perf_event_open - open a performance event, associate it to a task/cpu + * +@@ -8486,8 +8517,26 @@ SYSCALL_DEFINE5(perf_event_open, + } + + if (move_group) { +- gctx = group_leader->ctx; +- mutex_lock_double(&gctx->mutex, &ctx->mutex); ++ gctx = __perf_event_ctx_lock_double(group_leader, ctx); ++ ++ /* ++ * Check if we raced against another sys_perf_event_open() call ++ * moving the software group underneath us. ++ */ ++ if (!(group_leader->group_flags & PERF_GROUP_SOFTWARE)) { ++ /* ++ * If someone moved the group out from under us, check ++ * if this new event wound up on the same ctx, if so ++ * its the regular !move_group case, otherwise fail. ++ */ ++ if (gctx != ctx) { ++ err = -EINVAL; ++ goto err_locked; ++ } else { ++ perf_event_ctx_unlock(group_leader, gctx); ++ move_group = 0; ++ } ++ } + } else { + mutex_lock(&ctx->mutex); + } +@@ -8582,7 +8631,7 @@ SYSCALL_DEFINE5(perf_event_open, + perf_unpin_context(ctx); + + if (move_group) +- mutex_unlock(&gctx->mutex); ++ perf_event_ctx_unlock(group_leader, gctx); + mutex_unlock(&ctx->mutex); + + if (task) { +@@ -8610,7 +8659,7 @@ SYSCALL_DEFINE5(perf_event_open, + + err_locked: + if (move_group) +- mutex_unlock(&gctx->mutex); ++ perf_event_ctx_unlock(group_leader, gctx); + mutex_unlock(&ctx->mutex); + /* err_file: */ + fput(event_file); diff --git a/queue-4.4/ping-implement-proper-locking.patch b/queue-4.4/ping-implement-proper-locking.patch new file mode 100644 index 00000000000..7ceb56815fe --- /dev/null +++ b/queue-4.4/ping-implement-proper-locking.patch @@ -0,0 +1,55 @@ +From 43a6684519ab0a6c52024b5e25322476cabad893 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 24 Mar 2017 19:36:13 -0700 +Subject: ping: implement proper locking + +From: Eric Dumazet + +commit 43a6684519ab0a6c52024b5e25322476cabad893 upstream. + +We got a report of yet another bug in ping + +http://www.openwall.com/lists/oss-security/2017/03/24/6 + +->disconnect() is not called with socket lock held. + +Fix this by acquiring ping rwlock earlier. + +Thanks to Daniel, Alexander and Andrey for letting us know this problem. + +Fixes: c319b4d76b9e ("net: ipv4: add IPPROTO_ICMP socket kind") +Signed-off-by: Eric Dumazet +Reported-by: Daniel Jiang +Reported-by: Solar Designer +Reported-by: Andrey Konovalov +Signed-off-by: David S. Miller +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/ping.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/net/ipv4/ping.c ++++ b/net/ipv4/ping.c +@@ -154,17 +154,18 @@ void ping_hash(struct sock *sk) + void ping_unhash(struct sock *sk) + { + struct inet_sock *isk = inet_sk(sk); ++ + pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); ++ write_lock_bh(&ping_table.lock); + if (sk_hashed(sk)) { +- write_lock_bh(&ping_table.lock); + hlist_nulls_del(&sk->sk_nulls_node); + sk_nulls_node_init(&sk->sk_nulls_node); + sock_put(sk); + isk->inet_num = 0; + isk->inet_sport = 0; + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); +- write_unlock_bh(&ping_table.lock); + } ++ write_unlock_bh(&ping_table.lock); + } + EXPORT_SYMBOL_GPL(ping_unhash); + diff --git a/queue-4.4/series b/queue-4.4/series index c5f3933eb9a..664cc3e6438 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -7,3 +7,11 @@ hostap-avoid-uninitialized-variable-use-in-hfa384x_get_rid.patch gfs2-avoid-uninitialized-variable-warning.patch tipc-fix-random-link-resets-while-adding-a-second-bearer.patch tipc-fix-socket-timer-deadlock.patch +mnt-add-a-per-mount-namespace-limit-on-the-number-of-mounts.patch +xc2028-avoid-use-after-free.patch +netfilter-nfnetlink-correctly-validate-length-of-batch-messages.patch +tipc-check-minimum-bearer-mtu.patch +vfio-pci-fix-integer-overflows-bitmask-check.patch +staging-android-ion-fix-a-race-condition-in-the-ion-driver.patch +ping-implement-proper-locking.patch +perf-core-fix-concurrent-sys_perf_event_open-vs.-move_group-race.patch diff --git a/queue-4.4/staging-android-ion-fix-a-race-condition-in-the-ion-driver.patch b/queue-4.4/staging-android-ion-fix-a-race-condition-in-the-ion-driver.patch new file mode 100644 index 00000000000..7f8d8fa7861 --- /dev/null +++ b/queue-4.4/staging-android-ion-fix-a-race-condition-in-the-ion-driver.patch @@ -0,0 +1,177 @@ +From 9590232bb4f4cc824f3425a6e1349afbe6d6d2b7 Mon Sep 17 00:00:00 2001 +From: EunTaik Lee +Date: Wed, 24 Feb 2016 04:38:06 +0000 +Subject: staging/android/ion : fix a race condition in the ion driver + +From: EunTaik Lee + +commit 9590232bb4f4cc824f3425a6e1349afbe6d6d2b7 upstream. + +There is a use-after-free problem in the ion driver. +This is caused by a race condition in the ion_ioctl() +function. + +A handle has ref count of 1 and two tasks on different +cpus calls ION_IOC_FREE simultaneously. + +cpu 0 cpu 1 +------------------------------------------------------- +ion_handle_get_by_id() +(ref == 2) + ion_handle_get_by_id() + (ref == 3) + +ion_free() +(ref == 2) + +ion_handle_put() +(ref == 1) + + ion_free() + (ref == 0 so ion_handle_destroy() is + called + and the handle is freed.) + + ion_handle_put() is called and it + decreases the slub's next free pointer + +The problem is detected as an unaligned access in the +spin lock functions since it uses load exclusive + instruction. In some cases it corrupts the slub's +free pointer which causes a mis-aligned access to the +next free pointer.(kmalloc returns a pointer like +ffffc0745b4580aa). And it causes lots of other +hard-to-debug problems. + +This symptom is caused since the first member in the +ion_handle structure is the reference count and the +ion driver decrements the reference after it has been +freed. + +To fix this problem client->lock mutex is extended +to protect all the codes that uses the handle. + +Signed-off-by: Eun Taik Lee +Reviewed-by: Laura Abbott +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman + +index 7ff2a7ec871f..33b390e7ea31 +--- + drivers/staging/android/ion/ion.c | 55 +++++++++++++++++++++++++++++--------- + 1 file changed, 42 insertions(+), 13 deletions(-) + +--- a/drivers/staging/android/ion/ion.c ++++ b/drivers/staging/android/ion/ion.c +@@ -387,13 +387,22 @@ static void ion_handle_get(struct ion_ha + kref_get(&handle->ref); + } + +-static int ion_handle_put(struct ion_handle *handle) ++static int ion_handle_put_nolock(struct ion_handle *handle) ++{ ++ int ret; ++ ++ ret = kref_put(&handle->ref, ion_handle_destroy); ++ ++ return ret; ++} ++ ++int ion_handle_put(struct ion_handle *handle) + { + struct ion_client *client = handle->client; + int ret; + + mutex_lock(&client->lock); +- ret = kref_put(&handle->ref, ion_handle_destroy); ++ ret = ion_handle_put_nolock(handle); + mutex_unlock(&client->lock); + + return ret; +@@ -417,20 +426,30 @@ static struct ion_handle *ion_handle_loo + return ERR_PTR(-EINVAL); + } + +-static struct ion_handle *ion_handle_get_by_id(struct ion_client *client, ++static struct ion_handle *ion_handle_get_by_id_nolock(struct ion_client *client, + int id) + { + struct ion_handle *handle; + +- mutex_lock(&client->lock); + handle = idr_find(&client->idr, id); + if (handle) + ion_handle_get(handle); +- mutex_unlock(&client->lock); + + return handle ? handle : ERR_PTR(-EINVAL); + } + ++struct ion_handle *ion_handle_get_by_id(struct ion_client *client, ++ int id) ++{ ++ struct ion_handle *handle; ++ ++ mutex_lock(&client->lock); ++ handle = ion_handle_get_by_id_nolock(client, id); ++ mutex_unlock(&client->lock); ++ ++ return handle; ++} ++ + static bool ion_handle_validate(struct ion_client *client, + struct ion_handle *handle) + { +@@ -532,22 +551,28 @@ struct ion_handle *ion_alloc(struct ion_ + } + EXPORT_SYMBOL(ion_alloc); + +-void ion_free(struct ion_client *client, struct ion_handle *handle) ++static void ion_free_nolock(struct ion_client *client, struct ion_handle *handle) + { + bool valid_handle; + + BUG_ON(client != handle->client); + +- mutex_lock(&client->lock); + valid_handle = ion_handle_validate(client, handle); + + if (!valid_handle) { + WARN(1, "%s: invalid handle passed to free.\n", __func__); +- mutex_unlock(&client->lock); + return; + } ++ ion_handle_put_nolock(handle); ++} ++ ++void ion_free(struct ion_client *client, struct ion_handle *handle) ++{ ++ BUG_ON(client != handle->client); ++ ++ mutex_lock(&client->lock); ++ ion_free_nolock(client, handle); + mutex_unlock(&client->lock); +- ion_handle_put(handle); + } + EXPORT_SYMBOL(ion_free); + +@@ -1283,11 +1308,15 @@ static long ion_ioctl(struct file *filp, + { + struct ion_handle *handle; + +- handle = ion_handle_get_by_id(client, data.handle.handle); +- if (IS_ERR(handle)) ++ mutex_lock(&client->lock); ++ handle = ion_handle_get_by_id_nolock(client, data.handle.handle); ++ if (IS_ERR(handle)) { ++ mutex_unlock(&client->lock); + return PTR_ERR(handle); +- ion_free(client, handle); +- ion_handle_put(handle); ++ } ++ ion_free_nolock(client, handle); ++ ion_handle_put_nolock(handle); ++ mutex_unlock(&client->lock); + break; + } + case ION_IOC_SHARE: diff --git a/queue-4.4/tipc-check-minimum-bearer-mtu.patch b/queue-4.4/tipc-check-minimum-bearer-mtu.patch new file mode 100644 index 00000000000..3bae3894612 --- /dev/null +++ b/queue-4.4/tipc-check-minimum-bearer-mtu.patch @@ -0,0 +1,123 @@ +From 3de81b758853f0b29c61e246679d20b513c4cfec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Michal=20Kube=C4=8Dek?= +Date: Fri, 2 Dec 2016 09:33:41 +0100 +Subject: tipc: check minimum bearer MTU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Michal Kubeček + +commit 3de81b758853f0b29c61e246679d20b513c4cfec upstream. + +Qian Zhang (张谦) reported a potential socket buffer overflow in +tipc_msg_build() which is also known as CVE-2016-8632: due to +insufficient checks, a buffer overflow can occur if MTU is too short for +even tipc headers. As anyone can set device MTU in a user/net namespace, +this issue can be abused by a regular user. + +As agreed in the discussion on Ben Hutchings' original patch, we should +check the MTU at the moment a bearer is attached rather than for each +processed packet. We also need to repeat the check when bearer MTU is +adjusted to new device MTU. UDP case also needs a check to avoid +overflow when calculating bearer MTU. + +Fixes: b97bf3fd8f6a ("[TIPC] Initial merge") +Signed-off-by: Michal Kubecek +Reported-by: Qian Zhang (张谦) +Acked-by: Ying Xue +Signed-off-by: David S. Miller +[bwh: Backported to 4.4: + - Adjust context + - NETDEV_GOING_DOWN and NETDEV_CHANGEMTU cases in net notifier were combined] +Signed-off-by: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman +--- + net/tipc/bearer.c | 13 +++++++++++-- + net/tipc/bearer.h | 13 +++++++++++++ + net/tipc/udp_media.c | 5 +++++ + 3 files changed, 29 insertions(+), 2 deletions(-) + +--- a/net/tipc/bearer.c ++++ b/net/tipc/bearer.c +@@ -381,6 +381,10 @@ int tipc_enable_l2_media(struct net *net + dev = dev_get_by_name(net, driver_name); + if (!dev) + return -ENODEV; ++ if (tipc_mtu_bad(dev, 0)) { ++ dev_put(dev); ++ return -EINVAL; ++ } + + /* Associate TIPC bearer with L2 bearer */ + rcu_assign_pointer(b->media_ptr, dev); +@@ -570,14 +574,19 @@ static int tipc_l2_device_event(struct n + if (!b_ptr) + return NOTIFY_DONE; + +- b_ptr->mtu = dev->mtu; +- + switch (evt) { + case NETDEV_CHANGE: + if (netif_carrier_ok(dev)) + break; + case NETDEV_GOING_DOWN: ++ tipc_reset_bearer(net, b_ptr); ++ break; + case NETDEV_CHANGEMTU: ++ if (tipc_mtu_bad(dev, 0)) { ++ bearer_disable(net, b_ptr); ++ break; ++ } ++ b_ptr->mtu = dev->mtu; + tipc_reset_bearer(net, b_ptr); + break; + case NETDEV_CHANGEADDR: +--- a/net/tipc/bearer.h ++++ b/net/tipc/bearer.h +@@ -39,6 +39,7 @@ + + #include "netlink.h" + #include "core.h" ++#include "msg.h" + #include + + #define MAX_MEDIA 3 +@@ -61,6 +62,9 @@ + #define TIPC_MEDIA_TYPE_IB 2 + #define TIPC_MEDIA_TYPE_UDP 3 + ++/* minimum bearer MTU */ ++#define TIPC_MIN_BEARER_MTU (MAX_H_SIZE + INT_H_SIZE) ++ + /** + * struct tipc_node_map - set of node identifiers + * @count: # of nodes in set +@@ -226,4 +230,13 @@ void tipc_bearer_xmit(struct net *net, u + void tipc_bearer_bc_xmit(struct net *net, u32 bearer_id, + struct sk_buff_head *xmitq); + ++/* check if device MTU is too low for tipc headers */ ++static inline bool tipc_mtu_bad(struct net_device *dev, unsigned int reserve) ++{ ++ if (dev->mtu >= TIPC_MIN_BEARER_MTU + reserve) ++ return false; ++ netdev_warn(dev, "MTU too low for tipc bearer\n"); ++ return true; ++} ++ + #endif /* _TIPC_BEARER_H */ +--- a/net/tipc/udp_media.c ++++ b/net/tipc/udp_media.c +@@ -376,6 +376,11 @@ static int tipc_udp_enable(struct net *n + udp_conf.local_ip.s_addr = htonl(INADDR_ANY); + udp_conf.use_udp_checksums = false; + ub->ifindex = dev->ifindex; ++ if (tipc_mtu_bad(dev, sizeof(struct iphdr) + ++ sizeof(struct udphdr))) { ++ err = -EINVAL; ++ goto err; ++ } + b->mtu = dev->mtu - sizeof(struct iphdr) + - sizeof(struct udphdr); + #if IS_ENABLED(CONFIG_IPV6) diff --git a/queue-4.4/vfio-pci-fix-integer-overflows-bitmask-check.patch b/queue-4.4/vfio-pci-fix-integer-overflows-bitmask-check.patch new file mode 100644 index 00000000000..a292b50adf7 --- /dev/null +++ b/queue-4.4/vfio-pci-fix-integer-overflows-bitmask-check.patch @@ -0,0 +1,100 @@ +From 05692d7005a364add85c6e25a6c4447ce08f913a Mon Sep 17 00:00:00 2001 +From: Vlad Tsyrklevich +Date: Wed, 12 Oct 2016 18:51:24 +0200 +Subject: vfio/pci: Fix integer overflows, bitmask check + +From: Vlad Tsyrklevich + +commit 05692d7005a364add85c6e25a6c4447ce08f913a upstream. + +The VFIO_DEVICE_SET_IRQS ioctl did not sufficiently sanitize +user-supplied integers, potentially allowing memory corruption. This +patch adds appropriate integer overflow checks, checks the range bounds +for VFIO_IRQ_SET_DATA_NONE, and also verifies that only single element +in the VFIO_IRQ_SET_DATA_TYPE_MASK bitmask is set. +VFIO_IRQ_SET_ACTION_TYPE_MASK is already correctly checked later in +vfio_pci_set_irqs_ioctl(). + +Furthermore, a kzalloc is changed to a kcalloc because the use of a +kzalloc with an integer multiplication allowed an integer overflow +condition to be reached without this patch. kcalloc checks for overflow +and should prevent a similar occurrence. + +Signed-off-by: Vlad Tsyrklevich +Signed-off-by: Alex Williamson +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/vfio/pci/vfio_pci.c | 35 ++++++++++++++++++++++------------- + drivers/vfio/pci/vfio_pci_intrs.c | 2 +- + 2 files changed, 23 insertions(+), 14 deletions(-) + +--- a/drivers/vfio/pci/vfio_pci.c ++++ b/drivers/vfio/pci/vfio_pci.c +@@ -562,8 +562,9 @@ static long vfio_pci_ioctl(void *device_ + + } else if (cmd == VFIO_DEVICE_SET_IRQS) { + struct vfio_irq_set hdr; ++ size_t size; + u8 *data = NULL; +- int ret = 0; ++ int max, ret = 0; + + minsz = offsetofend(struct vfio_irq_set, count); + +@@ -571,23 +572,31 @@ static long vfio_pci_ioctl(void *device_ + return -EFAULT; + + if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS || ++ hdr.count >= (U32_MAX - hdr.start) || + hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK | + VFIO_IRQ_SET_ACTION_TYPE_MASK)) + return -EINVAL; + +- if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { +- size_t size; +- int max = vfio_pci_get_irq_count(vdev, hdr.index); +- +- if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL) +- size = sizeof(uint8_t); +- else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD) +- size = sizeof(int32_t); +- else +- return -EINVAL; ++ max = vfio_pci_get_irq_count(vdev, hdr.index); ++ if (hdr.start >= max || hdr.start + hdr.count > max) ++ return -EINVAL; ++ ++ switch (hdr.flags & VFIO_IRQ_SET_DATA_TYPE_MASK) { ++ case VFIO_IRQ_SET_DATA_NONE: ++ size = 0; ++ break; ++ case VFIO_IRQ_SET_DATA_BOOL: ++ size = sizeof(uint8_t); ++ break; ++ case VFIO_IRQ_SET_DATA_EVENTFD: ++ size = sizeof(int32_t); ++ break; ++ default: ++ return -EINVAL; ++ } + +- if (hdr.argsz - minsz < hdr.count * size || +- hdr.start >= max || hdr.start + hdr.count > max) ++ if (size) { ++ if (hdr.argsz - minsz < hdr.count * size) + return -EINVAL; + + data = memdup_user((void __user *)(arg + minsz), +--- a/drivers/vfio/pci/vfio_pci_intrs.c ++++ b/drivers/vfio/pci/vfio_pci_intrs.c +@@ -255,7 +255,7 @@ static int vfio_msi_enable(struct vfio_p + if (!is_irq_none(vdev)) + return -EINVAL; + +- vdev->ctx = kzalloc(nvec * sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL); ++ vdev->ctx = kcalloc(nvec, sizeof(struct vfio_pci_irq_ctx), GFP_KERNEL); + if (!vdev->ctx) + return -ENOMEM; + diff --git a/queue-4.4/xc2028-avoid-use-after-free.patch b/queue-4.4/xc2028-avoid-use-after-free.patch new file mode 100644 index 00000000000..df0889d826f --- /dev/null +++ b/queue-4.4/xc2028-avoid-use-after-free.patch @@ -0,0 +1,164 @@ +From 8dfbcc4351a0b6d2f2d77f367552f48ffefafe18 Mon Sep 17 00:00:00 2001 +From: Mauro Carvalho Chehab +Date: Thu, 28 Jan 2016 09:22:44 -0200 +Subject: [media] xc2028: avoid use after free + +From: Mauro Carvalho Chehab + +commit 8dfbcc4351a0b6d2f2d77f367552f48ffefafe18 upstream. + +If struct xc2028_config is passed without a firmware name, +the following trouble may happen: + +[11009.907205] xc2028 5-0061: type set to XCeive xc2028/xc3028 tuner +[11009.907491] ================================================================== +[11009.907750] BUG: KASAN: use-after-free in strcmp+0x96/0xb0 at addr ffff8803bd78ab40 +[11009.907992] Read of size 1 by task modprobe/28992 +[11009.907994] ============================================================================= +[11009.907997] BUG kmalloc-16 (Tainted: G W ): kasan: bad access detected +[11009.907999] ----------------------------------------------------------------------------- + +[11009.908008] INFO: Allocated in xhci_urb_enqueue+0x214/0x14c0 [xhci_hcd] age=0 cpu=3 pid=28992 +[11009.908012] ___slab_alloc+0x581/0x5b0 +[11009.908014] __slab_alloc+0x51/0x90 +[11009.908017] __kmalloc+0x27b/0x350 +[11009.908022] xhci_urb_enqueue+0x214/0x14c0 [xhci_hcd] +[11009.908026] usb_hcd_submit_urb+0x1e8/0x1c60 +[11009.908029] usb_submit_urb+0xb0e/0x1200 +[11009.908032] usb_serial_generic_write_start+0xb6/0x4c0 +[11009.908035] usb_serial_generic_write+0x92/0xc0 +[11009.908039] usb_console_write+0x38a/0x560 +[11009.908045] call_console_drivers.constprop.14+0x1ee/0x2c0 +[11009.908051] console_unlock+0x40d/0x900 +[11009.908056] vprintk_emit+0x4b4/0x830 +[11009.908061] vprintk_default+0x1f/0x30 +[11009.908064] printk+0x99/0xb5 +[11009.908067] kasan_report_error+0x10a/0x550 +[11009.908070] __asan_report_load1_noabort+0x43/0x50 +[11009.908074] INFO: Freed in xc2028_set_config+0x90/0x630 [tuner_xc2028] age=1 cpu=3 pid=28992 +[11009.908077] __slab_free+0x2ec/0x460 +[11009.908080] kfree+0x266/0x280 +[11009.908083] xc2028_set_config+0x90/0x630 [tuner_xc2028] +[11009.908086] xc2028_attach+0x310/0x8a0 [tuner_xc2028] +[11009.908090] em28xx_attach_xc3028.constprop.7+0x1f9/0x30d [em28xx_dvb] +[11009.908094] em28xx_dvb_init.part.3+0x8e4/0x5cf4 [em28xx_dvb] +[11009.908098] em28xx_dvb_init+0x81/0x8a [em28xx_dvb] +[11009.908101] em28xx_register_extension+0xd9/0x190 [em28xx] +[11009.908105] em28xx_dvb_register+0x10/0x1000 [em28xx_dvb] +[11009.908108] do_one_initcall+0x141/0x300 +[11009.908111] do_init_module+0x1d0/0x5ad +[11009.908114] load_module+0x6666/0x9ba0 +[11009.908117] SyS_finit_module+0x108/0x130 +[11009.908120] entry_SYSCALL_64_fastpath+0x16/0x76 +[11009.908123] INFO: Slab 0xffffea000ef5e280 objects=25 used=25 fp=0x (null) flags=0x2ffff8000004080 +[11009.908126] INFO: Object 0xffff8803bd78ab40 @offset=2880 fp=0x0000000000000001 + +[11009.908130] Bytes b4 ffff8803bd78ab30: 01 00 00 00 2a 07 00 00 9d 28 00 00 01 00 00 00 ....*....(...... +[11009.908133] Object ffff8803bd78ab40: 01 00 00 00 00 00 00 00 b0 1d c3 6a 00 88 ff ff ...........j.... +[11009.908137] CPU: 3 PID: 28992 Comm: modprobe Tainted: G B W 4.5.0-rc1+ #43 +[11009.908140] Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015 +[11009.908142] ffff8803bd78a000 ffff8802c273f1b8 ffffffff81932007 ffff8803c6407a80 +[11009.908148] ffff8802c273f1e8 ffffffff81556759 ffff8803c6407a80 ffffea000ef5e280 +[11009.908153] ffff8803bd78ab40 dffffc0000000000 ffff8802c273f210 ffffffff8155ccb4 +[11009.908158] Call Trace: +[11009.908162] [] dump_stack+0x4b/0x64 +[11009.908165] [] print_trailer+0xf9/0x150 +[11009.908168] [] object_err+0x34/0x40 +[11009.908171] [] kasan_report_error+0x230/0x550 +[11009.908175] [] ? trace_hardirqs_off_caller+0x21/0x290 +[11009.908179] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908182] [] __asan_report_load1_noabort+0x43/0x50 +[11009.908185] [] ? __asan_register_globals+0x50/0xa0 +[11009.908189] [] ? strcmp+0x96/0xb0 +[11009.908192] [] strcmp+0x96/0xb0 +[11009.908196] [] xc2028_set_config+0x15c/0x630 [tuner_xc2028] +[11009.908200] [] xc2028_attach+0x310/0x8a0 [tuner_xc2028] +[11009.908203] [] ? memset+0x28/0x30 +[11009.908206] [] ? xc2028_set_config+0x630/0x630 [tuner_xc2028] +[11009.908211] [] em28xx_attach_xc3028.constprop.7+0x1f9/0x30d [em28xx_dvb] +[11009.908215] [] ? em28xx_dvb_init.part.3+0x37c/0x5cf4 [em28xx_dvb] +[11009.908219] [] ? hauppauge_hvr930c_init+0x487/0x487 [em28xx_dvb] +[11009.908222] [] ? lgdt330x_attach+0x1cc/0x370 [lgdt330x] +[11009.908226] [] ? i2c_read_demod_bytes.isra.2+0x210/0x210 [lgdt330x] +[11009.908230] [] ? ref_module.part.15+0x10/0x10 +[11009.908233] [] ? module_assert_mutex_or_preempt+0x80/0x80 +[11009.908238] [] em28xx_dvb_init.part.3+0x8e4/0x5cf4 [em28xx_dvb] +[11009.908242] [] ? em28xx_attach_xc3028.constprop.7+0x30d/0x30d [em28xx_dvb] +[11009.908245] [] ? string+0x14d/0x1f0 +[11009.908249] [] ? symbol_string+0xff/0x1a0 +[11009.908253] [] ? uuid_string+0x6f0/0x6f0 +[11009.908257] [] ? __kernel_text_address+0x7e/0xa0 +[11009.908260] [] ? print_context_stack+0x7f/0xf0 +[11009.908264] [] ? __module_address+0xb6/0x360 +[11009.908268] [] ? is_ftrace_trampoline+0x99/0xe0 +[11009.908271] [] ? __kernel_text_address+0x7e/0xa0 +[11009.908275] [] ? debug_check_no_locks_freed+0x290/0x290 +[11009.908278] [] ? dump_trace+0x11b/0x300 +[11009.908282] [] ? em28xx_register_extension+0x23/0x190 [em28xx] +[11009.908285] [] ? trace_hardirqs_off_caller+0x21/0x290 +[11009.908289] [] ? trace_hardirqs_on_caller+0x16/0x590 +[11009.908292] [] ? trace_hardirqs_on+0xd/0x10 +[11009.908296] [] ? em28xx_register_extension+0x23/0x190 [em28xx] +[11009.908299] [] ? mutex_trylock+0x400/0x400 +[11009.908302] [] ? do_one_initcall+0x131/0x300 +[11009.908306] [] ? call_rcu_sched+0x17/0x20 +[11009.908309] [] ? put_object+0x48/0x70 +[11009.908314] [] em28xx_dvb_init+0x81/0x8a [em28xx_dvb] +[11009.908317] [] em28xx_register_extension+0xd9/0x190 [em28xx] +[11009.908320] [] ? 0xffffffffa0150000 +[11009.908324] [] em28xx_dvb_register+0x10/0x1000 [em28xx_dvb] +[11009.908327] [] do_one_initcall+0x141/0x300 +[11009.908330] [] ? try_to_run_init_process+0x40/0x40 +[11009.908333] [] ? trace_hardirqs_on_caller+0x16/0x590 +[11009.908337] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908340] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908343] [] ? kasan_unpoison_shadow+0x36/0x50 +[11009.908346] [] ? __asan_register_globals+0x87/0xa0 +[11009.908350] [] do_init_module+0x1d0/0x5ad +[11009.908353] [] load_module+0x6666/0x9ba0 +[11009.908356] [] ? symbol_put_addr+0x50/0x50 +[11009.908361] [] ? em28xx_dvb_init.part.3+0x5989/0x5cf4 [em28xx_dvb] +[11009.908366] [] ? module_frob_arch_sections+0x20/0x20 +[11009.908369] [] ? open_exec+0x50/0x50 +[11009.908374] [] ? ns_capable+0x5b/0xd0 +[11009.908377] [] SyS_finit_module+0x108/0x130 +[11009.908379] [] ? SyS_init_module+0x1f0/0x1f0 +[11009.908383] [] ? lockdep_sys_exit_thunk+0x12/0x14 +[11009.908394] [] entry_SYSCALL_64_fastpath+0x16/0x76 +[11009.908396] Memory state around the buggy address: +[11009.908398] ffff8803bd78aa00: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908401] ffff8803bd78aa80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908403] >ffff8803bd78ab00: fc fc fc fc fc fc fc fc 00 00 fc fc fc fc fc fc +[11009.908405] ^ +[11009.908407] ffff8803bd78ab80: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908409] ffff8803bd78ac00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[11009.908411] ================================================================== + +In order to avoid it, let's set the cached value of the firmware +name to NULL after freeing it. While here, return an error if +the memory allocation fails. + +Signed-off-by: Mauro Carvalho Chehab +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/media/tuners/tuner-xc2028.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/drivers/media/tuners/tuner-xc2028.c ++++ b/drivers/media/tuners/tuner-xc2028.c +@@ -1403,11 +1403,12 @@ static int xc2028_set_config(struct dvb_ + * in order to avoid troubles during device release. + */ + kfree(priv->ctrl.fname); ++ priv->ctrl.fname = NULL; + memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); + if (p->fname) { + priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); + if (priv->ctrl.fname == NULL) +- rc = -ENOMEM; ++ return -ENOMEM; + } + + /*