blob: c6799ef27533555442b63550e263c0eb543f113a [file] [log] [blame]
Joshua Brindle13cd4c82008-08-19 15:30:36 -04001#include <sys/syscall.h>
2#include <unistd.h>
3#include <fcntl.h>
Eric Paris1d403322013-01-09 11:37:43 +01004#include <pthread.h>
Joshua Brindle13cd4c82008-08-19 15:30:36 -04005#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
Stephen Smalley9eb9c932014-02-19 09:16:17 -050012#define UNSET (char *) -1
Dan Walshc32da692013-10-09 16:27:43 -040013
Stephen Smalley9eb9c932014-02-19 09:16:17 -050014static __thread char *prev_current = UNSET;
15static __thread char * prev_exec = UNSET;
16static __thread char * prev_fscreate = UNSET;
17static __thread char * prev_keycreate = UNSET;
18static __thread char * prev_sockcreate = UNSET;
Eric Paris1d403322013-01-09 11:37:43 +010019
20static pthread_once_t once = PTHREAD_ONCE_INIT;
21static pthread_key_t destructor_key;
22static int destructor_key_initialized = 0;
23static __thread char destructor_initialized;
24
Petr Lautrbach707e4b82019-03-11 16:00:41 +010025/* 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
Joshua Brindle13cd4c82008-08-19 15:30:36 -040038static pid_t gettid(void)
39{
40 return syscall(__NR_gettid);
41}
William Roberts0fdfdcc2016-09-26 10:33:39 -070042#endif
Joshua Brindle13cd4c82008-08-19 15:30:36 -040043
Eric Paris1d403322013-01-09 11:37:43 +010044static void procattr_thread_destructor(void __attribute__((unused)) *unused)
Joshua Brindle13cd4c82008-08-19 15:30:36 -040045{
Dan Walshc32da692013-10-09 16:27:43 -040046 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);
Eric Paris1d403322013-01-09 11:37:43 +010056}
57
Eric Paris1d403322013-01-09 11:37:43 +010058void __attribute__((destructor)) procattr_destructor(void);
59
60void hidden __attribute__((destructor)) procattr_destructor(void)
61{
62 if (destructor_key_initialized)
63 __selinux_key_delete(destructor_key);
64}
65
66static 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
74static void init_procattr(void)
75{
76 if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) {
Eric Paris1d403322013-01-09 11:37:43 +010077 destructor_key_initialized = 1;
78 }
79}
80
81static int openattr(pid_t pid, const char *attr, int flags)
82{
Joshua Brindle13cd4c82008-08-19 15:30:36 -040083 int fd, rc;
Eric Paris1d403322013-01-09 11:37:43 +010084 char *path;
Stephen Smalleyfec839c2015-07-20 12:36:01 -040085 pid_t tid;
Joshua Brindle13cd4c82008-08-19 15:30:36 -040086
dcashmanf77021d2016-02-23 12:23:59 -080087 if (pid > 0) {
Joshua Brindle13cd4c82008-08-19 15:30:36 -040088 rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
dcashmanf77021d2016-02-23 12:23:59 -080089 } else if (pid == 0) {
Stephen Smalley34305192015-07-13 09:00:40 -040090 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;
Stephen Smalleyfec839c2015-07-20 12:36:01 -040096 free(path);
97 tid = gettid();
Joshua Brindle13cd4c82008-08-19 15:30:36 -040098 rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
dcashmanf77021d2016-02-23 12:23:59 -080099 } else {
100 errno = EINVAL;
101 return -1;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400102 }
103 if (rc < 0)
104 return -1;
105
Eric Paris1d403322013-01-09 11:37:43 +0100106 fd = open(path, flags | O_CLOEXEC);
Stephen Smalley34305192015-07-13 09:00:40 -0400107out:
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400108 free(path);
Eric Paris1d403322013-01-09 11:37:43 +0100109 return fd;
110}
111
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500112static int getprocattrcon_raw(char ** context,
Eric Paris1d403322013-01-09 11:37:43 +0100113 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;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500120 char * prev_context;
Eric Paris1d403322013-01-09 11:37:43 +0100121
122 __selinux_once(once, init_procattr);
123 init_thread_destructor();
124
Eric Paris1d403322013-01-09 11:37:43 +0100125 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
Dan Walshc32da692013-10-09 16:27:43 -0400149 if (prev_context && prev_context != UNSET) {
Eric Paris1d403322013-01-09 11:37:43 +0100150 *context = strdup(prev_context);
151 if (!(*context)) {
152 return -1;
153 }
154 return 0;
155 }
156
Nick Kralevich64afa1a2016-12-11 09:30:16 -0800157 fd = openattr(pid, attr, O_RDONLY | O_CLOEXEC);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400158 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
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500195static int getprocattrcon(char ** context,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400196 pid_t pid, const char *attr)
197{
198 int ret;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500199 char * rcontext;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400200
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
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500211static int setprocattrcon_raw(const char * context,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400212 pid_t pid, const char *attr)
213{
Eric Paris1d403322013-01-09 11:37:43 +0100214 int fd;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400215 ssize_t ret;
216 int errno_hold;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500217 char **prev_context, *context2 = NULL;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400218
Eric Paris1d403322013-01-09 11:37:43 +0100219 __selinux_once(once, init_procattr);
220 init_thread_destructor();
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400221
Eric Paris1d403322013-01-09 11:37:43 +0100222 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;
Dan Walshc32da692013-10-09 16:27:43 -0400245 if (context && *prev_context && *prev_context != UNSET
246 && !strcmp(context, *prev_context))
Eric Paris1d403322013-01-09 11:37:43 +0100247 return 0;
248
Nick Kralevich64afa1a2016-12-11 09:30:16 -0800249 fd = openattr(pid, attr, O_RDWR | O_CLOEXEC);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400250 if (fd < 0)
251 return -1;
Eric Paris1d403322013-01-09 11:37:43 +0100252 if (context) {
253 ret = -1;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500254 context2 = strdup(context);
255 if (!context2)
Eric Paris1d403322013-01-09 11:37:43 +0100256 goto out;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400257 do {
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500258 ret = write(fd, context2, strlen(context2) + 1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400259 } while (ret < 0 && errno == EINTR);
Eric Paris1d403322013-01-09 11:37:43 +0100260 } else {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400261 do {
262 ret = write(fd, NULL, 0); /* clear */
263 } while (ret < 0 && errno == EINTR);
Eric Paris1d403322013-01-09 11:37:43 +0100264 }
265out:
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400266 errno_hold = errno;
267 close(fd);
268 errno = errno_hold;
Eric Paris1d403322013-01-09 11:37:43 +0100269 if (ret < 0) {
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500270 free(context2);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400271 return -1;
Eric Paris1d403322013-01-09 11:37:43 +0100272 } else {
Dan Walshc32da692013-10-09 16:27:43 -0400273 if (*prev_context != UNSET)
274 free(*prev_context);
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500275 *prev_context = context2;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400276 return 0;
Eric Paris1d403322013-01-09 11:37:43 +0100277 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400278}
279
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500280static int setprocattrcon(const char * context,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400281 pid_t pid, const char *attr)
282{
283 int ret;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500284 char * rcontext;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400285
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) \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500297 int get##fn##_raw(char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400298 { \
299 return getprocattrcon_raw(c, 0, #attr); \
300 } \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500301 int get##fn(char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400302 { \
303 return getprocattrcon(c, 0, #attr); \
304 }
305
306#define setselfattr_def(fn, attr) \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500307 int set##fn##_raw(const char * c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400308 { \
309 return setprocattrcon_raw(c, 0, #attr); \
310 } \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500311 int set##fn(const char * c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400312 { \
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) \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500321 int get##fn##_raw(pid_t pid, char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400322 { \
dcashmanc7cf5d82016-02-23 12:24:00 -0800323 if (pid <= 0) { \
324 errno = EINVAL; \
325 return -1; \
326 } else { \
327 return getprocattrcon_raw(c, pid, #attr); \
328 } \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400329 } \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500330 int get##fn(pid_t pid, char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400331 { \
dcashmanc7cf5d82016-02-23 12:24:00 -0800332 if (pid <= 0) { \
333 errno = EINVAL; \
334 return -1; \
335 } else { \
336 return getprocattrcon(c, pid, #attr); \
337 } \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400338 }
339
340all_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)