]> git.proxmox.com Git - lxc.git/blame - debian/patches/0009-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
update clean target
[lxc.git] / debian / patches / 0009-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch
CommitLineData
3c2b20b3
WB
1From 8095074e1aa2b308d8134638999a0ffe25e12347 Mon Sep 17 00:00:00 2001
2From: Christian Brauner <christian.brauner@ubuntu.com>
3Date: Sat, 28 Jan 2017 13:02:34 +0100
4Subject: [PATCH 9/9] CVE-2017-5985: Ensure target netns is caller-owned
5
6Before this commit, lxc-user-nic could potentially have been tricked into
7operating on a network namespace over which the caller did not hold privilege.
8
9This commit ensures that the caller is privileged over the network namespace by
10temporarily dropping privilege.
11
12Launchpad: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1654676
13Reported-by: Jann Horn <jannh@google.com>
14Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
15---
16 src/lxc/lxc_user_nic.c | 119 ++++++++++++++++++++++++++++++++++++-------------
17 1 file changed, 87 insertions(+), 32 deletions(-)
18
19diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c
20index 409a53a..96dc398 100644
21--- a/src/lxc/lxc_user_nic.c
22+++ b/src/lxc/lxc_user_nic.c
23@@ -50,6 +50,14 @@
24 #include "utils.h"
25 #include "network.h"
26
27+#define usernic_debug_stream(stream, format, ...) \
28+ do { \
29+ fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \
30+ __func__, __VA_ARGS__); \
31+ } while (false)
32+
33+#define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__)
34+
35 static void usage(char *me, bool fail)
36 {
37 fprintf(stderr, "Usage: %s lxcpath name pid type bridge nicname\n", me);
38@@ -670,68 +678,115 @@ again:
39 }
40
41 #define VETH_DEF_NAME "eth%d"
42-
43 static int rename_in_ns(int pid, char *oldname, char **newnamep)
44 {
45- int fd = -1, ofd = -1, ret, ifindex = -1;
46+ uid_t ruid, suid, euid;
47+ int fret = -1;
48+ int fd = -1, ifindex = -1, ofd = -1, ret;
49 bool grab_newname = false;
50
51 ofd = lxc_preserve_ns(getpid(), "net");
52 if (ofd < 0) {
53- fprintf(stderr, "Failed opening network namespace path for '%d'.", getpid());
54- return -1;
55+ usernic_error("Failed opening network namespace path for '%d'.", getpid());
56+ return fret;
57 }
58
59 fd = lxc_preserve_ns(pid, "net");
60 if (fd < 0) {
61- fprintf(stderr, "Failed opening network namespace path for '%d'.", pid);
62- return -1;
63+ usernic_error("Failed opening network namespace path for '%d'.", pid);
64+ goto do_partial_cleanup;
65+ }
66+
67+ ret = getresuid(&ruid, &euid, &suid);
68+ if (ret < 0) {
69+ usernic_error("Failed to retrieve real, effective, and saved "
70+ "user IDs: %s\n",
71+ strerror(errno));
72+ goto do_partial_cleanup;
73+ }
74+
75+ ret = setns(fd, CLONE_NEWNET);
76+ close(fd);
77+ fd = -1;
78+ if (ret < 0) {
79+ usernic_error("Failed to setns() to the network namespace of "
80+ "the container with PID %d: %s.\n",
81+ pid, strerror(errno));
82+ goto do_partial_cleanup;
83 }
84
85- if (setns(fd, 0) < 0) {
86- fprintf(stderr, "setns to container network namespace\n");
87- goto out_err;
88+ ret = setresuid(ruid, ruid, 0);
89+ if (ret < 0) {
90+ usernic_error("Failed to drop privilege by setting effective "
91+ "user id and real user id to %d, and saved user "
92+ "ID to 0: %s.\n",
93+ ruid, strerror(errno));
94+ // COMMENT(brauner): It's ok to jump to do_full_cleanup here
95+ // since setresuid() will succeed when trying to set real,
96+ // effective, and saved to values they currently have.
97+ goto do_full_cleanup;
98 }
99- close(fd); fd = -1;
100+
101 if (!*newnamep) {
102 grab_newname = true;
103 *newnamep = VETH_DEF_NAME;
104- if (!(ifindex = if_nametoindex(oldname))) {
105- fprintf(stderr, "failed to get netdev index\n");
106- goto out_err;
107+
108+ ifindex = if_nametoindex(oldname);
109+ if (!ifindex) {
110+ usernic_error("Failed to get netdev index: %s.\n", strerror(errno));
111+ goto do_full_cleanup;
112 }
113 }
114- if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) {
115- fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, *newnamep);
116- goto out_err;
117+
118+ ret = lxc_netdev_rename_by_name(oldname, *newnamep);
119+ if (ret < 0) {
120+ usernic_error("Error %d renaming netdev %s to %s in container.\n", ret, oldname, *newnamep);
121+ goto do_full_cleanup;
122 }
123+
124 if (grab_newname) {
125- char ifname[IFNAMSIZ], *namep = ifname;
126+ char ifname[IFNAMSIZ];
127+ char *namep = ifname;
128+
129 if (!if_indextoname(ifindex, namep)) {
130- fprintf(stderr, "Failed to get new netdev name\n");
131- goto out_err;
132+ usernic_error("Failed to get new netdev name: %s.\n", strerror(errno));
133+ goto do_full_cleanup;
134 }
135+
136 *newnamep = strdup(namep);
137 if (!*newnamep)
138- goto out_err;
139+ goto do_full_cleanup;
140 }
141- if (setns(ofd, 0) < 0) {
142- fprintf(stderr, "Error returning to original netns\n");
143- close(ofd);
144- return -1;
145+
146+ fret = 0;
147+
148+do_full_cleanup:
149+ ret = setresuid(ruid, euid, suid);
150+ if (ret < 0) {
151+ usernic_error("Failed to restore privilege by setting effective "
152+ "user id to %d, real user id to %d, and saved user "
153+ "ID to %d: %s.\n",
154+ ruid, euid, suid, strerror(errno));
155+ fret = -1;
156+ // COMMENT(brauner): setns() should fail if setresuid() doesn't
157+ // succeed but there's no harm in falling through; keeps the
158+ // code cleaner.
159 }
160- close(ofd);
161
162- return 0;
163+ ret = setns(ofd, CLONE_NEWNET);
164+ if (ret < 0) {
165+ usernic_error("Failed to setns() to original network namespace "
166+ "of PID %d: %s.\n",
167+ ofd, strerror(errno));
168+ fret = -1;
169+ }
170
171-out_err:
172- if (ofd >= 0)
173- close(ofd);
174- if (setns(ofd, 0) < 0)
175- fprintf(stderr, "Error returning to original network namespace\n");
176+do_partial_cleanup:
177 if (fd >= 0)
178 close(fd);
179- return -1;
180+ close(ofd);
181+
182+ return fret;
183 }
184
185 /*
186--
1872.1.4
188