blob: f9903505540f682a0419425d3113df18a9a112ab [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
Eric Paris1d403322013-01-09 11:37:43 +010014static __thread pid_t cpid;
15static __thread pid_t tid;
Stephen Smalley9eb9c932014-02-19 09:16:17 -050016static __thread char *prev_current = UNSET;
17static __thread char * prev_exec = UNSET;
18static __thread char * prev_fscreate = UNSET;
19static __thread char * prev_keycreate = UNSET;
20static __thread char * prev_sockcreate = UNSET;
Eric Paris1d403322013-01-09 11:37:43 +010021
22static pthread_once_t once = PTHREAD_ONCE_INIT;
23static pthread_key_t destructor_key;
24static int destructor_key_initialized = 0;
25static __thread char destructor_initialized;
26
Dan Walshc32da692013-10-09 16:27:43 -040027extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
28extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
29
30static int __selinux_atfork (void (*prepare) (void), void (*parent) (void), void (*child) (void))
31{
32 return __register_atfork (prepare, parent, child,
33 &__dso_handle == NULL ? NULL : __dso_handle);
34}
35
Joshua Brindle13cd4c82008-08-19 15:30:36 -040036static pid_t gettid(void)
37{
38 return syscall(__NR_gettid);
39}
40
Eric Paris1d403322013-01-09 11:37:43 +010041static void procattr_thread_destructor(void __attribute__((unused)) *unused)
Joshua Brindle13cd4c82008-08-19 15:30:36 -040042{
Dan Walshc32da692013-10-09 16:27:43 -040043 if (prev_current != UNSET)
44 free(prev_current);
45 if (prev_exec != UNSET)
46 free(prev_exec);
47 if (prev_fscreate != UNSET)
48 free(prev_fscreate);
49 if (prev_keycreate != UNSET)
50 free(prev_keycreate);
51 if (prev_sockcreate != UNSET)
52 free(prev_sockcreate);
Eric Paris1d403322013-01-09 11:37:43 +010053}
54
55static void free_procattr(void)
56{
57 procattr_thread_destructor(NULL);
58 tid = 0;
59 cpid = getpid();
Dan Walshc32da692013-10-09 16:27:43 -040060 prev_current = prev_exec = prev_fscreate = prev_keycreate = prev_sockcreate = UNSET;
Eric Paris1d403322013-01-09 11:37:43 +010061}
62
63void __attribute__((destructor)) procattr_destructor(void);
64
65void hidden __attribute__((destructor)) procattr_destructor(void)
66{
67 if (destructor_key_initialized)
68 __selinux_key_delete(destructor_key);
69}
70
71static inline void init_thread_destructor(void)
72{
73 if (destructor_initialized == 0) {
74 __selinux_setspecific(destructor_key, (void *)1);
75 destructor_initialized = 1;
76 }
77}
78
79static void init_procattr(void)
80{
81 if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) {
Dan Walshc32da692013-10-09 16:27:43 -040082 __selinux_atfork(NULL, NULL, free_procattr);
Eric Paris1d403322013-01-09 11:37:43 +010083 destructor_key_initialized = 1;
84 }
85}
86
87static int openattr(pid_t pid, const char *attr, int flags)
88{
Joshua Brindle13cd4c82008-08-19 15:30:36 -040089 int fd, rc;
Eric Paris1d403322013-01-09 11:37:43 +010090 char *path;
91
92 if (cpid != getpid())
93 free_procattr();
Joshua Brindle13cd4c82008-08-19 15:30:36 -040094
95 if (pid > 0)
96 rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
97 else {
Eric Paris1d403322013-01-09 11:37:43 +010098 if (!tid)
99 tid = gettid();
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400100 rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
101 }
102 if (rc < 0)
103 return -1;
104
Eric Paris1d403322013-01-09 11:37:43 +0100105 fd = open(path, flags | O_CLOEXEC);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400106 free(path);
Eric Paris1d403322013-01-09 11:37:43 +0100107 return fd;
108}
109
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500110static int getprocattrcon_raw(char ** context,
Eric Paris1d403322013-01-09 11:37:43 +0100111 pid_t pid, const char *attr)
112{
113 char *buf;
114 size_t size;
115 int fd;
116 ssize_t ret;
117 int errno_hold;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500118 char * prev_context;
Eric Paris1d403322013-01-09 11:37:43 +0100119
120 __selinux_once(once, init_procattr);
121 init_thread_destructor();
122
123 if (cpid != getpid())
124 free_procattr();
125
126 switch (attr[0]) {
127 case 'c':
128 prev_context = prev_current;
129 break;
130 case 'e':
131 prev_context = prev_exec;
132 break;
133 case 'f':
134 prev_context = prev_fscreate;
135 break;
136 case 'k':
137 prev_context = prev_keycreate;
138 break;
139 case 's':
140 prev_context = prev_sockcreate;
141 break;
142 case 'p':
143 prev_context = NULL;
144 break;
145 default:
146 errno = ENOENT;
147 return -1;
148 };
149
Dan Walshc32da692013-10-09 16:27:43 -0400150 if (prev_context && prev_context != UNSET) {
Eric Paris1d403322013-01-09 11:37:43 +0100151 *context = strdup(prev_context);
152 if (!(*context)) {
153 return -1;
154 }
155 return 0;
156 }
157
158 fd = openattr(pid, attr, O_RDONLY);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400159 if (fd < 0)
160 return -1;
161
162 size = selinux_page_size;
163 buf = malloc(size);
164 if (!buf) {
165 ret = -1;
166 goto out;
167 }
168 memset(buf, 0, size);
169
170 do {
171 ret = read(fd, buf, size - 1);
172 } while (ret < 0 && errno == EINTR);
173 if (ret < 0)
174 goto out2;
175
176 if (ret == 0) {
177 *context = NULL;
178 goto out2;
179 }
180
181 *context = strdup(buf);
182 if (!(*context)) {
183 ret = -1;
184 goto out2;
185 }
186 ret = 0;
187 out2:
188 free(buf);
189 out:
190 errno_hold = errno;
191 close(fd);
192 errno = errno_hold;
193 return ret;
194}
195
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500196static int getprocattrcon(char ** context,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400197 pid_t pid, const char *attr)
198{
199 int ret;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500200 char * rcontext;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400201
202 ret = getprocattrcon_raw(&rcontext, pid, attr);
203
204 if (!ret) {
205 ret = selinux_raw_to_trans_context(rcontext, context);
206 freecon(rcontext);
207 }
208
209 return ret;
210}
211
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500212static int setprocattrcon_raw(const char * context,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400213 pid_t pid, const char *attr)
214{
Eric Paris1d403322013-01-09 11:37:43 +0100215 int fd;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400216 ssize_t ret;
217 int errno_hold;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500218 char **prev_context, *context2 = NULL;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400219
Eric Paris1d403322013-01-09 11:37:43 +0100220 __selinux_once(once, init_procattr);
221 init_thread_destructor();
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400222
Eric Paris1d403322013-01-09 11:37:43 +0100223 if (cpid != getpid())
224 free_procattr();
225
226 switch (attr[0]) {
227 case 'c':
228 prev_context = &prev_current;
229 break;
230 case 'e':
231 prev_context = &prev_exec;
232 break;
233 case 'f':
234 prev_context = &prev_fscreate;
235 break;
236 case 'k':
237 prev_context = &prev_keycreate;
238 break;
239 case 's':
240 prev_context = &prev_sockcreate;
241 break;
242 default:
243 errno = ENOENT;
244 return -1;
245 };
246
247 if (!context && !*prev_context)
248 return 0;
Dan Walshc32da692013-10-09 16:27:43 -0400249 if (context && *prev_context && *prev_context != UNSET
250 && !strcmp(context, *prev_context))
Eric Paris1d403322013-01-09 11:37:43 +0100251 return 0;
252
253 fd = openattr(pid, attr, O_RDWR);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400254 if (fd < 0)
255 return -1;
Eric Paris1d403322013-01-09 11:37:43 +0100256 if (context) {
257 ret = -1;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500258 context2 = strdup(context);
259 if (!context2)
Eric Paris1d403322013-01-09 11:37:43 +0100260 goto out;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400261 do {
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500262 ret = write(fd, context2, strlen(context2) + 1);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400263 } while (ret < 0 && errno == EINTR);
Eric Paris1d403322013-01-09 11:37:43 +0100264 } else {
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400265 do {
266 ret = write(fd, NULL, 0); /* clear */
267 } while (ret < 0 && errno == EINTR);
Eric Paris1d403322013-01-09 11:37:43 +0100268 }
269out:
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400270 errno_hold = errno;
271 close(fd);
272 errno = errno_hold;
Eric Paris1d403322013-01-09 11:37:43 +0100273 if (ret < 0) {
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500274 free(context2);
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400275 return -1;
Eric Paris1d403322013-01-09 11:37:43 +0100276 } else {
Dan Walshc32da692013-10-09 16:27:43 -0400277 if (*prev_context != UNSET)
278 free(*prev_context);
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500279 *prev_context = context2;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400280 return 0;
Eric Paris1d403322013-01-09 11:37:43 +0100281 }
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400282}
283
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500284static int setprocattrcon(const char * context,
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400285 pid_t pid, const char *attr)
286{
287 int ret;
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500288 char * rcontext;
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400289
290 if (selinux_trans_to_raw_context(context, &rcontext))
291 return -1;
292
293 ret = setprocattrcon_raw(rcontext, pid, attr);
294
295 freecon(rcontext);
296
297 return ret;
298}
299
300#define getselfattr_def(fn, attr) \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500301 int get##fn##_raw(char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400302 { \
303 return getprocattrcon_raw(c, 0, #attr); \
304 } \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500305 int get##fn(char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400306 { \
307 return getprocattrcon(c, 0, #attr); \
308 }
309
310#define setselfattr_def(fn, attr) \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500311 int set##fn##_raw(const char * c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400312 { \
313 return setprocattrcon_raw(c, 0, #attr); \
314 } \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500315 int set##fn(const char * c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400316 { \
317 return setprocattrcon(c, 0, #attr); \
318 }
319
320#define all_selfattr_def(fn, attr) \
321 getselfattr_def(fn, attr) \
322 setselfattr_def(fn, attr)
323
324#define getpidattr_def(fn, attr) \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500325 int get##fn##_raw(pid_t pid, char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400326 { \
327 return getprocattrcon_raw(c, pid, #attr); \
328 } \
Stephen Smalley9eb9c932014-02-19 09:16:17 -0500329 int get##fn(pid_t pid, char **c) \
Joshua Brindle13cd4c82008-08-19 15:30:36 -0400330 { \
331 return getprocattrcon(c, pid, #attr); \
332 }
333
334all_selfattr_def(con, current)
335 getpidattr_def(pidcon, current)
336 getselfattr_def(prevcon, prev)
337 all_selfattr_def(execcon, exec)
338 all_selfattr_def(fscreatecon, fscreate)
339 all_selfattr_def(sockcreatecon, sockcreate)
340 all_selfattr_def(keycreatecon, keycreate)
341
342 hidden_def(getcon_raw)
343 hidden_def(getcon)
344 hidden_def(getexeccon_raw)
345 hidden_def(getfilecon_raw)
346 hidden_def(getfilecon)
347 hidden_def(getfscreatecon_raw)
348 hidden_def(getkeycreatecon_raw)
349 hidden_def(getpeercon_raw)
350 hidden_def(getpidcon_raw)
351 hidden_def(getprevcon_raw)
352 hidden_def(getprevcon)
353 hidden_def(getsockcreatecon_raw)
354 hidden_def(setcon_raw)
355 hidden_def(setexeccon_raw)
356 hidden_def(setexeccon)
357 hidden_def(setfilecon_raw)
358 hidden_def(setfscreatecon_raw)
359 hidden_def(setkeycreatecon_raw)
360 hidden_def(setsockcreatecon_raw)