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