]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/caps.c
spelling: keepdata
[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
d38dd64a
CB
24#ifndef _GNU_SOURCE
25#define _GNU_SOURCE 1
26#endif
ca364dc0
CB
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"
d38dd64a 35#include "config.h"
b3357a6f 36#include "log.h"
4e60664a 37#include "macro.h"
b3357a6f 38
ac2cecc4 39lxc_log_define(caps, lxc);
b3357a6f 40
e37dda71 41#if HAVE_LIBCAP
495d2046 42
b3357a6f
DL
43int lxc_caps_down(void)
44{
45 cap_t caps;
4e60664a 46 int ret = -1;
b3357a6f 47
4e60664a 48 /* When we are root, we don't want to play with capabilities. */
7ee895e4
DL
49 if (!getuid())
50 return 0;
51
b3357a6f
DL
52 caps = cap_get_proc();
53 if (!caps) {
4e60664a
CB
54 SYSERROR("Failed to retrieve capabilities");
55 return ret;
b3357a6f
DL
56 }
57
58 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
59 if (ret) {
4e60664a
CB
60 SYSERROR("Failed to clear effective capabilities");
61 goto on_error;
b3357a6f
DL
62 }
63
64 ret = cap_set_proc(caps);
65 if (ret) {
4e60664a
CB
66 SYSERROR("Failed to change effective capabilities");
67 goto on_error;
b3357a6f
DL
68 }
69
4e60664a
CB
70 ret = 0;
71
72on_error:
b3357a6f 73 cap_free(caps);
4e60664a
CB
74
75 return ret;
b3357a6f
DL
76}
77
78int lxc_caps_up(void)
79{
80 cap_t caps;
81 cap_value_t cap;
4e60664a 82 int ret = -1;
b3357a6f 83
4e60664a 84 /* When we are root, we don't want to play with capabilities. */
7ee895e4
DL
85 if (!getuid())
86 return 0;
87
b3357a6f
DL
88 caps = cap_get_proc();
89 if (!caps) {
4e60664a
CB
90 SYSERROR("Failed to retrieve capabilities");
91 return ret;
b3357a6f
DL
92 }
93
94 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
b3357a6f
DL
95 cap_flag_value_t flag;
96
97 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
98 if (ret) {
2b657f10 99 if (errno == EINVAL) {
4e60664a 100 INFO("Last supported cap was %d", cap - 1);
2b657f10
SH
101 break;
102 } else {
4e60664a
CB
103 SYSERROR("Failed to retrieve setting for "
104 "permitted capability %d", cap - 1);
105 goto on_error;
2b657f10 106 }
b3357a6f
DL
107 }
108
109 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
110 if (ret) {
4e60664a
CB
111 SYSERROR("Failed to set effective capability %d", cap - 1);
112 goto on_error;
b3357a6f
DL
113 }
114 }
115
116 ret = cap_set_proc(caps);
117 if (ret) {
4e60664a
CB
118 SYSERROR("Failed to change effective capabilities");
119 goto on_error;
b3357a6f
DL
120 }
121
4e60664a
CB
122 ret = 0;
123
124on_error:
b3357a6f 125 cap_free(caps);
4e60664a
CB
126
127 return ret;
b3357a6f
DL
128}
129
611ddd34
CB
130int lxc_ambient_caps_up(void)
131{
132 int ret;
133 cap_t caps;
134 cap_value_t cap;
135 int last_cap = CAP_LAST_CAP;
136 char *cap_names = NULL;
137
4e60664a 138 /* When we are root, we don't want to play with capabilities. */
611ddd34
CB
139 if (!getuid())
140 return 0;
141
142 caps = cap_get_proc();
143 if (!caps) {
144 SYSERROR("Failed to retrieve capabilities");
145 return -1;
146 }
147
148 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
149 cap_flag_value_t flag;
150
151 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
152 if (ret < 0) {
153 if (errno == EINVAL) {
154 last_cap = (cap - 1);
155 INFO("Last supported cap was %d", last_cap);
156 break;
157 }
158
159 SYSERROR("Failed to retrieve capability flag");
160 goto out;
161 }
162
163 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, flag);
164 if (ret < 0) {
165 SYSERROR("Failed to set capability flag");
166 goto out;
167 }
168 }
169
170 ret = cap_set_proc(caps);
171 if (ret < 0) {
172 SYSERROR("Failed to set capabilities");
173 goto out;
174 }
175
176 for (cap = 0; cap <= last_cap; cap++) {
b81689a1
CB
177 ret = prctl(PR_CAP_AMBIENT, prctl_arg(PR_CAP_AMBIENT_RAISE),
178 prctl_arg(cap), prctl_arg(0), prctl_arg(0));
611ddd34 179 if (ret < 0) {
a24c5678 180 SYSWARN("Failed to raise ambient capability %d", cap);
611ddd34
CB
181 goto out;
182 }
183 }
184
185 cap_names = cap_to_text(caps, NULL);
6f5e532f 186 if (!cap_names) {
187 SYSWARN("Failed to convert capabilities %d", cap);
611ddd34 188 goto out;
6f5e532f 189 }
611ddd34
CB
190
191 TRACE("Raised %s in inheritable and ambient capability set", cap_names);
192
193out:
194
195 cap_free(cap_names);
196 cap_free(caps);
197 return 0;
198}
199
200int lxc_ambient_caps_down(void)
201{
202 int ret;
203 cap_t caps;
204 cap_value_t cap;
205
4e60664a 206 /* When we are root, we don't want to play with capabilities. */
611ddd34
CB
207 if (!getuid())
208 return 0;
209
b81689a1
CB
210 ret = prctl(PR_CAP_AMBIENT, prctl_arg(PR_CAP_AMBIENT_CLEAR_ALL),
211 prctl_arg(0), prctl_arg(0), prctl_arg(0));
611ddd34
CB
212 if (ret < 0) {
213 SYSERROR("Failed to clear ambient capability set");
214 return -1;
215 }
216
217 caps = cap_get_proc();
218 if (!caps) {
219 SYSERROR("Failed to retrieve capabilities");
220 return -1;
221 }
222
223 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
224 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
225 if (ret < 0) {
226 SYSERROR("Failed to remove capability from inheritable set");
227 goto out;
228 }
229 }
230
231 ret = cap_set_proc(caps);
232 if (ret < 0) {
233 SYSERROR("Failed to set capabilities");
234 goto out;
235 }
236
237out:
238 cap_free(caps);
239 return 0;
240}
241
b3357a6f
DL
242int lxc_caps_init(void)
243{
4e60664a 244 uid_t euid, uid;
b3357a6f 245
4e60664a
CB
246 uid = getuid();
247 if (!uid)
b3357a6f 248 return 0;
b3357a6f 249
4e60664a 250 euid = geteuid();
b3357a6f 251 if (uid && !euid) {
4e60664a
CB
252 int ret;
253 gid_t gid;
254
255 INFO("Command is run as setuid root (uid: %d)", uid);
b3357a6f 256
b81689a1 257 ret = prctl(PR_SET_KEEPCAPS, prctl_arg(1));
4e60664a
CB
258 if (ret < 0) {
259 SYSERROR("Failed to set PR_SET_KEEPCAPS");
b3357a6f
DL
260 return -1;
261 }
262
4e60664a
CB
263 gid = getgid();
264 ret = setresgid(gid, gid, gid);
265 if (ret < 0) {
266 SYSERROR("Failed to change rgid, egid, and sgid to %d", gid);
b3357a6f
DL
267 return -1;
268 }
269
4e60664a
CB
270 ret = setresuid(uid, uid, uid);
271 if (ret < 0) {
272 SYSERROR("Failed to change ruid, euid, and suid to %d", uid);
b3357a6f
DL
273 return -1;
274 }
275
4e60664a
CB
276 ret = lxc_caps_up();
277 if (ret < 0) {
6d1400b5 278 SYSERROR("Failed to restore capabilities");
b3357a6f
DL
279 return -1;
280 }
281 }
282
283 if (uid == euid)
4e60664a 284 INFO("Command is run with uid %d", uid);
b3357a6f
DL
285
286 return 0;
287}
20d81659 288
92d5ea57 289static long int _real_caps_last_cap(void)
20d81659 290{
4e60664a 291 int fd, result = -1;
20d81659 292
4e60664a
CB
293 /* Try to get the maximum capability over the kernel interface
294 * introduced in v3.2.
295 */
296 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY | O_CLOEXEC);
20d81659 297 if (fd >= 0) {
4e60664a 298 ssize_t n;
20d81659 299 char *ptr;
22b67bfa 300 char buf[INTTYPE_TO_STRLEN(int)] = {0};
20d81659 301
81f87066 302 again:
6333c915 303 n = read(fd, buf, STRARRAYLEN(buf));
81f87066
CB
304 if (n < 0 && errno == EINTR) {
305 goto again;
306 } else if (n >= 0) {
4e60664a 307 errno = 0;
20d81659 308 result = strtol(buf, &ptr, 10);
09bbd745 309 if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
20d81659
CS
310 result = -1;
311 }
312
313 close(fd);
4e60664a 314 } else {
20d81659 315 int cap = 0;
6f5e532f 316
4e60664a
CB
317 /* Try to get it manually by trying to get the status of each
318 * capability individually from the kernel.
319 */
b81689a1 320 while (prctl(PR_CAPBSET_READ, prctl_arg(cap)) >= 0)
6f5e532f 321 cap++;
322
20d81659
CS
323 result = cap - 1;
324 }
325
326 return result;
327}
328
329int lxc_caps_last_cap(void)
330{
92d5ea57 331 static long int last_cap = -1;
6f5e532f 332
92d5ea57 333 if (last_cap < 0) {
6f5e532f 334 last_cap = _real_caps_last_cap();
92d5ea57 335 if (last_cap < 0 || last_cap > INT_MAX)
336 last_cap = -1;
337 }
20d81659
CS
338
339 return last_cap;
340}
4a2ca8b2 341
207c4c71 342static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
ca364dc0
CB
343{
344 int ret;
ca364dc0
CB
345 cap_flag_value_t flagval;
346
207c4c71
CB
347 ret = cap_get_flag(caps, cap, flag, &flagval);
348 if (ret < 0) {
4e60664a 349 SYSERROR("Failed to retrieve current setting for capability %d", cap);
207c4c71
CB
350 return false;
351 }
352
353 return flagval == CAP_SET;
354}
355
356bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
357{
4e60664a 358#if LIBCAP_SUPPORTS_FILE_CAPABILITIES
207c4c71
CB
359 bool cap_is_set;
360 cap_t caps;
361
362 caps = cap_get_file(path);
ca364dc0 363 if (!caps) {
207c4c71
CB
364 /* This is undocumented in the manpage but the source code show
365 * that cap_get_file() may return NULL when successful for the
366 * case where it didn't detect any file capabilities. In this
367 * case errno will be set to ENODATA.
368 */
369 if (errno != ENODATA)
4e60664a 370 SYSERROR("Failed to retrieve capabilities for file %s", path);
6d1400b5 371
ca364dc0
CB
372 return false;
373 }
374
207c4c71
CB
375 cap_is_set = lxc_cap_is_set(caps, cap, flag);
376 cap_free(caps);
377 return cap_is_set;
4e60664a 378#else
69924fff
CB
379 errno = ENODATA;
380 return false;
4e60664a 381#endif
207c4c71
CB
382}
383
384bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
385{
386 bool cap_is_set;
387 cap_t caps;
388
389 caps = cap_get_proc();
390 if (!caps) {
4e60664a 391 SYSERROR("Failed to retrieve capabilities");
ca364dc0
CB
392 return false;
393 }
394
207c4c71 395 cap_is_set = lxc_cap_is_set(caps, cap, flag);
ca364dc0 396 cap_free(caps);
207c4c71 397 return cap_is_set;
ca364dc0 398}
495d2046 399#endif