]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/caps.c
apparmor support: fix compilation with --disable-apparmor
[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:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#define _GNU_SOURCE
25#include <unistd.h>
20d81659
CS
26#include <fcntl.h>
27#include <stdlib.h>
28#include <limits.h>
b3357a6f
DL
29#include <sys/prctl.h>
30#include <sys/capability.h>
31
32#include "log.h"
33
34lxc_log_define(lxc_caps, lxc);
35
05cda563
DL
36int lxc_caps_reset(void)
37{
38 cap_t cap = cap_init();
39 int ret = 0;
40
41 if (!cap) {
42 ERROR("cap_init() failed : %m");
43 return -1;
44 }
45
46 if (cap_set_proc(cap)) {
47 ERROR("cap_set_proc() failed : %m");
48 ret = -1;
49 }
50
51 cap_free(cap);
52 return ret;
53}
54
b3357a6f
DL
55int lxc_caps_down(void)
56{
57 cap_t caps;
58 int ret;
59
7ee895e4
DL
60 /* when we are run as root, we don't want to play
61 * with the capabilities */
62 if (!getuid())
63 return 0;
64
b3357a6f
DL
65 caps = cap_get_proc();
66 if (!caps) {
67 ERROR("failed to cap_get_proc: %m");
68 return -1;
69 }
70
71 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
72 if (ret) {
73 ERROR("failed to cap_clear_flag: %m");
74 goto out;
75 }
76
77 ret = cap_set_proc(caps);
78 if (ret) {
79 ERROR("failed to cap_set_proc: %m");
80 goto out;
81 }
82
83out:
84 cap_free(caps);
85 return 0;
86}
87
88int lxc_caps_up(void)
89{
90 cap_t caps;
91 cap_value_t cap;
92 int ret;
93
7ee895e4
DL
94 /* when we are run as root, we don't want to play
95 * with the capabilities */
96 if (!getuid())
97 return 0;
98
b3357a6f
DL
99 caps = cap_get_proc();
100 if (!caps) {
101 ERROR("failed to cap_get_proc: %m");
102 return -1;
103 }
104
105 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
106
107 cap_flag_value_t flag;
108
109 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
110 if (ret) {
111 ERROR("failed to cap_get_flag: %m");
112 goto out;
113 }
114
115 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
116 if (ret) {
117 ERROR("failed to cap_set_flag: %m");
118 goto out;
119 }
120 }
121
122 ret = cap_set_proc(caps);
123 if (ret) {
124 ERROR("failed to cap_set_proc: %m");
125 goto out;
126 }
127
128out:
129 cap_free(caps);
130 return 0;
131}
132
133int lxc_caps_init(void)
134{
135 uid_t uid = getuid();
136 gid_t gid = getgid();
137 uid_t euid = geteuid();
138
139 if (!uid) {
140 INFO("command is run as 'root'");
141 return 0;
142 }
143
144 if (uid && !euid) {
145 INFO("command is run as setuid root (uid : %d)", uid);
146
147 if (prctl(PR_SET_KEEPCAPS, 1)) {
148 ERROR("failed to 'PR_SET_KEEPCAPS': %m");
149 return -1;
150 }
151
152 if (setresgid(gid, gid, gid)) {
153 ERROR("failed to change gid to '%d': %m", gid);
154 return -1;
155 }
156
157 if (setresuid(uid, uid, uid)) {
158 ERROR("failed to change uid to '%d': %m", uid);
159 return -1;
160 }
161
162 if (lxc_caps_up()) {
163 ERROR("failed to restore capabilities: %m");
164 return -1;
165 }
166 }
167
168 if (uid == euid)
169 INFO("command is run as user '%d'", uid);
170
171 return 0;
172}
20d81659
CS
173
174static int _real_caps_last_cap(void)
175{
176 int fd;
177 int result = -1;
178
179 /* try to get the maximum capability over the kernel
180 * interface introduced in v3.2 */
181 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
182 if (fd >= 0) {
183 char buf[32];
184 char *ptr;
185 int n;
186
187 if ((n = read(fd, buf, 31)) >= 0) {
188 buf[n] = '\0';
189 result = strtol(buf, &ptr, 10);
190 if (!ptr || (*ptr != '\0' && *ptr != '\n') ||
191 result == LONG_MIN || result == LONG_MAX)
192 result = -1;
193 }
194
195 close(fd);
196 }
197
198 /* try to get it manually by trying to get the status of
199 * each capability indiviually from the kernel */
200 if (result < 0) {
201 int cap = 0;
202 while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
203 result = cap - 1;
204 }
205
206 return result;
207}
208
209int lxc_caps_last_cap(void)
210{
211 static int last_cap = -1;
212 if (last_cap < 0) last_cap = _real_caps_last_cap();
213
214 return last_cap;
215}
4a2ca8b2
SH
216
217/*
218 * check if we have the caps needed to start a container. returns 1 on
219 * success, 0 on error. (I'd prefer this be a bool, but am afraid that
220 * might fail to build on some distros).
221 */
222int lxc_caps_check(void)
223{
224 uid_t uid = getuid();
225 cap_t caps;
226 cap_flag_value_t value;
227 int i, ret;
228
229 cap_value_t needed_caps[] = { CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_SETUID, CAP_SETGID };
230
231#define NUMCAPS ((int) (sizeof(needed_caps) / sizeof(cap_t)))
232
233 if (!uid)
234 return 1;
235
236 caps = cap_get_proc();
237 if (!caps) {
238 ERROR("failed to cap_get_proc: %m");
239 return 0;
240 }
241
242 for (i=0; i<NUMCAPS; i++) {
243 ret = cap_get_flag(caps, needed_caps[i], CAP_EFFECTIVE, &value);
244 if (ret) {
245 ERROR("Failed to cap_get_flag: %m");
246 return 0;
247 }
248 if (!value) {
249 return 0;
250 }
251 }
252
253 return 1;
254}