From ce59045163d48c9f15b5279ad6b5f07d4a4be885 Mon Sep 17 00:00:00 2001 From: Tad Date: Sun, 29 Oct 2017 04:19:13 -0400 Subject: [PATCH] Add some more Linux CVE patches --- Patches/Linux_CVEs/CVE-2017-13080/0.patch | 78 ++++++ Patches/Linux_CVEs/LVT-2017-0001/0.patch | 260 ++++++++++++++++++ Patches/Linux_CVEs/LVT-2017-0002/0.patch | 26 ++ Patches/Linux_CVEs/LVT-2017-0003/0.patch | 33 +++ Patches/Linux_CVEs/LVT-2017-0004/0.patch | 52 ++++ .../CVE_Patchers/android_kernel_lge_mako.sh | 2 +- 6 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 Patches/Linux_CVEs/CVE-2017-13080/0.patch create mode 100644 Patches/Linux_CVEs/LVT-2017-0001/0.patch create mode 100644 Patches/Linux_CVEs/LVT-2017-0002/0.patch create mode 100644 Patches/Linux_CVEs/LVT-2017-0003/0.patch create mode 100644 Patches/Linux_CVEs/LVT-2017-0004/0.patch diff --git a/Patches/Linux_CVEs/CVE-2017-13080/0.patch b/Patches/Linux_CVEs/CVE-2017-13080/0.patch new file mode 100644 index 00000000..1214bf09 --- /dev/null +++ b/Patches/Linux_CVEs/CVE-2017-13080/0.patch @@ -0,0 +1,78 @@ +From 3adf241382f15b64df74f7c0eeea4583e094eaf9 Mon Sep 17 00:00:00 2001 +From: Johannes Berg +Date: Tue, 5 Sep 2017 14:54:54 +0200 +Subject: [PATCH] mac80211: accept key reinstall without changing anything + +When a key is reinstalled we can reset the replay counters +etc. which can lead to nonce reuse and/or replay detection +being impossible, breaking security properties, as described +in the "KRACK attacks". + +In particular, CVE-2017-13080 applies to GTK rekeying that +happened in firmware while the host is in D3, with the second +part of the attack being done after the host wakes up. In +this case, the wpa_supplicant mitigation isn't sufficient +since wpa_supplicant doesn't know the GTK material. + +In case this happens, simply silently accept the new key +coming from userspace but don't take any action on it since +it's the same key; this keeps the PN replay counters intact. + +Change-Id: I7576ed8c8df85a767ebf15e74a642063eb34d0f5 +Signed-off-by: Johannes Berg +--- + net/mac80211/key.c | 20 +++++++++++++++++--- + 1 file changed, 17 insertions(+), 3 deletions(-) + +diff --git a/net/mac80211/key.c b/net/mac80211/key.c +index 635d0972b68..417f047f2dc 100644 +--- a/net/mac80211/key.c ++++ b/net/mac80211/key.c +@@ -3,6 +3,7 @@ + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007-2008 Johannes Berg ++ * Copyright 2015-2017 Intel Deutschland GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as +@@ -464,9 +465,6 @@ int ieee80211_key_link(struct ieee80211_key *key, + + pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE; + idx = key->conf.keyidx; +- key->local = sdata->local; +- key->sdata = sdata; +- key->sta = sta; + + mutex_lock(&sdata->local->key_mtx); + +@@ -477,6 +475,21 @@ int ieee80211_key_link(struct ieee80211_key *key, + else + old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]); + ++ /* ++ * Silently accept key re-installation without really installing the ++ * new version of the key to avoid nonce reuse or replay issues. ++ */ ++ if (old_key && key->conf.keylen == old_key->conf.keylen && ++ !memcmp(key->conf.key, old_key->conf.key, key->conf.keylen)) { ++ ieee80211_key_free_unused(key); ++ ret = 0; ++ goto out; ++ } ++ ++ key->local = sdata->local; ++ key->sdata = sdata; ++ key->sta = sta; ++ + increment_tailroom_need_count(sdata); + + ieee80211_key_replace(sdata, sta, pairwise, old_key, key); +@@ -489,6 +502,7 @@ int ieee80211_key_link(struct ieee80211_key *key, + if (ret) + ieee80211_key_free(key, true); + ++ out: + mutex_unlock(&sdata->local->key_mtx); + + return ret; diff --git a/Patches/Linux_CVEs/LVT-2017-0001/0.patch b/Patches/Linux_CVEs/LVT-2017-0001/0.patch new file mode 100644 index 00000000..af456734 --- /dev/null +++ b/Patches/Linux_CVEs/LVT-2017-0001/0.patch @@ -0,0 +1,260 @@ +From 9d76d20a000ff47633ece50db4be52bd210db79b Mon Sep 17 00:00:00 2001 +From: Tom Marshall +Date: Wed, 25 Jan 2017 18:01:03 +0100 +Subject: [PATCH] kernel: Only expose su when daemon is running + +It has been claimed that the PG implementation of 'su' has security +vulnerabilities even when disabled. Unfortunately, the people that +find these vulnerabilities often like to keep them private so they +can profit from exploits while leaving users exposed to malicious +hackers. + +In order to reduce the attack surface for vulnerabilites, it is +therefore necessary to make 'su' completely inaccessible when it +is not in use (except by the root and system users). + +Change-Id: I79716c72f74d0b7af34ec3a8054896c6559a181d +--- + fs/exec.c | 5 +++++ + fs/namei.c | 8 ++++++++ + fs/readdir.c | 15 +++++++++++++++ + include/linux/dcache.h | 7 +++++++ + include/linux/fs.h | 1 + + include/linux/sched.h | 8 ++++++++ + include/linux/uidgid.h | 3 +++ + kernel/exit.c | 5 +++++ + kernel/fork.c | 2 ++ + kernel/sched/core.c | 32 ++++++++++++++++++++++++++++++++ + 10 files changed, 86 insertions(+) + +diff --git a/fs/exec.c b/fs/exec.c +index 4d5006cff73..0238899eeaa 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1693,6 +1693,11 @@ static int do_execve_common(const char *filename, + if (retval < 0) + goto out; + ++ if (d_is_su(file->f_dentry) && capable(CAP_SYS_ADMIN)) { ++ current->flags |= PF_SU; ++ su_exec(); ++ } ++ + /* execve succeeded */ + current->fs->in_exec = 0; + current->in_execve = 0; +diff --git a/fs/namei.c b/fs/namei.c +index de342fb9ed0..b3cbf53dda2 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2025,6 +2025,14 @@ static int path_lookupat(int dfd, const char *name, + } + } + ++ if (!err) { ++ struct super_block *sb = nd->inode->i_sb; ++ if (sb->s_flags & MS_RDONLY) { ++ if (d_is_su(nd->path.dentry) && !su_visible()) ++ err = -ENOENT; ++ } ++ } ++ + if (base) + fput(base); + +diff --git a/fs/readdir.c b/fs/readdir.c +index 5d6578affbb..516fc904513 100644 +--- a/fs/readdir.c ++++ b/fs/readdir.c +@@ -39,6 +39,7 @@ int iterate_dir(struct file *file, struct dir_context *ctx) + if (!IS_DEADDIR(inode)) { + if (file->f_op->iterate) { + ctx->pos = file->f_pos; ++ ctx->romnt = (inode->i_sb->s_flags & MS_RDONLY); + res = file->f_op->iterate(file, ctx); + file->f_pos = ctx->pos; + } else { +@@ -53,6 +54,14 @@ int iterate_dir(struct file *file, struct dir_context *ctx) + } + EXPORT_SYMBOL(iterate_dir); + ++static bool hide_name(const char *name, int namlen) ++{ ++ if (namlen == 2 && !memcmp(name, "su", 2)) ++ if (!su_visible()) ++ return true; ++ return false; ++} ++ + /* + * Traditional linux readdir() handling.. + * +@@ -91,6 +100,8 @@ static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset + buf->result = -EOVERFLOW; + return -EOVERFLOW; + } ++ if (hide_name(name, namlen) && buf->ctx.romnt) ++ return 0; + buf->result++; + dirent = buf->dirent; + if (!access_ok(VERIFY_WRITE, dirent, +@@ -169,6 +180,8 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, + buf->error = -EOVERFLOW; + return -EOVERFLOW; + } ++ if (hide_name(name, namlen) && buf->ctx.romnt) ++ return 0; + dirent = buf->previous; + if (dirent) { + if (__put_user(offset, &dirent->d_off)) +@@ -249,6 +262,8 @@ static int filldir64(void * __buf, const char * name, int namlen, loff_t offset, + buf->error = -EINVAL; /* only used if we fail.. */ + if (reclen > buf->count) + return -EINVAL; ++ if (hide_name(name, namlen) && buf->ctx.romnt) ++ return 0; + dirent = buf->previous; + if (dirent) { + if (__put_user(offset, &dirent->d_off)) +diff --git a/include/linux/dcache.h b/include/linux/dcache.h +index 7bd16b926d5..a660e2b1a28 100644 +--- a/include/linux/dcache.h ++++ b/include/linux/dcache.h +@@ -411,6 +411,13 @@ static inline bool d_mountpoint(struct dentry *dentry) + return dentry->d_flags & DCACHE_MOUNTED; + } + ++static inline bool d_is_su(const struct dentry *dentry) ++{ ++ return dentry && ++ dentry->d_name.len == 2 && ++ !memcmp(dentry->d_name.name, "su", 2); ++} ++ + extern int sysctl_vfs_cache_pressure; + + #endif /* __LINUX_DCACHE_H */ +diff --git a/include/linux/fs.h b/include/linux/fs.h +index fe4a8fe4630..e686a31375d 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1538,6 +1538,7 @@ typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); + struct dir_context { + filldir_t actor; + loff_t pos; ++ bool romnt; + }; + + static inline bool dir_emit(struct dir_context *ctx, +diff --git a/include/linux/sched.h b/include/linux/sched.h +index 6dbecacfe05..96cd3c15967 100644 +--- a/include/linux/sched.h ++++ b/include/linux/sched.h +@@ -55,6 +55,12 @@ struct sched_param { + + #include + ++int su_instances(void); ++bool su_running(void); ++bool su_visible(void); ++void su_exec(void); ++void su_exit(void); ++ + struct exec_domain; + struct futex_pi_state; + struct robust_list_head; +@@ -1678,6 +1684,8 @@ extern int task_free_unregister(struct notifier_block *n); + #define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ + #define PF_WAKE_UP_IDLE 0x80000000 /* try to wake up on an idle CPU */ + ++#define PF_SU 0x00000002 /* task is su */ ++ + /* + * Only the _current_ task can read/write to tsk->flags, but other + * tasks can access tsk->flags in readonly mode for example +diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h +index 8e522cbcef2..cb4c867a523 100644 +--- a/include/linux/uidgid.h ++++ b/include/linux/uidgid.h +@@ -64,6 +64,9 @@ static inline gid_t __kgid_val(kgid_t gid) + #define GLOBAL_ROOT_UID KUIDT_INIT(0) + #define GLOBAL_ROOT_GID KGIDT_INIT(0) + ++#define GLOBAL_SYSTEM_UID KUIDT_INIT(1000) ++#define GLOBAL_SYSTEM_GID KGIDT_INIT(1000) ++ + #define INVALID_UID KUIDT_INIT(-1) + #define INVALID_GID KGIDT_INIT(-1) + +diff --git a/kernel/exit.c b/kernel/exit.c +index 8e2166363b4..89b8cd8499d 100644 +--- a/kernel/exit.c ++++ b/kernel/exit.c +@@ -754,6 +754,11 @@ void do_exit(long code) + } + + exit_signals(tsk); /* sets PF_EXITING */ ++ ++ if (tsk->flags & PF_SU) { ++ su_exit(); ++ } ++ + /* + * tsk->flags are checked in the futex code to protect against + * an exiting task cleaning up the robust pi futexes. +diff --git a/kernel/fork.c b/kernel/fork.c +index 5bb57843fa4..bce1c62fc6c 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -326,6 +326,8 @@ static struct task_struct *dup_task_struct(struct task_struct *orig) + if (err) + goto free_ti; + ++ tsk->flags &= ~PF_SU; ++ + tsk->stack = ti; + #ifdef CONFIG_SECCOMP + /* +diff --git a/kernel/sched/core.c b/kernel/sched/core.c +index d80cef29661..b8fdeb468b3 100644 +--- a/kernel/sched/core.c ++++ b/kernel/sched/core.c +@@ -92,6 +92,38 @@ + #define CREATE_TRACE_POINTS + #include + ++static atomic_t __su_instances; ++ ++int su_instances(void) ++{ ++ return atomic_read(&__su_instances); ++} ++ ++bool su_running(void) ++{ ++ return su_instances() > 0; ++} ++ ++bool su_visible(void) ++{ ++ kuid_t uid = current_uid(); ++ if (su_running()) ++ return true; ++ if (uid_eq(uid, GLOBAL_ROOT_UID) || uid_eq(uid, GLOBAL_SYSTEM_UID)) ++ return true; ++ return false; ++} ++ ++void su_exec(void) ++{ ++ atomic_inc(&__su_instances); ++} ++ ++void su_exit(void) ++{ ++ atomic_dec(&__su_instances); ++} ++ + void start_bandwidth_timer(struct hrtimer *period_timer, ktime_t period) + { + unsigned long delta; diff --git a/Patches/Linux_CVEs/LVT-2017-0002/0.patch b/Patches/Linux_CVEs/LVT-2017-0002/0.patch new file mode 100644 index 00000000..92435519 --- /dev/null +++ b/Patches/Linux_CVEs/LVT-2017-0002/0.patch @@ -0,0 +1,26 @@ +From 20ad8a951b24ec89e887070364b386169b3ad89a Mon Sep 17 00:00:00 2001 +From: Tom Marshall +Date: Thu, 18 May 2017 23:50:22 +0000 +Subject: [PATCH] kernel: Fix potential refcount leak in su check + +Change-Id: I8d2c8bed65a01eb0928308df638a04449a5bd881 +--- + fs/namei.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/namei.c b/fs/namei.c +index 40d9a30eaf3a..bdfbb34dd137 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -2029,8 +2029,10 @@ static int path_lookupat(int dfd, const char *name, + if (!err) { + struct super_block *sb = nd->inode->i_sb; + if (sb->s_flags & MS_RDONLY) { +- if (d_is_su(nd->path.dentry) && !su_visible()) ++ if (d_is_su(nd->path.dentry) && !su_visible()) { ++ path_put(&nd->path); + err = -ENOENT; ++ } + } + } + diff --git a/Patches/Linux_CVEs/LVT-2017-0003/0.patch b/Patches/Linux_CVEs/LVT-2017-0003/0.patch new file mode 100644 index 00000000..f108f0d9 --- /dev/null +++ b/Patches/Linux_CVEs/LVT-2017-0003/0.patch @@ -0,0 +1,33 @@ +From 29bcc180806c11559706af51f284b7217825c372 Mon Sep 17 00:00:00 2001 +From: Alberto97 +Date: Tue, 23 May 2017 21:47:00 +0200 +Subject: [PATCH] fs: readdir: Fix su hide patch for non-iterate filesystems + +* 3.10 doesn't normally use iterate for filesystems, + but it was backported in hopes of removing vfs_readdir() +* Because the romnt variable was only set for filesystems + using iterate, the su hide patches were broken for many + filesytems like ext4, which still use vfs_readdir() + instead of iterate_dir() like their mainline counterparts +* Remove the iterate check around setting romnt to fix this + +Change-Id: I26426683df0fd199a80f053294f352e31754bec5 +--- + fs/readdir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/readdir.c b/fs/readdir.c +index d52d18d9887..b22bbbfabee 100644 +--- a/fs/readdir.c ++++ b/fs/readdir.c +@@ -37,9 +37,9 @@ int iterate_dir(struct file *file, struct dir_context *ctx) + + res = -ENOENT; + if (!IS_DEADDIR(inode)) { ++ ctx->romnt = (inode->i_sb->s_flags & MS_RDONLY); + if (file->f_op->iterate) { + ctx->pos = file->f_pos; +- ctx->romnt = (inode->i_sb->s_flags & MS_RDONLY); + res = file->f_op->iterate(file, ctx); + file->f_pos = ctx->pos; + } else { diff --git a/Patches/Linux_CVEs/LVT-2017-0004/0.patch b/Patches/Linux_CVEs/LVT-2017-0004/0.patch new file mode 100644 index 00000000..74fc1dde --- /dev/null +++ b/Patches/Linux_CVEs/LVT-2017-0004/0.patch @@ -0,0 +1,52 @@ +From d710842e8f38921571a19b6df18a078d6622f842 Mon Sep 17 00:00:00 2001 +From: Andrea Arcangeli +Date: Tue, 25 Jul 2017 22:22:45 +0200 +Subject: [PATCH] fs/exec: fix use after free in execve + +"file" can be already freed if bprm->file is NULL after +search_binary_handler() return. binfmt_script will do exactly that for +example. If the VM reuses the file after fput run(), this will result in +a use ater free. + +So obtain d_is_su before search_binary_handler() runs. + +This should explain this crash: + +[25333.009554] Unable to handle kernel NULL pointer dereference at virtual address 00000185 +[..] +[25333.009918] [2: am:21861] PC is at do_execve+0x354/0x474 + +Change-Id: I2a8a814d1c0aa75625be83cb30432cf13f1a0681 +Signed-off-by: Kevin F. Haggerty +--- + fs/exec.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/exec.c b/fs/exec.c +index 09f2a8ccde6..b48461148cb 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1531,6 +1531,7 @@ static int do_execve_common(const char *filename, + bool clear_in_exec; + int retval; + const struct cred *cred = current_cred(); ++ bool is_su; + + /* + * We move the actual failure in case of RLIMIT_NPROC excess from +@@ -1607,11 +1608,14 @@ static int do_execve_common(const char *filename, + if (retval < 0) + goto out; + ++ /* search_binary_handler can release file and it may be freed */ ++ is_su = d_is_su(file->f_dentry); ++ + retval = search_binary_handler(bprm,regs); + if (retval < 0) + goto out; + +- if (d_is_su(file->f_dentry) && capable(CAP_SYS_ADMIN)) { ++ if (is_su && capable(CAP_SYS_ADMIN)) { + current->flags |= PF_SU; + su_exec(); + } diff --git a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_lge_mako.sh b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_lge_mako.sh index 349758c5..eafaf0c5 100644 --- a/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_lge_mako.sh +++ b/Scripts/LineageOS-14.1/CVE_Patchers/android_kernel_lge_mako.sh @@ -1,6 +1,6 @@ #!/bin/bash cd $base"kernel/lge/mako" -git apply $cvePatches/CVE-2012-6703/0.patch +#git apply $cvePatches/CVE-2012-6703/0.patch git apply $cvePatches/CVE-2016-3134/0.patch git apply $cvePatches/CVE-2016-8404/0.patch git apply $cvePatches/CVE-2016-9793/0.patch