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 14static __thread char *prev_current = UNSET; 15static __thread char * prev_exec = UNSET; 16static __thread char * prev_fscreate = UNSET; 17static __thread char * prev_keycreate = UNSET; 18static __thread char * prev_sockcreate = UNSET; 19 20static pthread_once_t once = PTHREAD_ONCE_INIT; 21static pthread_key_t destructor_key; 22static int destructor_key_initialized = 0; 23static __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 37static pid_t selinux_gettid(void) 38{ 39#if HAVE_GETTID 40 return gettid(); 41#else 42 return syscall(__NR_gettid); 43#endif 44} 45 46static 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 60void __attribute__((destructor)) procattr_destructor(void); 61 62void __attribute__((destructor)) procattr_destructor(void) 63{ 64 if (destructor_key_initialized) 65 __selinux_key_delete(destructor_key); 66} 67 68static 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 76static void init_procattr(void) 77{ 78 if (__selinux_key_create(&destructor_key, procattr_thread_destructor) == 0) { 79 destructor_key_initialized = 1; 80 } 81} 82 83static 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); 109out: 110 free(path); 111 return fd; 112} 113 114static 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 197static 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 213static 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 } 267out: 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 282static 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 342all_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