From bf9f65248fb89bc2d72cb869bb5b212ad9c01f8f Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Sat, 3 May 2014 14:04:59 +0200 Subject: [PATCH 1/6] n_tty: Fix n_tty_write crash when echoing in raw mode The tty atomic_write_lock does not provide an exclusion guarantee for the tty driver if the termios settings are LECHO & !OPOST. And since it is unexpected and not allowed to call TTY buffer helpers like tty_insert_flip_string concurrently, this may lead to crashes when concurrect writers call pty_write. In that case the following two writers: * the ECHOing from a workqueue and * pty_write from the process race and can overflow the corresponding TTY buffer like follows. If we look into tty_insert_flip_string_fixed_flag, there is: int space = __tty_buffer_request_room(port, goal, flags); struct tty_buffer *tb = port->buf.tail; ... memcpy(char_buf_ptr(tb, tb->used), chars, space); ... tb->used += space; so the race of the two can result in something like this: A B __tty_buffer_request_room __tty_buffer_request_room memcpy(buf(tb->used), ...) tb->used += space; memcpy(buf(tb->used), ...) ->BOOM B's memcpy is past the tty_buffer due to the previous A's tb->used increment. Since the N_TTY line discipline input processing can output concurrently with a tty write, obtain the N_TTY ldisc output_lock to serialize echo output with normal tty writes. This ensures the tty buffer helper tty_insert_flip_string is not called concurrently and everything is fine. Note that this is nicely reproducible by an ordinary user using forkpty and some setup around that (raw termios + ECHO). And it is present in kernels at least after commit d945cb9cce20ac7143c2de8d88b187f62db99bdc (pty: Rework the pty layer to use the normal buffering logic) in 2.6.31-rc3. js: add more info to the commit log js: switch to bool js: lock unconditionally js: lock only the tty->ops->write call References: CVE-2014-0196 Reported-and-tested-by: Jiri Slaby Signed-off-by: Peter Hurley Signed-off-by: Jiri Slaby Cc: Linus Torvalds Cc: Alan Cox Cc: Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 428f4fe0b5f7..7b4007b2c3a0 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1980,8 +1980,11 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, if (tty->ops->flush_chars) tty->ops->flush_chars(tty); } else { + while (nr > 0) { + mutex_lock(&tty->output_lock); c = tty->ops->write(tty, b, nr); + mutex_unlock(&tty->output_lock); if (c < 0) { retval = c; goto break_out; From b9f4b26235a161fd0506d530f6b03e91320e68d3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 3 Jun 2014 12:27:06 +0000 Subject: [PATCH 2/6] Fix CVE-2014-3153 futex-prevent-requeue-pi-on-same-futex.patch futex: Forbid uaddr == uaddr2 in futex_requeue(..., requeue_pi=1) If uaddr == uaddr2, then we have broken the rule of only requeueing from a non-pi futex to a pi futex with this call. If we attempt this, then dangling pointers may be left for rt_waiter resulting in an exploitable condition. This change brings futex_requeue() in line with futex_wait_requeue_pi() which performs the same check as per commit 6f7b0a2a5c0f ("futex: Forbid uaddr == uaddr2 in futex_wait_requeue_pi()") [ tglx: Compare the resulting keys as well, as uaddrs might be different depending on the mapping ] Change-Id: Ibe6195215657c86bf2e39305656fdacf7230389d Reported-by: Pinkie Pie Signed-off-by: Will Drewry Signed-off-by: Kees Cook Cc: stable@vger.kernel.org Signed-off-by: Thomas Gleixner Reviewed-by: Darren Hart Signed-off-by: Linus Torvalds --- kernel/futex.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/kernel/futex.c b/kernel/futex.c index 902fc39067a2..8cdeccd80571 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -1234,6 +1234,13 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, u32 curval2; if (requeue_pi) { + /* + * Requeue PI only works on two distinct uaddrs. This + * check is only valid for private futexes. See below. + */ + if (uaddr1 == uaddr2) + return -EINVAL; + /* * requeue_pi requires a pi_state, try to allocate it now * without any locks in case it fails. @@ -1271,6 +1278,15 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, if (unlikely(ret != 0)) goto out_put_key1; + /* + * The check above which compares uaddrs is not sufficient for + * shared futexes. We need to compare the keys: + */ + if (requeue_pi && match_futex(&key1, &key2)) { + ret = -EINVAL; + goto out_put_keys; + } + hb1 = hash_futex(&key1); hb2 = hash_futex(&key2); @@ -2288,6 +2304,15 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, if (ret) goto out_key2; + /* + * The check above which compares uaddrs is not sufficient for + * shared futexes. We need to compare the keys: + */ + if (match_futex(&q.key, &key2)) { + ret = -EINVAL; + goto out_put_keys; + } + /* Queue the futex_q, drop the hb lock, wait for wakeup. */ futex_wait_queue_me(hb, &q, to); From 728925b3b136cdfb531f3d57831d9a0d85b654a2 Mon Sep 17 00:00:00 2001 From: Corey Moyer Date: Sun, 4 Nov 2012 23:17:09 -0500 Subject: [PATCH 3/6] Increase readahead buffer --- include/linux/mm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index a021c046e774..89839c7d25b6 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1490,7 +1490,7 @@ int write_one_page(struct page *page, int wait); void task_dirty_inc(struct task_struct *tsk); /* readahead.c */ -#define VM_MAX_READAHEAD 128 /* kbytes */ +#define VM_MAX_READAHEAD 2048 /* kbytes */ #define VM_MIN_READAHEAD 16 /* kbytes (includes current page) */ int force_page_cache_readahead(struct address_space *mapping, struct file *filp, From 47dbacaabd7b624e09116deb6c94cb86c57696c6 Mon Sep 17 00:00:00 2001 From: spezi77 Date: Sun, 16 Mar 2014 15:51:02 +0100 Subject: [PATCH 4/6] Prevent SELinux audit error from coming up in logcat --- arch/arm/configs/evervolv_bravo_defconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/evervolv_bravo_defconfig b/arch/arm/configs/evervolv_bravo_defconfig index 281674c1fbbd..97040b647db0 100644 --- a/arch/arm/configs/evervolv_bravo_defconfig +++ b/arch/arm/configs/evervolv_bravo_defconfig @@ -48,7 +48,8 @@ CONFIG_SWAP=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_AUDIT is not set +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y CONFIG_HAVE_GENERIC_HARDIRQS=y # From 77589cad8a4c7eff7c5b7ed50f0932676ae49749 Mon Sep 17 00:00:00 2001 From: Tianyi Gou Date: Tue, 31 May 2011 13:23:01 -0700 Subject: [PATCH 5/6] net_sched: Add flow control support to prio qdisc Add enable_flow flag to the prio qdisc. Packet flow is enabled by default, but can be disabled from userspace (e.g. IPROUTE2 tc tool). This allows for suspending packet dequeue on a per-qdisc basis, which is needed to supprot Quality of Service (QOS) when using WWAN modem. Change-Id: I932f296be946f1acc3b00c7d8569bbb733d33622 Acked-by: Andrew Richardson CRs-Fixed: 283471 Signed-off-by: Tianyi Gou --- include/linux/pkt_sched.h | 1 + net/sched/sch_prio.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 2cfa4bc8dea6..4541898b9199 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -118,6 +118,7 @@ struct tc_fifo_qopt { struct tc_prio_qopt { int bands; /* Number of bands */ __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ + __u8 enable_flow; /* Enable dequeue */ }; /* MULTIQ section */ diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index fbd710d619bf..716aff5a37c8 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -28,6 +28,7 @@ struct prio_sched_data struct tcf_proto *filter_list; u8 prio2band[TC_PRIO_MAX+1]; struct Qdisc *queues[TCQ_PRIO_BANDS]; + u8 enable_flow; }; @@ -97,6 +98,9 @@ static struct sk_buff *prio_peek(struct Qdisc *sch) struct prio_sched_data *q = qdisc_priv(sch); int prio; + if (!q->enable_flow) + return NULL; + for (prio = 0; prio < q->bands; prio++) { struct Qdisc *qdisc = q->queues[prio]; struct sk_buff *skb = qdisc->ops->peek(qdisc); @@ -111,6 +115,9 @@ static struct sk_buff *prio_dequeue(struct Qdisc* sch) struct prio_sched_data *q = qdisc_priv(sch); int prio; + if (!q->enable_flow) + return NULL; + for (prio = 0; prio < q->bands; prio++) { struct Qdisc *qdisc = q->queues[prio]; struct sk_buff *skb = qdisc->dequeue(qdisc); @@ -151,6 +158,7 @@ prio_reset(struct Qdisc* sch) for (prio=0; priobands; prio++) qdisc_reset(q->queues[prio]); sch->q.qlen = 0; + q->enable_flow = 1; } static void @@ -183,6 +191,7 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) } sch_tree_lock(sch); + q->enable_flow = qopt->enable_flow; q->bands = qopt->bands; memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); @@ -245,6 +254,7 @@ static int prio_dump(struct Qdisc *sch, struct sk_buff *skb) struct tc_prio_qopt opt; opt.bands = q->bands; + opt.enable_flow = q->enable_flow; memcpy(&opt.priomap, q->prio2band, TC_PRIO_MAX+1); NLA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt); From 570ac1fcfae703b798e28dfb776b8d5cc274c491 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 7 Aug 2013 23:39:41 +0100 Subject: [PATCH 6/6] ARM: 7809/1: perf: fix event validation for software group leaders It is possible to construct an event group with a software event as a group leader and then subsequently add a hardware event to the group. This results in the event group being validated by adding all members of the group to a fake PMU and attempting to allocate each event on their respective PMU. Unfortunately, for software events wthout a corresponding arm_pmu, this results in a kernel crash attempting to dereference the ->get_event_idx function pointer. This patch fixes the problem by checking explicitly for software events and ignoring those in event validation (since they can always be scheduled). We will probably want to revisit this for 3.12, since the validation checks don't appear to work correctly when dealing with multiple hardware PMUs anyway. Cc: Reported-by: Vince Weaver Tested-by: Vince Weaver Tested-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Russell King Conflicts: arch/arm/kernel/perf_event.c --- arch/arm/kernel/perf_event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index bc2a90da2504..6a8949c5c6b2 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -358,6 +358,9 @@ validate_event(struct cpu_hw_events *cpuc, { struct hw_perf_event fake_event = event->hw; + if (is_software_event(event)) + return 1; + if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF) return 1;