]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/caps.c
log: change WARN macro using strerror to SYSWARN
[mirror_lxc.git] / src / lxc / caps.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #define _GNU_SOURCE
25 #include "config.h"
26
27 #include <errno.h>
28 #include <limits.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/prctl.h>
33
34 #include "caps.h"
35 #include "log.h"
36
37 lxc_log_define(lxc_caps, lxc);
38
39 #if HAVE_LIBCAP
40
41 #ifndef PR_CAPBSET_READ
42 #define PR_CAPBSET_READ 23
43 #endif
44
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
66 int lxc_caps_down(void)
67 {
68 cap_t caps;
69 int ret;
70
71 /* when we are run as root, we don't want to play
72 * with the capabilities */
73 if (!getuid())
74 return 0;
75
76 caps = cap_get_proc();
77 if (!caps) {
78 ERROR("failed to cap_get_proc: %s", strerror(errno));
79 return -1;
80 }
81
82 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
83 if (ret) {
84 ERROR("failed to cap_clear_flag: %s", strerror(errno));
85 goto out;
86 }
87
88 ret = cap_set_proc(caps);
89 if (ret) {
90 ERROR("failed to cap_set_proc: %s", strerror(errno));
91 goto out;
92 }
93
94 out:
95 cap_free(caps);
96 return 0;
97 }
98
99 int lxc_caps_up(void)
100 {
101 cap_t caps;
102 cap_value_t cap;
103 int ret;
104
105 /* when we are run as root, we don't want to play
106 * with the capabilities */
107 if (!getuid())
108 return 0;
109
110 caps = cap_get_proc();
111 if (!caps) {
112 ERROR("failed to cap_get_proc: %s", strerror(errno));
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) {
122 if (errno == EINVAL) {
123 INFO("Last supported cap was %d", cap-1);
124 break;
125 } else {
126 ERROR("failed to cap_get_flag: %s",
127 strerror(errno));
128 goto out;
129 }
130 }
131
132 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
133 if (ret) {
134 ERROR("failed to cap_set_flag: %s", strerror(errno));
135 goto out;
136 }
137 }
138
139 ret = cap_set_proc(caps);
140 if (ret) {
141 ERROR("failed to cap_set_proc: %s", strerror(errno));
142 goto out;
143 }
144
145 out:
146 cap_free(caps);
147 return 0;
148 }
149
150 int 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 SYSWARN("Failed to raise ambient capability %d", cap);
200 goto out;
201 }
202 }
203
204 cap_names = cap_to_text(caps, NULL);
205 if (!cap_names)
206 goto out;
207
208 TRACE("Raised %s in inheritable and ambient capability set", cap_names);
209
210 out:
211
212 cap_free(cap_names);
213 cap_free(caps);
214 return 0;
215 }
216
217 int lxc_ambient_caps_down(void)
218 {
219 int ret;
220 cap_t caps;
221 cap_value_t cap;
222
223 /* When we are run as root, we don't want to play with the capabilities. */
224 if (!getuid())
225 return 0;
226
227 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
228 if (ret < 0) {
229 SYSERROR("Failed to clear ambient capability set");
230 return -1;
231 }
232
233 caps = cap_get_proc();
234 if (!caps) {
235 SYSERROR("Failed to retrieve capabilities");
236 return -1;
237 }
238
239 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
240 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
241 if (ret < 0) {
242 SYSERROR("Failed to remove capability from inheritable set");
243 goto out;
244 }
245 }
246
247 ret = cap_set_proc(caps);
248 if (ret < 0) {
249 SYSERROR("Failed to set capabilities");
250 goto out;
251 }
252
253 out:
254 cap_free(caps);
255 return 0;
256 }
257
258 int lxc_caps_init(void)
259 {
260 uid_t uid = getuid();
261 gid_t gid = getgid();
262 uid_t euid = geteuid();
263
264 if (!uid) {
265 INFO("command is run as 'root'");
266 return 0;
267 }
268
269 if (uid && !euid) {
270 INFO("command is run as setuid root (uid : %d)", uid);
271
272 if (prctl(PR_SET_KEEPCAPS, 1)) {
273 ERROR("failed to 'PR_SET_KEEPCAPS': %s",
274 strerror(errno));
275 return -1;
276 }
277
278 if (setresgid(gid, gid, gid)) {
279 ERROR("failed to change gid to '%d': %s", gid,
280 strerror(errno));
281 return -1;
282 }
283
284 if (setresuid(uid, uid, uid)) {
285 ERROR("failed to change uid to '%d': %s", uid,
286 strerror(errno));
287 return -1;
288 }
289
290 if (lxc_caps_up()) {
291 ERROR("failed to restore capabilities: %s",
292 strerror(errno));
293 return -1;
294 }
295 }
296
297 if (uid == euid)
298 INFO("command is run as user '%d'", uid);
299
300 return 0;
301 }
302
303 static int _real_caps_last_cap(void)
304 {
305 int fd;
306 int result = -1;
307
308 /* try to get the maximum capability over the kernel
309 * interface introduced in v3.2 */
310 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
311 if (fd >= 0) {
312 char buf[32];
313 char *ptr;
314 int n;
315
316 if ((n = read(fd, buf, 31)) >= 0) {
317 buf[n] = '\0';
318 errno = 0;
319 result = strtol(buf, &ptr, 10);
320 if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
321 result = -1;
322 }
323
324 close(fd);
325 }
326
327 /* try to get it manually by trying to get the status of
328 * each capability indiviually from the kernel */
329 if (result < 0) {
330 int cap = 0;
331 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
332 result = cap - 1;
333 }
334
335 return result;
336 }
337
338 int lxc_caps_last_cap(void)
339 {
340 static int last_cap = -1;
341 if (last_cap < 0) last_cap = _real_caps_last_cap();
342
343 return last_cap;
344 }
345
346 static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
347 {
348 int ret;
349 cap_flag_value_t flagval;
350
351 ret = cap_get_flag(caps, cap, flag, &flagval);
352 if (ret < 0) {
353 ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
354 return false;
355 }
356
357 return flagval == CAP_SET;
358 }
359
360 bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
361 {
362 #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
363 bool cap_is_set;
364 cap_t caps;
365
366 caps = cap_get_file(path);
367 if (!caps) {
368 /* This is undocumented in the manpage but the source code show
369 * that cap_get_file() may return NULL when successful for the
370 * case where it didn't detect any file capabilities. In this
371 * case errno will be set to ENODATA.
372 */
373 if (errno != ENODATA)
374 ERROR("Failed to perform cap_get_file(): %s.\n", strerror(errno));
375 return false;
376 }
377
378 cap_is_set = lxc_cap_is_set(caps, cap, flag);
379 cap_free(caps);
380 return cap_is_set;
381 #else
382 errno = ENODATA;
383 return false;
384 #endif
385 }
386
387 bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
388 {
389 bool cap_is_set;
390 cap_t caps;
391
392 caps = cap_get_proc();
393 if (!caps) {
394 ERROR("Failed to perform cap_get_proc(): %s.\n", strerror(errno));
395 return false;
396 }
397
398 cap_is_set = lxc_cap_is_set(caps, cap, flag);
399 cap_free(caps);
400 return cap_is_set;
401 }
402
403 #endif