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