]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/caps.c
tree-wide: use lxc_drop_groups() instead of lxc_setgroups(0, NULL)
[mirror_lxc.git] / src / lxc / caps.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE 1
5 #endif
6 #include <errno.h>
7 #include <limits.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <sys/prctl.h>
12
13 #include "caps.h"
14 #include "config.h"
15 #include "file_utils.h"
16 #include "log.h"
17 #include "macro.h"
18 #include "memory_utils.h"
19
20 lxc_log_define(caps, lxc);
21
22 #if HAVE_LIBCAP
23
24 define_cleanup_function(cap_t, cap_free);
25
26 int lxc_caps_down(void)
27 {
28 call_cleaner(cap_free) cap_t caps = NULL;
29 int ret = -1;
30
31 /* When we are root, we don't want to play with capabilities. */
32 if (!getuid())
33 return 0;
34
35 caps = cap_get_proc();
36 if (!caps)
37 return log_error_errno(ret, errno, "Failed to retrieve capabilities");
38
39 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
40 if (ret)
41 return log_error_errno(ret, errno, "Failed to clear effective capabilities");
42
43 ret = cap_set_proc(caps);
44 if (ret)
45 return log_error_errno(ret, errno, "Failed to change effective capabilities");
46
47 return 0;
48 }
49
50 int lxc_caps_up(void)
51 {
52 call_cleaner(cap_free) cap_t caps = NULL;
53 cap_value_t cap;
54 int ret = -1;
55
56 /* When we are root, we don't want to play with capabilities. */
57 if (!getuid())
58 return 0;
59
60 caps = cap_get_proc();
61 if (!caps)
62 return log_error_errno(ret, errno, "Failed to retrieve capabilities");
63
64 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
65 cap_flag_value_t flag;
66
67 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
68 if (ret) {
69 if (errno == EINVAL) {
70 INFO("Last supported cap was %d", cap - 1);
71 break;
72 } else {
73 return log_error_errno(ret, errno, "Failed to retrieve setting for permitted capability %d", cap - 1);
74 }
75 }
76
77 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
78 if (ret)
79 return log_error_errno(ret, errno, "Failed to set effective capability %d", cap - 1);
80 }
81
82 ret = cap_set_proc(caps);
83 if (ret)
84 return log_error_errno(ret, errno, "Failed to change effective capabilities");
85
86 return 0;
87 }
88
89 int lxc_ambient_caps_up(void)
90 {
91 call_cleaner(cap_free) cap_t caps = NULL;
92 __do_free char *cap_names = NULL;
93 int ret;
94 cap_value_t cap;
95 int last_cap = CAP_LAST_CAP;
96
97 if (!getuid() || geteuid())
98 return 0;
99
100 caps = cap_get_proc();
101 if (!caps)
102 return log_error_errno(-1, errno, "Failed to retrieve capabilities");
103
104 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
105 cap_flag_value_t flag;
106
107 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
108 if (ret < 0) {
109 if (errno == EINVAL) {
110 last_cap = (cap - 1);
111 INFO("Last supported cap was %d", last_cap);
112 break;
113 }
114
115 return log_error_errno(ret, errno, "Failed to retrieve capability flag");
116 }
117
118 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, flag);
119 if (ret < 0)
120 return log_error_errno(ret, errno, "Failed to set capability flag");
121 }
122
123 ret = cap_set_proc(caps);
124 if (ret < 0)
125 return log_error_errno(ret, errno, "Failed to set capabilities");
126
127 for (cap = 0; cap <= last_cap; cap++) {
128 ret = prctl(PR_CAP_AMBIENT, prctl_arg(PR_CAP_AMBIENT_RAISE),
129 prctl_arg(cap), prctl_arg(0), prctl_arg(0));
130 if (ret < 0)
131 return log_warn_errno(ret, errno, "Failed to raise ambient capability %d", cap);
132 }
133
134 cap_names = cap_to_text(caps, NULL);
135 if (!cap_names)
136 return log_warn_errno(0, errno, "Failed to convert capabilities %d", cap);
137
138 TRACE("Raised %s in inheritable and ambient capability set", cap_names);
139 return 0;
140 }
141
142 int lxc_ambient_caps_down(void)
143 {
144 call_cleaner(cap_free) cap_t caps = NULL;
145 int ret;
146 cap_value_t cap;
147
148 if (!getuid() || geteuid())
149 return 0;
150
151 ret = prctl(PR_CAP_AMBIENT, prctl_arg(PR_CAP_AMBIENT_CLEAR_ALL),
152 prctl_arg(0), prctl_arg(0), prctl_arg(0));
153 if (ret < 0)
154 return log_error_errno(-1, errno, "Failed to clear ambient capability set");
155
156 caps = cap_get_proc();
157 if (!caps)
158 return log_error_errno(-1, errno, "Failed to retrieve capabilities");
159
160 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
161 ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
162 if (ret < 0)
163 return log_error_errno(-1, errno, "Failed to clear capability");
164 }
165
166 ret = cap_set_proc(caps);
167 if (ret < 0)
168 return log_error_errno(ret, errno, "Failed to set capabilities");
169
170 return 0;
171 }
172
173 int lxc_caps_init(void)
174 {
175 uid_t euid, uid;
176
177 uid = getuid();
178 if (!uid)
179 return 0;
180
181 euid = geteuid();
182 if (uid && !euid) {
183 int ret;
184 gid_t gid;
185
186 INFO("Command is run as setuid root (uid: %d)", uid);
187
188 ret = prctl(PR_SET_KEEPCAPS, prctl_arg(1));
189 if (ret < 0)
190 return log_error_errno(-1, errno, "Failed to set PR_SET_KEEPCAPS");
191
192 gid = getgid();
193 ret = setresgid(gid, gid, gid);
194 if (ret < 0)
195 return log_error_errno(-1, errno, "Failed to change rgid, egid, and sgid to %d", gid);
196
197 ret = setresuid(uid, uid, uid);
198 if (ret < 0)
199 return log_error_errno(-1, errno, "Failed to change ruid, euid, and suid to %d", uid);
200
201 ret = lxc_caps_up();
202 if (ret < 0)
203 return log_error_errno(-1, errno, "Failed to restore capabilities");
204 }
205
206 if (uid == euid)
207 INFO("Command is run with uid %d", uid);
208
209 return 0;
210 }
211
212 static long int _real_caps_last_cap(void)
213 {
214 int fd, result = -1;
215
216 /* Try to get the maximum capability over the kernel interface
217 * introduced in v3.2.
218 */
219 fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY | O_CLOEXEC);
220 if (fd >= 0) {
221 ssize_t n;
222 char *ptr;
223 char buf[INTTYPE_TO_STRLEN(int)] = {0};
224
225 n = lxc_read_nointr(fd, buf, STRARRAYLEN(buf));
226 if (n >= 0) {
227 errno = 0;
228 result = strtol(buf, &ptr, 10);
229 if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
230 result = -1;
231 }
232
233 close(fd);
234 } else {
235 int cap = 0;
236
237 /* Try to get it manually by trying to get the status of each
238 * capability individually from the kernel.
239 */
240 while (prctl(PR_CAPBSET_READ, prctl_arg(cap)) >= 0)
241 cap++;
242
243 result = cap - 1;
244 }
245
246 return result;
247 }
248
249 int lxc_caps_last_cap(void)
250 {
251 static long int last_cap = -1;
252
253 if (last_cap < 0) {
254 last_cap = _real_caps_last_cap();
255 if (last_cap < 0 || last_cap > INT_MAX)
256 last_cap = -1;
257 }
258
259 return last_cap;
260 }
261
262 static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
263 {
264 int ret;
265 cap_flag_value_t flagval;
266
267 ret = cap_get_flag(caps, cap, flag, &flagval);
268 if (ret < 0)
269 return log_error_errno(false, errno, "Failed to retrieve current setting for capability %d", cap);
270
271 return flagval == CAP_SET;
272 }
273
274 bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
275 {
276 #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
277 call_cleaner(cap_free) cap_t caps = NULL;
278
279 caps = cap_get_file(path);
280 if (!caps) {
281 /* This is undocumented in the manpage but the source code show
282 * that cap_get_file() may return NULL when successful for the
283 * case where it didn't detect any file capabilities. In this
284 * case errno will be set to ENODATA.
285 */
286 if (errno != ENODATA)
287 SYSERROR("Failed to retrieve capabilities for file %s", path);
288
289 return false;
290 }
291
292 return lxc_cap_is_set(caps, cap, flag);
293 #else
294 errno = ENODATA;
295 return false;
296 #endif
297 }
298
299 bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
300 {
301 call_cleaner(cap_free) cap_t caps = NULL;
302
303 caps = cap_get_proc();
304 if (!caps)
305 return log_error_errno(false, errno, "Failed to retrieve capabilities");
306
307 return lxc_cap_is_set(caps, cap, flag);
308 }
309 #endif