xref: /unit/src/nxt_capability.c (revision 1489:4a3ec07f4b19)
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