diff --git a/fuse-verify-ioctl-retries.patch b/fuse-verify-ioctl-retries.patch new file mode 100644 index 000000000..d95d8cef2 --- /dev/null +++ b/fuse-verify-ioctl-retries.patch @@ -0,0 +1,56 @@ +From: Miklos Szeredi +Date: Tue, 30 Nov 2010 15:39:27 +0000 (+0100) +Subject: fuse: verify ioctl retries +X-Git-Tag: v2.6.37-rc6~31^2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=7572777eef78ebdee1ecb7c258c0ef94d35bad16 + +fuse: verify ioctl retries + +Verify that the total length of the iovec returned in FUSE_IOCTL_RETRY +doesn't overflow iov_length(). + +Signed-off-by: Miklos Szeredi +CC: Tejun Heo +CC: [2.6.31+] +--- + +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 0e2e25b..8b984a2 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1666,6 +1666,20 @@ static int fuse_copy_ioctl_iovec(struct iovec *dst, void *src, + return 0; + } + ++/* Make sure iov_length() won't overflow */ ++static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) ++{ ++ size_t n; ++ u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; ++ ++ for (n = 0; n < count; n++) { ++ if (iov->iov_len > (size_t) max) ++ return -ENOMEM; ++ max -= iov->iov_len; ++ } ++ return 0; ++} ++ + /* + * For ioctls, there is no generic way to determine how much memory + * needs to be read and/or written. Furthermore, ioctls are allowed +@@ -1858,6 +1872,14 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, + in_iov = page_address(iov_page); + out_iov = in_iov + in_iovs; + ++ err = fuse_verify_ioctl_iov(in_iov, in_iovs); ++ if (err) ++ goto out; ++ ++ err = fuse_verify_ioctl_iov(out_iov, out_iovs); ++ if (err) ++ goto out; ++ + goto retry; + } + diff --git a/ib-uverbs-handle-large-number-of-poll-entries-in-poll-cq.patch b/ib-uverbs-handle-large-number-of-poll-entries-in-poll-cq.patch new file mode 100644 index 000000000..cfa5bf92b --- /dev/null +++ b/ib-uverbs-handle-large-number-of-poll-entries-in-poll-cq.patch @@ -0,0 +1,160 @@ +From: Dan Carpenter +Date: Wed, 13 Oct 2010 09:13:12 +0000 (+0000) +Subject: IB/uverbs: Handle large number of entries in poll CQ +X-Git-Tag: v2.6.37-rc6~22^2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=7182afea8d1afd432a17c18162cc3fd441d0da93 + +IB/uverbs: Handle large number of entries in poll CQ + +In ib_uverbs_poll_cq() code there is a potential integer overflow if +userspace passes in a large cmd.ne. The calls to kmalloc() would +allocate smaller buffers than intended, leading to memory corruption. +There iss also an information leak if resp wasn't all used. +Unprivileged userspace may call this function, although only if an +RDMA device that uses this function is present. + +Fix this by copying CQ entries one at a time, which avoids the +allocation entirely, and also by moving this copying into a function +that makes sure to initialize all memory copied to userspace. + +Special thanks to Jason Gunthorpe +for his help and advice. + +Cc: +Signed-off-by: Dan Carpenter + +[ Monkey around with things a bit to avoid bad code generation by gcc + when designated initializers are used. - Roland ] + +Signed-off-by: Roland Dreier +--- + +diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c +index b342248..c426992 100644 +--- a/drivers/infiniband/core/uverbs_cmd.c ++++ b/drivers/infiniband/core/uverbs_cmd.c +@@ -893,68 +893,81 @@ out: + return ret ? ret : in_len; + } + ++static int copy_wc_to_user(void __user *dest, struct ib_wc *wc) ++{ ++ struct ib_uverbs_wc tmp; ++ ++ tmp.wr_id = wc->wr_id; ++ tmp.status = wc->status; ++ tmp.opcode = wc->opcode; ++ tmp.vendor_err = wc->vendor_err; ++ tmp.byte_len = wc->byte_len; ++ tmp.ex.imm_data = (__u32 __force) wc->ex.imm_data; ++ tmp.qp_num = wc->qp->qp_num; ++ tmp.src_qp = wc->src_qp; ++ tmp.wc_flags = wc->wc_flags; ++ tmp.pkey_index = wc->pkey_index; ++ tmp.slid = wc->slid; ++ tmp.sl = wc->sl; ++ tmp.dlid_path_bits = wc->dlid_path_bits; ++ tmp.port_num = wc->port_num; ++ tmp.reserved = 0; ++ ++ if (copy_to_user(dest, &tmp, sizeof tmp)) ++ return -EFAULT; ++ ++ return 0; ++} ++ + ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, + const char __user *buf, int in_len, + int out_len) + { + struct ib_uverbs_poll_cq cmd; +- struct ib_uverbs_poll_cq_resp *resp; ++ struct ib_uverbs_poll_cq_resp resp; ++ u8 __user *header_ptr; ++ u8 __user *data_ptr; + struct ib_cq *cq; +- struct ib_wc *wc; +- int ret = 0; +- int i; +- int rsize; ++ struct ib_wc wc; ++ int ret; + + if (copy_from_user(&cmd, buf, sizeof cmd)) + return -EFAULT; + +- wc = kmalloc(cmd.ne * sizeof *wc, GFP_KERNEL); +- if (!wc) +- return -ENOMEM; +- +- rsize = sizeof *resp + cmd.ne * sizeof(struct ib_uverbs_wc); +- resp = kmalloc(rsize, GFP_KERNEL); +- if (!resp) { +- ret = -ENOMEM; +- goto out_wc; +- } +- + cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0); +- if (!cq) { +- ret = -EINVAL; +- goto out; +- } ++ if (!cq) ++ return -EINVAL; + +- resp->count = ib_poll_cq(cq, cmd.ne, wc); ++ /* we copy a struct ib_uverbs_poll_cq_resp to user space */ ++ header_ptr = (void __user *)(unsigned long) cmd.response; ++ data_ptr = header_ptr + sizeof resp; + +- put_cq_read(cq); ++ memset(&resp, 0, sizeof resp); ++ while (resp.count < cmd.ne) { ++ ret = ib_poll_cq(cq, 1, &wc); ++ if (ret < 0) ++ goto out_put; ++ if (!ret) ++ break; ++ ++ ret = copy_wc_to_user(data_ptr, &wc); ++ if (ret) ++ goto out_put; + +- for (i = 0; i < resp->count; i++) { +- resp->wc[i].wr_id = wc[i].wr_id; +- resp->wc[i].status = wc[i].status; +- resp->wc[i].opcode = wc[i].opcode; +- resp->wc[i].vendor_err = wc[i].vendor_err; +- resp->wc[i].byte_len = wc[i].byte_len; +- resp->wc[i].ex.imm_data = (__u32 __force) wc[i].ex.imm_data; +- resp->wc[i].qp_num = wc[i].qp->qp_num; +- resp->wc[i].src_qp = wc[i].src_qp; +- resp->wc[i].wc_flags = wc[i].wc_flags; +- resp->wc[i].pkey_index = wc[i].pkey_index; +- resp->wc[i].slid = wc[i].slid; +- resp->wc[i].sl = wc[i].sl; +- resp->wc[i].dlid_path_bits = wc[i].dlid_path_bits; +- resp->wc[i].port_num = wc[i].port_num; ++ data_ptr += sizeof(struct ib_uverbs_wc); ++ ++resp.count; + } + +- if (copy_to_user((void __user *) (unsigned long) cmd.response, resp, rsize)) ++ if (copy_to_user(header_ptr, &resp, sizeof resp)) { + ret = -EFAULT; ++ goto out_put; ++ } + +-out: +- kfree(resp); ++ ret = in_len; + +-out_wc: +- kfree(wc); +- return ret ? ret : in_len; ++out_put: ++ put_cq_read(cq); ++ return ret; + } + + ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, diff --git a/ima-fix-add-lsm-rule-bug.patch b/ima-fix-add-lsm-rule-bug.patch new file mode 100644 index 000000000..ac56bcdd6 --- /dev/null +++ b/ima-fix-add-lsm-rule-bug.patch @@ -0,0 +1,62 @@ +From: Mimi Zohar +Date: Mon, 3 Jan 2011 22:59:10 +0000 (-0800) +Subject: ima: fix add LSM rule bug +X-Git-Tag: v2.6.37~5 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=867c20265459d30a01b021a9c1e81fb4c5832aa9 + +ima: fix add LSM rule bug + +If security_filter_rule_init() doesn't return a rule, then not everything +is as fine as the return code implies. + +This bug only occurs when the LSM (eg. SELinux) is disabled at runtime. + +Adding an empty LSM rule causes ima_match_rules() to always succeed, +ignoring any remaining rules. + + default IMA TCB policy: + # PROC_SUPER_MAGIC + dont_measure fsmagic=0x9fa0 + # SYSFS_MAGIC + dont_measure fsmagic=0x62656572 + # DEBUGFS_MAGIC + dont_measure fsmagic=0x64626720 + # TMPFS_MAGIC + dont_measure fsmagic=0x01021994 + # SECURITYFS_MAGIC + dont_measure fsmagic=0x73636673 + + < LSM specific rule > + dont_measure obj_type=var_log_t + + measure func=BPRM_CHECK + measure func=FILE_MMAP mask=MAY_EXEC + measure func=FILE_CHECK mask=MAY_READ uid=0 + +Thus without the patch, with the boot parameters 'tcb selinux=0', adding +the above 'dont_measure obj_type=var_log_t' rule to the default IMA TCB +measurement policy, would result in nothing being measured. The patch +prevents the default TCB policy from being replaced. + +Signed-off-by: Mimi Zohar +Cc: James Morris +Acked-by: Serge Hallyn +Cc: David Safford +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +--- + +diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c +index aef8c0a..d661afb 100644 +--- a/security/integrity/ima/ima_policy.c ++++ b/security/integrity/ima/ima_policy.c +@@ -253,6 +253,8 @@ static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, + result = security_filter_rule_init(entry->lsm[lsm_rule].type, + Audit_equal, args, + &entry->lsm[lsm_rule].rule); ++ if (!entry->lsm[lsm_rule].rule) ++ return -EINVAL; + return result; + } + diff --git a/install-special-mapping-skips-security-file-mmap-check.patch b/install-special-mapping-skips-security-file-mmap-check.patch new file mode 100644 index 000000000..b53b39954 --- /dev/null +++ b/install-special-mapping-skips-security-file-mmap-check.patch @@ -0,0 +1,107 @@ +From: Tavis Ormandy +Date: Thu, 9 Dec 2010 14:29:42 +0000 (+0100) +Subject: install_special_mapping skips security_file_mmap check. +X-Git-Tag: v2.6.37-rc6~5 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=462e635e5b73ba9a4c03913b77138cd57ce4b050 + +install_special_mapping skips security_file_mmap check. + +[ Trivial backport to 2.6.34 ] + +The install_special_mapping routine (used, for example, to setup the +vdso) skips the security check before insert_vm_struct, allowing a local +attacker to bypass the mmap_min_addr security restriction by limiting +the available pages for special mappings. + +bprm_mm_init() also skips the check, and although I don't think this can +be used to bypass any restrictions, I don't see any reason not to have +the security check. + + $ uname -m + x86_64 + $ cat /proc/sys/vm/mmap_min_addr + 65536 + $ cat install_special_mapping.s + section .bss + resb BSS_SIZE + section .text + global _start + _start: + mov eax, __NR_pause + int 0x80 + $ nasm -D__NR_pause=29 -DBSS_SIZE=0xfffed000 -f elf -o install_special_mapping.o install_special_mapping.s + $ ld -m elf_i386 -Ttext=0x10000 -Tbss=0x11000 -o install_special_mapping install_special_mapping.o + $ ./install_special_mapping & + [1] 14303 + $ cat /proc/14303/maps + 0000f000-00010000 r-xp 00000000 00:00 0 [vdso] + 00010000-00011000 r-xp 00001000 00:19 2453665 /home/taviso/install_special_mapping + 00011000-ffffe000 rwxp 00000000 00:00 0 [stack] + +It's worth noting that Red Hat are shipping with mmap_min_addr set to +4096. + +Signed-off-by: Tavis Ormandy +Acked-by: Kees Cook +Acked-by: Robert Swiecki +[ Changed to not drop the error code - akpm ] +Reviewed-by: James Morris +Signed-off-by: Linus Torvalds +--- + +diff --git a/fs/exec.c b/fs/exec.c +index d68c378..c62efcb 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -275,6 +275,11 @@ static int __bprm_mm_init(struct linux_binprm *bprm) + vma->vm_flags = VM_STACK_FLAGS; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + INIT_LIST_HEAD(&vma->anon_vma_chain); ++ ++ err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); ++ if (err) ++ goto err; ++ + err = insert_vm_struct(mm, vma); + if (err) + goto err; +diff --git a/mm/mmap.c b/mm/mmap.c +index b179abb..50a4aa0 100644 +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -2462,6 +2462,7 @@ int install_special_mapping(struct mm_struct *mm, + unsigned long addr, unsigned long len, + unsigned long vm_flags, struct page **pages) + { ++ int ret; + struct vm_area_struct *vma; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); +@@ -2479,16 +2480,23 @@ int install_special_mapping(struct mm_struct *mm, + vma->vm_ops = &special_mapping_vmops; + vma->vm_private_data = pages; + +- if (unlikely(insert_vm_struct(mm, vma))) { +- kmem_cache_free(vm_area_cachep, vma); +- return -ENOMEM; +- } ++ ret = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); ++ if (ret) ++ goto out; ++ ++ ret = insert_vm_struct(mm, vma); ++ if (ret) ++ goto out; + + mm->total_vm += len >> PAGE_SHIFT; + + perf_event_mmap(vma); + + return 0; ++ ++out: ++ kmem_cache_free(vm_area_cachep, vma); ++ return ret; + } + + static DEFINE_MUTEX(mm_all_locks_mutex); diff --git a/kernel.spec b/kernel.spec index cfc99f7ae..d6e21b4ec 100644 --- a/kernel.spec +++ b/kernel.spec @@ -918,6 +918,17 @@ Patch13925: block-check-for-proper-length-of-iov-entries-earlier-in-blk_rq_map_u # rhbz#643758 Patch13926: hostap_cs-fix-sleeping-function-called-from-invalid-context.patch +# CVE-2010-4346 +Patch13930: install-special-mapping-skips-security-file-mmap-check.patch +# CVE-2010-4649 +Patch13931: ib-uverbs-handle-large-number-of-poll-entries-in-poll-cq.patch +# CVE-2011-0006 +Patch13932: ima-fix-add-lsm-rule-bug.patch +# CVE-2010-4648 +Patch13933: orinoco-fix-tkip-countermeasure-behaviour.patch +# CVE-2010-4650 +Patch13934: fuse-verify-ioctl-retries.patch + %endif BuildRoot: %{_tmppath}/kernel-%{KVERREL}-root @@ -1759,6 +1770,17 @@ ApplyPatch block-check-for-proper-length-of-iov-entries-earlier-in-blk_rq_map_us # rhbz#643758 ApplyPatch hostap_cs-fix-sleeping-function-called-from-invalid-context.patch +# CVE-2010-4346 +ApplyPatch install-special-mapping-skips-security-file-mmap-check.patch +# CVE-2010-4649 +ApplyPatch ib-uverbs-handle-large-number-of-poll-entries-in-poll-cq.patch +# CVE-2011-0006 +ApplyPatch ima-fix-add-lsm-rule-bug.patch +# CVE-2010-4648 +ApplyPatch orinoco-fix-tkip-countermeasure-behaviour.patch +# CVE-2010-4650 +ApplyPatch fuse-verify-ioctl-retries.patch + # END OF PATCH APPLICATIONS %endif @@ -2380,6 +2402,14 @@ fi %changelog +* Sat Jan 22 2011 Chuck Ebbert +- Security updates + CVE-2010-4346: install_special_mapping skips security_file_mmap check + CVE-2010-4649: IB/uverbs: Handle large number of entries in poll CQ + CVE-2011-0006: ima: fix add LSM rule bug + CVE-2010-4648: orinoco: fix TKIP countermeasure behaviour + CVE-2010-4650: fuse: verify ioctl retries + * Tue Jan 18 2011 Kyle McMartin - sgruszka: hostap_cs: fix sleeping function called in invalid context (#643758) diff --git a/orinoco-fix-tkip-countermeasure-behaviour.patch b/orinoco-fix-tkip-countermeasure-behaviour.patch new file mode 100644 index 000000000..f62a6018c --- /dev/null +++ b/orinoco-fix-tkip-countermeasure-behaviour.patch @@ -0,0 +1,59 @@ +From: David Kilroy +Date: Sun, 5 Dec 2010 15:43:55 +0000 (+0000) +Subject: orinoco: fix TKIP countermeasure behaviour +X-Git-Tag: v2.6.37-rc6~14^2~14^2 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=0a54917c3fc295cb61f3fb52373c173fd3b69f48 + +orinoco: fix TKIP countermeasure behaviour + +Enable the port when disabling countermeasures, and disable it on +enabling countermeasures. + +This bug causes the response of the system to certain attacks to be +ineffective. + +It also prevents wpa_supplicant from getting scan results, as +wpa_supplicant disables countermeasures on startup - preventing the +hardware from scanning. + +wpa_supplicant works with ap_mode=2 despite this bug because the commit +handler re-enables the port. + +The log tends to look like: + +State: DISCONNECTED -> SCANNING +Starting AP scan for wildcard SSID +Scan requested (ret=0) - scan timeout 5 seconds +EAPOL: disable timer tick +EAPOL: Supplicant port status: Unauthorized +Scan timeout - try to get results +Failed to get scan results +Failed to get scan results - try scanning again +Setting scan request: 1 sec 0 usec +Starting AP scan for wildcard SSID +Scan requested (ret=-1) - scan timeout 5 seconds +Failed to initiate AP scan. + +Reported by: Giacomo Comes +Signed-off by: David Kilroy +Cc: stable@kernel.org +Signed-off-by: John W. Linville +--- + +diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c +index 93505f9..e5afabe 100644 +--- a/drivers/net/wireless/orinoco/wext.c ++++ b/drivers/net/wireless/orinoco/wext.c +@@ -911,10 +911,10 @@ static int orinoco_ioctl_set_auth(struct net_device *dev, + */ + if (param->value) { + priv->tkip_cm_active = 1; +- ret = hermes_enable_port(hw, 0); ++ ret = hermes_disable_port(hw, 0); + } else { + priv->tkip_cm_active = 0; +- ret = hermes_disable_port(hw, 0); ++ ret = hermes_enable_port(hw, 0); + } + break; +