1 /*
2 * Copyright (C) Igor Sysoev
3 * Copyright (C) NGINX, Inc.
4 */
5
6 #include <nxt_main.h>
7
8 #if (NXT_HAVE_LINUX_CAPABILITY)
9
10 #include <linux/capability.h>
11 #include <sys/syscall.h>
12
13
14 #if (_LINUX_CAPABILITY_VERSION_3)
15 #define NXT_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3
16 #elif (_LINUX_CAPABILITY_VERSION_2)
17 #define NXT_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_2
18 #else
19 #define NXT_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION
20 #endif
21
22
23 #define nxt_capget(hdrp, datap) \
24 syscall(SYS_capget, hdrp, datap)
25 #define nxt_capset(hdrp, datap) \
26 syscall(SYS_capset, hdrp, datap)
27
28 #endif /* NXT_HAVE_LINUX_CAPABILITY */
29
30
31 static nxt_int_t nxt_capability_specific_set(nxt_task_t *task,
32 nxt_capabilities_t *cap);
33
34
35 nxt_int_t
nxt_capability_set(nxt_task_t * task,nxt_capabilities_t * cap)36 nxt_capability_set(nxt_task_t *task, nxt_capabilities_t *cap)
37 {
38 nxt_assert(cap->setid == 0);
39
40 if (geteuid() == 0) {
41 cap->setid = 1;
42 cap->chroot = 1;
43 return NXT_OK;
44 }
45
46 return nxt_capability_specific_set(task, cap);
47 }
48
49
50 #if (NXT_HAVE_LINUX_CAPABILITY)
51
52 static uint32_t
nxt_capability_linux_get_version()53 nxt_capability_linux_get_version()
54 {
55 struct __user_cap_header_struct hdr;
56
57 hdr.version = NXT_CAPABILITY_VERSION;
58 hdr.pid = nxt_pid;
59
60 nxt_capget(&hdr, NULL);
61 return hdr.version;
62 }
63
64
65 static nxt_int_t
nxt_capability_specific_set(nxt_task_t * task,nxt_capabilities_t * cap)66 nxt_capability_specific_set(nxt_task_t *task, nxt_capabilities_t *cap)
67 {
68 struct __user_cap_data_struct *val, data[2];
69 struct __user_cap_header_struct hdr;
70
71 /*
72 * Linux capability v1 fills an u32 struct.
73 * Linux capability v2 and v3 fills an u64 struct.
74 * We allocate data[2] for compatibility, we waste 4 bytes on v1.
75 *
76 * This is safe as we only need to check CAP_SETUID and CAP_SETGID
77 * that resides in the first 32-bit chunk.
78 */
79
80 val = &data[0];
81
82 /*
83 * Ask the kernel the preferred capability version
84 * instead of using _LINUX_CAPABILITY_VERSION from header.
85 * This is safer when distributing a pre-compiled Unit binary.
86 */
87 hdr.version = nxt_capability_linux_get_version();
88 hdr.pid = nxt_pid;
89
90 if (nxt_slow_path(nxt_capget(&hdr, val) == -1)) {
91 nxt_alert(task, "failed to get process capabilities: %E", nxt_errno);
92 return NXT_ERROR;
93 }
94
95 if ((val->effective & (1 << CAP_SYS_CHROOT)) != 0) {
96 cap->chroot = 1;
97 }
98
99 if ((val->effective & (1 << CAP_SETUID)) == 0) {
100 return NXT_OK;
101 }
102
103 if ((val->effective & (1 << CAP_SETGID)) == 0) {
104 return NXT_OK;
105 }
106
107 cap->setid = 1;
108 return NXT_OK;
109 }
110
111 #else
112
113 static nxt_int_t
nxt_capability_specific_set(nxt_task_t * task,nxt_capabilities_t * cap)114 nxt_capability_specific_set(nxt_task_t *task, nxt_capabilities_t *cap)
115 {
116 return NXT_OK;
117 }
118
119 #endif
120