diff options
Diffstat (limited to 'src/secontext.c')
-rw-r--r-- | src/secontext.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/secontext.c b/src/secontext.c new file mode 100644 index 000000000..ccf9b346b --- /dev/null +++ b/src/secontext.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2020-2021 The strace developers. + * All rights reserved. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#include "defs.h" + +#include <stdlib.h> +#include <fcntl.h> +#include <limits.h> +#include <selinux/selinux.h> + +#include "secontext.h" +#include "xstring.h" + +bool selinux_context = false; +bool selinux_context_full = false; + +static int +getcontext(int rc, char **secontext, char **result) +{ + if (rc < 0) + return rc; + + *result = NULL; + if (!selinux_context_full) { + char *saveptr = NULL; + char *secontext_copy = xstrdup(*secontext); + const char *token; + unsigned int i; + + /* + * We only want to keep the type (3rd field, ':' separator). + */ + for (token = strtok_r(secontext_copy, ":", &saveptr), i = 0; + token; token = strtok_r(NULL, ":", &saveptr), i++) { + if (i == 2) { + *result = xstrdup(token); + break; + } + } + free(secontext_copy); + } + + if (*result == NULL) { + /* + * On the CI at least, the context may have a trailing \n, + * let's remove it just in case. + */ + size_t len = strlen(*secontext); + for (; len > 0; --len) { + if ((*secontext)[len - 1] != '\n') + break; + } + *result = xstrndup(*secontext, len); + } + freecon(*secontext); + return 0; +} +/* + * Retrieves the SELinux context of the given PID (extracted from the tcb). + * Memory must be freed. + * Returns 0 on success, -1 on failure. + */ +int +selinux_getpidcon(struct tcb *tcp, char **result) +{ + if (!selinux_context) + return -1; + + int proc_pid = 0; + translate_pid(NULL, tcp->pid, PT_TID, &proc_pid); + if (!proc_pid) + return -1; + + char *secontext; + return getcontext(getpidcon(proc_pid, &secontext), &secontext, result); +} + +/* + * Retrieves the SELinux context of the given pid and descriptor. + * Memory must be freed. + * Returns 0 on success, -1 on failure. + */ +int +selinux_getfdcon(pid_t pid, int fd, char **result) +{ + if (!selinux_context || pid <= 0 || fd < 0) + return -1; + + int proc_pid = 0; + translate_pid(NULL, pid, PT_TID, &proc_pid); + if (!proc_pid) + return -1; + + char linkpath[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3]; + xsprintf(linkpath, "/proc/%u/fd/%u", proc_pid, fd); + + char *secontext; + return getcontext(getfilecon(linkpath, &secontext), &secontext, result); +} + +/* + * Retrieves the SELinux context of the given path. + * Memory must be freed. + * Returns 0 on success, -1 on failure. + */ +int +selinux_getfilecon(struct tcb *tcp, const char *path, char **result) +{ + if (!selinux_context) + return -1; + + int proc_pid = 0; + translate_pid(NULL, tcp->pid, PT_TID, &proc_pid); + if (!proc_pid) + return -1; + + int ret = -1; + char fname[PATH_MAX]; + + if (path[0] == '/') + ret = snprintf(fname, sizeof(fname), "/proc/%u/root%s", + proc_pid, path); + else if (tcp->last_dirfd == AT_FDCWD) + ret = snprintf(fname, sizeof(fname), "/proc/%u/cwd/%s", + proc_pid, path); + else if (tcp->last_dirfd >= 0 ) + ret = snprintf(fname, sizeof(fname), "/proc/%u/fd/%u/%s", + proc_pid, tcp->last_dirfd, path); + + if ((unsigned int) ret >= sizeof(fname)) + return -1; + + char *secontext; + return getcontext(getfilecon(fname, &secontext), &secontext, result); +} |