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 static pid_t gettid(void) 26 { 27 return syscall(__NR_gettid); 28 } 29 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 46 void hidden __attribute__((destructor)) procattr_destructor(void) 47 { 48 if (destructor_key_initialized) 49 __selinux_key_delete(destructor_key); 50 } 51 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 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 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 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 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 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 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