Add some more Linux CVE patches

This commit is contained in:
Tad 2017-10-29 04:19:13 -04:00
parent 86c2d7a648
commit ce59045163
6 changed files with 450 additions and 1 deletions

View File

@ -0,0 +1,78 @@
From 3adf241382f15b64df74f7c0eeea4583e094eaf9 Mon Sep 17 00:00:00 2001
From: Johannes Berg <johannes.berg@intel.com>
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 <johannes.berg@intel.com>
---
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 <jbenc@suse.cz>
* Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
+ * 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;

View File

@ -0,0 +1,260 @@
From 9d76d20a000ff47633ece50db4be52bd210db79b Mon Sep 17 00:00:00 2001
From: Tom Marshall <tdm.code@gmail.com>
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 <asm/processor.h>
+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 <trace/events/sched.h>
+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;

View File

@ -0,0 +1,26 @@
From 20ad8a951b24ec89e887070364b386169b3ad89a Mon Sep 17 00:00:00 2001
From: Tom Marshall <tdm.code@gmail.com>
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;
+ }
}
}

View File

@ -0,0 +1,33 @@
From 29bcc180806c11559706af51f284b7217825c372 Mon Sep 17 00:00:00 2001
From: Alberto97 <albertop2197@gmail.com>
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 {

View File

@ -0,0 +1,52 @@
From d710842e8f38921571a19b6df18a078d6622f842 Mon Sep 17 00:00:00 2001
From: Andrea Arcangeli <andrea@cpushare.com>
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 <haggertk@lineageos.org>
---
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();
}

View File

@ -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