aboutsummaryrefslogtreecommitdiffstats
path: root/main/lxc/CVE-2014-1334.patch
blob: e40492fa6a398db9f32ca52b8e458bf406aa3d65 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
From 94bdaef2e636351cc2966387d02e4412bda1d613 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] 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.

Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/1475050
Reported-by: Roman Fiedler
Signed-off-by: Stéphane Graber <stgraber@ubuntu.com>
---
 src/lxc/attach.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 93 insertions(+), 4 deletions(-)

diff --git a/src/lxc/attach.c b/src/lxc/attach.c
index ed6ea8d..16d942c 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));
@@ -573,6 +649,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);
@@ -625,6 +702,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)
@@ -836,6 +914,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
 	 */
@@ -863,7 +948,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
@@ -901,6 +987,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
@@ -1026,12 +1113,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, 0, on_exec);
-		if (ret < 0) {
+		if (lsm_set_label_at(procfd, on_exec, init_ctx->lsm_label) < 0) {
 			rexit(-1);
 		}
 	}
@@ -1082,6 +1168,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));
 }
-- 
1.9.1