]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/caps.c
log: change ERROR macro using sterror to SYSERROR
[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 SYSERROR("Failed to cap_get_proc");
79 return -1;
80 }
81
82 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
83 if (ret) {
84 SYSERROR("Failed to cap_clear_flag");
85 goto out;
86 }
87
88 ret = cap_set_proc(caps);
89 if (ret) {
90 SYSERROR("Failed to cap_set_proc");
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 SYSERROR("Failed to cap_get_proc");
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 SYSERROR("Failed to cap_get_flag");
127 goto out;
128 }
129 }
130
131 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
132 if (ret) {
133 SYSERROR("Failed to cap_set_flag");
134 goto out;
135 }
136 }
137
138 ret = cap_set_proc(caps);
139 if (ret) {
140 SYSERROR("Failed to cap_set_proc");
141 goto out;
142 }
143
144 out:
145 cap_free(caps);
146 return 0;
147 }
148
149 int lxc_ambient_caps_up(void)
150 {
151 int ret;
152 cap_t caps;
153 cap_value_t cap;
154 int last_cap = CAP_LAST_CAP;
155 char *cap_names = NULL;
156
157 /* When we are run as root, we don't want to play with the capabilities. */
158 if (!getuid())
159 return 0;
160
161 caps = cap_get_proc();
162 if (!caps) {
163 SYSERROR("Failed to retrieve capabilities");
164 return -1;
165 }
166
167 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
168 cap_flag_value_t flag;
169
170 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
171 if (ret < 0) {
172 if (errno == EINVAL) {
173 last_cap = (cap - 1);
174 INFO("Last supported cap was %d", last_cap);
175 break;
176 }
177
178 SYSERROR("Failed to retrieve capability flag");
179 goto out;
180 }
181
182 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, flag);
183 if (ret < 0) {
184 SYSERROR("Failed to set capability flag");
185 goto out;
186 }
187 }
188
189 ret = cap_set_proc(caps);
190 if (ret < 0) {
191 SYSERROR("Failed to set capabilities");
192 goto out;
193 }
194
195 for (cap = 0; cap <= last_cap; cap++) {
196 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
197 if (ret < 0) {
198 SYSWARN("Failed to raise ambient capability %d", cap);
199 goto out;
200 }
201 }
202
203 cap_names = cap_to_text(caps, NULL);
204 if (!cap_names)
205 goto out;
206
207 TRACE("Raised %s in inheritable and ambient capability set", cap_names);
208
209 out:
210
211 cap_free(cap_names);
212 cap_free(caps);
213 return 0;
214 }
215
216 int lxc_ambient_caps_down(void)
217 {
218 int ret;
219 cap_t caps;
220 cap_value_t cap;
221
222 /* When we are run as root, we don't want to play with the capabilities. */
223 if (!getuid())
224 return 0;
225
226 ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
227 if (ret < 0) {
228 SYSERROR("Failed to clear ambient capability set");
229 return -1;
230 }
231
232 caps = cap_get_proc();
233 if (!caps) {
234 SYSERROR("Failed to retrieve capabilities");
235 return -1;
236 }
237
238 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
239 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
240 if (ret < 0) {
241 SYSERROR("Failed to remove capability from inheritable set");
242 goto out;
243 }
244 }
245
246 ret = cap_set_proc(caps);
247 if (ret < 0) {
248 SYSERROR("Failed to set capabilities");
249 goto out;
250 }
251
252 out:
253 cap_free(caps);
254 return 0;
255 }
256
257 int lxc_caps_init(void)
258 {
259 uid_t uid = getuid();
260 gid_t gid = getgid();
261 uid_t euid = geteuid();
262
263 if (!uid) {
264 INFO("command is run as 'root'");
265 return 0;
266 }
267
268 if (uid && !euid) {
269 INFO("command is run as setuid root (uid : %d)", uid);
270
271 if (prctl(PR_SET_KEEPCAPS, 1)) {
272 SYSERROR("Failed to 'PR_SET_KEEPCAPS'");
273 return -1;
274 }
275
276 if (setresgid(gid, gid, gid)) {
277 SYSERROR("Failed to change gid to '%d'", gid);
278 return -1;
279 }
280
281 if (setresuid(uid, uid, uid)) {
282 SYSERROR("Failed to change uid to '%d'", uid);
283 return -1;
284 }
285
286 if (lxc_caps_up()) {
287 SYSERROR("Failed to restore capabilities");
288 return -1;
289 }
290 }
291
292 if (uid == euid)
293 INFO("command is run as user '%d'", uid);
294
295 return 0;
296 }
297
298 static int _real_caps_last_cap(void)
299 {
300 int fd;
301 int result = -1;
302
303 /* try to get the maximum capability over the kernel
304 * interface introduced in v3.2 */
305 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
306 if (fd >= 0) {
307 char buf[32];
308 char *ptr;
309 int n;
310
311 if ((n = read(fd, buf, 31)) >= 0) {
312 buf[n] = '\0';
313 errno = 0;
314 result = strtol(buf, &ptr, 10);
315 if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
316 result = -1;
317 }
318
319 close(fd);
320 }
321
322 /* try to get it manually by trying to get the status of
323 * each capability indiviually from the kernel */
324 if (result < 0) {
325 int cap = 0;
326 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
327 result = cap - 1;
328 }
329
330 return result;
331 }
332
333 int lxc_caps_last_cap(void)
334 {
335 static int last_cap = -1;
336 if (last_cap < 0) last_cap = _real_caps_last_cap();
337
338 return last_cap;
339 }
340
341 static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
342 {
343 int ret;
344 cap_flag_value_t flagval;
345
346 ret = cap_get_flag(caps, cap, flag, &flagval);
347 if (ret < 0) {
348 SYSERROR("Failed to perform cap_get_flag()");
349 return false;
350 }
351
352 return flagval == CAP_SET;
353 }
354
355 bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
356 {
357 #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
358 bool cap_is_set;
359 cap_t caps;
360
361 caps = cap_get_file(path);
362 if (!caps) {
363 /* This is undocumented in the manpage but the source code show
364 * that cap_get_file() may return NULL when successful for the
365 * case where it didn't detect any file capabilities. In this
366 * case errno will be set to ENODATA.
367 */
368 if (errno != ENODATA)
369 SYSERROR("Failed to perform cap_get_file()");
370
371 return false;
372 }
373
374 cap_is_set = lxc_cap_is_set(caps, cap, flag);
375 cap_free(caps);
376 return cap_is_set;
377 #else
378 errno = ENODATA;
379 return false;
380 #endif
381 }
382
383 bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
384 {
385 bool cap_is_set;
386 cap_t caps;
387
388 caps = cap_get_proc();
389 if (!caps) {
390 SYSERROR("Failed to perform cap_get_proc()");
391 return false;
392 }
393
394 cap_is_set = lxc_cap_is_set(caps, cap, flag);
395 cap_free(caps);
396 return cap_is_set;
397 }
398
399 #endif