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