parent
cf3c9ccc09
commit
4283bef697
@ -1,113 +0,0 @@
|
||||
From f50da74a71f2c33f869e6da15f131bf5c9174c12 Mon Sep 17 00:00:00 2001
|
||||
From: Serge Hallyn <serge.hallyn@ubuntu.com>
|
||||
Date: Fri, 3 Jul 2015 09:26:17 -0500
|
||||
Subject: [PATCH 1/2] CVE-2015-1331: lxclock: use /run/lxc/lock rather than
|
||||
/run/lock/lxc
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This prevents an unprivileged user to use LXC to create arbitrary file
|
||||
on the filesystem.
|
||||
|
||||
Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
|
||||
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
|
||||
Acked-by: Stéphane Graber <stgraber@ubuntu.com>
|
||||
---
|
||||
src/lxc/lxclock.c | 47 ++++++++++-------------------------------------
|
||||
src/tests/locktests.c | 2 +-
|
||||
2 files changed, 11 insertions(+), 38 deletions(-)
|
||||
|
||||
diff --git a/src/lxc/lxclock.c b/src/lxc/lxclock.c
|
||||
index fe13898..e9e95f7 100644
|
||||
--- a/src/lxc/lxclock.c
|
||||
+++ b/src/lxc/lxclock.c
|
||||
@@ -103,13 +103,13 @@ static char *lxclock_name(const char *p, const char *n)
|
||||
char *rundir;
|
||||
|
||||
/* lockfile will be:
|
||||
- * "/run" + "/lock/lxc/$lxcpath/$lxcname + '\0' if root
|
||||
+ * "/run" + "/lxc/lock/$lxcpath/$lxcname + '\0' if root
|
||||
* or
|
||||
- * $XDG_RUNTIME_DIR + "/lock/lxc/$lxcpath/$lxcname + '\0' if non-root
|
||||
+ * $XDG_RUNTIME_DIR + "/lxc/lock/$lxcpath/$lxcname + '\0' if non-root
|
||||
*/
|
||||
|
||||
- /* length of "/lock/lxc/" + $lxcpath + "/" + "." + $lxcname + '\0' */
|
||||
- len = strlen("/lock/lxc/") + strlen(n) + strlen(p) + 3;
|
||||
+ /* length of "/lxc/lock/" + $lxcpath + "/" + "." + $lxcname + '\0' */
|
||||
+ len = strlen("/lxc/lock/") + strlen(n) + strlen(p) + 3;
|
||||
rundir = get_rundir();
|
||||
if (!rundir)
|
||||
return NULL;
|
||||
@@ -120,7 +120,7 @@ static char *lxclock_name(const char *p, const char *n)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- ret = snprintf(dest, len, "%s/lock/lxc/%s", rundir, p);
|
||||
+ ret = snprintf(dest, len, "%s/lxc/lock/%s", rundir, p);
|
||||
if (ret < 0 || ret >= len) {
|
||||
free(dest);
|
||||
free(rundir);
|
||||
@@ -128,40 +128,13 @@ static char *lxclock_name(const char *p, const char *n)
|
||||
}
|
||||
ret = mkdir_p(dest, 0755);
|
||||
if (ret < 0) {
|
||||
- /* fall back to "/tmp/" + $(id -u) + "/lxc" + $lxcpath + "/" + "." + $lxcname + '\0'
|
||||
- * * maximum length of $(id -u) is 10 calculated by (log (2 ** (sizeof(uid_t) * 8) - 1) / log 10 + 1)
|
||||
- * * lxcpath always starts with '/'
|
||||
- */
|
||||
- int l2 = 22 + strlen(n) + strlen(p);
|
||||
- if (l2 > len) {
|
||||
- char *d;
|
||||
- d = realloc(dest, l2);
|
||||
- if (!d) {
|
||||
- free(dest);
|
||||
- free(rundir);
|
||||
- return NULL;
|
||||
- }
|
||||
- len = l2;
|
||||
- dest = d;
|
||||
- }
|
||||
- ret = snprintf(dest, len, "/tmp/%d/lxc%s", geteuid(), p);
|
||||
- if (ret < 0 || ret >= len) {
|
||||
- free(dest);
|
||||
- free(rundir);
|
||||
- return NULL;
|
||||
- }
|
||||
- ret = mkdir_p(dest, 0755);
|
||||
- if (ret < 0) {
|
||||
- free(dest);
|
||||
- free(rundir);
|
||||
- return NULL;
|
||||
- }
|
||||
- ret = snprintf(dest, len, "/tmp/%d/lxc%s/.%s", geteuid(), p, n);
|
||||
- } else
|
||||
- ret = snprintf(dest, len, "%s/lock/lxc/%s/.%s", rundir, p, n);
|
||||
+ free(dest);
|
||||
+ free(rundir);
|
||||
+ return NULL;
|
||||
+ }
|
||||
|
||||
+ ret = snprintf(dest, len, "%s/lxc/lock/%s/.%s", rundir, p, n);
|
||||
free(rundir);
|
||||
-
|
||||
if (ret < 0 || ret >= len) {
|
||||
free(dest);
|
||||
return NULL;
|
||||
diff --git a/src/tests/locktests.c b/src/tests/locktests.c
|
||||
index dd3393a..233ca12 100644
|
||||
--- a/src/tests/locktests.c
|
||||
+++ b/src/tests/locktests.c
|
||||
@@ -122,7 +122,7 @@ int main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
struct stat sb;
|
||||
- char *pathname = RUNTIME_PATH "/lock/lxc/var/lib/lxc/";
|
||||
+ char *pathname = RUNTIME_PATH "/lxc/lock/var/lib/lxc/";
|
||||
ret = stat(pathname, &sb);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%d: filename %s not created\n", __LINE__,
|
||||
--
|
||||
2.4.3
|
||||
|
@ -1,184 +0,0 @@
|
||||
From ef62305193a5bb7ec00ccf00451be4ff0efac3ca Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber@ubuntu.com>
|
||||
Date: Thu, 16 Jul 2015 16:37:51 -0400
|
||||
Subject: [PATCH 2/2] CVE-2015-1334: Don't use the container's /proc during
|
||||
attach
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
A user could otherwise over-mount /proc and prevent the apparmor profile
|
||||
or selinux label from being written which combined with a modified
|
||||
/bin/sh or other commonly used binary would lead to unconfined code
|
||||
execution.
|
||||
|
||||
Reported-by: Roman Fiedler
|
||||
Signed-off-by: Stéphane Graber <stgraber@ubuntu.com>
|
||||
---
|
||||
src/lxc/attach.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||
1 file changed, 93 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/src/lxc/attach.c b/src/lxc/attach.c
|
||||
index 69dafd4..436ae7a 100644
|
||||
--- a/src/lxc/attach.c
|
||||
+++ b/src/lxc/attach.c
|
||||
@@ -76,6 +76,82 @@
|
||||
|
||||
lxc_log_define(lxc_attach, lxc);
|
||||
|
||||
+int lsm_set_label_at(int procfd, int on_exec, char* lsm_label) {
|
||||
+ int labelfd = -1;
|
||||
+ int ret = 0;
|
||||
+ const char* name;
|
||||
+ char* command = NULL;
|
||||
+
|
||||
+ name = lsm_name();
|
||||
+
|
||||
+ if (strcmp(name, "nop") == 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (strcmp(name, "none") == 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ /* We don't support on-exec with AppArmor */
|
||||
+ if (strcmp(name, "AppArmor") == 0)
|
||||
+ on_exec = 0;
|
||||
+
|
||||
+ if (on_exec) {
|
||||
+ labelfd = openat(procfd, "self/attr/exec", O_RDWR);
|
||||
+ }
|
||||
+ else {
|
||||
+ labelfd = openat(procfd, "self/attr/current", O_RDWR);
|
||||
+ }
|
||||
+
|
||||
+ if (labelfd < 0) {
|
||||
+ SYSERROR("Unable to open LSM label");
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (strcmp(name, "AppArmor") == 0) {
|
||||
+ int size;
|
||||
+
|
||||
+ command = malloc(strlen(lsm_label) + strlen("changeprofile ") + 1);
|
||||
+ if (!command) {
|
||||
+ SYSERROR("Failed to write apparmor profile");
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ size = sprintf(command, "changeprofile %s", lsm_label);
|
||||
+ if (size < 0) {
|
||||
+ SYSERROR("Failed to write apparmor profile");
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (write(labelfd, command, size + 1) < 0) {
|
||||
+ SYSERROR("Unable to set LSM label");
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (strcmp(name, "SELinux") == 0) {
|
||||
+ if (write(labelfd, lsm_label, strlen(lsm_label) + 1) < 0) {
|
||||
+ SYSERROR("Unable to set LSM label");
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ }
|
||||
+ else {
|
||||
+ ERROR("Unable to restore label for unknown LSM: %s", name);
|
||||
+ ret = -1;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+out:
|
||||
+ free(command);
|
||||
+
|
||||
+ if (labelfd != -1)
|
||||
+ close(labelfd);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
|
||||
{
|
||||
struct lxc_proc_context_info *info = calloc(1, sizeof(*info));
|
||||
@@ -570,6 +646,7 @@ struct attach_clone_payload {
|
||||
struct lxc_proc_context_info* init_ctx;
|
||||
lxc_attach_exec_t exec_function;
|
||||
void* exec_payload;
|
||||
+ int procfd;
|
||||
};
|
||||
|
||||
static int attach_child_main(void* data);
|
||||
@@ -622,6 +699,7 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
|
||||
char* cwd;
|
||||
char* new_cwd;
|
||||
int ipc_sockets[2];
|
||||
+ int procfd;
|
||||
signed long personality;
|
||||
|
||||
if (!options)
|
||||
@@ -833,6 +911,13 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
|
||||
rexit(-1);
|
||||
}
|
||||
|
||||
+ procfd = open("/proc", O_DIRECTORY | O_RDONLY);
|
||||
+ if (procfd < 0) {
|
||||
+ SYSERROR("Unable to open /proc");
|
||||
+ shutdown(ipc_sockets[1], SHUT_RDWR);
|
||||
+ rexit(-1);
|
||||
+ }
|
||||
+
|
||||
/* attach now, create another subprocess later, since pid namespaces
|
||||
* only really affect the children of the current process
|
||||
*/
|
||||
@@ -860,7 +945,8 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
|
||||
.options = options,
|
||||
.init_ctx = init_ctx,
|
||||
.exec_function = exec_function,
|
||||
- .exec_payload = exec_payload
|
||||
+ .exec_payload = exec_payload,
|
||||
+ .procfd = procfd
|
||||
};
|
||||
/* We use clone_parent here to make this subprocess a direct child of
|
||||
* the initial process. Then this intermediate process can exit and
|
||||
@@ -898,6 +984,7 @@ static int attach_child_main(void* data)
|
||||
{
|
||||
struct attach_clone_payload* payload = (struct attach_clone_payload*)data;
|
||||
int ipc_socket = payload->ipc_socket;
|
||||
+ int procfd = payload->procfd;
|
||||
lxc_attach_options_t* options = payload->options;
|
||||
struct lxc_proc_context_info* init_ctx = payload->init_ctx;
|
||||
#if HAVE_SYS_PERSONALITY_H
|
||||
@@ -1038,13 +1125,11 @@ static int attach_child_main(void* data)
|
||||
close(ipc_socket);
|
||||
|
||||
/* set new apparmor profile/selinux context */
|
||||
- if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) {
|
||||
+ if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM) && init_ctx->lsm_label) {
|
||||
int on_exec;
|
||||
|
||||
on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0;
|
||||
- ret = lsm_process_label_set(init_ctx->lsm_label,
|
||||
- init_ctx->container->lxc_conf, 0, on_exec);
|
||||
- if (ret < 0) {
|
||||
+ if (lsm_set_label_at(procfd, on_exec, init_ctx->lsm_label) < 0) {
|
||||
rexit(-1);
|
||||
}
|
||||
}
|
||||
@@ -1095,6 +1180,9 @@ static int attach_child_main(void* data)
|
||||
}
|
||||
}
|
||||
|
||||
+ /* we don't need proc anymore */
|
||||
+ close(procfd);
|
||||
+
|
||||
/* we're done, so we can now do whatever the user intended us to do */
|
||||
rexit(payload->exec_function(payload->exec_payload));
|
||||
}
|
||||
--
|
||||
2.4.3
|
||||
|
@ -1,15 +0,0 @@
|
||||
diff --git a/src/lua-lxc/core.c b/src/lua-lxc/core.c
|
||||
index 630a3e4..34180a7 100644
|
||||
--- a/src/lua-lxc/core.c
|
||||
+++ b/src/lua-lxc/core.c
|
||||
@@ -39,8 +39,10 @@
|
||||
#endif
|
||||
|
||||
#if LUA_VERSION_NUM >= 503
|
||||
+#ifndef luaL_checkunsigned
|
||||
#define luaL_checkunsigned(L,n) ((lua_Unsigned)luaL_checkinteger(L,n))
|
||||
#endif
|
||||
+#endif
|
||||
|
||||
#ifdef NO_CHECK_UDATA
|
||||
#define checkudata(L,i,tname) lua_touserdata(L, i)
|
Loading…
Reference in new issue