1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
82#include <linux/capability.h>
83
84
85
86
87extern int capset(cap_user_header_t header, cap_user_data_t data);
88extern int capget(cap_user_header_t header, const cap_user_data_t data);
89
90
91#endif
92#include <sys/prctl.h>
93#include "libbb.h"
94
95#ifndef PR_CAPBSET_READ
96#define PR_CAPBSET_READ 23
97#endif
98
99#ifndef PR_SET_NO_NEW_PRIVS
100#define PR_SET_NO_NEW_PRIVS 38
101#endif
102
103#ifndef PR_GET_NO_NEW_PRIVS
104#define PR_GET_NO_NEW_PRIVS 39
105#endif
106
107#ifndef PR_CAP_AMBIENT
108#define PR_CAP_AMBIENT 47
109#define PR_CAP_AMBIENT_IS_SET 1
110#define PR_CAP_AMBIENT_RAISE 2
111#define PR_CAP_AMBIENT_LOWER 3
112#endif
113
114enum {
115 IF_FEATURE_SETPRIV_DUMP(OPTBIT_DUMP,)
116 IF_FEATURE_SETPRIV_CAPABILITIES(OPTBIT_INH,)
117 IF_FEATURE_SETPRIV_CAPABILITIES(OPTBIT_AMB,)
118 OPTBIT_NNP,
119
120 IF_FEATURE_SETPRIV_DUMP(OPT_DUMP = (1 << OPTBIT_DUMP),)
121 IF_FEATURE_SETPRIV_CAPABILITIES(OPT_INH = (1 << OPTBIT_INH),)
122 IF_FEATURE_SETPRIV_CAPABILITIES(OPT_AMB = (1 << OPTBIT_AMB),)
123 OPT_NNP = (1 << OPTBIT_NNP),
124};
125
126#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
127DEFINE_STRUCT_CAPS;
128
129static unsigned parse_cap(const char *cap)
130{
131 switch (cap[0]) {
132 case '-':
133 break;
134 case '+':
135 break;
136 default:
137 bb_error_msg_and_die("invalid capability '%s'", cap);
138 break;
139 }
140
141 cap++;
142 return cap_name_to_number(cap);
143}
144
145static void set_inh_caps(char *capstring)
146{
147 struct caps caps;
148
149 getcaps(&caps);
150
151 capstring = strtok(capstring, ",");
152 while (capstring) {
153 unsigned cap;
154
155 cap = parse_cap(capstring);
156 if (CAP_TO_INDEX(cap) >= caps.u32s)
157 bb_error_msg_and_die("invalid capability '%s'", capstring);
158
159 if (capstring[0] == '+')
160 caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap);
161 else
162 caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap);
163 capstring = strtok(NULL, ",");
164 }
165
166 if (capset(&caps.header, caps.data) != 0)
167 bb_perror_msg_and_die("capset");
168}
169
170static void set_ambient_caps(char *string)
171{
172 char *cap;
173
174 cap = strtok(string, ",");
175 while (cap) {
176 unsigned idx;
177
178 idx = parse_cap(cap);
179 if (cap[0] == '+') {
180 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, idx, 0, 0) < 0)
181 bb_perror_msg("cap_ambient_raise");
182 } else {
183 if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, idx, 0, 0) < 0)
184 bb_perror_msg("cap_ambient_lower");
185 }
186 cap = strtok(NULL, ",");
187 }
188}
189#endif
190
191#if ENABLE_FEATURE_SETPRIV_DUMP
192# if !ENABLE_FEATURE_SETPRIV_CAPABILITY_NAMES
193# define printf_cap(pfx, cap_no) printf("%scap_%u", (pfx), (cap_no))
194# endif
195
196static int dump(void)
197{
198 IF_FEATURE_SETPRIV_CAPABILITIES(struct caps caps;)
199 const char *fmt;
200 uid_t ruid, euid, suid;
201 gid_t rgid, egid, sgid;
202 gid_t *gids;
203 int i, ngids, nnp;
204
205 getresuid(&ruid, &euid, &suid);
206 getresgid(&rgid, &egid, &sgid);
207 ngids = 0;
208 gids = bb_getgroups(&ngids, NULL);
209
210 nnp = prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0);
211 if (nnp < 0)
212 bb_perror_msg_and_die("prctl: %s", "GET_NO_NEW_PRIVS");
213
214 printf("uid: %u\n", (unsigned)ruid);
215 printf("euid: %u\n", (unsigned)euid);
216 printf("gid: %u\n", (unsigned)rgid);
217 printf("egid: %u\n", (unsigned)egid);
218
219 printf("Supplementary groups: ");
220 if (ngids == 0) {
221 printf("[none]");
222 } else {
223 fmt = ",%u" + 1;
224 for (i = 0; i < ngids; i++) {
225 printf(fmt, (unsigned)gids[i]);
226 fmt = ",%u";
227 }
228 }
229 printf("\nno_new_privs: %d\n", nnp);
230
231# if ENABLE_FEATURE_SETPRIV_CAPABILITIES
232 getcaps(&caps);
233 printf("Inheritable capabilities: ");
234 fmt = "";
235 for (i = 0; cap_valid(i); i++) {
236 unsigned idx = CAP_TO_INDEX(i);
237 if (idx >= caps.u32s) {
238 printf("\nindex: %u u32s: %u capability: %u\n", idx, caps.u32s, i);
239 bb_error_msg_and_die("unsupported capability");
240 }
241 if (caps.data[idx].inheritable & CAP_TO_MASK(i)) {
242 printf_cap(fmt, i);
243 fmt = ",";
244 }
245 }
246 if (!fmt[0])
247 printf("[none]");
248
249 printf("\nAmbient capabilities: ");
250 fmt = "";
251 for (i = 0; cap_valid(i); i++) {
252 int ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, (unsigned long) i, 0UL, 0UL);
253 if (ret < 0)
254 bb_perror_msg_and_die("prctl: %s", "CAP_AMBIENT_IS_SET");
255 if (ret) {
256 printf_cap(fmt, i);
257 fmt = ",";
258 }
259 }
260 if (i == 0)
261 printf("[unsupported]");
262 else if (!fmt[0])
263 printf("[none]");
264
265 printf("\nCapability bounding set: ");
266 fmt = "";
267 for (i = 0; cap_valid(i); i++) {
268 int ret = prctl(PR_CAPBSET_READ, (unsigned long) i, 0UL, 0UL, 0UL);
269 if (ret < 0)
270 bb_perror_msg_and_die("prctl: %s", "CAPBSET_READ");
271 if (ret) {
272 printf_cap(fmt, i);
273 fmt = ",";
274 }
275 }
276 if (!fmt[0])
277 printf("[none]");
278 bb_putchar('\n');
279# endif
280
281 if (ENABLE_FEATURE_CLEAN_UP)
282 free(gids);
283
284 return EXIT_SUCCESS;
285}
286#endif
287
288int setpriv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
289int setpriv_main(int argc UNUSED_PARAM, char **argv)
290{
291 static const char setpriv_longopts[] ALIGN1 =
292 IF_FEATURE_SETPRIV_DUMP(
293 "dump\0" No_argument "d"
294 )
295 "nnp\0" No_argument "\xff"
296 "no-new-privs\0" No_argument "\xff"
297 IF_FEATURE_SETPRIV_CAPABILITIES(
298 "inh-caps\0" Required_argument "\xfe"
299 "ambient-caps\0" Required_argument "\xfd"
300 )
301 ;
302 int opts;
303 IF_FEATURE_SETPRIV_CAPABILITIES(char *inh_caps, *ambient_caps;)
304
305 opts = getopt32long(argv, "+"
306 IF_FEATURE_SETPRIV_DUMP("d")
307 IF_FEATURE_SETPRIV_CAPABILITIES("\xfe:\xfd:"),
308 setpriv_longopts
309 IF_FEATURE_SETPRIV_CAPABILITIES(, &inh_caps, &ambient_caps)
310 );
311 argv += optind;
312
313#if ENABLE_FEATURE_SETPRIV_DUMP
314 if (opts & OPT_DUMP) {
315 if (argv[0] || (opts - OPT_DUMP) != 0)
316 bb_show_usage();
317 return dump();
318 }
319#endif
320 if (opts & OPT_NNP) {
321 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0))
322 bb_perror_msg_and_die("prctl: %s", "SET_NO_NEW_PRIVS");
323 }
324
325#if ENABLE_FEATURE_SETPRIV_CAPABILITIES
326 if (opts & OPT_INH)
327 set_inh_caps(inh_caps);
328 if (opts & OPT_AMB)
329 set_ambient_caps(ambient_caps);
330#endif
331
332 if (!argv[0])
333 bb_show_usage();
334 BB_EXECVP_or_die(argv);
335}
336