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