summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_capability.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/nxt_capability.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/nxt_capability.c b/src/nxt_capability.c
new file mode 100644
index 00000000..805faff6
--- /dev/null
+++ b/src/nxt_capability.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) Igor Sysoev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_main.h>
+
+#if (NXT_HAVE_LINUX_CAPABILITY)
+
+#include <linux/capability.h>
+#include <sys/syscall.h>
+
+#define nxt_capget(hdrp, datap) \
+ syscall(SYS_capget, hdrp, datap)
+#define nxt_capset(hdrp, datap) \
+ syscall(SYS_capset, hdrp, datap)
+
+#endif /* NXT_HAVE_LINUX_CAPABILITY */
+
+
+static nxt_int_t nxt_capability_specific_set(nxt_task_t *task,
+ nxt_capabilities_t *cap);
+
+
+nxt_int_t
+nxt_capability_set(nxt_task_t *task, nxt_capabilities_t *cap)
+{
+ nxt_assert(cap->setid == 0);
+
+ if (geteuid() == 0) {
+ cap->setid = 1;
+ return NXT_OK;
+ }
+
+ return nxt_capability_specific_set(task, cap);
+}
+
+
+#if (NXT_HAVE_LINUX_CAPABILITY)
+
+static uint32_t
+nxt_capability_linux_get_version()
+{
+ struct __user_cap_header_struct hdr;
+
+ hdr.version = _LINUX_CAPABILITY_VERSION;
+ hdr.pid = nxt_pid;
+
+ nxt_capget(&hdr, NULL);
+ return hdr.version;
+}
+
+
+static nxt_int_t
+nxt_capability_specific_set(nxt_task_t *task, nxt_capabilities_t *cap)
+{
+ struct __user_cap_data_struct *val, data[2];
+ struct __user_cap_header_struct hdr;
+
+ /*
+ * Linux capability v1 fills an u32 struct.
+ * Linux capability v2 and v3 fills an u64 struct.
+ * We allocate data[2] for compatibility, we waste 4 bytes on v1.
+ *
+ * This is safe as we only need to check CAP_SETUID and CAP_SETGID
+ * that resides in the first 32-bit chunk.
+ */
+
+ val = &data[0];
+
+ /*
+ * Ask the kernel the preferred capability version
+ * instead of using _LINUX_CAPABILITY_VERSION from header.
+ * This is safer when distributing a pre-compiled Unit binary.
+ */
+ hdr.version = nxt_capability_linux_get_version();
+ hdr.pid = nxt_pid;
+
+ if (nxt_slow_path(nxt_capget(&hdr, val) == -1)) {
+ nxt_alert(task, "failed to get process capabilities: %E", nxt_errno);
+ return NXT_ERROR;
+ }
+
+ if ((val->effective & (1 << CAP_SETUID)) == 0) {
+ return NXT_OK;
+ }
+
+ if ((val->effective & (1 << CAP_SETGID)) == 0) {
+ return NXT_OK;
+ }
+
+ cap->setid = 1;
+ return NXT_OK;
+}
+
+#else
+
+static nxt_int_t
+nxt_capability_specific_set(nxt_task_t *task, nxt_capabilities_t *cap)
+{
+ return NXT_OK;
+}
+
+#endif