From 1b74baddf0d380d30ac06817f077a20eae10b0ce Mon Sep 17 00:00:00 2001 From: Tad Date: Fri, 10 Nov 2017 03:06:09 -0500 Subject: [PATCH] Patch against towelroot --- .../Linux_CVEs/CVE-2014-3153/ANY/0001.patch | 84 +++++ .../Linux_CVEs/CVE-2014-3153/ANY/0002.patch | 100 ++++++ .../Linux_CVEs/CVE-2014-3153/ANY/0003.patch | 279 +++++++++++++++ .../Linux_CVEs/CVE-2014-3153/ANY/0004.patch | 56 +++ .../Linux_CVEs/CVE-2015-1805/ANY/0005.patch | 132 +++++++ .../Linux_CVEs/CVE-2015-1805/ANY/0006.patch | 326 ++++++++++++++++++ Patches/Linux_CVEs/Kernel_CVE_Patch_List.txt | 12 +- .../android_kernel_amazon_hdx-common.sh | 2 + .../android_kernel_htc_msm8974.sh | 2 + .../android_kernel_samsung_smdk4412.sh | 1 + 10 files changed, 990 insertions(+), 4 deletions(-) create mode 100644 Patches/Linux_CVEs/CVE-2014-3153/ANY/0001.patch create mode 100644 Patches/Linux_CVEs/CVE-2014-3153/ANY/0002.patch create mode 100644 Patches/Linux_CVEs/CVE-2014-3153/ANY/0003.patch create mode 100644 Patches/Linux_CVEs/CVE-2014-3153/ANY/0004.patch create mode 100644 Patches/Linux_CVEs/CVE-2015-1805/ANY/0005.patch create mode 100644 Patches/Linux_CVEs/CVE-2015-1805/ANY/0006.patch diff --git a/Patches/Linux_CVEs/CVE-2014-3153/ANY/0001.patch b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0001.patch new file mode 100644 index 00000000..aa84e2d1 --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0001.patch @@ -0,0 +1,84 @@ +From e9c243a5a6de0be8e584c604d353412584b592f8 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:06 +0000 +Subject: 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 ] + +Fixes CVE-2014-3153. + +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 81dbe77..663ea2b 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -1442,6 +1442,13 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, + + 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. + */ +@@ -1479,6 +1486,15 @@ retry: + 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); + +@@ -2525,6 +2541,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); + +-- +cgit v1.1 + diff --git a/Patches/Linux_CVEs/CVE-2014-3153/ANY/0002.patch b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0002.patch new file mode 100644 index 00000000..3a9932a5 --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0002.patch @@ -0,0 +1,100 @@ +From 13fbca4c6ecd96ec1a1cfa2e4f2ce191fe928a5e Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:07 +0000 +Subject: futex: Always cleanup owner tid in unlock_pi + +If the owner died bit is set at futex_unlock_pi, we currently do not +cleanup the user space futex. So the owner TID of the current owner +(the unlocker) persists. That's observable inconsistant state, +especially when the ownership of the pi state got transferred. + +Clean it up unconditionally. + +Signed-off-by: Thomas Gleixner +Cc: Kees Cook +Cc: Will Drewry +Cc: Darren Hart +Cc: stable@vger.kernel.org +Signed-off-by: Linus Torvalds +--- + kernel/futex.c | 40 ++++++++++++++++++---------------------- + 1 file changed, 18 insertions(+), 22 deletions(-) + +diff --git a/kernel/futex.c b/kernel/futex.c +index 520e7b2..e1cb1ba 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -1052,6 +1052,7 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) + struct task_struct *new_owner; + struct futex_pi_state *pi_state = this->pi_state; + u32 uninitialized_var(curval), newval; ++ int ret = 0; + + if (!pi_state) + return -EINVAL; +@@ -1075,23 +1076,19 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this) + new_owner = this->task; + + /* +- * We pass it to the next owner. (The WAITERS bit is always +- * kept enabled while there is PI state around. We must also +- * preserve the owner died bit.) ++ * We pass it to the next owner. The WAITERS bit is always ++ * kept enabled while there is PI state around. We cleanup the ++ * owner died bit, because we are the owner. + */ +- if (!(uval & FUTEX_OWNER_DIED)) { +- int ret = 0; +- +- newval = FUTEX_WAITERS | task_pid_vnr(new_owner); ++ newval = FUTEX_WAITERS | task_pid_vnr(new_owner); + +- if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) +- ret = -EFAULT; +- else if (curval != uval) +- ret = -EINVAL; +- if (ret) { +- raw_spin_unlock(&pi_state->pi_mutex.wait_lock); +- return ret; +- } ++ if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) ++ ret = -EFAULT; ++ else if (curval != uval) ++ ret = -EINVAL; ++ if (ret) { ++ raw_spin_unlock(&pi_state->pi_mutex.wait_lock); ++ return ret; + } + + raw_spin_lock_irq(&pi_state->owner->pi_lock); +@@ -2351,9 +2348,10 @@ retry: + /* + * To avoid races, try to do the TID -> 0 atomic transition + * again. If it succeeds then we can return without waking +- * anyone else up: ++ * anyone else up. We only try this if neither the waiters nor ++ * the owner died bit are set. + */ +- if (!(uval & FUTEX_OWNER_DIED) && ++ if (!(uval & ~FUTEX_TID_MASK) && + cmpxchg_futex_value_locked(&uval, uaddr, vpid, 0)) + goto pi_faulted; + /* +@@ -2383,11 +2381,9 @@ retry: + /* + * No waiters - kernel unlocks the futex: + */ +- if (!(uval & FUTEX_OWNER_DIED)) { +- ret = unlock_futex_pi(uaddr, uval); +- if (ret == -EFAULT) +- goto pi_faulted; +- } ++ ret = unlock_futex_pi(uaddr, uval); ++ if (ret == -EFAULT) ++ goto pi_faulted; + + out_unlock: + spin_unlock(&hb->lock); +-- +cgit v1.1 + diff --git a/Patches/Linux_CVEs/CVE-2014-3153/ANY/0003.patch b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0003.patch new file mode 100644 index 00000000..beda251e --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0003.patch @@ -0,0 +1,279 @@ +From 54a217887a7b658e2650c3feff22756ab80c7339 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:08 +0000 +Subject: futex: Make lookup_pi_state more robust + +The current implementation of lookup_pi_state has ambigous handling of +the TID value 0 in the user space futex. We can get into the kernel +even if the TID value is 0, because either there is a stale waiters bit +or the owner died bit is set or we are called from the requeue_pi path +or from user space just for fun. + +The current code avoids an explicit sanity check for pid = 0 in case +that kernel internal state (waiters) are found for the user space +address. This can lead to state leakage and worse under some +circumstances. + +Handle the cases explicit: + + Waiter | pi_state | pi->owner | uTID | uODIED | ? + + [1] NULL | --- | --- | 0 | 0/1 | Valid + [2] NULL | --- | --- | >0 | 0/1 | Valid + + [3] Found | NULL | -- | Any | 0/1 | Invalid + + [4] Found | Found | NULL | 0 | 1 | Valid + [5] Found | Found | NULL | >0 | 1 | Invalid + + [6] Found | Found | task | 0 | 1 | Valid + + [7] Found | Found | NULL | Any | 0 | Invalid + + [8] Found | Found | task | ==taskTID | 0/1 | Valid + [9] Found | Found | task | 0 | 0 | Invalid + [10] Found | Found | task | !=taskTID | 0/1 | Invalid + + [1] Indicates that the kernel can acquire the futex atomically. We + came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit. + + [2] Valid, if TID does not belong to a kernel thread. If no matching + thread is found then it indicates that the owner TID has died. + + [3] Invalid. The waiter is queued on a non PI futex + + [4] Valid state after exit_robust_list(), which sets the user space + value to FUTEX_WAITERS | FUTEX_OWNER_DIED. + + [5] The user space value got manipulated between exit_robust_list() + and exit_pi_state_list() + + [6] Valid state after exit_pi_state_list() which sets the new owner in + the pi_state but cannot access the user space value. + + [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set. + + [8] Owner and user space value match + + [9] There is no transient state which sets the user space TID to 0 + except exit_robust_list(), but this is indicated by the + FUTEX_OWNER_DIED bit. See [4] + +[10] There is no transient state which leaves owner and user space + TID out of sync. + +Signed-off-by: Thomas Gleixner +Cc: Kees Cook +Cc: Will Drewry +Cc: Darren Hart +Cc: stable@vger.kernel.org +Signed-off-by: Linus Torvalds +--- + kernel/futex.c | 134 +++++++++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 106 insertions(+), 28 deletions(-) + +diff --git a/kernel/futex.c b/kernel/futex.c +index e1cb1ba..de938d2 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -743,10 +743,58 @@ void exit_pi_state_list(struct task_struct *curr) + raw_spin_unlock_irq(&curr->pi_lock); + } + ++/* ++ * We need to check the following states: ++ * ++ * Waiter | pi_state | pi->owner | uTID | uODIED | ? ++ * ++ * [1] NULL | --- | --- | 0 | 0/1 | Valid ++ * [2] NULL | --- | --- | >0 | 0/1 | Valid ++ * ++ * [3] Found | NULL | -- | Any | 0/1 | Invalid ++ * ++ * [4] Found | Found | NULL | 0 | 1 | Valid ++ * [5] Found | Found | NULL | >0 | 1 | Invalid ++ * ++ * [6] Found | Found | task | 0 | 1 | Valid ++ * ++ * [7] Found | Found | NULL | Any | 0 | Invalid ++ * ++ * [8] Found | Found | task | ==taskTID | 0/1 | Valid ++ * [9] Found | Found | task | 0 | 0 | Invalid ++ * [10] Found | Found | task | !=taskTID | 0/1 | Invalid ++ * ++ * [1] Indicates that the kernel can acquire the futex atomically. We ++ * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit. ++ * ++ * [2] Valid, if TID does not belong to a kernel thread. If no matching ++ * thread is found then it indicates that the owner TID has died. ++ * ++ * [3] Invalid. The waiter is queued on a non PI futex ++ * ++ * [4] Valid state after exit_robust_list(), which sets the user space ++ * value to FUTEX_WAITERS | FUTEX_OWNER_DIED. ++ * ++ * [5] The user space value got manipulated between exit_robust_list() ++ * and exit_pi_state_list() ++ * ++ * [6] Valid state after exit_pi_state_list() which sets the new owner in ++ * the pi_state but cannot access the user space value. ++ * ++ * [7] pi_state->owner can only be NULL when the OWNER_DIED bit is set. ++ * ++ * [8] Owner and user space value match ++ * ++ * [9] There is no transient state which sets the user space TID to 0 ++ * except exit_robust_list(), but this is indicated by the ++ * FUTEX_OWNER_DIED bit. See [4] ++ * ++ * [10] There is no transient state which leaves owner and user space ++ * TID out of sync. ++ */ + static int + lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, +- union futex_key *key, struct futex_pi_state **ps, +- struct task_struct *task) ++ union futex_key *key, struct futex_pi_state **ps) + { + struct futex_pi_state *pi_state = NULL; + struct futex_q *this, *next; +@@ -756,12 +804,13 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, + plist_for_each_entry_safe(this, next, &hb->chain, list) { + if (match_futex(&this->key, key)) { + /* +- * Another waiter already exists - bump up +- * the refcount and return its pi_state: ++ * Sanity check the waiter before increasing ++ * the refcount and attaching to it. + */ + pi_state = this->pi_state; + /* +- * Userspace might have messed up non-PI and PI futexes ++ * Userspace might have messed up non-PI and ++ * PI futexes [3] + */ + if (unlikely(!pi_state)) + return -EINVAL; +@@ -769,44 +818,70 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, + WARN_ON(!atomic_read(&pi_state->refcount)); + + /* +- * When pi_state->owner is NULL then the owner died +- * and another waiter is on the fly. pi_state->owner +- * is fixed up by the task which acquires +- * pi_state->rt_mutex. +- * +- * We do not check for pid == 0 which can happen when +- * the owner died and robust_list_exit() cleared the +- * TID. ++ * Handle the owner died case: + */ +- if (pid && pi_state->owner) { ++ if (uval & FUTEX_OWNER_DIED) { + /* +- * Bail out if user space manipulated the +- * futex value. ++ * exit_pi_state_list sets owner to NULL and ++ * wakes the topmost waiter. The task which ++ * acquires the pi_state->rt_mutex will fixup ++ * owner. + */ +- if (pid != task_pid_vnr(pi_state->owner)) ++ if (!pi_state->owner) { ++ /* ++ * No pi state owner, but the user ++ * space TID is not 0. Inconsistent ++ * state. [5] ++ */ ++ if (pid) ++ return -EINVAL; ++ /* ++ * Take a ref on the state and ++ * return. [4] ++ */ ++ goto out_state; ++ } ++ ++ /* ++ * If TID is 0, then either the dying owner ++ * has not yet executed exit_pi_state_list() ++ * or some waiter acquired the rtmutex in the ++ * pi state, but did not yet fixup the TID in ++ * user space. ++ * ++ * Take a ref on the state and return. [6] ++ */ ++ if (!pid) ++ goto out_state; ++ } else { ++ /* ++ * If the owner died bit is not set, ++ * then the pi_state must have an ++ * owner. [7] ++ */ ++ if (!pi_state->owner) + return -EINVAL; + } + + /* +- * Protect against a corrupted uval. If uval +- * is 0x80000000 then pid is 0 and the waiter +- * bit is set. So the deadlock check in the +- * calling code has failed and we did not fall +- * into the check above due to !pid. ++ * Bail out if user space manipulated the ++ * futex value. If pi state exists then the ++ * owner TID must be the same as the user ++ * space TID. [9/10] + */ +- if (task && pi_state->owner == task) +- return -EDEADLK; ++ if (pid != task_pid_vnr(pi_state->owner)) ++ return -EINVAL; + ++ out_state: + atomic_inc(&pi_state->refcount); + *ps = pi_state; +- + return 0; + } + } + + /* + * We are the first waiter - try to look up the real owner and attach +- * the new pi_state to it, but bail out when TID = 0 ++ * the new pi_state to it, but bail out when TID = 0 [1] + */ + if (!pid) + return -ESRCH; +@@ -839,6 +914,9 @@ lookup_pi_state(u32 uval, struct futex_hash_bucket *hb, + return ret; + } + ++ /* ++ * No existing pi state. First waiter. [2] ++ */ + pi_state = alloc_pi_state(); + + /* +@@ -959,7 +1037,7 @@ retry: + * We dont have the lock. Look up the PI state (or create it if + * we are the first waiter): + */ +- ret = lookup_pi_state(uval, hb, key, ps, task); ++ ret = lookup_pi_state(uval, hb, key, ps); + + if (unlikely(ret)) { + switch (ret) { +@@ -1565,7 +1643,7 @@ retry_private: + * rereading and handing potential crap to + * lookup_pi_state. + */ +- ret = lookup_pi_state(ret, hb2, &key2, &pi_state, NULL); ++ ret = lookup_pi_state(ret, hb2, &key2, &pi_state); + } + + switch (ret) { +-- +cgit v1.1 + diff --git a/Patches/Linux_CVEs/CVE-2014-3153/ANY/0004.patch b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0004.patch new file mode 100644 index 00000000..05ac287f --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2014-3153/ANY/0004.patch @@ -0,0 +1,56 @@ +From b3eaa9fc5cd0a4d74b18f6b8dc617aeaf1873270 Mon Sep 17 00:00:00 2001 +From: Thomas Gleixner +Date: Tue, 3 Jun 2014 12:27:06 +0000 +Subject: futex: Validate atomic acquisition in futex_lock_pi_atomic() + +We need to protect the atomic acquisition in the kernel against rogue +user space which sets the user space futex to 0, so the kernel side +acquisition succeeds while there is existing state in the kernel +associated to the real owner. + +Verify whether the futex has waiters associated with kernel state. If +it has, return -EINVAL. The state is corrupted already, so no point in +cleaning it up. Subsequent calls will fail as well. Not our problem. + +[ tglx: Use futex_top_waiter() and explain why we do not need to try + restoring the already corrupted user space state. ] + +Signed-off-by: Darren Hart +Cc: Kees Cook +Cc: Will Drewry +Cc: stable@vger.kernel.org +Signed-off-by: Thomas Gleixner +Signed-off-by: Linus Torvalds +--- + kernel/futex.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/kernel/futex.c b/kernel/futex.c +index 663ea2b..520e7b2 100644 +--- a/kernel/futex.c ++++ b/kernel/futex.c +@@ -910,10 +910,18 @@ retry: + return -EDEADLK; + + /* +- * Surprise - we got the lock. Just return to userspace: ++ * Surprise - we got the lock, but we do not trust user space at all. + */ +- if (unlikely(!curval)) +- return 1; ++ if (unlikely(!curval)) { ++ /* ++ * We verify whether there is kernel state for this ++ * futex. If not, we can safely assume, that the 0 -> ++ * TID transition is correct. If state exists, we do ++ * not bother to fixup the user space state as it was ++ * corrupted already. ++ */ ++ return futex_top_waiter(hb, key) ? -EINVAL : 1; ++ } + + uval = curval; + +-- +cgit v1.1 + diff --git a/Patches/Linux_CVEs/CVE-2015-1805/ANY/0005.patch b/Patches/Linux_CVEs/CVE-2015-1805/ANY/0005.patch new file mode 100644 index 00000000..02c24662 --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2015-1805/ANY/0005.patch @@ -0,0 +1,132 @@ +From 637b58c2887e5e57850865839cc75f59184b23d1 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Mon, 3 Feb 2014 19:11:42 -0500 +Subject: switch pipe_read() to copy_page_to_iter() + +Signed-off-by: Al Viro +--- + fs/pipe.c | 79 +++++++-------------------------------------------------------- + 1 file changed, 8 insertions(+), 71 deletions(-) + +diff --git a/fs/pipe.c b/fs/pipe.c +index 6679c95..034bffa 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -142,55 +142,6 @@ pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, + return 0; + } + +-static int +-pipe_iov_copy_to_user(struct iovec *iov, const void *from, unsigned long len, +- int atomic) +-{ +- unsigned long copy; +- +- while (len > 0) { +- while (!iov->iov_len) +- iov++; +- copy = min_t(unsigned long, len, iov->iov_len); +- +- if (atomic) { +- if (__copy_to_user_inatomic(iov->iov_base, from, copy)) +- return -EFAULT; +- } else { +- if (copy_to_user(iov->iov_base, from, copy)) +- return -EFAULT; +- } +- from += copy; +- len -= copy; +- iov->iov_base += copy; +- iov->iov_len -= copy; +- } +- return 0; +-} +- +-/* +- * Attempt to pre-fault in the user memory, so we can use atomic copies. +- * Returns the number of bytes not faulted in. +- */ +-static int iov_fault_in_pages_write(struct iovec *iov, unsigned long len) +-{ +- while (!iov->iov_len) +- iov++; +- +- while (len > 0) { +- unsigned long this_len; +- +- this_len = min_t(unsigned long, len, iov->iov_len); +- if (fault_in_pages_writeable(iov->iov_base, this_len)) +- break; +- +- len -= this_len; +- iov++; +- } +- +- return len; +-} +- + /* + * Pre-fault in the user memory, so we can use atomic copies. + */ +@@ -329,12 +280,15 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + ssize_t ret; + struct iovec *iov = (struct iovec *)_iov; + size_t total_len; ++ struct iov_iter iter; + + total_len = iov_length(iov, nr_segs); + /* Null read succeeds. */ + if (unlikely(total_len == 0)) + return 0; + ++ iov_iter_init(&iter, iov, nr_segs, total_len, 0); ++ + do_wakeup = 0; + ret = 0; + __pipe_lock(pipe); +@@ -344,9 +298,9 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + int curbuf = pipe->curbuf; + struct pipe_buffer *buf = pipe->bufs + curbuf; + const struct pipe_buf_operations *ops = buf->ops; +- void *addr; + size_t chars = buf->len; +- int error, atomic; ++ size_t written; ++ int error; + + if (chars > total_len) + chars = total_len; +@@ -358,27 +312,10 @@ pipe_read(struct kiocb *iocb, const struct iovec *_iov, + break; + } + +- atomic = !iov_fault_in_pages_write(iov, chars); +-redo: +- if (atomic) +- addr = kmap_atomic(buf->page); +- else +- addr = kmap(buf->page); +- error = pipe_iov_copy_to_user(iov, addr + buf->offset, chars, atomic); +- if (atomic) +- kunmap_atomic(addr); +- else +- kunmap(buf->page); +- if (unlikely(error)) { +- /* +- * Just retry with the slow path if we failed. +- */ +- if (atomic) { +- atomic = 0; +- goto redo; +- } ++ written = copy_page_to_iter(buf->page, buf->offset, chars, &iter); ++ if (unlikely(written < chars)) { + if (!ret) +- ret = error; ++ ret = -EFAULT; + break; + } + ret += chars; +-- +cgit v1.1 + diff --git a/Patches/Linux_CVEs/CVE-2015-1805/ANY/0006.patch b/Patches/Linux_CVEs/CVE-2015-1805/ANY/0006.patch new file mode 100644 index 00000000..17af5dbc --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2015-1805/ANY/0006.patch @@ -0,0 +1,326 @@ +From f0d1bec9d58d4c038d0ac958c9af82be6eb18045 Mon Sep 17 00:00:00 2001 +From: Al Viro +Date: Thu, 3 Apr 2014 15:05:18 -0400 +Subject: new helper: copy_page_from_iter() + +parallel to copy_page_to_iter(). pipe_write() switched to it (and became +->write_iter()). + +Signed-off-by: Al Viro +--- + fs/pipe.c | 129 ++++++++-------------------------------------------- + include/linux/uio.h | 2 + + mm/iov_iter.c | 78 +++++++++++++++++++++++++++++++ + 3 files changed, 99 insertions(+), 110 deletions(-) + +diff --git a/fs/pipe.c b/fs/pipe.c +index 05ccb00..21981e5 100644 +--- a/fs/pipe.c ++++ b/fs/pipe.c +@@ -116,50 +116,6 @@ void pipe_wait(struct pipe_inode_info *pipe) + pipe_lock(pipe); + } + +-static int +-pipe_iov_copy_from_user(void *to, struct iovec *iov, unsigned long len, +- int atomic) +-{ +- unsigned long copy; +- +- while (len > 0) { +- while (!iov->iov_len) +- iov++; +- copy = min_t(unsigned long, len, iov->iov_len); +- +- if (atomic) { +- if (__copy_from_user_inatomic(to, iov->iov_base, copy)) +- return -EFAULT; +- } else { +- if (copy_from_user(to, iov->iov_base, copy)) +- return -EFAULT; +- } +- to += copy; +- len -= copy; +- iov->iov_base += copy; +- iov->iov_len -= copy; +- } +- return 0; +-} +- +-/* +- * Pre-fault in the user memory, so we can use atomic copies. +- */ +-static void iov_fault_in_pages_read(struct iovec *iov, unsigned long len) +-{ +- while (!iov->iov_len) +- iov++; +- +- while (len > 0) { +- unsigned long this_len; +- +- this_len = min_t(unsigned long, len, iov->iov_len); +- fault_in_pages_readable(iov->iov_base, this_len); +- len -= this_len; +- iov++; +- } +-} +- + static void anon_pipe_buf_release(struct pipe_inode_info *pipe, + struct pipe_buffer *buf) + { +@@ -380,24 +336,19 @@ static inline int is_packetized(struct file *file) + } + + static ssize_t +-pipe_write(struct kiocb *iocb, const struct iovec *_iov, +- unsigned long nr_segs, loff_t ppos) ++pipe_write(struct kiocb *iocb, struct iov_iter *from) + { + struct file *filp = iocb->ki_filp; + struct pipe_inode_info *pipe = filp->private_data; +- ssize_t ret; +- int do_wakeup; +- struct iovec *iov = (struct iovec *)_iov; +- size_t total_len; ++ ssize_t ret = 0; ++ int do_wakeup = 0; ++ size_t total_len = iov_iter_count(from); + ssize_t chars; + +- total_len = iov_length(iov, nr_segs); + /* Null write succeeds. */ + if (unlikely(total_len == 0)) + return 0; + +- do_wakeup = 0; +- ret = 0; + __pipe_lock(pipe); + + if (!pipe->readers) { +@@ -416,38 +367,19 @@ pipe_write(struct kiocb *iocb, const struct iovec *_iov, + int offset = buf->offset + buf->len; + + if (ops->can_merge && offset + chars <= PAGE_SIZE) { +- int error, atomic = 1; +- void *addr; +- +- error = ops->confirm(pipe, buf); ++ int error = ops->confirm(pipe, buf); + if (error) + goto out; + +- iov_fault_in_pages_read(iov, chars); +-redo1: +- if (atomic) +- addr = kmap_atomic(buf->page); +- else +- addr = kmap(buf->page); +- error = pipe_iov_copy_from_user(offset + addr, iov, +- chars, atomic); +- if (atomic) +- kunmap_atomic(addr); +- else +- kunmap(buf->page); +- ret = error; +- do_wakeup = 1; +- if (error) { +- if (atomic) { +- atomic = 0; +- goto redo1; +- } ++ ret = copy_page_from_iter(buf->page, offset, chars, from); ++ if (unlikely(ret < chars)) { ++ error = -EFAULT; + goto out; + } ++ do_wakeup = 1; + buf->len += chars; +- total_len -= chars; + ret = chars; +- if (!total_len) ++ if (!iov_iter_count(from)) + goto out; + } + } +@@ -466,8 +398,7 @@ redo1: + int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1); + struct pipe_buffer *buf = pipe->bufs + newbuf; + struct page *page = pipe->tmp_page; +- char *src; +- int error, atomic = 1; ++ int copied; + + if (!page) { + page = alloc_page(GFP_HIGHUSER); +@@ -483,40 +414,19 @@ redo1: + * FIXME! Is this really true? + */ + do_wakeup = 1; +- chars = PAGE_SIZE; +- if (chars > total_len) +- chars = total_len; +- +- iov_fault_in_pages_read(iov, chars); +-redo2: +- if (atomic) +- src = kmap_atomic(page); +- else +- src = kmap(page); +- +- error = pipe_iov_copy_from_user(src, iov, chars, +- atomic); +- if (atomic) +- kunmap_atomic(src); +- else +- kunmap(page); +- +- if (unlikely(error)) { +- if (atomic) { +- atomic = 0; +- goto redo2; +- } ++ copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); ++ if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) { + if (!ret) +- ret = error; ++ ret = -EFAULT; + break; + } +- ret += chars; ++ ret += copied; + + /* Insert it into the buffer array */ + buf->page = page; + buf->ops = &anon_pipe_buf_ops; + buf->offset = 0; +- buf->len = chars; ++ buf->len = copied; + buf->flags = 0; + if (is_packetized(filp)) { + buf->ops = &packet_pipe_buf_ops; +@@ -525,8 +435,7 @@ redo2: + pipe->nrbufs = ++bufs; + pipe->tmp_page = NULL; + +- total_len -= chars; +- if (!total_len) ++ if (!iov_iter_count(from)) + break; + } + if (bufs < pipe->buffers) +@@ -1040,8 +949,8 @@ const struct file_operations pipefifo_fops = { + .llseek = no_llseek, + .read = new_sync_read, + .read_iter = pipe_read, +- .write = do_sync_write, +- .aio_write = pipe_write, ++ .write = new_sync_write, ++ .write_iter = pipe_write, + .poll = pipe_poll, + .unlocked_ioctl = pipe_ioctl, + .release = pipe_release, +diff --git a/include/linux/uio.h b/include/linux/uio.h +index 532f59d..6601235 100644 +--- a/include/linux/uio.h ++++ b/include/linux/uio.h +@@ -68,6 +68,8 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); + size_t iov_iter_single_seg_count(const struct iov_iter *i); + size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, + struct iov_iter *i); ++size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, ++ struct iov_iter *i); + unsigned long iov_iter_alignment(const struct iov_iter *i); + void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, + unsigned long nr_segs, size_t count); +diff --git a/mm/iov_iter.c b/mm/iov_iter.c +index a5c691c..081e327 100644 +--- a/mm/iov_iter.c ++++ b/mm/iov_iter.c +@@ -82,6 +82,84 @@ done: + } + EXPORT_SYMBOL(copy_page_to_iter); + ++size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, ++ struct iov_iter *i) ++{ ++ size_t skip, copy, left, wanted; ++ const struct iovec *iov; ++ char __user *buf; ++ void *kaddr, *to; ++ ++ if (unlikely(bytes > i->count)) ++ bytes = i->count; ++ ++ if (unlikely(!bytes)) ++ return 0; ++ ++ wanted = bytes; ++ iov = i->iov; ++ skip = i->iov_offset; ++ buf = iov->iov_base + skip; ++ copy = min(bytes, iov->iov_len - skip); ++ ++ if (!fault_in_pages_readable(buf, copy)) { ++ kaddr = kmap_atomic(page); ++ to = kaddr + offset; ++ ++ /* first chunk, usually the only one */ ++ left = __copy_from_user_inatomic(to, buf, copy); ++ copy -= left; ++ skip += copy; ++ to += copy; ++ bytes -= copy; ++ ++ while (unlikely(!left && bytes)) { ++ iov++; ++ buf = iov->iov_base; ++ copy = min(bytes, iov->iov_len); ++ left = __copy_from_user_inatomic(to, buf, copy); ++ copy -= left; ++ skip = copy; ++ to += copy; ++ bytes -= copy; ++ } ++ if (likely(!bytes)) { ++ kunmap_atomic(kaddr); ++ goto done; ++ } ++ offset = to - kaddr; ++ buf += copy; ++ kunmap_atomic(kaddr); ++ copy = min(bytes, iov->iov_len - skip); ++ } ++ /* Too bad - revert to non-atomic kmap */ ++ kaddr = kmap(page); ++ to = kaddr + offset; ++ left = __copy_from_user(to, buf, copy); ++ copy -= left; ++ skip += copy; ++ to += copy; ++ bytes -= copy; ++ while (unlikely(!left && bytes)) { ++ iov++; ++ buf = iov->iov_base; ++ copy = min(bytes, iov->iov_len); ++ left = __copy_from_user(to, buf, copy); ++ copy -= left; ++ skip = copy; ++ to += copy; ++ bytes -= copy; ++ } ++ kunmap(page); ++done: ++ i->count -= wanted - bytes; ++ i->nr_segs -= iov - i->iov; ++ i->iov = iov; ++ i->iov_offset = skip; ++ return wanted - bytes; ++} ++EXPORT_SYMBOL(copy_page_from_iter); ++ + static size_t __iovec_copy_from_user_inatomic(char *vaddr, + const struct iovec *iov, size_t base, size_t bytes) + { +-- +cgit v1.1 + diff --git a/Patches/Linux_CVEs/Kernel_CVE_Patch_List.txt b/Patches/Linux_CVEs/Kernel_CVE_Patch_List.txt index 71c31444..c28d4f70 100644 --- a/Patches/Linux_CVEs/Kernel_CVE_Patch_List.txt +++ b/Patches/Linux_CVEs/Kernel_CVE_Patch_List.txt @@ -1,5 +1,6 @@ #This is a combined list from the following sources # https://source.android.com/security/bulletin +# https://source.android.com/security/advisory # https://cve.lineageos.org # https://www.codeaurora.org/security-advisories # https://www.codeaurora.org/security-advisories/security-bulletins @@ -77,6 +78,11 @@ CVE-2014-0196 Link - 3.4 - https://source.codeaurora.org/quic/la/kernel/msm/commit/?h=LA.BF.1.1.3_rb1.12&id=9aabfc9e7775abbbcf534cdecccc4f12ee423b27 CVE-2014-0206 Link - https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/commit/?id=d36db46c2cba973557eb6138d22210c4e0cf17d6 +CVE-2014-3153 + Link - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e9c243a5a6de0be8e584c604d353412584b592f8 + Link - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=13fbca4c6ecd96ec1a1cfa2e4f2ce191fe928a5e + Link - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=54a217887a7b658e2650c3feff22756ab80c7339 + Link - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b3eaa9fc5cd0a4d74b18f6b8dc617aeaf1873270 CVE-2014-0972 Link - https://source.codeaurora.org/quic/la/kernel/msm-3.10/commit/?id=7613c9d520ee4d227e635f6db0270d4cf26102bc Link - https://source.codeaurora.org/quic/la/kernel/msm-3.10/commit/?id=d7d07936a166e7421a6308eec443b707a9678580 @@ -329,6 +335,8 @@ CVE-2015-1805 Link - 3.10 - https://android.googlesource.com/kernel/common/+/4a5a45669796c5b4617109182e25b321f9f00beb Link - 3.14 - https://android.googlesource.com/kernel/common/+/bf010e99c9bc48002f6bfa1ad801a59bf996270f Link - 3.16 - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?id=a39bf4a8e29c7336c0c72652b7d0dd1cd1b13c51 + Link - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=637b58c2887e5e57850865839cc75f59184b23d1 + Link - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=f0d1bec9d58d4c038d0ac958c9af82be6eb18045 CVE-2015-2041 Link - 3.2 - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?id=88fe14be08a475ad0eea4ca7c51f32437baf41af Link - ^3.19 - https://github.com/torvalds/linux/commit/6b8d9117ccb4f81b1244aafa7bc70ef8fa45fc49 @@ -553,8 +561,6 @@ CVE-2016-2053 Link - http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=0d62e9dd6da45bbf0f33a8617afc5fe774c8f45f CVE-2016-2059 Link - https://source.codeaurora.org/quic/la/kernel/msm-3.18/commit/?id=9e8bdd63f7011dff5523ea435433834b3702398d -CVE-2016-2059 - Link - https://source.codeaurora.org/quic/la/kernel/msm-3.18/commit/?id=9e8bdd63f7011dff5523ea435433834b3702398d CVE-2016-2060 Link - https://source.codeaurora.org/quic/la/platform/system/netd/commit/?id=e9925f5acb4401588e23ea8a27c3e318f71b5cf8 CVE-2016-2061 @@ -802,8 +808,6 @@ CVE-2016-4998 CVE-2016-5195 Link - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?id=9691eac5593ff1e2f82391ad327f21d90322aec1 Link - https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/commit/?id=e45a502bdeae5a075257c4f061d1ff4ff0821354 -CVE-2016-5340 - Link - https://source.codeaurora.org/quic/la//kernel/msm-3.10/commit/?id=06e51489061e5473b4e2035c79dcf7c27a6f75a6 CVE-2016-5340 Link - https://source.codeaurora.org/quic/la/kernel/msm-3.10/commit/?id=06e51489061e5473b4e2035c79dcf7c27a6f75a6 CVE-2016-5342 diff --git a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_amazon_hdx-common.sh b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_amazon_hdx-common.sh index 041d89b2..394f61cf 100644 --- a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_amazon_hdx-common.sh +++ b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_amazon_hdx-common.sh @@ -2,6 +2,8 @@ cd $base"kernel/amazon/hdx-common" git apply $cvePatches/CVE-2012-6704/^3.5/0001.patch git apply $cvePatches/CVE-2014-1739/ANY/0001.patch +git apply $cvePatches/CVE-2014-3153/ANY/0002.patch +git apply $cvePatches/CVE-2014-3153/ANY/0004.patch git apply $cvePatches/CVE-2014-4656/ANY/0001.patch git apply $cvePatches/CVE-2014-7822/3.2-^3.16/0001.patch git apply $cvePatches/CVE-2014-8709/ANY/0001.patch diff --git a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_htc_msm8974.sh b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_htc_msm8974.sh index f6548325..a42aed6c 100644 --- a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_htc_msm8974.sh +++ b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_htc_msm8974.sh @@ -1,6 +1,8 @@ #!/bin/bash cd $base"kernel/htc/msm8974" git apply $cvePatches/CVE-2014-1739/ANY/0001.patch +git apply $cvePatches/CVE-2014-3153/ANY/0002.patch +git apply $cvePatches/CVE-2014-3153/ANY/0004.patch git apply $cvePatches/CVE-2014-9715/^3.14/0002.patch git apply $cvePatches/CVE-2014-9781/ANY/0001.patch git apply $cvePatches/CVE-2015-1593/ANY/0001.patch diff --git a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_samsung_smdk4412.sh b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_samsung_smdk4412.sh index 11605556..f94dbf19 100644 --- a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_samsung_smdk4412.sh +++ b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_samsung_smdk4412.sh @@ -1,6 +1,7 @@ #!/bin/bash cd $base"kernel/samsung/smdk4412" git apply $cvePatches/CVE-2014-1739/ANY/0001.patch +git apply $cvePatches/CVE-2014-3153/ANY/0004.patch git apply $cvePatches/CVE-2014-4656/ANY/0001.patch git apply $cvePatches/CVE-2014-9420/ANY/0001.patch git apply $cvePatches/CVE-2014-9781/ANY/0001.patch