blob: 06d9c578f9aa63aea5763d8b5776528dbc8a61af [file] [log] [blame]
Mike Frysinger50e31fa2018-01-19 18:59:49 -05001/* Copyright 2017 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -04004 */
5
6#include "system.h"
7
8#include <errno.h>
9#include <fcntl.h>
Luis Hector Chavez71323552017-09-05 09:17:22 -070010#include <grp.h>
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040011#include <net/if.h>
Luis Hector Chavez71323552017-09-05 09:17:22 -070012#include <pwd.h>
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040013#include <stdbool.h>
14#include <stdio.h>
15#include <string.h>
16#include <sys/ioctl.h>
Kevin Hamacher64cf3cb2019-06-05 17:28:46 +020017#include <sys/mount.h>
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040018#include <sys/prctl.h>
19#include <sys/socket.h>
20#include <sys/stat.h>
Luis Hector Chavez0bacbf82018-07-10 20:06:55 -070021#include <sys/statvfs.h>
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040022#include <unistd.h>
23
Mattias Nisslere5200192018-10-18 12:29:40 +020024#include <linux/securebits.h>
25
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040026#include "util.h"
27
Kevin Hamacher64cf3cb2019-06-05 17:28:46 +020028/* Old libc versions might not define all constants that we need. */
29#ifndef ST_RDONLY
30#define ST_RDONLY 0x0001
31#endif
32#ifndef ST_NOSUID
33#define ST_NOSUID 0x0002
34#endif
35#ifndef ST_NODEV
36#define ST_NODEV 0x0004
37#endif
38#ifndef ST_NOEXEC
39#define ST_NOEXEC 0x0008
40#endif
41#ifndef ST_SYNCHRONOUS
42#define ST_SYNCHRONOUS 0x0010
43#endif
44#ifndef ST_MANDLOCK
45#define ST_MANDLOCK 0x0040
46#endif
47#ifndef ST_NOATIME
48#define ST_NOATIME 0x0400
49#endif
50#ifndef ST_NODIRATIME
51#define ST_NODIRATIME 0x0800
52#endif
53#ifndef ST_RELATIME
54#define ST_RELATIME 0x1000
55#endif
56
Mattias Nisslere5200192018-10-18 12:29:40 +020057/*
58 * SECBIT_NO_CAP_AMBIENT_RAISE was added in kernel 4.3, so fill in the
59 * definition if the securebits header doesn't provide it.
60 */
61#ifndef SECBIT_NO_CAP_AMBIENT_RAISE
62#define SECBIT_NO_CAP_AMBIENT_RAISE (issecure_mask(6))
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040063#endif
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -040064
Mattias Nisslere5200192018-10-18 12:29:40 +020065#ifndef SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED
66#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED (issecure_mask(7))
67#endif
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040068
69/*
70 * Assert the value of SECURE_ALL_BITS at compile-time.
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -040071 * Android devices are currently compiled against 4.4 kernel headers. Kernel 4.3
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040072 * added a new securebit.
73 * When a new securebit is added, the new SECURE_ALL_BITS mask will return EPERM
74 * when used on older kernels. The compile-time assert will catch this situation
75 * at compile time.
76 */
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -040077#if defined(__ANDROID__)
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040078_Static_assert(SECURE_ALL_BITS == 0x55, "SECURE_ALL_BITS == 0x55.");
79#endif
80
Jorge Lucangeli Obes54234212018-04-26 11:52:15 -040081int secure_noroot_set_and_locked(uint64_t mask)
82{
83 return (mask & (SECBIT_NOROOT | SECBIT_NOROOT_LOCKED)) ==
84 (SECBIT_NOROOT | SECBIT_NOROOT_LOCKED);
85}
86
Mattias Nissler48b5ff12018-10-11 15:31:41 +020087int lock_securebits(uint64_t skip_mask, bool require_keep_caps)
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -040088{
Mattias Nissler48b5ff12018-10-11 15:31:41 +020089 /* The general idea is to set all bits, subject to exceptions below. */
90 unsigned long securebits = SECURE_ALL_BITS | SECURE_ALL_LOCKS;
91
92 /*
93 * SECBIT_KEEP_CAPS is special in that it is automatically cleared on
94 * execve(2). This implies that attempts to set SECBIT_KEEP_CAPS (as is
95 * the default) in processes that have it locked already (such as nested
96 * minijail usage) would fail. Thus, unless the caller requires it,
97 * allow it to remain off if it is already locked.
98 */
99 if (!require_keep_caps) {
100 int current_securebits = prctl(PR_GET_SECUREBITS);
101 if (current_securebits < 0) {
102 pwarn("prctl(PR_GET_SECUREBITS) failed");
103 return -1;
104 }
105
106 if ((current_securebits & SECBIT_KEEP_CAPS_LOCKED) != 0 &&
107 (current_securebits & SECBIT_KEEP_CAPS) == 0) {
108 securebits &= ~SECBIT_KEEP_CAPS;
109 }
110 }
111
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400112 /*
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400113 * Ambient capabilities can only be raised if they're already present
114 * in the permitted *and* inheritable set. Therefore, we don't really
115 * need to lock the NO_CAP_AMBIENT_RAISE securebit, since we are already
116 * configuring the permitted and inheritable set.
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400117 */
Mattias Nissler48b5ff12018-10-11 15:31:41 +0200118 securebits &=
119 ~(SECBIT_NO_CAP_AMBIENT_RAISE | SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED);
120
121 /* Don't set any bits that the user requested not to be touched. */
122 securebits &= ~skip_mask;
123
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700124 if (!securebits) {
Jorge Lucangeli Obes54234212018-04-26 11:52:15 -0400125 warn("not locking any securebits");
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700126 return 0;
127 }
128 int securebits_ret = prctl(PR_SET_SECUREBITS, securebits);
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400129 if (securebits_ret < 0) {
130 pwarn("prctl(PR_SET_SECUREBITS) failed");
131 return -1;
132 }
133
134 return 0;
135}
136
137int write_proc_file(pid_t pid, const char *content, const char *basename)
138{
139 int fd, ret;
140 size_t sz, len;
141 ssize_t written;
142 char filename[32];
143
144 sz = sizeof(filename);
145 ret = snprintf(filename, sz, "/proc/%d/%s", pid, basename);
146 if (ret < 0 || (size_t)ret >= sz) {
147 warn("failed to generate %s filename", basename);
148 return -1;
149 }
150
151 fd = open(filename, O_WRONLY | O_CLOEXEC);
152 if (fd < 0) {
153 pwarn("failed to open '%s'", filename);
154 return -errno;
155 }
156
157 len = strlen(content);
158 written = write(fd, content, len);
159 if (written < 0) {
160 pwarn("failed to write '%s'", filename);
Jorge Lucangeli Obes673c89d2018-10-04 16:08:10 -0400161 return -errno;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400162 }
163
164 if ((size_t)written < len) {
165 warn("failed to write %zu bytes to '%s'", len, filename);
166 return -1;
167 }
168 close(fd);
169 return 0;
170}
171
172/*
173 * We specifically do not use cap_valid() as that only tells us the last
174 * valid cap we were *compiled* against (i.e. what the version of kernel
175 * headers says). If we run on a different kernel version, then it's not
176 * uncommon for that to be less (if an older kernel) or more (if a newer
177 * kernel).
178 * Normally, we suck up the answer via /proc. On Android, not all processes are
179 * guaranteed to be able to access '/proc/sys/kernel/cap_last_cap' so we
180 * programmatically find the value by calling prctl(PR_CAPBSET_READ).
181 */
182unsigned int get_last_valid_cap(void)
183{
184 unsigned int last_valid_cap = 0;
185 if (is_android()) {
186 for (; prctl(PR_CAPBSET_READ, last_valid_cap, 0, 0, 0) >= 0;
187 ++last_valid_cap)
188 ;
189
190 /* |last_valid_cap| will be the first failing value. */
191 if (last_valid_cap > 0) {
192 last_valid_cap--;
193 }
194 } else {
195 const char cap_file[] = "/proc/sys/kernel/cap_last_cap";
196 FILE *fp = fopen(cap_file, "re");
197 if (fscanf(fp, "%u", &last_valid_cap) != 1)
198 pdie("fscanf(%s)", cap_file);
199 fclose(fp);
200 }
201 return last_valid_cap;
202}
203
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400204int cap_ambient_supported(void)
205{
206 return prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) >=
207 0;
208}
209
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400210int config_net_loopback(void)
211{
212 const char ifname[] = "lo";
213 int sock;
214 struct ifreq ifr;
215
216 /* Make sure people don't try to add really long names. */
217 _Static_assert(sizeof(ifname) <= IFNAMSIZ, "interface name too long");
218
219 sock = socket(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0);
220 if (sock < 0) {
221 pwarn("socket(AF_LOCAL) failed");
222 return -1;
223 }
224
225 /*
226 * Do the equiv of `ip link set up lo`. The kernel will assign
227 * IPv4 (127.0.0.1) & IPv6 (::1) addresses automatically!
228 */
229 strcpy(ifr.ifr_name, ifname);
230 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
231 pwarn("ioctl(SIOCGIFFLAGS) failed");
232 return -1;
233 }
234
235 /* The kernel preserves ifr.ifr_name for use. */
236 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
237 if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
238 pwarn("ioctl(SIOCSIFFLAGS) failed");
239 return -1;
240 }
241
242 close(sock);
243 return 0;
244}
245
246int setup_pipe_end(int fds[2], size_t index)
247{
248 if (index > 1)
249 return -1;
250
251 close(fds[1 - index]);
252 return fds[index];
253}
254
255int setup_and_dupe_pipe_end(int fds[2], size_t index, int fd)
256{
257 if (index > 1)
258 return -1;
259
260 close(fds[1 - index]);
261 /* dup2(2) the corresponding end of the pipe into |fd|. */
262 return dup2(fds[index], fd);
263}
264
265int write_pid_to_path(pid_t pid, const char *path)
266{
Jorge Lucangeli Obes1f5d0952019-06-04 09:18:26 -0400267 FILE *fp = fopen(path, "we");
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400268
269 if (!fp) {
Jorge Lucangeli Obes1f5d0952019-06-04 09:18:26 -0400270 pwarn("failed to open '%s'", path);
271 return -errno;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400272 }
273 if (fprintf(fp, "%d\n", (int)pid) < 0) {
274 /* fprintf(3) does not set errno on failure. */
275 warn("fprintf(%s) failed", path);
Jorge Lucangeli Obes1f5d0952019-06-04 09:18:26 -0400276 return -1;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400277 }
278 if (fclose(fp)) {
279 pwarn("fclose(%s) failed", path);
Jorge Lucangeli Obes1f5d0952019-06-04 09:18:26 -0400280 return -errno;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400281 }
282
Jorge Lucangeli Obes1f5d0952019-06-04 09:18:26 -0400283 return 0;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400284}
285
286/*
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500287 * Create the |path| directory and its parents (if need be) with |mode|.
288 * If not |isdir|, then |path| is actually a file, so the last component
289 * will not be created.
290 */
291int mkdir_p(const char *path, mode_t mode, bool isdir)
292{
yusukes059e0bd2018-03-05 10:22:16 -0800293 int rc;
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500294 char *dir = strdup(path);
yusukes059e0bd2018-03-05 10:22:16 -0800295 if (!dir) {
296 rc = errno;
297 pwarn("strdup(%s) failed", path);
298 return -rc;
299 }
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500300
301 /* Starting from the root, work our way out to the end. */
302 char *p = strchr(dir + 1, '/');
303 while (p) {
304 *p = '\0';
305 if (mkdir(dir, mode) && errno != EEXIST) {
yusukes059e0bd2018-03-05 10:22:16 -0800306 rc = errno;
307 pwarn("mkdir(%s, 0%o) failed", dir, mode);
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500308 free(dir);
yusukes059e0bd2018-03-05 10:22:16 -0800309 return -rc;
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500310 }
311 *p = '/';
312 p = strchr(p + 1, '/');
313 }
314
315 /*
316 * Create the last directory. We still check EEXIST here in case
317 * of trailing slashes.
318 */
319 free(dir);
yusukes059e0bd2018-03-05 10:22:16 -0800320 if (isdir && mkdir(path, mode) && errno != EEXIST) {
321 rc = errno;
322 pwarn("mkdir(%s, 0%o) failed", path, mode);
323 return -rc;
324 }
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500325 return 0;
326}
327
328/*
Kevin Hamacher64cf3cb2019-06-05 17:28:46 +0200329 * get_mount_flags_for_directory: Returns the mount flags for the given
330 * directory.
331 */
332int get_mount_flags_for_directory(const char *path, unsigned long *mnt_flags)
333{
334 int rc;
335 struct statvfs stvfs_buf;
336
337 if (!mnt_flags)
338 return 0;
339
340 rc = statvfs(path, &stvfs_buf);
341 if (rc) {
342 rc = errno;
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400343 pwarn("statvfs('%s') failed", path);
Kevin Hamacher64cf3cb2019-06-05 17:28:46 +0200344 return -rc;
345 }
346 *mnt_flags = vfs_flags_to_mount_flags(stvfs_buf.f_flag);
347 return 0;
348}
349
350/*
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400351 * setup_mount_destination: Ensures the mount target exists.
352 * Creates it if needed and possible.
353 */
354int setup_mount_destination(const char *source, const char *dest, uid_t uid,
Luis Hector Chavez0bacbf82018-07-10 20:06:55 -0700355 uid_t gid, bool bind, unsigned long *mnt_flags)
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400356{
357 int rc;
358 struct stat st_buf;
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400359 bool do_mkdir = false;
360 bool is_abspath = source && source[0] == '/';
361 /* Assume relative |source| paths are pseudo filesystems. */
362 bool is_pseudofs = !is_abspath;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400363
364 rc = stat(dest, &st_buf);
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400365 if (rc) {
366 /*
367 * |dest| does not exist. Try to create it.
368 * Either make a directory or touch a file depending on the
369 * source type.
370 *
371 * If |source| isn't an absolute path, assume it is a filesystem
372 * type such as "tmpfs" and create a directory to mount it on.
373 * |dest| will be something like "none" or "proc" which we
374 * shouldn't be checking.
375 */
376 if (is_abspath) {
377 /* |source| is an absolute path -- it better exist! */
378 rc = stat(source, &st_buf);
379 if (rc) {
380 rc = errno;
381 pwarn("stat('%s') failed", source);
382 return -rc;
383 }
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400384
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400385 /*
386 * If bind mounting, we only create a directory if the
387 * source is a directory, else we always bind mount it
388 * as a file to support device nodes, sockets, etc...
389 *
390 * For all other mounts, we assume a block/char source
391 * is going to want a directory to mount to. If the
392 * source is something else (e.g. a fifo or socket),
393 * this probably will not do the right thing, but we'll
394 * fail later on when we try to mount(), so shouldn't be
395 * a big deal.
396 */
397 do_mkdir = S_ISDIR(st_buf.st_mode) ||
398 (!bind && (S_ISBLK(st_buf.st_mode) ||
399 S_ISCHR(st_buf.st_mode)));
400
401 } else {
402 /*
403 * |source| is a relative path -- assume it's a pseudo
404 * fs.
405 */
406
407 /* Disallow relative bind mounts. */
408 if (bind) {
409 warn("relative bind-mounts are not allowed: "
410 "source=%s",
411 source);
412 return -EINVAL;
413 }
414
415 do_mkdir = true;
yusukes059e0bd2018-03-05 10:22:16 -0800416 }
Mike Frysingereaab4202017-08-14 14:57:21 -0400417
418 /*
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400419 * Now that we know what we want to do, do it!
420 * We always create the intermediate dirs and the final path
421 * with 0755 perms and root/root ownership. This shouldn't be a
422 * problem because the actual mount will set those
423 * perms/ownership on the mount point which is all people should
424 * need to access it.
Mike Frysingereaab4202017-08-14 14:57:21 -0400425 */
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400426 rc = mkdir_p(dest, 0755, do_mkdir);
427 if (rc)
428 return rc;
429 if (!do_mkdir) {
430 int fd = open(dest, O_RDWR | O_CREAT | O_CLOEXEC, 0700);
431 if (fd < 0) {
432 rc = errno;
433 pwarn("open('%s') failed", dest);
434 return -rc;
435 }
436 close(fd);
yusukes059e0bd2018-03-05 10:22:16 -0800437 }
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400438 if (chown(dest, uid, gid)) {
439 rc = errno;
440 pwarn("chown('%s', %u, %u) failed", dest, uid, gid);
441 return -rc;
442 }
Mike Frysingereaab4202017-08-14 14:57:21 -0400443 }
444
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500445 /*
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400446 * At this point, either because it already existed or because it was
447 * created above, |dest| exists.
Mike Frysinger5fdba4e2018-01-17 15:39:48 -0500448 */
Jorge Lucangeli Obes9299cae2019-08-23 11:28:39 -0400449 if (is_pseudofs) {
450 /* If |source| is a pseudo fs, it will have no mount flags. */
451 if (mnt_flags)
452 *mnt_flags = 0;
453 return 0;
454 } else {
455 return get_mount_flags_for_directory(source, mnt_flags);
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400456 }
Kevin Hamacher64cf3cb2019-06-05 17:28:46 +0200457}
458
459/*
460 * vfs_flags_to_mount_flags: Converts the given flags returned by statvfs to
461 * flags that can be used by mount().
462 */
463unsigned long vfs_flags_to_mount_flags(unsigned long vfs_flags)
464{
465 unsigned int i;
466 unsigned long mount_flags = 0;
467
468 static struct {
469 unsigned long mount_flag;
470 unsigned long vfs_flag;
471 } const flag_translation_table[] = {
472 {MS_NOSUID, ST_NOSUID}, {MS_NODEV, ST_NODEV},
473 {MS_NOEXEC, ST_NOEXEC}, {MS_SYNCHRONOUS, ST_SYNCHRONOUS},
474 {MS_MANDLOCK, ST_MANDLOCK}, {MS_NOATIME, ST_NOATIME},
475 {MS_NODIRATIME, ST_NODIRATIME}, {MS_RELATIME, ST_RELATIME},
476 };
477
478 for (i = 0; i < ARRAY_SIZE(flag_translation_table); i++) {
479 if (vfs_flags & flag_translation_table[i].vfs_flag) {
480 mount_flags |= flag_translation_table[i].mount_flag;
481 }
482 }
483
484 return mount_flags;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400485}
Luis Hector Chavez71323552017-09-05 09:17:22 -0700486
487/*
488 * lookup_user: Gets the uid/gid for the given username.
489 */
490int lookup_user(const char *user, uid_t *uid, gid_t *gid)
491{
492 char *buf = NULL;
493 struct passwd pw;
494 struct passwd *ppw = NULL;
495 ssize_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
496 if (sz == -1)
497 sz = 65536; /* your guess is as good as mine... */
498
499 /*
500 * sysconf(_SC_GETPW_R_SIZE_MAX), under glibc, is documented to return
501 * the maximum needed size of the buffer, so we don't have to search.
502 */
503 buf = malloc(sz);
504 if (!buf)
505 return -ENOMEM;
506 getpwnam_r(user, &pw, buf, sz, &ppw);
507 /*
508 * We're safe to free the buffer here. The strings inside |pw| point
509 * inside |buf|, but we don't use any of them; this leaves the pointers
510 * dangling but it's safe. |ppw| points at |pw| if getpwnam_r(3)
511 * succeeded.
512 */
513 free(buf);
514 /* getpwnam_r(3) does *not* set errno when |ppw| is NULL. */
515 if (!ppw)
516 return -1;
517
518 *uid = ppw->pw_uid;
519 *gid = ppw->pw_gid;
520 return 0;
521}
522
523/*
524 * lookup_group: Gets the gid for the given group name.
525 */
526int lookup_group(const char *group, gid_t *gid)
527{
528 char *buf = NULL;
529 struct group gr;
530 struct group *pgr = NULL;
531 ssize_t sz = sysconf(_SC_GETGR_R_SIZE_MAX);
532 if (sz == -1)
533 sz = 65536; /* and mine is as good as yours, really */
534
535 /*
536 * sysconf(_SC_GETGR_R_SIZE_MAX), under glibc, is documented to return
537 * the maximum needed size of the buffer, so we don't have to search.
538 */
539 buf = malloc(sz);
540 if (!buf)
541 return -ENOMEM;
542 getgrnam_r(group, &gr, buf, sz, &pgr);
543 /*
544 * We're safe to free the buffer here. The strings inside gr point
545 * inside buf, but we don't use any of them; this leaves the pointers
546 * dangling but it's safe. pgr points at gr if getgrnam_r succeeded.
547 */
548 free(buf);
549 /* getgrnam_r(3) does *not* set errno when |pgr| is NULL. */
550 if (!pgr)
551 return -1;
552
553 *gid = pgr->gr_gid;
554 return 0;
555}
Jorge Lucangeli Obes32201f82019-06-12 14:45:06 -0400556
557static int seccomp_action_is_available(const char *wanted)
558{
559 if (is_android()) {
560 /*
561 * Accessing |actions_avail| is generating SELinux denials, so
562 * skip for now.
563 * TODO(crbug.com/978022, jorgelo): Remove once the denial is
564 * fixed.
565 */
566 return 0;
567 }
568 const char actions_avail_path[] =
569 "/proc/sys/kernel/seccomp/actions_avail";
570 FILE *f = fopen(actions_avail_path, "re");
571
572 if (!f) {
573 pwarn("fopen(%s) failed", actions_avail_path);
574 return 0;
575 }
576
577 char *actions_avail = NULL;
578 size_t buf_size = 0;
579 if (getline(&actions_avail, &buf_size, f) < 0) {
580 pwarn("getline() failed");
581 free(actions_avail);
582 return 0;
583 }
584
585 /*
586 * This is just substring search, which means that partial matches will
587 * match too (e.g. "action" would match "longaction"). There are no
588 * seccomp actions which include other actions though, so we're good for
589 * now. Eventually we might want to split the string by spaces.
590 */
591 return strstr(actions_avail, wanted) != NULL;
592}
593
594int seccomp_ret_log_available(void)
595{
596 static int ret_log_available = -1;
597
598 if (ret_log_available == -1)
599 ret_log_available = seccomp_action_is_available("log");
600
601 return ret_log_available;
602}
603
604int seccomp_ret_kill_process_available(void)
605{
606 static int ret_kill_process_available = -1;
607
608 if (ret_kill_process_available == -1)
609 ret_kill_process_available =
610 seccomp_action_is_available("kill_process");
611
612 return ret_kill_process_available;
613}