summaryrefslogtreecommitdiff
path: root/src/secontext.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/secontext.c')
-rw-r--r--src/secontext.c139
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);
+}