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 pid_t cpid;
15 static __thread pid_t tid;
16 static __thread char *prev_current = UNSET;
17 static __thread char * prev_exec = UNSET;
18 static __thread char * prev_fscreate = UNSET;
19 static __thread char * prev_keycreate = UNSET;
20 static __thread char * prev_sockcreate = UNSET;
21
22 static pthread_once_t once = PTHREAD_ONCE_INIT;
23 static pthread_key_t destructor_key;
24 static int destructor_key_initialized = 0;
25 static __thread char destructor_initialized;
26
27 extern void *__dso_handle __attribute__ ((__weak__, __visibility__ ("hidden")));
28 extern int __register_atfork (void (*) (void), void (*) (void), void (*) (void), void *);
29
__selinux_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void))30 static 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
gettid(void)36 static pid_t gettid(void)
37 {
38 return syscall(__NR_gettid);
39 }
40
procattr_thread_destructor(void * unused)41 static void procattr_thread_destructor(void __attribute__((unused)) *unused)
42 {
43 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);
53 }
54
free_procattr(void)55 static void free_procattr(void)
56 {
57 procattr_thread_destructor(NULL);
58 tid = 0;
59 cpid = getpid();
60 prev_current = prev_exec = prev_fscreate = prev_keycreate = prev_sockcreate = UNSET;
61 }
62
63 void __attribute__((destructor)) procattr_destructor(void);
64
procattr_destructor(void)65 void hidden __attribute__((destructor)) procattr_destructor(void)
66 {
67 if (destructor_key_initialized)
68 __selinux_key_delete(destructor_key);
69 }
70
init_thread_destructor(void)71 static 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
init_procattr(void)79 static void init_procattr(void)
80 {
81 if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) {
82 __selinux_atfork(NULL, NULL, free_procattr);
83 destructor_key_initialized = 1;
84 }
85 }
86
openattr(pid_t pid,const char * attr,int flags)87 static int openattr(pid_t pid, const char *attr, int flags)
88 {
89 int fd, rc;
90 char *path;
91
92 if (cpid != getpid())
93 free_procattr();
94
95 if (pid > 0)
96 rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
97 else {
98 if (!tid)
99 tid = gettid();
100 rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
101 }
102 if (rc < 0)
103 return -1;
104
105 fd = open(path, flags | O_CLOEXEC);
106 free(path);
107 return fd;
108 }
109
getprocattrcon_raw(char ** context,pid_t pid,const char * attr)110 static int getprocattrcon_raw(char ** context,
111 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;
118 char * prev_context;
119
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
150 if (prev_context && prev_context != UNSET) {
151 *context = strdup(prev_context);
152 if (!(*context)) {
153 return -1;
154 }
155 return 0;
156 }
157
158 fd = openattr(pid, attr, O_RDONLY);
159 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
getprocattrcon(char ** context,pid_t pid,const char * attr)196 static int getprocattrcon(char ** context,
197 pid_t pid, const char *attr)
198 {
199 int ret;
200 char * rcontext;
201
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
setprocattrcon_raw(const char * context,pid_t pid,const char * attr)212 static int setprocattrcon_raw(const char * context,
213 pid_t pid, const char *attr)
214 {
215 int fd;
216 ssize_t ret;
217 int errno_hold;
218 char **prev_context, *context2 = NULL;
219
220 __selinux_once(once, init_procattr);
221 init_thread_destructor();
222
223 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;
249 if (context && *prev_context && *prev_context != UNSET
250 && !strcmp(context, *prev_context))
251 return 0;
252
253 fd = openattr(pid, attr, O_RDWR);
254 if (fd < 0)
255 return -1;
256 if (context) {
257 ret = -1;
258 context2 = strdup(context);
259 if (!context2)
260 goto out;
261 do {
262 ret = write(fd, context2, strlen(context2) + 1);
263 } while (ret < 0 && errno == EINTR);
264 } else {
265 do {
266 ret = write(fd, NULL, 0); /* clear */
267 } while (ret < 0 && errno == EINTR);
268 }
269 out:
270 errno_hold = errno;
271 close(fd);
272 errno = errno_hold;
273 if (ret < 0) {
274 free(context2);
275 return -1;
276 } else {
277 if (*prev_context != UNSET)
278 free(*prev_context);
279 *prev_context = context2;
280 return 0;
281 }
282 }
283
setprocattrcon(const char * context,pid_t pid,const char * attr)284 static int setprocattrcon(const char * context,
285 pid_t pid, const char *attr)
286 {
287 int ret;
288 char * rcontext;
289
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) \
301 int get##fn##_raw(char **c) \
302 { \
303 return getprocattrcon_raw(c, 0, #attr); \
304 } \
305 int get##fn(char **c) \
306 { \
307 return getprocattrcon(c, 0, #attr); \
308 }
309
310 #define setselfattr_def(fn, attr) \
311 int set##fn##_raw(const char * c) \
312 { \
313 return setprocattrcon_raw(c, 0, #attr); \
314 } \
315 int set##fn(const char * c) \
316 { \
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) \
325 int get##fn##_raw(pid_t pid, char **c) \
326 { \
327 return getprocattrcon_raw(c, pid, #attr); \
328 } \
329 int get##fn(pid_t pid, char **c) \
330 { \
331 return getprocattrcon(c, pid, #attr); \
332 }
333
334 all_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)
361