1 #include <sys/syscall.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <pthread.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include "selinux_internal.h"
10 #include "policy.h"
11
12 #define UNSET (char *) -1
13
14 static __thread char *prev_current = UNSET;
15 static __thread char * prev_exec = UNSET;
16 static __thread char * prev_fscreate = UNSET;
17 static __thread char * prev_keycreate = UNSET;
18 static __thread char * prev_sockcreate = UNSET;
19
20 static pthread_once_t once = PTHREAD_ONCE_INIT;
21 static pthread_key_t destructor_key;
22 static int destructor_key_initialized = 0;
23 static __thread char destructor_initialized;
24
25 /* Bionic and glibc >= 2.30 declare gettid() system call wrapper in unistd.h and
26 * has a definition for it */
27 #ifdef __BIONIC__
28 #define OVERRIDE_GETTID 0
29 #elif !defined(__GLIBC_PREREQ)
30 #define OVERRIDE_GETTID 1
31 #elif !__GLIBC_PREREQ(2,30)
32 #define OVERRIDE_GETTID 1
33 #else
34 #define OVERRIDE_GETTID 0
35 #endif
36
37 #if OVERRIDE_GETTID
gettid(void)38 static pid_t gettid(void)
39 {
40 return syscall(__NR_gettid);
41 }
42 #endif
43
procattr_thread_destructor(void * unused)44 static void procattr_thread_destructor(void __attribute__((unused)) *unused)
45 {
46 if (prev_current != UNSET)
47 free(prev_current);
48 if (prev_exec != UNSET)
49 free(prev_exec);
50 if (prev_fscreate != UNSET)
51 free(prev_fscreate);
52 if (prev_keycreate != UNSET)
53 free(prev_keycreate);
54 if (prev_sockcreate != UNSET)
55 free(prev_sockcreate);
56 }
57
58 void __attribute__((destructor)) procattr_destructor(void);
59
procattr_destructor(void)60 void hidden __attribute__((destructor)) procattr_destructor(void)
61 {
62 if (destructor_key_initialized)
63 __selinux_key_delete(destructor_key);
64 }
65
init_thread_destructor(void)66 static inline void init_thread_destructor(void)
67 {
68 if (destructor_initialized == 0) {
69 __selinux_setspecific(destructor_key, (void *)1);
70 destructor_initialized = 1;
71 }
72 }
73
init_procattr(void)74 static void init_procattr(void)
75 {
76 if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) {
77 destructor_key_initialized = 1;
78 }
79 }
80
openattr(pid_t pid,const char * attr,int flags)81 static int openattr(pid_t pid, const char *attr, int flags)
82 {
83 int fd, rc;
84 char *path;
85 pid_t tid;
86
87 if (pid > 0) {
88 rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
89 } else if (pid == 0) {
90 rc = asprintf(&path, "/proc/thread-self/attr/%s", attr);
91 if (rc < 0)
92 return -1;
93 fd = open(path, flags | O_CLOEXEC);
94 if (fd >= 0 || errno != ENOENT)
95 goto out;
96 free(path);
97 tid = gettid();
98 rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
99 } else {
100 errno = EINVAL;
101 return -1;
102 }
103 if (rc < 0)
104 return -1;
105
106 fd = open(path, flags | O_CLOEXEC);
107 out:
108 free(path);
109 return fd;
110 }
111
getprocattrcon_raw(char ** context,pid_t pid,const char * attr)112 static int getprocattrcon_raw(char ** context,
113 pid_t pid, const char *attr)
114 {
115 char *buf;
116 size_t size;
117 int fd;
118 ssize_t ret;
119 int errno_hold;
120 char * prev_context;
121
122 __selinux_once(once, init_procattr);
123 init_thread_destructor();
124
125 switch (attr[0]) {
126 case 'c':
127 prev_context = prev_current;
128 break;
129 case 'e':
130 prev_context = prev_exec;
131 break;
132 case 'f':
133 prev_context = prev_fscreate;
134 break;
135 case 'k':
136 prev_context = prev_keycreate;
137 break;
138 case 's':
139 prev_context = prev_sockcreate;
140 break;
141 case 'p':
142 prev_context = NULL;
143 break;
144 default:
145 errno = ENOENT;
146 return -1;
147 };
148
149 if (prev_context && prev_context != UNSET) {
150 *context = strdup(prev_context);
151 if (!(*context)) {
152 return -1;
153 }
154 return 0;
155 }
156
157 fd = openattr(pid, attr, O_RDONLY | O_CLOEXEC);
158 if (fd < 0)
159 return -1;
160
161 size = selinux_page_size;
162 buf = malloc(size);
163 if (!buf) {
164 ret = -1;
165 goto out;
166 }
167 memset(buf, 0, size);
168
169 do {
170 ret = read(fd, buf, size - 1);
171 } while (ret < 0 && errno == EINTR);
172 if (ret < 0)
173 goto out2;
174
175 if (ret == 0) {
176 *context = NULL;
177 goto out2;
178 }
179
180 *context = strdup(buf);
181 if (!(*context)) {
182 ret = -1;
183 goto out2;
184 }
185 ret = 0;
186 out2:
187 free(buf);
188 out:
189 errno_hold = errno;
190 close(fd);
191 errno = errno_hold;
192 return ret;
193 }
194
getprocattrcon(char ** context,pid_t pid,const char * attr)195 static int getprocattrcon(char ** context,
196 pid_t pid, const char *attr)
197 {
198 int ret;
199 char * rcontext;
200
201 ret = getprocattrcon_raw(&rcontext, pid, attr);
202
203 if (!ret) {
204 ret = selinux_raw_to_trans_context(rcontext, context);
205 freecon(rcontext);
206 }
207
208 return ret;
209 }
210
setprocattrcon_raw(const char * context,pid_t pid,const char * attr)211 static int setprocattrcon_raw(const char * context,
212 pid_t pid, const char *attr)
213 {
214 int fd;
215 ssize_t ret;
216 int errno_hold;
217 char **prev_context, *context2 = NULL;
218
219 __selinux_once(once, init_procattr);
220 init_thread_destructor();
221
222 switch (attr[0]) {
223 case 'c':
224 prev_context = &prev_current;
225 break;
226 case 'e':
227 prev_context = &prev_exec;
228 break;
229 case 'f':
230 prev_context = &prev_fscreate;
231 break;
232 case 'k':
233 prev_context = &prev_keycreate;
234 break;
235 case 's':
236 prev_context = &prev_sockcreate;
237 break;
238 default:
239 errno = ENOENT;
240 return -1;
241 };
242
243 if (!context && !*prev_context)
244 return 0;
245 if (context && *prev_context && *prev_context != UNSET
246 && !strcmp(context, *prev_context))
247 return 0;
248
249 fd = openattr(pid, attr, O_RDWR | O_CLOEXEC);
250 if (fd < 0)
251 return -1;
252 if (context) {
253 ret = -1;
254 context2 = strdup(context);
255 if (!context2)
256 goto out;
257 do {
258 ret = write(fd, context2, strlen(context2) + 1);
259 } while (ret < 0 && errno == EINTR);
260 } else {
261 do {
262 ret = write(fd, NULL, 0); /* clear */
263 } while (ret < 0 && errno == EINTR);
264 }
265 out:
266 errno_hold = errno;
267 close(fd);
268 errno = errno_hold;
269 if (ret < 0) {
270 free(context2);
271 return -1;
272 } else {
273 if (*prev_context != UNSET)
274 free(*prev_context);
275 *prev_context = context2;
276 return 0;
277 }
278 }
279
setprocattrcon(const char * context,pid_t pid,const char * attr)280 static int setprocattrcon(const char * context,
281 pid_t pid, const char *attr)
282 {
283 int ret;
284 char * rcontext;
285
286 if (selinux_trans_to_raw_context(context, &rcontext))
287 return -1;
288
289 ret = setprocattrcon_raw(rcontext, pid, attr);
290
291 freecon(rcontext);
292
293 return ret;
294 }
295
296 #define getselfattr_def(fn, attr) \
297 int get##fn##_raw(char **c) \
298 { \
299 return getprocattrcon_raw(c, 0, #attr); \
300 } \
301 int get##fn(char **c) \
302 { \
303 return getprocattrcon(c, 0, #attr); \
304 }
305
306 #define setselfattr_def(fn, attr) \
307 int set##fn##_raw(const char * c) \
308 { \
309 return setprocattrcon_raw(c, 0, #attr); \
310 } \
311 int set##fn(const char * c) \
312 { \
313 return setprocattrcon(c, 0, #attr); \
314 }
315
316 #define all_selfattr_def(fn, attr) \
317 getselfattr_def(fn, attr) \
318 setselfattr_def(fn, attr)
319
320 #define getpidattr_def(fn, attr) \
321 int get##fn##_raw(pid_t pid, char **c) \
322 { \
323 if (pid <= 0) { \
324 errno = EINVAL; \
325 return -1; \
326 } else { \
327 return getprocattrcon_raw(c, pid, #attr); \
328 } \
329 } \
330 int get##fn(pid_t pid, char **c) \
331 { \
332 if (pid <= 0) { \
333 errno = EINVAL; \
334 return -1; \
335 } else { \
336 return getprocattrcon(c, pid, #attr); \
337 } \
338 }
339
340 all_selfattr_def(con, current)
341 getpidattr_def(pidcon, current)
342 getselfattr_def(prevcon, prev)
343 all_selfattr_def(execcon, exec)
344 all_selfattr_def(fscreatecon, fscreate)
345 all_selfattr_def(sockcreatecon, sockcreate)
346 all_selfattr_def(keycreatecon, keycreate)
347
348 hidden_def(getcon_raw)
349 hidden_def(getcon)
350 hidden_def(getexeccon_raw)
351 hidden_def(getfilecon_raw)
352 hidden_def(getfilecon)
353 hidden_def(getfscreatecon_raw)
354 hidden_def(getkeycreatecon_raw)
355 hidden_def(getpeercon_raw)
356 hidden_def(getpidcon_raw)
357 hidden_def(getprevcon_raw)
358 hidden_def(getprevcon)
359 hidden_def(getsockcreatecon_raw)
360 hidden_def(setcon_raw)
361 hidden_def(setexeccon_raw)
362 hidden_def(setexeccon)
363 hidden_def(setfilecon_raw)
364 hidden_def(setfscreatecon_raw)
365 hidden_def(setkeycreatecon_raw)
366 hidden_def(setsockcreatecon_raw)
367