]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/caps.c
lxc-start: remove unnecessary checks
[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
24#define _GNU_SOURCE
ca364dc0
CB
25#include "config.h"
26
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"
b3357a6f
DL
35#include "log.h"
36
37lxc_log_define(lxc_caps, lxc);
38
e37dda71 39#if HAVE_LIBCAP
495d2046 40
cbec0030
SG
41#ifndef PR_CAPBSET_READ
42#define PR_CAPBSET_READ 23
43#endif
44
b3357a6f
DL
45int lxc_caps_down(void)
46{
47 cap_t caps;
48 int ret;
49
7ee895e4
DL
50 /* when we are run as root, we don't want to play
51 * with the capabilities */
52 if (!getuid())
53 return 0;
54
b3357a6f
DL
55 caps = cap_get_proc();
56 if (!caps) {
13277ec4 57 ERROR("failed to cap_get_proc: %s", strerror(errno));
b3357a6f
DL
58 return -1;
59 }
60
61 ret = cap_clear_flag(caps, CAP_EFFECTIVE);
62 if (ret) {
13277ec4 63 ERROR("failed to cap_clear_flag: %s", strerror(errno));
b3357a6f
DL
64 goto out;
65 }
66
67 ret = cap_set_proc(caps);
68 if (ret) {
13277ec4 69 ERROR("failed to cap_set_proc: %s", strerror(errno));
b3357a6f
DL
70 goto out;
71 }
72
73out:
74 cap_free(caps);
d028235d 75 return 0;
b3357a6f
DL
76}
77
78int lxc_caps_up(void)
79{
80 cap_t caps;
81 cap_value_t cap;
82 int ret;
83
7ee895e4
DL
84 /* when we are run as root, we don't want to play
85 * with the capabilities */
86 if (!getuid())
87 return 0;
88
b3357a6f
DL
89 caps = cap_get_proc();
90 if (!caps) {
13277ec4 91 ERROR("failed to cap_get_proc: %s", strerror(errno));
b3357a6f
DL
92 return -1;
93 }
94
95 for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
96
97 cap_flag_value_t flag;
98
99 ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
100 if (ret) {
2b657f10 101 if (errno == EINVAL) {
959aee9c 102 INFO("Last supported cap was %d", cap-1);
2b657f10
SH
103 break;
104 } else {
13277ec4 105 ERROR("failed to cap_get_flag: %s",
106 strerror(errno));
2b657f10
SH
107 goto out;
108 }
b3357a6f
DL
109 }
110
111 ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
112 if (ret) {
13277ec4 113 ERROR("failed to cap_set_flag: %s", strerror(errno));
b3357a6f
DL
114 goto out;
115 }
116 }
117
118 ret = cap_set_proc(caps);
119 if (ret) {
13277ec4 120 ERROR("failed to cap_set_proc: %s", strerror(errno));
b3357a6f
DL
121 goto out;
122 }
123
124out:
125 cap_free(caps);
d028235d 126 return 0;
b3357a6f
DL
127}
128
129int lxc_caps_init(void)
130{
131 uid_t uid = getuid();
132 gid_t gid = getgid();
133 uid_t euid = geteuid();
134
135 if (!uid) {
136 INFO("command is run as 'root'");
137 return 0;
138 }
139
140 if (uid && !euid) {
141 INFO("command is run as setuid root (uid : %d)", uid);
142
143 if (prctl(PR_SET_KEEPCAPS, 1)) {
13277ec4 144 ERROR("failed to 'PR_SET_KEEPCAPS': %s",
145 strerror(errno));
b3357a6f
DL
146 return -1;
147 }
148
149 if (setresgid(gid, gid, gid)) {
13277ec4 150 ERROR("failed to change gid to '%d': %s", gid,
151 strerror(errno));
b3357a6f
DL
152 return -1;
153 }
154
155 if (setresuid(uid, uid, uid)) {
13277ec4 156 ERROR("failed to change uid to '%d': %s", uid,
157 strerror(errno));
b3357a6f
DL
158 return -1;
159 }
160
161 if (lxc_caps_up()) {
13277ec4 162 ERROR("failed to restore capabilities: %s",
163 strerror(errno));
b3357a6f
DL
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';
09bbd745 189 errno = 0;
20d81659 190 result = strtol(buf, &ptr, 10);
09bbd745 191 if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
20d81659
CS
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 216
207c4c71 217static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
ca364dc0
CB
218{
219 int ret;
ca364dc0
CB
220 cap_flag_value_t flagval;
221
207c4c71
CB
222 ret = cap_get_flag(caps, cap, flag, &flagval);
223 if (ret < 0) {
224 ERROR("Failed to perform cap_get_flag(): %s.", strerror(errno));
225 return false;
226 }
227
228 return flagval == CAP_SET;
229}
230
231bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
232{
69924fff 233 #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
207c4c71
CB
234 bool cap_is_set;
235 cap_t caps;
236
237 caps = cap_get_file(path);
ca364dc0 238 if (!caps) {
207c4c71
CB
239 /* This is undocumented in the manpage but the source code show
240 * that cap_get_file() may return NULL when successful for the
241 * case where it didn't detect any file capabilities. In this
242 * case errno will be set to ENODATA.
243 */
244 if (errno != ENODATA)
245 ERROR("Failed to perform cap_get_file(): %s.\n", strerror(errno));
ca364dc0
CB
246 return false;
247 }
248
207c4c71
CB
249 cap_is_set = lxc_cap_is_set(caps, cap, flag);
250 cap_free(caps);
251 return cap_is_set;
69924fff
CB
252 #else
253 errno = ENODATA;
254 return false;
d6018f88 255 #endif
207c4c71
CB
256}
257
258bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
259{
260 bool cap_is_set;
261 cap_t caps;
262
263 caps = cap_get_proc();
264 if (!caps) {
265 ERROR("Failed to perform cap_get_proc(): %s.\n", strerror(errno));
ca364dc0
CB
266 return false;
267 }
268
207c4c71 269 cap_is_set = lxc_cap_is_set(caps, cap, flag);
ca364dc0 270 cap_free(caps);
207c4c71 271 return cap_is_set;
ca364dc0
CB
272}
273
495d2046 274#endif