]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/caps.c
capabilities: raise ambient capabilities
[mirror_lxc.git] / src / lxc / caps.c
CommitLineData
b3357a6f
DL
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
b3357a6f
DL
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b3357a6f
DL
22 */
23
24#define _GNU_SOURCE
ca364dc0
CB
25#include "config.h"
26
27#include <errno.h>
28#include <limits.h>
20d81659
CS
29#include <fcntl.h>
30#include <stdlib.h>
ca364dc0 31#include <unistd.h>
b3357a6f 32#include <sys/prctl.h>
b3357a6f 33
ca364dc0 34#include "caps.h"
b3357a6f
DL
35#include "log.h"
36
37lxc_log_define(lxc_caps, lxc);
38
e37dda71 39#if HAVE_LIBCAP
495d2046 40
cbec0030
SG
41#ifndef PR_CAPBSET_READ
42#define PR_CAPBSET_READ 23
43#endif
44
611ddd34
CB
45/* Control the ambient capability set */
46#ifndef PR_CAP_AMBIENT
47#define PR_CAP_AMBIENT 47
48#endif
49
50#ifndef PR_CAP_AMBIENT_IS_SET
51#define PR_CAP_AMBIENT_IS_SET 1
52#endif
53
54#ifndef PR_CAP_AMBIENT_RAISE
55#define PR_CAP_AMBIENT_RAISE 2
56#endif
57
58#ifndef PR_CAP_AMBIENT_LOWER
59#define PR_CAP_AMBIENT_LOWER 3
60#endif
61
62#ifndef PR_CAP_AMBIENT_CLEAR_ALL
63#define PR_CAP_AMBIENT_CLEAR_ALL 4
64#endif
65
b3357a6f
DL
66int lxc_caps_down(void)
67{
68 cap_t caps;
69 int ret;
70
7ee895e4
DL
71 /* when we are run as root, we don't want to play
72 * with the capabilities */
73 if (!getuid())
74 return 0;
75
b3357a6f
DL
76 caps = cap_get_proc();
77 if (!caps) {
13277ec4 78 ERROR("failed to cap_get_proc: %s", strerror(errno));
b3357a6f
DL
79 return -1;
80 }
81
82 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
83 if (ret) {
13277ec4 84 ERROR("failed to cap_clear_flag: %s", strerror(errno));
b3357a6f
DL
85 goto out;
86 }
87
88 ret = cap_set_proc(caps);
89 if (ret) {
13277ec4 90 ERROR("failed to cap_set_proc: %s", strerror(errno));
b3357a6f
DL
91 goto out;
92 }
93
94out:
95 cap_free(caps);
d028235d 96 return 0;
b3357a6f
DL
97}
98
99int lxc_caps_up(void)
100{
101 cap_t caps;
102 cap_value_t cap;
103 int ret;
104
7ee895e4
DL
105 /* when we are run as root, we don't want to play
106 * with the capabilities */
107 if (!getuid())
108 return 0;
109
b3357a6f
DL
110 caps = cap_get_proc();
111 if (!caps) {
13277ec4 112 ERROR("failed to cap_get_proc: %s", strerror(errno));
b3357a6f
DL
113 return -1;
114 }
115
116 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
117
118 cap_flag_value_t flag;
119
120 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
121 if (ret) {
2b657f10 122 if (errno == EINVAL) {
959aee9c 123 INFO("Last supported cap was %d", cap-1);
2b657f10
SH
124 break;
125 } else {
13277ec4 126 ERROR("failed to cap_get_flag: %s",
127 strerror(errno));
2b657f10
SH
128 goto out;
129 }
b3357a6f
DL
130 }
131
132 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
133 if (ret) {
13277ec4 134 ERROR("failed to cap_set_flag: %s", strerror(errno));
b3357a6f
DL
135 goto out;
136 }
137 }
138
139 ret = cap_set_proc(caps);
140 if (ret) {
13277ec4 141 ERROR("failed to cap_set_proc: %s", strerror(errno));
b3357a6f
DL
142 goto out;
143 }
144
145out:
146 cap_free(caps);
d028235d 147 return 0;
b3357a6f
DL
148}
149
611ddd34
CB
150int lxc_ambient_caps_up(void)
151{
152 int ret;
153 cap_t caps;
154 cap_value_t cap;
155 int last_cap = CAP_LAST_CAP;
156 char *cap_names = NULL;
157
158 /* When we are run as root, we don't want to play with the capabilities. */
159 if (!getuid())
160 return 0;
161
162 caps = cap_get_proc();
163 if (!caps) {
164 SYSERROR("Failed to retrieve capabilities");
165 return -1;
166 }
167
168 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
169 cap_flag_value_t flag;
170
171 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
172 if (ret < 0) {
173 if (errno == EINVAL) {
174 last_cap = (cap - 1);
175 INFO("Last supported cap was %d", last_cap);
176 break;
177 }
178
179 SYSERROR("Failed to retrieve capability flag");
180 goto out;
181 }
182
183 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, flag);
184 if (ret < 0) {
185 SYSERROR("Failed to set capability flag");
186 goto out;
187 }
188 }
189
190 ret = cap_set_proc(caps);
191 if (ret < 0) {
192 SYSERROR("Failed to set capabilities");
193 goto out;
194 }
195
196 for (cap = 0; cap <= last_cap; cap++) {
197 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
198 if (ret < 0) {
199 WARN("%s - Failed to raise ambient capability %d",
200 strerror(errno), cap);
201 goto out;
202 }
203 }
204
205 cap_names = cap_to_text(caps, NULL);
206 if (!cap_names)
207 goto out;
208
209 TRACE("Raised %s in inheritable and ambient capability set", cap_names);
210
211out:
212
213 cap_free(cap_names);
214 cap_free(caps);
215 return 0;
216}
217
218int lxc_ambient_caps_down(void)
219{
220 int ret;
221 cap_t caps;
222 cap_value_t cap;
223
224 /* When we are run as root, we don't want to play with the capabilities. */
225 if (!getuid())
226 return 0;
227
228 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
229 if (ret < 0) {
230 SYSERROR("Failed to clear ambient capability set");
231 return -1;
232 }
233
234 caps = cap_get_proc();
235 if (!caps) {
236 SYSERROR("Failed to retrieve capabilities");
237 return -1;
238 }
239
240 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
241 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
242 if (ret < 0) {
243 SYSERROR("Failed to remove capability from inheritable set");
244 goto out;
245 }
246 }
247
248 ret = cap_set_proc(caps);
249 if (ret < 0) {
250 SYSERROR("Failed to set capabilities");
251 goto out;
252 }
253
254out:
255 cap_free(caps);
256 return 0;
257}
258
b3357a6f
DL
259int lxc_caps_init(void)
260{
261 uid_t uid = getuid();
262 gid_t gid = getgid();
263 uid_t euid = geteuid();
264
265 if (!uid) {
266 INFO("command is run as 'root'");
267 return 0;
268 }
269
270 if (uid && !euid) {
271 INFO("command is run as setuid root (uid : %d)", uid);
272
273 if (prctl(PR_SET_KEEPCAPS, 1)) {
13277ec4 274 ERROR("failed to 'PR_SET_KEEPCAPS': %s",
275 strerror(errno));
b3357a6f
DL
276 return -1;
277 }
278
279 if (setresgid(gid, gid, gid)) {
13277ec4 280 ERROR("failed to change gid to '%d': %s", gid,
281 strerror(errno));
b3357a6f
DL
282 return -1;
283 }
284
285 if (setresuid(uid, uid, uid)) {
13277ec4 286 ERROR("failed to change uid to '%d': %s", uid,
287 strerror(errno));
b3357a6f
DL
288 return -1;
289 }
290
291 if (lxc_caps_up()) {
13277ec4 292 ERROR("failed to restore capabilities: %s",
293 strerror(errno));
b3357a6f
DL
294 return -1;
295 }
296 }
297
298 if (uid == euid)
299 INFO("command is run as user '%d'", uid);
300
301 return 0;
302}
20d81659
CS
303
304static int _real_caps_last_cap(void)
305{
306 int fd;
307 int result = -1;
308
309 /* try to get the maximum capability over the kernel
310 * interface introduced in v3.2 */
311 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
312 if (fd >= 0) {
313 char buf[32];
314 char *ptr;
315 int n;
316
317 if ((n = read(fd, buf, 31)) >= 0) {
318 buf[n] = '\0';
09bbd745 319 errno = 0;
20d81659 320 result = strtol(buf, &ptr, 10);
09bbd745 321 if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
20d81659
CS
322 result = -1;
323 }
324
325 close(fd);
326 }
327
328 /* try to get it manually by trying to get the status of
329 * each capability indiviually from the kernel */
330 if (result < 0) {
331 int cap = 0;
332 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
333 result = cap - 1;
334 }
335
336 return result;
337}
338
339int lxc_caps_last_cap(void)
340{
341 static int last_cap = -1;
342 if (last_cap < 0) last_cap = _real_caps_last_cap();
343
344 return last_cap;
345}
4a2ca8b2 346
207c4c71 347static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
ca364dc0
CB
348{
349 int ret;
ca364dc0
CB
350 cap_flag_value_t flagval;
351
207c4c71
CB
352 ret = cap_get_flag(caps, cap, flag, &flagval);
353 if (ret < 0) {
354 ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
355 return false;
356 }
357
358 return flagval == CAP_SET;
359}
360
361bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
362{
69924fff 363 #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
207c4c71
CB
364 bool cap_is_set;
365 cap_t caps;
366
367 caps = cap_get_file(path);
ca364dc0 368 if (!caps) {
207c4c71
CB
369 /* This is undocumented in the manpage but the source code show
370 * that cap_get_file() may return NULL when successful for the
371 * case where it didn't detect any file capabilities. In this
372 * case errno will be set to ENODATA.
373 */
374 if (errno != ENODATA)
375 ERROR("Failed to perform cap_get_file(): %s.\n", strerror(errno));
ca364dc0
CB
376 return false;
377 }
378
207c4c71
CB
379 cap_is_set = lxc_cap_is_set(caps, cap, flag);
380 cap_free(caps);
381 return cap_is_set;
69924fff
CB
382 #else
383 errno = ENODATA;
384 return false;
d6018f88 385 #endif
207c4c71
CB
386}
387
388bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
389{
390 bool cap_is_set;
391 cap_t caps;
392
393 caps = cap_get_proc();
394 if (!caps) {
395 ERROR("Failed to perform cap_get_proc(): %s.\n", strerror(errno));
ca364dc0
CB
396 return false;
397 }
398
207c4c71 399 cap_is_set = lxc_cap_is_set(caps, cap, flag);
ca364dc0 400 cap_free(caps);
207c4c71 401 return cap_is_set;
ca364dc0
CB
402}
403
495d2046 404#endif