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