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 */ 27 static pid_t gettid(void) 28 { 29 return syscall(__NR_gettid); 30 } 31 #endif 32 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 49 void hidden __attribute__((destructor)) procattr_destructor(void) 50 { 51 if (destructor_key_initialized) 52 __selinux_key_delete(destructor_key); 53 } 54 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 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 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 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 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 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 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