diff options
author | Zefan Li <lizefan@huawei.com> | 2016-03-07 20:37:11 +0800 |
---|---|---|
committer | Zefan Li <lizefan@huawei.com> | 2016-03-16 11:31:43 +0800 |
commit | a3b42e94e6b3cc9b6d57c9dca94e0bfbcba84265 (patch) | |
tree | 0cb8a733f8fb65d2e1e1993fa0ce64b89d6e05ff | |
parent | b3475c6db84ff6e2e52fac3f53b383054abc34c1 (diff) | |
download | linux-3.4.y-queue-a3b42e94e6b3cc9b6d57c9dca94e0bfbcba84265.tar.gz |
Backport some fixes for CVE
18 files changed, 1769 insertions, 0 deletions
diff --git a/patches/get-rid-of-s_files-and-files_lock.patch b/patches/get-rid-of-s_files-and-files_lock.patch new file mode 100644 index 0000000..8453158 --- /dev/null +++ b/patches/get-rid-of-s_files-and-files_lock.patch @@ -0,0 +1,304 @@ +From eee5cc2702929fd41cce28058dc6d6717f723f87 Mon Sep 17 00:00:00 2001 +From: Al Viro <viro@zeniv.linux.org.uk> +Date: Fri, 4 Oct 2013 11:06:42 -0400 +Subject: get rid of s_files and files_lock + +commit eee5cc2702929fd41cce28058dc6d6717f723f87 upstream. + +The only thing we need it for is alt-sysrq-r (emergency remount r/o) +and these days we can do just as well without going through the +list of files. + +Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> +[lizf: Backported to 3.4: adjust context] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + fs/file_table.c | 130 ----------------------------------------------------- + fs/internal.h | 3 - + fs/open.c | 2 + fs/super.c | 21 -------- + include/linux/fs.h | 13 ----- + 5 files changed, 2 insertions(+), 167 deletions(-) + +--- a/fs/internal.h ++++ b/fs/internal.h +@@ -67,9 +67,6 @@ extern void chroot_fs_refs(struct path * + /* + * file_table.c + */ +-extern void file_sb_list_add(struct file *f, struct super_block *sb); +-extern void file_sb_list_del(struct file *f); +-extern void mark_files_ro(struct super_block *); + extern struct file *get_empty_filp(void); + + /* +--- a/fs/open.c ++++ b/fs/open.c +@@ -672,7 +672,6 @@ static struct file *__dentry_open(struct + f->f_path.dentry = dentry; + f->f_path.mnt = mnt; + f->f_pos = 0; +- file_sb_list_add(f, inode->i_sb); + + if (unlikely(f->f_mode & FMODE_PATH)) { + f->f_op = &empty_fops; +@@ -730,7 +729,6 @@ cleanup_all: + mnt_drop_write(mnt); + } + } +- file_sb_list_del(f); + f->f_path.dentry = NULL; + f->f_path.mnt = NULL; + cleanup_file: +--- a/fs/super.c ++++ b/fs/super.c +@@ -122,22 +122,7 @@ static struct super_block *alloc_super(s + s = NULL; + goto out; + } +-#ifdef CONFIG_SMP +- s->s_files = alloc_percpu(struct list_head); +- if (!s->s_files) { +- security_sb_free(s); +- kfree(s); +- s = NULL; +- goto out; +- } else { +- int i; + +- for_each_possible_cpu(i) +- INIT_LIST_HEAD(per_cpu_ptr(s->s_files, i)); +- } +-#else +- INIT_LIST_HEAD(&s->s_files); +-#endif + s->s_bdi = &default_backing_dev_info; + INIT_HLIST_NODE(&s->s_instances); + INIT_HLIST_BL_HEAD(&s->s_anon); +@@ -200,9 +185,6 @@ out: + */ + static inline void destroy_super(struct super_block *s) + { +-#ifdef CONFIG_SMP +- free_percpu(s->s_files); +-#endif + security_sb_free(s); + WARN_ON(!list_empty(&s->s_mounts)); + kfree(s->s_subtype); +@@ -744,7 +726,8 @@ int do_remount_sb(struct super_block *sb + make sure there are no rw files opened */ + if (remount_ro) { + if (force) { +- mark_files_ro(sb); ++ sb->s_readonly_remount = 1; ++ smp_wmb(); + } else { + retval = sb_prepare_remount_readonly(sb); + if (retval) +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -976,12 +976,7 @@ static inline int ra_has_index(struct fi + #define FILE_MNT_WRITE_RELEASED 2 + + struct file { +- /* +- * fu_list becomes invalid after file_free is called and queued via +- * fu_rcuhead for RCU freeing +- */ + union { +- struct list_head fu_list; + struct rcu_head fu_rcuhead; + } f_u; + struct path f_path; +@@ -994,9 +989,6 @@ struct file { + * Must not be taken from IRQ context. + */ + spinlock_t f_lock; +-#ifdef CONFIG_SMP +- int f_sb_list_cpu; +-#endif + atomic_long_t f_count; + unsigned int f_flags; + fmode_t f_mode; +@@ -1443,11 +1435,6 @@ struct super_block { + + struct list_head s_inodes; /* all inodes */ + struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ +-#ifdef CONFIG_SMP +- struct list_head __percpu *s_files; +-#else +- struct list_head s_files; +-#endif + struct list_head s_mounts; /* list of mounts; _not_ for fs use */ + /* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */ + struct list_head s_dentry_lru; /* unused dentry lru */ +--- a/fs/file_table.c ++++ b/fs/file_table.c +@@ -34,9 +34,6 @@ struct files_stat_struct files_stat = { + .max_files = NR_FILE + }; + +-DECLARE_LGLOCK(files_lglock); +-DEFINE_LGLOCK(files_lglock); +- + /* SLAB cache for file structures */ + static struct kmem_cache *filp_cachep __read_mostly; + +@@ -129,7 +126,6 @@ struct file *get_empty_filp(void) + if (security_file_alloc(f)) + goto fail_sec; + +- INIT_LIST_HEAD(&f->f_u.fu_list); + atomic_long_set(&f->f_count, 1); + rwlock_init(&f->f_owner.lock); + spin_lock_init(&f->f_lock); +@@ -252,7 +248,6 @@ static void __fput(struct file *file) + } + fops_put(file->f_op); + put_pid(file->f_owner.pid); +- file_sb_list_del(file); + if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) + i_readcount_dec(inode); + if (file->f_mode & FMODE_WRITE) +@@ -382,134 +377,10 @@ void put_filp(struct file *file) + { + if (atomic_long_dec_and_test(&file->f_count)) { + security_file_free(file); +- file_sb_list_del(file); + file_free(file); + } + } + +-static inline int file_list_cpu(struct file *file) +-{ +-#ifdef CONFIG_SMP +- return file->f_sb_list_cpu; +-#else +- return smp_processor_id(); +-#endif +-} +- +-/* helper for file_sb_list_add to reduce ifdefs */ +-static inline void __file_sb_list_add(struct file *file, struct super_block *sb) +-{ +- struct list_head *list; +-#ifdef CONFIG_SMP +- int cpu; +- cpu = smp_processor_id(); +- file->f_sb_list_cpu = cpu; +- list = per_cpu_ptr(sb->s_files, cpu); +-#else +- list = &sb->s_files; +-#endif +- list_add(&file->f_u.fu_list, list); +-} +- +-/** +- * file_sb_list_add - add a file to the sb's file list +- * @file: file to add +- * @sb: sb to add it to +- * +- * Use this function to associate a file with the superblock of the inode it +- * refers to. +- */ +-void file_sb_list_add(struct file *file, struct super_block *sb) +-{ +- lg_local_lock(files_lglock); +- __file_sb_list_add(file, sb); +- lg_local_unlock(files_lglock); +-} +- +-/** +- * file_sb_list_del - remove a file from the sb's file list +- * @file: file to remove +- * @sb: sb to remove it from +- * +- * Use this function to remove a file from its superblock. +- */ +-void file_sb_list_del(struct file *file) +-{ +- if (!list_empty(&file->f_u.fu_list)) { +- lg_local_lock_cpu(files_lglock, file_list_cpu(file)); +- list_del_init(&file->f_u.fu_list); +- lg_local_unlock_cpu(files_lglock, file_list_cpu(file)); +- } +-} +- +-#ifdef CONFIG_SMP +- +-/* +- * These macros iterate all files on all CPUs for a given superblock. +- * files_lglock must be held globally. +- */ +-#define do_file_list_for_each_entry(__sb, __file) \ +-{ \ +- int i; \ +- for_each_possible_cpu(i) { \ +- struct list_head *list; \ +- list = per_cpu_ptr((__sb)->s_files, i); \ +- list_for_each_entry((__file), list, f_u.fu_list) +- +-#define while_file_list_for_each_entry \ +- } \ +-} +- +-#else +- +-#define do_file_list_for_each_entry(__sb, __file) \ +-{ \ +- struct list_head *list; \ +- list = &(sb)->s_files; \ +- list_for_each_entry((__file), list, f_u.fu_list) +- +-#define while_file_list_for_each_entry \ +-} +- +-#endif +- +-/** +- * mark_files_ro - mark all files read-only +- * @sb: superblock in question +- * +- * All files are marked read-only. We don't care about pending +- * delete files so this should be used in 'force' mode only. +- */ +-void mark_files_ro(struct super_block *sb) +-{ +- struct file *f; +- +-retry: +- lg_global_lock(files_lglock); +- do_file_list_for_each_entry(sb, f) { +- struct vfsmount *mnt; +- if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) +- continue; +- if (!file_count(f)) +- continue; +- if (!(f->f_mode & FMODE_WRITE)) +- continue; +- spin_lock(&f->f_lock); +- f->f_mode &= ~FMODE_WRITE; +- spin_unlock(&f->f_lock); +- if (file_check_writeable(f) != 0) +- continue; +- file_release_write(f); +- mnt = mntget(f->f_path.mnt); +- /* This can sleep, so we can't hold the spinlock. */ +- lg_global_unlock(files_lglock); +- mnt_drop_write(mnt); +- mntput(mnt); +- goto retry; +- } while_file_list_for_each_entry; +- lg_global_unlock(files_lglock); +-} +- + void __init files_init(unsigned long mempages) + { + unsigned long n; +@@ -525,6 +396,5 @@ void __init files_init(unsigned long mem + n = (mempages * (PAGE_SIZE / 1024)) / 10; + files_stat.max_files = max_t(unsigned long, n, NR_FILE); + files_defer_init(); +- lg_lock_init(files_lglock); + percpu_counter_init(&nr_files, 0); + } diff --git a/patches/initialize-msg-shm-ipc-objects-before-doing-ipc_addid.patch b/patches/initialize-msg-shm-ipc-objects-before-doing-ipc_addid.patch new file mode 100644 index 0000000..ee1fe73 --- /dev/null +++ b/patches/initialize-msg-shm-ipc-objects-before-doing-ipc_addid.patch @@ -0,0 +1,115 @@ +From b9a532277938798b53178d5a66af6e2915cb27cf Mon Sep 17 00:00:00 2001 +From: Linus Torvalds <torvalds@linux-foundation.org> +Date: Wed, 30 Sep 2015 12:48:40 -0400 +Subject: Initialize msg/shm IPC objects before doing ipc_addid() + +commit b9a532277938798b53178d5a66af6e2915cb27cf upstream. + +As reported by Dmitry Vyukov, we really shouldn't do ipc_addid() before +having initialized the IPC object state. Yes, we initialize the IPC +object in a locked state, but with all the lockless RCU lookup work, +that IPC object lock no longer means that the state cannot be seen. + +We already did this for the IPC semaphore code (see commit e8577d1f0329: +"ipc/sem.c: fully initialize sem_array before making it visible") but we +clearly forgot about msg and shm. + +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Cc: Manfred Spraul <manfred@colorfullife.com> +Cc: Davidlohr Bueso <dbueso@suse.de> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +[lizf: Backported to 3.4: adjust context] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + ipc/msg.c | 18 +++++++++--------- + ipc/shm.c | 13 +++++++------ + ipc/util.c | 8 ++++---- + 3 files changed, 20 insertions(+), 19 deletions(-) + +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -500,12 +500,6 @@ static int newseg(struct ipc_namespace * + if (IS_ERR(file)) + goto no_file; + +- id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); +- if (id < 0) { +- error = id; +- goto no_id; +- } +- + shp->shm_cprid = task_tgid_vnr(current); + shp->shm_lprid = 0; + shp->shm_atim = shp->shm_dtim = 0; +@@ -514,6 +508,13 @@ static int newseg(struct ipc_namespace * + shp->shm_nattch = 0; + shp->shm_file = file; + shp->shm_creator = current; ++ ++ id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni); ++ if (id < 0) { ++ error = id; ++ goto no_id; ++ } ++ + /* + * shmid gets reported as "inode#" in /proc/pid/maps. + * proc-ps tools use this. Changing this will break them. +--- a/ipc/util.c ++++ b/ipc/util.c +@@ -264,6 +264,10 @@ int ipc_addid(struct ipc_ids* ids, struc + rcu_read_lock(); + spin_lock(&new->lock); + ++ current_euid_egid(&euid, &egid); ++ new->cuid = new->uid = euid; ++ new->gid = new->cgid = egid; ++ + err = idr_get_new(&ids->ipcs_idr, new, &id); + if (err) { + spin_unlock(&new->lock); +@@ -273,10 +277,6 @@ int ipc_addid(struct ipc_ids* ids, struc + + ids->in_use++; + +- current_euid_egid(&euid, &egid); +- new->cuid = new->uid = euid; +- new->gid = new->cgid = egid; +- + new->seq = ids->seq++; + if(ids->seq > ids->seq_max) + ids->seq = 0; +--- a/ipc/msg.c ++++ b/ipc/msg.c +@@ -198,6 +198,15 @@ static int newque(struct ipc_namespace * + return retval; + } + ++ msq->q_stime = msq->q_rtime = 0; ++ msq->q_ctime = get_seconds(); ++ msq->q_cbytes = msq->q_qnum = 0; ++ msq->q_qbytes = ns->msg_ctlmnb; ++ msq->q_lspid = msq->q_lrpid = 0; ++ INIT_LIST_HEAD(&msq->q_messages); ++ INIT_LIST_HEAD(&msq->q_receivers); ++ INIT_LIST_HEAD(&msq->q_senders); ++ + /* + * ipc_addid() locks msq + */ +@@ -208,15 +217,6 @@ static int newque(struct ipc_namespace * + return id; + } + +- msq->q_stime = msq->q_rtime = 0; +- msq->q_ctime = get_seconds(); +- msq->q_cbytes = msq->q_qnum = 0; +- msq->q_qbytes = ns->msg_ctlmnb; +- msq->q_lspid = msq->q_lrpid = 0; +- INIT_LIST_HEAD(&msq->q_messages); +- INIT_LIST_HEAD(&msq->q_receivers); +- INIT_LIST_HEAD(&msq->q_senders); +- + msg_unlock(msq); + + return msq->q_perm.id; diff --git a/patches/ipv6-addrconf-validate-new-mtu-before-applying-it.patch b/patches/ipv6-addrconf-validate-new-mtu-before-applying-it.patch new file mode 100644 index 0000000..5803eb0 --- /dev/null +++ b/patches/ipv6-addrconf-validate-new-mtu-before-applying-it.patch @@ -0,0 +1,64 @@ +From 77751427a1ff25b27d47a4c36b12c3c8667855ac Mon Sep 17 00:00:00 2001 +From: Marcelo Leitner <mleitner@redhat.com> +Date: Mon, 23 Feb 2015 11:17:13 -0300 +Subject: ipv6: addrconf: validate new MTU before applying it + +commit 77751427a1ff25b27d47a4c36b12c3c8667855ac upstream. + +Currently we don't check if the new MTU is valid or not and this allows +one to configure a smaller than minimum allowed by RFCs or even bigger +than interface own MTU, which is a problem as it may lead to packet +drops. + +If you have a daemon like NetworkManager running, this may be exploited +by remote attackers by forging RA packets with an invalid MTU, possibly +leading to a DoS. (NetworkManager currently only validates for values +too small, but not for too big ones.) + +The fix is just to make sure the new value is valid. That is, between +IPV6_MIN_MTU and interface's MTU. + +Note that similar check is already performed at +ndisc_router_discovery(), for when kernel itself parses the RA. + +Signed-off-by: Marcelo Ricardo Leitner <mleitner@redhat.com> +Signed-off-by: Sabrina Dubroca <sd@queasysnail.net> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + net/ipv6/addrconf.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -4340,6 +4340,21 @@ int addrconf_sysctl_forward(ctl_table *c + return ret; + } + ++static ++int addrconf_sysctl_mtu(struct ctl_table *ctl, int write, ++ void __user *buffer, size_t *lenp, loff_t *ppos) ++{ ++ struct inet6_dev *idev = ctl->extra1; ++ int min_mtu = IPV6_MIN_MTU; ++ struct ctl_table lctl; ++ ++ lctl = *ctl; ++ lctl.extra1 = &min_mtu; ++ lctl.extra2 = idev ? &idev->dev->mtu : NULL; ++ ++ return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos); ++} ++ + static void dev_disable_change(struct inet6_dev *idev) + { + if (!idev || !idev->dev) +@@ -4449,7 +4464,7 @@ static struct addrconf_sysctl_table + .data = &ipv6_devconf.mtu6, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = addrconf_sysctl_mtu, + }, + { + .procname = "accept_ra", diff --git a/patches/isdn_ppp-add-checks-for-allocation-failure-in-isdn_ppp_open.patch b/patches/isdn_ppp-add-checks-for-allocation-failure-in-isdn_ppp_open.patch new file mode 100644 index 0000000..865f73d --- /dev/null +++ b/patches/isdn_ppp-add-checks-for-allocation-failure-in-isdn_ppp_open.patch @@ -0,0 +1,38 @@ +From 0baa57d8dc32db78369d8b5176ef56c5e2e18ab3 Mon Sep 17 00:00:00 2001 +From: Ben Hutchings <ben@decadent.org.uk> +Date: Sun, 1 Nov 2015 16:21:24 +0000 +Subject: isdn_ppp: Add checks for allocation failure in isdn_ppp_open() + +commit 0baa57d8dc32db78369d8b5176ef56c5e2e18ab3 upstream. + +Compile-tested only. + +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/isdn/i4l/isdn_ppp.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/isdn/i4l/isdn_ppp.c ++++ b/drivers/isdn/i4l/isdn_ppp.c +@@ -301,6 +301,8 @@ isdn_ppp_open(int min, struct file *file + is->compflags = 0; + + is->reset = isdn_ppp_ccp_reset_alloc(is); ++ if (!is->reset) ++ return -ENOMEM; + + is->lp = NULL; + is->mp_seqno = 0; /* MP sequence number */ +@@ -320,6 +322,10 @@ isdn_ppp_open(int min, struct file *file + * VJ header compression init + */ + is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ ++ if (!is->slcomp) { ++ isdn_ppp_ccp_reset_free(is); ++ return -ENOMEM; ++ } + #endif + #ifdef CONFIG_IPPP_FILTER + is->pass_filter = NULL; diff --git a/patches/keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch b/patches/keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch new file mode 100644 index 0000000..5f30e46 --- /dev/null +++ b/patches/keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch @@ -0,0 +1,78 @@ +From f05819df10d7b09f6d1eb6f8534a8f68e5a4fe61 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Thu, 15 Oct 2015 17:21:37 +0100 +Subject: KEYS: Fix crash when attempt to garbage collect an uninstantiated + keyring + +commit f05819df10d7b09f6d1eb6f8534a8f68e5a4fe61 upstream. + +The following sequence of commands: + + i=`keyctl add user a a @s` + keyctl request2 keyring foo bar @t + keyctl unlink $i @s + +tries to invoke an upcall to instantiate a keyring if one doesn't already +exist by that name within the user's keyring set. However, if the upcall +fails, the code sets keyring->type_data.reject_error to -ENOKEY or some +other error code. When the key is garbage collected, the key destroy +function is called unconditionally and keyring_destroy() uses list_empty() +on keyring->type_data.link - which is in a union with reject_error. +Subsequently, the kernel tries to unlink the keyring from the keyring names +list - which oopses like this: + + BUG: unable to handle kernel paging request at 00000000ffffff8a + IP: [<ffffffff8126e051>] keyring_destroy+0x3d/0x88 + ... + Workqueue: events key_garbage_collector + ... + RIP: 0010:[<ffffffff8126e051>] keyring_destroy+0x3d/0x88 + RSP: 0018:ffff88003e2f3d30 EFLAGS: 00010203 + RAX: 00000000ffffff82 RBX: ffff88003bf1a900 RCX: 0000000000000000 + RDX: 0000000000000000 RSI: 000000003bfc6901 RDI: ffffffff81a73a40 + RBP: ffff88003e2f3d38 R08: 0000000000000152 R09: 0000000000000000 + R10: ffff88003e2f3c18 R11: 000000000000865b R12: ffff88003bf1a900 + R13: 0000000000000000 R14: ffff88003bf1a908 R15: ffff88003e2f4000 + ... + CR2: 00000000ffffff8a CR3: 000000003e3ec000 CR4: 00000000000006f0 + ... + Call Trace: + [<ffffffff8126c756>] key_gc_unused_keys.constprop.1+0x5d/0x10f + [<ffffffff8126ca71>] key_garbage_collector+0x1fa/0x351 + [<ffffffff8105ec9b>] process_one_work+0x28e/0x547 + [<ffffffff8105fd17>] worker_thread+0x26e/0x361 + [<ffffffff8105faa9>] ? rescuer_thread+0x2a8/0x2a8 + [<ffffffff810648ad>] kthread+0xf3/0xfb + [<ffffffff810647ba>] ? kthread_create_on_node+0x1c2/0x1c2 + [<ffffffff815f2ccf>] ret_from_fork+0x3f/0x70 + [<ffffffff810647ba>] ? kthread_create_on_node+0x1c2/0x1c2 + +Note the value in RAX. This is a 32-bit representation of -ENOKEY. + +The solution is to only call ->destroy() if the key was successfully +instantiated. + +Reported-by: Dmitry Vyukov <dvyukov@google.com> +Signed-off-by: David Howells <dhowells@redhat.com> +Tested-by: Dmitry Vyukov <dvyukov@google.com> +[lizf: Backported to 3.4: adjust indentation] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + security/keys/gc.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/security/keys/gc.c ++++ b/security/keys/gc.c +@@ -174,8 +174,10 @@ static noinline void key_gc_unused_key(s + { + key_check(key); + +- /* Throw away the key data */ +- if (key->type->destroy) ++ /* Throw away the key data if the key is instantiated */ ++ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && ++ !test_bit(KEY_FLAG_NEGATIVE, &key->flags) && ++ key->type->destroy) + key->type->destroy(key); + + security_key_free(key); diff --git a/patches/keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch b/patches/keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch new file mode 100644 index 0000000..6540eaa --- /dev/null +++ b/patches/keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch @@ -0,0 +1,51 @@ +From 94c4554ba07adbdde396748ee7ae01e86cf2d8d7 Mon Sep 17 00:00:00 2001 +From: David Howells <dhowells@redhat.com> +Date: Fri, 25 Sep 2015 16:30:08 +0100 +Subject: KEYS: Fix race between key destruction and finding a keyring by name + +commit 94c4554ba07adbdde396748ee7ae01e86cf2d8d7 upstream. + +There appears to be a race between: + + (1) key_gc_unused_keys() which frees key->security and then calls + keyring_destroy() to unlink the name from the name list + + (2) find_keyring_by_name() which calls key_permission(), thus accessing + key->security, on a key before checking to see whether the key usage is 0 + (ie. the key is dead and might be cleaned up). + +Fix this by calling ->destroy() before cleaning up the core key data - +including key->security. + +Reported-by: Petr Matousek <pmatouse@redhat.com> +Signed-off-by: David Howells <dhowells@redhat.com> +[lizf: Backported to 3.4: adjust indentation] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + security/keys/gc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/security/keys/gc.c ++++ b/security/keys/gc.c +@@ -174,6 +174,10 @@ static noinline void key_gc_unused_key(s + { + key_check(key); + ++ /* Throw away the key data */ ++ if (key->type->destroy) ++ key->type->destroy(key); ++ + security_key_free(key); + + /* deal with the user's key tracking and quota */ +@@ -188,10 +192,6 @@ static noinline void key_gc_unused_key(s + if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) + atomic_dec(&key->user->nikeys); + +- /* now throw away the key memory */ +- if (key->type->destroy) +- key->type->destroy(key); +- + key_user_put(key->user); + + kfree(key->description); diff --git a/patches/kvm-svm-unconditionally-intercept-db.patch b/patches/kvm-svm-unconditionally-intercept-db.patch new file mode 100644 index 0000000..d4e5cb3 --- /dev/null +++ b/patches/kvm-svm-unconditionally-intercept-db.patch @@ -0,0 +1,80 @@ +From: Paolo Bonzini <pbonzini@redhat.com> +Date: Tue, 10 Nov 2015 09:14:39 +0100 +Subject: KVM: svm: unconditionally intercept #DB + +commit cbdb967af3d54993f5814f1cee0ed311a055377d upstream. + +This is needed to avoid the possibility that the guest triggers +an infinite stream of #DB exceptions (CVE-2015-8104). + +VMX is not affected: because it does not save DR6 in the VMCS, +it already intercepts #DB unconditionally. + +Reported-by: Jan Beulich <jbeulich@suse.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +[bwh: Backported to 3.2, with thanks to Paolo: + - update_db_bp_intercept() was called update_db_intercept() + - The remaining call is in svm_guest_debug() rather than through svm_x86_ops] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + arch/x86/kvm/svm.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -1082,6 +1082,7 @@ static void init_vmcb(struct vcpu_svm *s + set_exception_intercept(svm, UD_VECTOR); + set_exception_intercept(svm, MC_VECTOR); + set_exception_intercept(svm, AC_VECTOR); ++ set_exception_intercept(svm, DB_VECTOR); + + set_intercept(svm, INTERCEPT_INTR); + set_intercept(svm, INTERCEPT_NMI); +@@ -1637,20 +1638,13 @@ static void svm_set_segment(struct kvm_v + mark_dirty(svm->vmcb, VMCB_SEG); + } + +-static void update_db_intercept(struct kvm_vcpu *vcpu) ++static void update_bp_intercept(struct kvm_vcpu *vcpu) + { + struct vcpu_svm *svm = to_svm(vcpu); + +- clr_exception_intercept(svm, DB_VECTOR); + clr_exception_intercept(svm, BP_VECTOR); + +- if (svm->nmi_singlestep) +- set_exception_intercept(svm, DB_VECTOR); +- + if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { +- if (vcpu->guest_debug & +- (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) +- set_exception_intercept(svm, DB_VECTOR); + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + set_exception_intercept(svm, BP_VECTOR); + } else +@@ -1668,7 +1662,7 @@ static void svm_guest_debug(struct kvm_v + + mark_dirty(svm->vmcb, VMCB_DR); + +- update_db_intercept(vcpu); ++ update_bp_intercept(vcpu); + } + + static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) +@@ -1742,7 +1736,6 @@ static int db_interception(struct vcpu_s + if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) + svm->vmcb->save.rflags &= + ~(X86_EFLAGS_TF | X86_EFLAGS_RF); +- update_db_intercept(&svm->vcpu); + } + + if (svm->vcpu.guest_debug & +@@ -3661,7 +3654,6 @@ static void enable_nmi_window(struct kvm + */ + svm->nmi_singlestep = true; + svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); +- update_db_intercept(vcpu); + } + + static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr) diff --git a/patches/kvm-x86-work-around-infinite-loop-in-microcode-when-ac-is-delivered.patch b/patches/kvm-x86-work-around-infinite-loop-in-microcode-when-ac-is-delivered.patch new file mode 100644 index 0000000..4c91a7e --- /dev/null +++ b/patches/kvm-x86-work-around-infinite-loop-in-microcode-when-ac-is-delivered.patch @@ -0,0 +1,100 @@ +From 54a20552e1eae07aa240fa370a0293e006b5faed Mon Sep 17 00:00:00 2001 +From: Eric Northup <digitaleric@google.com> +Date: Tue, 3 Nov 2015 18:03:53 +0100 +Subject: KVM: x86: work around infinite loop in microcode when #AC is + delivered + +commit 54a20552e1eae07aa240fa370a0293e006b5faed upstream. + +It was found that a guest can DoS a host by triggering an infinite +stream of "alignment check" (#AC) exceptions. This causes the +microcode to enter an infinite loop where the core never receives +another interrupt. The host kernel panics pretty quickly due to the +effects (CVE-2015-5307). + +Signed-off-by: Eric Northup <digitaleric@google.com> +Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> +[lizf: Backported to 3.4: + - adjust filename + - adjust context + - add definition of AC_VECTOR] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + arch/x86/include/asm/kvm_host.h | 1 + + arch/x86/kvm/svm.c | 8 ++++++++ + arch/x86/kvm/trace.h | 1 + + arch/x86/kvm/vmx.c | 5 ++++- + 4 files changed, 14 insertions(+), 1 deletion(-) + +--- a/arch/x86/kvm/trace.h ++++ b/arch/x86/kvm/trace.h +@@ -244,6 +244,7 @@ TRACE_EVENT(kvm_apic, + { SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \ + { SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \ + { SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \ ++ { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \ + { SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \ + { SVM_EXIT_INTR, "interrupt" }, \ + { SVM_EXIT_NMI, "nmi" }, \ +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -1081,6 +1081,7 @@ static void init_vmcb(struct vcpu_svm *s + set_exception_intercept(svm, PF_VECTOR); + set_exception_intercept(svm, UD_VECTOR); + set_exception_intercept(svm, MC_VECTOR); ++ set_exception_intercept(svm, AC_VECTOR); + + set_intercept(svm, INTERCEPT_INTR); + set_intercept(svm, INTERCEPT_NMI); +@@ -1776,6 +1777,12 @@ static int ud_interception(struct vcpu_s + return 1; + } + ++static int ac_interception(struct vcpu_svm *svm) ++{ ++ kvm_queue_exception_e(&svm->vcpu, AC_VECTOR, 0); ++ return 1; ++} ++ + static void svm_fpu_activate(struct kvm_vcpu *vcpu) + { + struct vcpu_svm *svm = to_svm(vcpu); +@@ -3291,6 +3298,7 @@ static int (*svm_exit_handlers[])(struct + [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, + [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, + [SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception, ++ [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception, + [SVM_EXIT_INTR] = intr_interception, + [SVM_EXIT_NMI] = nmi_interception, + [SVM_EXIT_SMI] = nop_on_interception, +--- a/arch/x86/kvm/vmx.c ++++ b/arch/x86/kvm/vmx.c +@@ -1169,7 +1169,7 @@ static void update_exception_bitmap(stru + u32 eb; + + eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) | +- (1u << NM_VECTOR) | (1u << DB_VECTOR); ++ (1u << NM_VECTOR) | (1u << DB_VECTOR) | (1u << AC_VECTOR); + if ((vcpu->guest_debug & + (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) == + (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) +@@ -4260,6 +4260,9 @@ static int handle_exception(struct kvm_v + + ex_no = intr_info & INTR_INFO_VECTOR_MASK; + switch (ex_no) { ++ case AC_VECTOR: ++ kvm_queue_exception_e(vcpu, AC_VECTOR, error_code); ++ return 1; + case DB_VECTOR: + dr6 = vmcs_readl(EXIT_QUALIFICATION); + if (!(vcpu->guest_debug & +--- a/arch/x86/include/asm/kvm_host.h ++++ b/arch/x86/include/asm/kvm_host.h +@@ -87,6 +87,7 @@ + #define GP_VECTOR 13 + #define PF_VECTOR 14 + #define MF_VECTOR 16 ++#define AC_VECTOR 17 + #define MC_VECTOR 18 + + #define SELECTOR_TI_MASK (1 << 2) diff --git a/patches/net-add-validation-for-the-socket-syscall-protocol-argument.patch b/patches/net-add-validation-for-the-socket-syscall-protocol-argument.patch new file mode 100644 index 0000000..5b39971 --- /dev/null +++ b/patches/net-add-validation-for-the-socket-syscall-protocol-argument.patch @@ -0,0 +1,128 @@ +From 79462ad02e861803b3840cc782248c7359451cd9 Mon Sep 17 00:00:00 2001 +From: Hannes Frederic Sowa <hannes@stressinduktion.org> +Date: Mon, 14 Dec 2015 22:03:39 +0100 +Subject: net: add validation for the socket syscall protocol argument +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 79462ad02e861803b3840cc782248c7359451cd9 upstream. + +郭永刚 reported that one could simply crash the kernel as root by +using a simple program: + + int socket_fd; + struct sockaddr_in addr; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = 10; + + socket_fd = socket(10,3,0x40000000); + connect(socket_fd , &addr,16); + +AF_INET, AF_INET6 sockets actually only support 8-bit protocol +identifiers. inet_sock's skc_protocol field thus is sized accordingly, +thus larger protocol identifiers simply cut off the higher bits and +store a zero in the protocol fields. + +This could lead to e.g. NULL function pointer because as a result of +the cut off inet_num is zero and we call down to inet_autobind, which +is NULL for raw sockets. + +kernel: Call Trace: +kernel: [<ffffffff816db90e>] ? inet_autobind+0x2e/0x70 +kernel: [<ffffffff816db9a4>] inet_dgram_connect+0x54/0x80 +kernel: [<ffffffff81645069>] SYSC_connect+0xd9/0x110 +kernel: [<ffffffff810ac51b>] ? ptrace_notify+0x5b/0x80 +kernel: [<ffffffff810236d8>] ? syscall_trace_enter_phase2+0x108/0x200 +kernel: [<ffffffff81645e0e>] SyS_connect+0xe/0x10 +kernel: [<ffffffff81779515>] tracesys_phase2+0x84/0x89 + +I found no particular commit which introduced this problem. + +CVE: CVE-2015-8543 +Cc: Cong Wang <cwang@twopensource.com> +Reported-by: 郭永刚 <guoyonggang@360.cn> +Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> +Signed-off-by: David S. Miller <davem@davemloft.net> +[lizf: Backported to 3.4: open-code U8_MAX] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + include/net/sock.h | 1 + + net/ax25/af_ax25.c | 3 +++ + net/decnet/af_decnet.c | 3 +++ + net/ipv4/af_inet.c | 3 +++ + net/ipv6/af_inet6.c | 3 +++ + net/irda/af_irda.c | 3 +++ + 6 files changed, 16 insertions(+) + +--- a/include/net/sock.h ++++ b/include/net/sock.h +@@ -328,6 +328,7 @@ struct sock { + sk_no_check : 2, + sk_userlocks : 4, + sk_protocol : 8, ++#define SK_PROTOCOL_MAX ((u8)~0U) + sk_type : 16; + kmemcheck_bitfield_end(flags); + int sk_wmem_queued; +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -811,6 +811,9 @@ static int ax25_create(struct net *net, + struct sock *sk; + ax25_cb *ax25; + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + +--- a/net/decnet/af_decnet.c ++++ b/net/decnet/af_decnet.c +@@ -680,6 +680,9 @@ static int dn_create(struct net *net, st + { + struct sock *sk; + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT; + +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -284,6 +284,9 @@ static int inet_create(struct net *net, + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) + build_ehash_secret(); + ++ if (protocol < 0 || protocol >= IPPROTO_MAX) ++ return -EINVAL; ++ + sock->state = SS_UNCONNECTED; + + /* Look for the requested type/protocol pair. */ +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -113,6 +113,9 @@ static int inet6_create(struct net *net, + !inet_ehash_secret) + build_ehash_secret(); + ++ if (protocol < 0 || protocol >= IPPROTO_MAX) ++ return -EINVAL; ++ + /* Look for the requested type/protocol pair. */ + lookup_protocol: + err = -ESOCKTNOSUPPORT; +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -1106,6 +1106,9 @@ static int irda_create(struct net *net, + + IRDA_DEBUG(2, "%s()\n", __func__); + ++ if (protocol < 0 || protocol > SK_PROTOCOL_MAX) ++ return -EINVAL; ++ + if (net != &init_net) + return -EAFNOSUPPORT; + diff --git a/patches/ppp-slip-validate-vj-compression-slot-parameters-completely.patch b/patches/ppp-slip-validate-vj-compression-slot-parameters-completely.patch new file mode 100644 index 0000000..df544e2 --- /dev/null +++ b/patches/ppp-slip-validate-vj-compression-slot-parameters-completely.patch @@ -0,0 +1,131 @@ +From 4ab42d78e37a294ac7bc56901d563c642e03c4ae Mon Sep 17 00:00:00 2001 +From: Ben Hutchings <ben@decadent.org.uk> +Date: Sun, 1 Nov 2015 16:22:53 +0000 +Subject: ppp, slip: Validate VJ compression slot parameters completely +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +commit 4ab42d78e37a294ac7bc56901d563c642e03c4ae upstream. + +Currently slhc_init() treats out-of-range values of rslots and tslots +as equivalent to 0, except that if tslots is too large it will +dereference a null pointer (CVE-2015-7799). + +Add a range-check at the top of the function and make it return an +ERR_PTR() on error instead of NULL. Change the callers accordingly. + +Compile-tested only. + +Reported-by: 郭永刚 <guoyonggang@360.cn> +References: http://article.gmane.org/gmane.comp.security.oss.general/17908 +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/isdn/i4l/isdn_ppp.c | 10 ++++------ + drivers/net/ppp/ppp_generic.c | 6 ++---- + drivers/net/slip/slhc.c | 12 ++++++++---- + drivers/net/slip/slip.c | 2 +- + 4 files changed, 15 insertions(+), 15 deletions(-) + +--- a/drivers/isdn/i4l/isdn_ppp.c ++++ b/drivers/isdn/i4l/isdn_ppp.c +@@ -322,9 +322,9 @@ isdn_ppp_open(int min, struct file *file + * VJ header compression init + */ + is->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ +- if (!is->slcomp) { ++ if (IS_ERR(is->slcomp)) { + isdn_ppp_ccp_reset_free(is); +- return -ENOMEM; ++ return PTR_ERR(is->slcomp); + } + #endif + #ifdef CONFIG_IPPP_FILTER +@@ -574,10 +574,8 @@ isdn_ppp_ioctl(int min, struct file *fil + is->maxcid = val; + #ifdef CONFIG_ISDN_PPP_VJ + sltmp = slhc_init(16, val); +- if (!sltmp) { +- printk(KERN_ERR "ippp, can't realloc slhc struct\n"); +- return -ENOMEM; +- } ++ if (IS_ERR(sltmp)) ++ return PTR_ERR(sltmp); + if (is->slcomp) + slhc_free(is->slcomp); + is->slcomp = sltmp; +--- a/drivers/net/ppp/ppp_generic.c ++++ b/drivers/net/ppp/ppp_generic.c +@@ -703,10 +703,8 @@ static long ppp_ioctl(struct file *file, + val &= 0xffff; + } + vj = slhc_init(val2+1, val+1); +- if (!vj) { +- netdev_err(ppp->dev, +- "PPP: no memory (VJ compressor)\n"); +- err = -ENOMEM; ++ if (IS_ERR(vj)) { ++ err = PTR_ERR(vj); + break; + } + ppp_lock(ppp); +--- a/drivers/net/slip/slhc.c ++++ b/drivers/net/slip/slhc.c +@@ -84,8 +84,9 @@ static long decode(unsigned char **cpp); + static unsigned char * put16(unsigned char *cp, unsigned short x); + static unsigned short pull16(unsigned char **cpp); + +-/* Initialize compression data structure ++/* Allocate compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) ++ * Returns pointer to structure or ERR_PTR() on error. + */ + struct slcompress * + slhc_init(int rslots, int tslots) +@@ -94,11 +95,14 @@ slhc_init(int rslots, int tslots) + register struct cstate *ts; + struct slcompress *comp; + ++ if (rslots < 0 || rslots > 255 || tslots < 0 || tslots > 255) ++ return ERR_PTR(-EINVAL); ++ + comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL); + if (! comp) + goto out_fail; + +- if ( rslots > 0 && rslots < 256 ) { ++ if (rslots > 0) { + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = kzalloc(rsize, GFP_KERNEL); + if (! comp->rstate) +@@ -106,7 +110,7 @@ slhc_init(int rslots, int tslots) + comp->rslot_limit = rslots - 1; + } + +- if ( tslots > 0 && tslots < 256 ) { ++ if (tslots > 0) { + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = kzalloc(tsize, GFP_KERNEL); + if (! comp->tstate) +@@ -141,7 +145,7 @@ out_free2: + out_free: + kfree(comp); + out_fail: +- return NULL; ++ return ERR_PTR(-ENOMEM); + } + + +--- a/drivers/net/slip/slip.c ++++ b/drivers/net/slip/slip.c +@@ -163,7 +163,7 @@ static int sl_alloc_bufs(struct slip *sl + if (cbuff == NULL) + goto err_exit; + slcomp = slhc_init(16, 16); +- if (slcomp == NULL) ++ if (IS_ERR(slcomp)) + goto err_exit; + #endif + spin_lock_bh(&sl->lock); diff --git a/patches/pptp-verify-sockaddr_len-in-pptp_bind-and-pptp_connect.patch b/patches/pptp-verify-sockaddr_len-in-pptp_bind-and-pptp_connect.patch new file mode 100644 index 0000000..4dc839f --- /dev/null +++ b/patches/pptp-verify-sockaddr_len-in-pptp_bind-and-pptp_connect.patch @@ -0,0 +1,37 @@ +From 09ccfd238e5a0e670d8178cf50180ea81ae09ae1 Mon Sep 17 00:00:00 2001 +From: WANG Cong <xiyou.wangcong@gmail.com> +Date: Mon, 14 Dec 2015 13:48:36 -0800 +Subject: pptp: verify sockaddr_len in pptp_bind() and pptp_connect() + +commit 09ccfd238e5a0e670d8178cf50180ea81ae09ae1 upstream. + +Reported-by: Dmitry Vyukov <dvyukov@gmail.com> +Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/net/ppp/pptp.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/drivers/net/ppp/pptp.c ++++ b/drivers/net/ppp/pptp.c +@@ -420,6 +420,9 @@ static int pptp_bind(struct socket *sock + struct pptp_opt *opt = &po->proto.pptp; + int error = 0; + ++ if (sockaddr_len < sizeof(struct sockaddr_pppox)) ++ return -EINVAL; ++ + lock_sock(sk); + + opt->src_addr = sp->sa_addr.pptp; +@@ -441,6 +444,9 @@ static int pptp_connect(struct socket *s + struct flowi4 fl4; + int error = 0; + ++ if (sockaddr_len < sizeof(struct sockaddr_pppox)) ++ return -EINVAL; ++ + if (sp->sa_protocol != PX_PROTO_PPTP) + return -EINVAL; + diff --git a/patches/rds-fix-race-condition-when-sending-a-message-on-unbound-socket.patch b/patches/rds-fix-race-condition-when-sending-a-message-on-unbound-socket.patch new file mode 100644 index 0000000..9e42c5c --- /dev/null +++ b/patches/rds-fix-race-condition-when-sending-a-message-on-unbound-socket.patch @@ -0,0 +1,70 @@ +From 8c7188b23474cca017b3ef354c4a58456f68303a Mon Sep 17 00:00:00 2001 +From: Quentin Casasnovas <quentin.casasnovas@oracle.com> +Date: Tue, 24 Nov 2015 17:13:21 -0500 +Subject: RDS: fix race condition when sending a message on unbound socket + +commit 8c7188b23474cca017b3ef354c4a58456f68303a upstream. + +Sasha's found a NULL pointer dereference in the RDS connection code when +sending a message to an apparently unbound socket. The problem is caused +by the code checking if the socket is bound in rds_sendmsg(), which checks +the rs_bound_addr field without taking a lock on the socket. This opens a +race where rs_bound_addr is temporarily set but where the transport is not +in rds_bind(), leading to a NULL pointer dereference when trying to +dereference 'trans' in __rds_conn_create(). + +Vegard wrote a reproducer for this issue, so kindly ask him to share if +you're interested. + +I cannot reproduce the NULL pointer dereference using Vegard's reproducer +with this patch, whereas I could without. + +Complete earlier incomplete fix to CVE-2015-6937: + + 74e98eb08588 ("RDS: verify the underlying transport exists before creating a connection") + +Cc: David S. Miller <davem@davemloft.net> + +Reviewed-by: Vegard Nossum <vegard.nossum@oracle.com> +Reviewed-by: Sasha Levin <sasha.levin@oracle.com> +Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> +Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + net/rds/connection.c | 6 ------ + net/rds/send.c | 4 +++- + 2 files changed, 3 insertions(+), 7 deletions(-) + +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -178,12 +178,6 @@ static struct rds_connection *__rds_conn + } + } + +- if (trans == NULL) { +- kmem_cache_free(rds_conn_slab, conn); +- conn = ERR_PTR(-ENODEV); +- goto out; +- } +- + conn->c_trans = trans; + + ret = trans->conn_alloc(conn, gfp); +--- a/net/rds/send.c ++++ b/net/rds/send.c +@@ -955,11 +955,13 @@ int rds_sendmsg(struct kiocb *iocb, stru + release_sock(sk); + } + +- /* racing with another thread binding seems ok here */ ++ lock_sock(sk); + if (daddr == 0 || rs->rs_bound_addr == 0) { ++ release_sock(sk); + ret = -ENOTCONN; /* XXX not a great errno */ + goto out; + } ++ release_sock(sk); + + /* size of rm including all sgs */ + ret = rds_rm_size(msg, payload_len); diff --git a/patches/rds-verify-the-underlying-transport-exists-before-creating-a-connection.patch b/patches/rds-verify-the-underlying-transport-exists-before-creating-a-connection.patch new file mode 100644 index 0000000..19b3ca2 --- /dev/null +++ b/patches/rds-verify-the-underlying-transport-exists-before-creating-a-connection.patch @@ -0,0 +1,77 @@ +From 74e98eb085889b0d2d4908f59f6e00026063014f Mon Sep 17 00:00:00 2001 +From: Sasha Levin <sasha.levin@oracle.com> +Date: Tue, 8 Sep 2015 10:53:40 -0400 +Subject: RDS: verify the underlying transport exists before creating a + connection + +commit 74e98eb085889b0d2d4908f59f6e00026063014f upstream. + +There was no verification that an underlying transport exists when creating +a connection, this would cause dereferencing a NULL ptr. + +It might happen on sockets that weren't properly bound before attempting to +send a message, which will cause a NULL ptr deref: + +[135546.047719] kasan: GPF could be caused by NULL-ptr deref or user memory accessgeneral protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN +[135546.051270] Modules linked in: +[135546.051781] CPU: 4 PID: 15650 Comm: trinity-c4 Not tainted 4.2.0-next-20150902-sasha-00041-gbaa1222-dirty #2527 +[135546.053217] task: ffff8800835bc000 ti: ffff8800bc708000 task.ti: ffff8800bc708000 +[135546.054291] RIP: __rds_conn_create (net/rds/connection.c:194) +[135546.055666] RSP: 0018:ffff8800bc70fab0 EFLAGS: 00010202 +[135546.056457] RAX: dffffc0000000000 RBX: 0000000000000f2c RCX: ffff8800835bc000 +[135546.057494] RDX: 0000000000000007 RSI: ffff8800835bccd8 RDI: 0000000000000038 +[135546.058530] RBP: ffff8800bc70fb18 R08: 0000000000000001 R09: 0000000000000000 +[135546.059556] R10: ffffed014d7a3a23 R11: ffffed014d7a3a21 R12: 0000000000000000 +[135546.060614] R13: 0000000000000001 R14: ffff8801ec3d0000 R15: 0000000000000000 +[135546.061668] FS: 00007faad4ffb700(0000) GS:ffff880252000000(0000) knlGS:0000000000000000 +[135546.062836] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b +[135546.063682] CR2: 000000000000846a CR3: 000000009d137000 CR4: 00000000000006a0 +[135546.064723] Stack: +[135546.065048] ffffffffafe2055c ffffffffafe23fc1 ffffed00493097bf ffff8801ec3d0008 +[135546.066247] 0000000000000000 00000000000000d0 0000000000000000 ac194a24c0586342 +[135546.067438] 1ffff100178e1f78 ffff880320581b00 ffff8800bc70fdd0 ffff880320581b00 +[135546.068629] Call Trace: +[135546.069028] ? __rds_conn_create (include/linux/rcupdate.h:856 net/rds/connection.c:134) +[135546.069989] ? rds_message_copy_from_user (net/rds/message.c:298) +[135546.071021] rds_conn_create_outgoing (net/rds/connection.c:278) +[135546.071981] rds_sendmsg (net/rds/send.c:1058) +[135546.072858] ? perf_trace_lock (include/trace/events/lock.h:38) +[135546.073744] ? lockdep_init (kernel/locking/lockdep.c:3298) +[135546.074577] ? rds_send_drop_to (net/rds/send.c:976) +[135546.075508] ? __might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3795) +[135546.076349] ? __might_fault (mm/memory.c:3795) +[135546.077179] ? rds_send_drop_to (net/rds/send.c:976) +[135546.078114] sock_sendmsg (net/socket.c:611 net/socket.c:620) +[135546.078856] SYSC_sendto (net/socket.c:1657) +[135546.079596] ? SYSC_connect (net/socket.c:1628) +[135546.080510] ? trace_dump_stack (kernel/trace/trace.c:1926) +[135546.081397] ? ring_buffer_unlock_commit (kernel/trace/ring_buffer.c:2479 kernel/trace/ring_buffer.c:2558 kernel/trace/ring_buffer.c:2674) +[135546.082390] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) +[135546.083410] ? trace_event_raw_event_sys_enter (include/trace/events/syscalls.h:16) +[135546.084481] ? do_audit_syscall_entry (include/trace/events/syscalls.h:16) +[135546.085438] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) +[135546.085515] rds_ib_laddr_check(): addr 36.74.25.172 ret -99 node type -1 + +Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> +Signed-off-by: Sasha Levin <sasha.levin@oracle.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + net/rds/connection.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +--- a/net/rds/connection.c ++++ b/net/rds/connection.c +@@ -178,6 +178,12 @@ static struct rds_connection *__rds_conn + } + } + ++ if (trans == NULL) { ++ kmem_cache_free(rds_conn_slab, conn); ++ conn = ERR_PTR(-ENODEV); ++ goto out; ++ } ++ + conn->c_trans = trans; + + ret = trans->conn_alloc(conn, gfp); diff --git a/patches/series b/patches/series index 5d1fad0..ae678a2 100644 --- a/patches/series +++ b/patches/series @@ -72,3 +72,20 @@ ipc-sem-fix-use-after-free-on-ipc_rmid-after-a-task-using-same-semaphore-set-exi net-fix-rcu-splat-in-af_key.patch sctp-donot-reset-the-overall_error_count-in-shutdown_receive-state.patch revert-usb-dwc3-reset-the-transfer-resource-index-on.patch +unix-avoid-use-after-free-in-ep_remove_wait_queue.patch +pptp-verify-sockaddr_len-in-pptp_bind-and-pptp_connect.patch +net-add-validation-for-the-socket-syscall-protocol-argument.patch +rds-verify-the-underlying-transport-exists-before-creating-a-connection.patch +rds-fix-race-condition-when-sending-a-message-on-unbound-socket.patch +sg_start_req-make-sure-that-there-s-not-too-many-elements-in-iovec.patch +virtio-net-drop-netif_f_fraglist.patch +isdn_ppp-add-checks-for-allocation-failure-in-isdn_ppp_open.patch +ppp-slip-validate-vj-compression-slot-parameters-completely.patch +usb-whiteheat-fix-potential-null-deref-at-probe.patch +keys-fix-race-between-key-destruction-and-finding-a-keyring-by-name.patch +keys-fix-crash-when-attempt-to-garbage-collect-an-uninstantiated-keyring.patch +ipv6-addrconf-validate-new-mtu-before-applying-it.patch +kvm-x86-work-around-infinite-loop-in-microcode-when-ac-is-delivered.patch +kvm-svm-unconditionally-intercept-db.patch +get-rid-of-s_files-and-files_lock.patch +initialize-msg-shm-ipc-objects-before-doing-ipc_addid.patch diff --git a/patches/sg_start_req-make-sure-that-there-s-not-too-many-elements-in-iovec.patch b/patches/sg_start_req-make-sure-that-there-s-not-too-many-elements-in-iovec.patch new file mode 100644 index 0000000..5502873 --- /dev/null +++ b/patches/sg_start_req-make-sure-that-there-s-not-too-many-elements-in-iovec.patch @@ -0,0 +1,34 @@ +From 451a2886b6bf90e2fb378f7c46c655450fb96e81 Mon Sep 17 00:00:00 2001 +From: Al Viro <viro@zeniv.linux.org.uk> +Date: Sat, 21 Mar 2015 20:08:18 -0400 +Subject: sg_start_req(): make sure that there's not too many elements in iovec + +commit 451a2886b6bf90e2fb378f7c46c655450fb96e81 upstream. + +unfortunately, allowing an arbitrary 16bit value means a possibility of +overflow in the calculation of total number of pages in bio_map_user_iov() - +we rely on there being no more than PAGE_SIZE members of sum in the +first loop there. If that sum wraps around, we end up allocating +too small array of pointers to pages and it's easy to overflow it in +the second loop. + +X-Coverup: TINC (and there's no lumber cartel either) +Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> +[lizf: Backported to 3.4: s/MAX_UIOVEC/UIO_MAXIOV] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/scsi/sg.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/drivers/scsi/sg.c ++++ b/drivers/scsi/sg.c +@@ -1687,6 +1687,9 @@ static int sg_start_req(Sg_request *srp, + md->from_user = 0; + } + ++ if (unlikely(iov_count > UIO_MAXIOV)) ++ return -EINVAL; ++ + if (iov_count) { + int len, size = sizeof(struct sg_iovec) * iov_count; + struct iovec *iov; diff --git a/patches/unix-avoid-use-after-free-in-ep_remove_wait_queue.patch b/patches/unix-avoid-use-after-free-in-ep_remove_wait_queue.patch new file mode 100644 index 0000000..162c7a6 --- /dev/null +++ b/patches/unix-avoid-use-after-free-in-ep_remove_wait_queue.patch @@ -0,0 +1,327 @@ +From 7d267278a9ece963d77eefec61630223fce08c6c Mon Sep 17 00:00:00 2001 +From: Rainer Weikusat <rweikusat@mobileactivedefense.com> +Date: Fri, 20 Nov 2015 22:07:23 +0000 +Subject: unix: avoid use-after-free in ep_remove_wait_queue + +commit 7d267278a9ece963d77eefec61630223fce08c6c upstream. + +Rainer Weikusat <rweikusat@mobileactivedefense.com> writes: +An AF_UNIX datagram socket being the client in an n:1 association with +some server socket is only allowed to send messages to the server if the +receive queue of this socket contains at most sk_max_ack_backlog +datagrams. This implies that prospective writers might be forced to go +to sleep despite none of the message presently enqueued on the server +receive queue were sent by them. In order to ensure that these will be +woken up once space becomes again available, the present unix_dgram_poll +routine does a second sock_poll_wait call with the peer_wait wait queue +of the server socket as queue argument (unix_dgram_recvmsg does a wake +up on this queue after a datagram was received). This is inherently +problematic because the server socket is only guaranteed to remain alive +for as long as the client still holds a reference to it. In case the +connection is dissolved via connect or by the dead peer detection logic +in unix_dgram_sendmsg, the server socket may be freed despite "the +polling mechanism" (in particular, epoll) still has a pointer to the +corresponding peer_wait queue. There's no way to forcibly deregister a +wait queue with epoll. + +Based on an idea by Jason Baron, the patch below changes the code such +that a wait_queue_t belonging to the client socket is enqueued on the +peer_wait queue of the server whenever the peer receive queue full +condition is detected by either a sendmsg or a poll. A wake up on the +peer queue is then relayed to the ordinary wait queue of the client +socket via wake function. The connection to the peer wait queue is again +dissolved if either a wake up is about to be relayed or the client +socket reconnects or a dead peer is detected or the client socket is +itself closed. This enables removing the second sock_poll_wait from +unix_dgram_poll, thus avoiding the use-after-free, while still ensuring +that no blocked writer sleeps forever. + +Signed-off-by: Rainer Weikusat <rweikusat@mobileactivedefense.com> +Fixes: ec0d215f9420 ("af_unix: fix 'poll for write'/connected DGRAM sockets") +Reviewed-by: Jason Baron <jbaron@akamai.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + include/net/af_unix.h | 1 + net/unix/af_unix.c | 183 ++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 165 insertions(+), 19 deletions(-) + +--- a/include/net/af_unix.h ++++ b/include/net/af_unix.h +@@ -60,6 +60,7 @@ struct unix_sock { + unsigned int gc_maybe_cycle : 1; + unsigned char recursion_level; + struct socket_wq peer_wq; ++ wait_queue_t peer_wake; + }; + #define unix_sk(__sk) ((struct unix_sock *)__sk) + +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -306,6 +306,118 @@ found: + return s; + } + ++/* Support code for asymmetrically connected dgram sockets ++ * ++ * If a datagram socket is connected to a socket not itself connected ++ * to the first socket (eg, /dev/log), clients may only enqueue more ++ * messages if the present receive queue of the server socket is not ++ * "too large". This means there's a second writeability condition ++ * poll and sendmsg need to test. The dgram recv code will do a wake ++ * up on the peer_wait wait queue of a socket upon reception of a ++ * datagram which needs to be propagated to sleeping would-be writers ++ * since these might not have sent anything so far. This can't be ++ * accomplished via poll_wait because the lifetime of the server ++ * socket might be less than that of its clients if these break their ++ * association with it or if the server socket is closed while clients ++ * are still connected to it and there's no way to inform "a polling ++ * implementation" that it should let go of a certain wait queue ++ * ++ * In order to propagate a wake up, a wait_queue_t of the client ++ * socket is enqueued on the peer_wait queue of the server socket ++ * whose wake function does a wake_up on the ordinary client socket ++ * wait queue. This connection is established whenever a write (or ++ * poll for write) hit the flow control condition and broken when the ++ * association to the server socket is dissolved or after a wake up ++ * was relayed. ++ */ ++ ++static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags, ++ void *key) ++{ ++ struct unix_sock *u; ++ wait_queue_head_t *u_sleep; ++ ++ u = container_of(q, struct unix_sock, peer_wake); ++ ++ __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait, ++ q); ++ u->peer_wake.private = NULL; ++ ++ /* relaying can only happen while the wq still exists */ ++ u_sleep = sk_sleep(&u->sk); ++ if (u_sleep) ++ wake_up_interruptible_poll(u_sleep, key); ++ ++ return 0; ++} ++ ++static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other) ++{ ++ struct unix_sock *u, *u_other; ++ int rc; ++ ++ u = unix_sk(sk); ++ u_other = unix_sk(other); ++ rc = 0; ++ spin_lock(&u_other->peer_wait.lock); ++ ++ if (!u->peer_wake.private) { ++ u->peer_wake.private = other; ++ __add_wait_queue(&u_other->peer_wait, &u->peer_wake); ++ ++ rc = 1; ++ } ++ ++ spin_unlock(&u_other->peer_wait.lock); ++ return rc; ++} ++ ++static void unix_dgram_peer_wake_disconnect(struct sock *sk, ++ struct sock *other) ++{ ++ struct unix_sock *u, *u_other; ++ ++ u = unix_sk(sk); ++ u_other = unix_sk(other); ++ spin_lock(&u_other->peer_wait.lock); ++ ++ if (u->peer_wake.private == other) { ++ __remove_wait_queue(&u_other->peer_wait, &u->peer_wake); ++ u->peer_wake.private = NULL; ++ } ++ ++ spin_unlock(&u_other->peer_wait.lock); ++} ++ ++static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk, ++ struct sock *other) ++{ ++ unix_dgram_peer_wake_disconnect(sk, other); ++ wake_up_interruptible_poll(sk_sleep(sk), ++ POLLOUT | ++ POLLWRNORM | ++ POLLWRBAND); ++} ++ ++/* preconditions: ++ * - unix_peer(sk) == other ++ * - association is stable ++ */ ++static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other) ++{ ++ int connected; ++ ++ connected = unix_dgram_peer_wake_connect(sk, other); ++ ++ if (unix_recvq_full(other)) ++ return 1; ++ ++ if (connected) ++ unix_dgram_peer_wake_disconnect(sk, other); ++ ++ return 0; ++} ++ + static inline int unix_writable(struct sock *sk) + { + return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; +@@ -410,6 +522,8 @@ static void unix_release_sock(struct soc + skpair->sk_state_change(skpair); + sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP); + } ++ ++ unix_dgram_peer_wake_disconnect(sk, skpair); + sock_put(skpair); /* It may now die */ + unix_peer(sk) = NULL; + } +@@ -646,6 +760,7 @@ static struct sock *unix_create1(struct + INIT_LIST_HEAD(&u->link); + mutex_init(&u->readlock); /* single task reading lock */ + init_waitqueue_head(&u->peer_wait); ++ init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay); + unix_insert_socket(unix_sockets_unbound, sk); + out: + if (sk == NULL) +@@ -1020,6 +1135,8 @@ restart: + if (unix_peer(sk)) { + struct sock *old_peer = unix_peer(sk); + unix_peer(sk) = other; ++ unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer); ++ + unix_state_double_unlock(sk, other); + + if (other != old_peer) +@@ -1459,6 +1576,7 @@ static int unix_dgram_sendmsg(struct kio + long timeo; + struct scm_cookie tmp_scm; + int max_level; ++ int sk_locked; + + if (NULL == siocb->scm) + siocb->scm = &tmp_scm; +@@ -1527,12 +1645,14 @@ restart: + goto out_free; + } + ++ sk_locked = 0; + unix_state_lock(other); ++restart_locked: + err = -EPERM; + if (!unix_may_send(sk, other)) + goto out_unlock; + +- if (sock_flag(other, SOCK_DEAD)) { ++ if (unlikely(sock_flag(other, SOCK_DEAD))) { + /* + * Check with 1003.1g - what should + * datagram error +@@ -1540,10 +1660,14 @@ restart: + unix_state_unlock(other); + sock_put(other); + ++ if (!sk_locked) ++ unix_state_lock(sk); ++ + err = 0; +- unix_state_lock(sk); + if (unix_peer(sk) == other) { + unix_peer(sk) = NULL; ++ unix_dgram_peer_wake_disconnect_wakeup(sk, other); ++ + unix_state_unlock(sk); + + unix_dgram_disconnected(sk, other); +@@ -1569,21 +1693,38 @@ restart: + goto out_unlock; + } + +- if (unix_peer(other) != sk && unix_recvq_full(other)) { +- if (!timeo) { +- err = -EAGAIN; +- goto out_unlock; ++ if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) { ++ if (timeo) { ++ timeo = unix_wait_for_peer(other, timeo); ++ ++ err = sock_intr_errno(timeo); ++ if (signal_pending(current)) ++ goto out_free; ++ ++ goto restart; + } + +- timeo = unix_wait_for_peer(other, timeo); ++ if (!sk_locked) { ++ unix_state_unlock(other); ++ unix_state_double_lock(sk, other); ++ } + +- err = sock_intr_errno(timeo); +- if (signal_pending(current)) +- goto out_free; ++ if (unix_peer(sk) != other || ++ unix_dgram_peer_wake_me(sk, other)) { ++ err = -EAGAIN; ++ sk_locked = 1; ++ goto out_unlock; ++ } + +- goto restart; ++ if (!sk_locked) { ++ sk_locked = 1; ++ goto restart_locked; ++ } + } + ++ if (unlikely(sk_locked)) ++ unix_state_unlock(sk); ++ + if (sock_flag(other, SOCK_RCVTSTAMP)) + __net_timestamp(skb); + maybe_add_creds(skb, sock, other); +@@ -1597,6 +1738,8 @@ restart: + return len; + + out_unlock: ++ if (sk_locked) ++ unix_state_unlock(sk); + unix_state_unlock(other); + out_free: + kfree_skb(skb); +@@ -2229,14 +2372,16 @@ static unsigned int unix_dgram_poll(stru + return mask; + + writable = unix_writable(sk); +- other = unix_peer_get(sk); +- if (other) { +- if (unix_peer(other) != sk) { +- sock_poll_wait(file, &unix_sk(other)->peer_wait, wait); +- if (unix_recvq_full(other)) +- writable = 0; +- } +- sock_put(other); ++ if (writable) { ++ unix_state_lock(sk); ++ ++ other = unix_peer(sk); ++ if (other && unix_peer(other) != sk && ++ unix_recvq_full(other) && ++ unix_dgram_peer_wake_me(sk, other)) ++ writable = 0; ++ ++ unix_state_unlock(sk); + } + + if (writable) diff --git a/patches/usb-whiteheat-fix-potential-null-deref-at-probe.patch b/patches/usb-whiteheat-fix-potential-null-deref-at-probe.patch new file mode 100644 index 0000000..893a4ed --- /dev/null +++ b/patches/usb-whiteheat-fix-potential-null-deref-at-probe.patch @@ -0,0 +1,79 @@ +From cbb4be652d374f64661137756b8f357a1827d6a4 Mon Sep 17 00:00:00 2001 +From: Johan Hovold <johan@kernel.org> +Date: Wed, 23 Sep 2015 11:41:42 -0700 +Subject: USB: whiteheat: fix potential null-deref at probe + +commit cbb4be652d374f64661137756b8f357a1827d6a4 upstream. + +Fix potential null-pointer dereference at probe by making sure that the +required endpoints are present. + +The whiteheat driver assumes there are at least five pairs of bulk +endpoints, of which the final pair is used for the "command port". An +attempt to bind to an interface with fewer bulk endpoints would +currently lead to an oops. + +Fixes CVE-2015-5257. + +Reported-by: Moein Ghasemzadeh <moein@istuary.com> +Signed-off-by: Johan Hovold <johan@kernel.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/usb/serial/whiteheat.c | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +--- a/drivers/usb/serial/whiteheat.c ++++ b/drivers/usb/serial/whiteheat.c +@@ -91,6 +91,8 @@ static int whiteheat_firmware_download( + static int whiteheat_firmware_attach(struct usb_serial *serial); + + /* function prototypes for the Connect Tech WhiteHEAT serial converter */ ++static int whiteheat_probe(struct usb_serial *serial, ++ const struct usb_device_id *id); + static int whiteheat_attach(struct usb_serial *serial); + static void whiteheat_release(struct usb_serial *serial); + static int whiteheat_open(struct tty_struct *tty, +@@ -134,6 +136,7 @@ static struct usb_serial_driver whitehea + .description = "Connect Tech - WhiteHEAT", + .id_table = id_table_std, + .num_ports = 4, ++ .probe = whiteheat_probe, + .attach = whiteheat_attach, + .release = whiteheat_release, + .open = whiteheat_open, +@@ -336,6 +339,34 @@ static int whiteheat_firmware_attach(str + /***************************************************************************** + * Connect Tech's White Heat serial driver functions + *****************************************************************************/ ++ ++static int whiteheat_probe(struct usb_serial *serial, ++ const struct usb_device_id *id) ++{ ++ struct usb_host_interface *iface_desc; ++ struct usb_endpoint_descriptor *endpoint; ++ size_t num_bulk_in = 0; ++ size_t num_bulk_out = 0; ++ size_t min_num_bulk; ++ unsigned int i; ++ ++ iface_desc = serial->interface->cur_altsetting; ++ ++ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { ++ endpoint = &iface_desc->endpoint[i].desc; ++ if (usb_endpoint_is_bulk_in(endpoint)) ++ ++num_bulk_in; ++ if (usb_endpoint_is_bulk_out(endpoint)) ++ ++num_bulk_out; ++ } ++ ++ min_num_bulk = COMMAND_PORT + 1; ++ if (num_bulk_in < min_num_bulk || num_bulk_out < min_num_bulk) ++ return -ENODEV; ++ ++ return 0; ++} ++ + static int whiteheat_attach(struct usb_serial *serial) + { + struct usb_serial_port *command_port; diff --git a/patches/virtio-net-drop-netif_f_fraglist.patch b/patches/virtio-net-drop-netif_f_fraglist.patch new file mode 100644 index 0000000..91d2088 --- /dev/null +++ b/patches/virtio-net-drop-netif_f_fraglist.patch @@ -0,0 +1,39 @@ +From 48900cb6af4282fa0fb6ff4d72a81aa3dadb5c39 Mon Sep 17 00:00:00 2001 +From: Jason Wang <jasowang@redhat.com> +Date: Wed, 5 Aug 2015 10:34:04 +0800 +Subject: virtio-net: drop NETIF_F_FRAGLIST + +commit 48900cb6af4282fa0fb6ff4d72a81aa3dadb5c39 upstream. + +virtio declares support for NETIF_F_FRAGLIST, but assumes +that there are at most MAX_SKB_FRAGS + 2 fragments which isn't +always true with a fraglist. + +A longer fraglist in the skb will make the call to skb_to_sgvec overflow +the sg array, leading to memory corruption. + +Drop NETIF_F_FRAGLIST so we only get what we can handle. + +Cc: Michael S. Tsirkin <mst@redhat.com> +Signed-off-by: Jason Wang <jasowang@redhat.com> +Acked-by: Michael S. Tsirkin <mst@redhat.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/net/virtio_net.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/drivers/net/virtio_net.c ++++ b/drivers/net/virtio_net.c +@@ -1036,9 +1036,9 @@ static int virtnet_probe(struct virtio_d + /* Do we support "hardware" checksums? */ + if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { + /* This opens up the world of extra features. */ +- dev->hw_features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; ++ dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG; + if (csum) +- dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST; ++ dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; + + if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { + dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO |