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