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