Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Maintenance:7017
lxc.openSUSE_Leap_42.2_Update
0001-CVE-2017-5985-Ensure-target-netns-is-calle...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0001-CVE-2017-5985-Ensure-target-netns-is-caller-owned.patch of Package lxc.openSUSE_Leap_42.2_Update
From 7e678d3d2a297abe8a6e2d673a7ada3994ebe4e5 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brauner@ubuntu.com> Date: Sat, 11 Feb 2017 13:27:06 +0100 Subject: [PATCH] CVE-2017-5985: Ensure target netns is caller-owned Before this commit, lxc-user-nic could potentially have been tricked into operating on a network namespace over which the caller did not hold privilege. This commit ensures that the caller is privileged over the network namespace by temporarily dropping privilege. Launchpad: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1654676 Reported-by: Jann Horn <jannh@google.com> Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> --- src/lxc/lxc_user_nic.c | 130 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 34 deletions(-) diff --git a/src/lxc/lxc_user_nic.c b/src/lxc/lxc_user_nic.c index 6622db0d..4ea23a0c 100644 --- a/src/lxc/lxc_user_nic.c +++ b/src/lxc/lxc_user_nic.c @@ -50,6 +50,14 @@ #include "utils.h" #include "network.h" +#define usernic_debug_stream(stream, format, ...) \ + do { \ + fprintf(stream, "%s: %d: %s: " format, __FILE__, __LINE__, \ + __func__, __VA_ARGS__); \ + } while (false) + +#define usernic_error(format, ...) usernic_debug_stream(stderr, format, __VA_ARGS__) + static void usage(char *me, bool fail) { fprintf(stderr, "Usage: %s pid type bridge nicname\n", me); @@ -154,7 +162,7 @@ static char *get_eow(char *s, char *e) static char *find_line(char *p, char *e, char *u, char *t, char *l) { char *p1, *p2, *ret; - + while (p<e && (p1 = get_eol(p, e)) < e) { ret = p; if (*p == '#') @@ -474,68 +482,122 @@ again: static int rename_in_ns(int pid, char *oldname, char **newnamep) { char nspath[MAXPATHLEN]; + uid_t ruid, suid, euid; + int fret = -1; int fd = -1, ofd = -1, ret, ifindex = -1; bool grab_newname = false; ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid()); if (ret < 0 || ret >= MAXPATHLEN) - return -1; + goto do_partial_cleanup; + if ((ofd = open(nspath, O_RDONLY)) < 0) { - fprintf(stderr, "Opening %s\n", nspath); - return -1; + usernic_error("Failed opening network namespace path for '%d'.", getpid()); + goto do_partial_cleanup; } + ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", pid); if (ret < 0 || ret >= MAXPATHLEN) - goto out_err; + goto do_partial_cleanup; if ((fd = open(nspath, O_RDONLY)) < 0) { - fprintf(stderr, "Opening %s\n", nspath); - goto out_err; + usernic_error("Failed opening network namespace path for '%d'.", pid); + goto do_partial_cleanup; } - if (setns(fd, 0) < 0) { - fprintf(stderr, "setns to container network namespace\n"); - goto out_err; + + ret = getresuid(&ruid, &euid, &suid); + if (ret < 0) { + usernic_error("Failed to retrieve real, effective, and saved " + "user IDs: %s\n", + strerror(errno)); + goto do_partial_cleanup; + } + + ret = setns(fd, CLONE_NEWNET); + close(fd); + fd = -1; + if (ret < 0) { + usernic_error("Failed to setns() to the network namespace of " + "the container with PID %d: %s.\n", + pid, strerror(errno)); + goto do_partial_cleanup; + } + + ret = setresuid(ruid, ruid, 0); + if (ret < 0) { + usernic_error("Failed to drop privilege by setting effective " + "user id and real user id to %d, and saved user " + "ID to 0: %s.\n", + ruid, strerror(errno)); + // COMMENT(brauner): It's ok to jump to do_full_cleanup here + // since setresuid() will succeed when trying to set real, + // effective, and saved to values they currently have. + goto do_full_cleanup; } - close(fd); fd = -1; + if (!*newnamep) { grab_newname = true; *newnamep = VETH_DEF_NAME; - if (!(ifindex = if_nametoindex(oldname))) { - fprintf(stderr, "failed to get netdev index\n"); - goto out_err; + + ifindex = if_nametoindex(oldname); + if (!ifindex) { + usernic_error("Failed to get netdev index: %s.\n", + strerror(errno)); + goto do_full_cleanup; } } - if ((ret = lxc_netdev_rename_by_name(oldname, *newnamep)) < 0) { - fprintf(stderr, "Error %d renaming netdev %s to %s in container\n", ret, oldname, *newnamep); - goto out_err; + + ret = lxc_netdev_rename_by_name(oldname, *newnamep); + if (ret < 0) { + usernic_error( + "Error %d renaming netdev %s to %s in container.\n", ret, + oldname, *newnamep); + goto do_full_cleanup; } + if (grab_newname) { - char ifname[IFNAMSIZ], *namep = ifname; + char ifname[IFNAMSIZ]; + char *namep = ifname; if (!if_indextoname(ifindex, namep)) { - fprintf(stderr, "Failed to get new netdev name\n"); - goto out_err; + usernic_error("Failed to get new netdev name: %s.\n", + strerror(errno)); + goto do_full_cleanup; } *newnamep = strdup(namep); if (!*newnamep) - goto out_err; - } - if (setns(ofd, 0) < 0) { - fprintf(stderr, "Error returning to original netns\n"); - close(ofd); - return -1; + goto do_full_cleanup; } - close(ofd); - return 0; + fret = 0; -out_err: - if (ofd >= 0) - close(ofd); - if (setns(ofd, 0) < 0) - fprintf(stderr, "Error returning to original network namespace\n"); +do_full_cleanup: + ret = setresuid(ruid, euid, suid); + if (ret < 0) { + usernic_error( + "Failed to restore privilege by setting effective " + "user id to %d, real user id to %d, and saved user " + "ID to %d: %s.\n", + ruid, euid, suid, strerror(errno)); + fret = -1; + // COMMENT(brauner): setns() should fail if setresuid() doesn't + // succeed but there's no harm in falling through; keeps the + // code cleaner. + } + + ret = setns(ofd, CLONE_NEWNET); + if (ret < 0) { + usernic_error("Failed to setns() to original network namespace " + "of PID %d: %s.\n", + ofd, strerror(errno)); + fret = -1; + } + +do_partial_cleanup: if (fd >= 0) close(fd); - return -1; + close(ofd); + + return fret; } /* -- 2.12.2
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor