• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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