16cd6a6acSopenharmony_ci#include <sys/stat.h> 26cd6a6acSopenharmony_ci#include <string.h> 36cd6a6acSopenharmony_ci#include <errno.h> 46cd6a6acSopenharmony_ci#include <stdio.h> 56cd6a6acSopenharmony_ci#include "selinux_internal.h" 66cd6a6acSopenharmony_ci#include "label_internal.h" 76cd6a6acSopenharmony_ci#include "callbacks.h" 86cd6a6acSopenharmony_ci#include <limits.h> 96cd6a6acSopenharmony_ci 106cd6a6acSopenharmony_cistatic int (*myinvalidcon) (const char *p, unsigned l, char *c) = NULL; 116cd6a6acSopenharmony_cistatic int (*mycanoncon) (const char *p, unsigned l, char **c) = NULL; 126cd6a6acSopenharmony_ci 136cd6a6acSopenharmony_cistatic void 146cd6a6acSopenharmony_ci#ifdef __GNUC__ 156cd6a6acSopenharmony_ci __attribute__ ((format(printf, 1, 2))) 166cd6a6acSopenharmony_ci#endif 176cd6a6acSopenharmony_ci default_printf(const char *fmt, ...) 186cd6a6acSopenharmony_ci{ 196cd6a6acSopenharmony_ci va_list ap; 206cd6a6acSopenharmony_ci va_start(ap, fmt); 216cd6a6acSopenharmony_ci vfprintf(stderr, fmt, ap); 226cd6a6acSopenharmony_ci va_end(ap); 236cd6a6acSopenharmony_ci} 246cd6a6acSopenharmony_ci 256cd6a6acSopenharmony_civoid 266cd6a6acSopenharmony_ci#ifdef __GNUC__ 276cd6a6acSopenharmony_ci __attribute__ ((format(printf, 1, 2))) 286cd6a6acSopenharmony_ci#endif 296cd6a6acSopenharmony_ci (*myprintf) (const char *fmt,...) = &default_printf; 306cd6a6acSopenharmony_ciint myprintf_compat = 0; 316cd6a6acSopenharmony_ci 326cd6a6acSopenharmony_civoid set_matchpathcon_printf(void (*f) (const char *fmt, ...)) 336cd6a6acSopenharmony_ci{ 346cd6a6acSopenharmony_ci myprintf = f ? f : &default_printf; 356cd6a6acSopenharmony_ci myprintf_compat = 1; 366cd6a6acSopenharmony_ci} 376cd6a6acSopenharmony_ci 386cd6a6acSopenharmony_ciint compat_validate(struct selabel_handle *rec, 396cd6a6acSopenharmony_ci struct selabel_lookup_rec *contexts, 406cd6a6acSopenharmony_ci const char *path, unsigned lineno) 416cd6a6acSopenharmony_ci{ 426cd6a6acSopenharmony_ci int rc; 436cd6a6acSopenharmony_ci char **ctx = &contexts->ctx_raw; 446cd6a6acSopenharmony_ci 456cd6a6acSopenharmony_ci if (myinvalidcon) 466cd6a6acSopenharmony_ci rc = myinvalidcon(path, lineno, *ctx); 476cd6a6acSopenharmony_ci else if (mycanoncon) 486cd6a6acSopenharmony_ci rc = mycanoncon(path, lineno, ctx); 496cd6a6acSopenharmony_ci else { 506cd6a6acSopenharmony_ci rc = selabel_validate(rec, contexts); 516cd6a6acSopenharmony_ci if (rc < 0) { 526cd6a6acSopenharmony_ci if (lineno) { 536cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_WARNING, 546cd6a6acSopenharmony_ci "%s: line %u has invalid context %s\n", 556cd6a6acSopenharmony_ci path, lineno, *ctx); 566cd6a6acSopenharmony_ci } else { 576cd6a6acSopenharmony_ci COMPAT_LOG(SELINUX_WARNING, 586cd6a6acSopenharmony_ci "%s: has invalid context %s\n", path, *ctx); 596cd6a6acSopenharmony_ci } 606cd6a6acSopenharmony_ci } 616cd6a6acSopenharmony_ci } 626cd6a6acSopenharmony_ci 636cd6a6acSopenharmony_ci return rc ? -1 : 0; 646cd6a6acSopenharmony_ci} 656cd6a6acSopenharmony_ci 666cd6a6acSopenharmony_ci#ifndef BUILD_HOST 676cd6a6acSopenharmony_ci 686cd6a6acSopenharmony_cistatic __thread struct selabel_handle *hnd; 696cd6a6acSopenharmony_ci 706cd6a6acSopenharmony_ci/* 716cd6a6acSopenharmony_ci * An array for mapping integers to contexts 726cd6a6acSopenharmony_ci */ 736cd6a6acSopenharmony_cistatic __thread char **con_array; 746cd6a6acSopenharmony_cistatic __thread int con_array_size; 756cd6a6acSopenharmony_cistatic __thread int con_array_used; 766cd6a6acSopenharmony_ci 776cd6a6acSopenharmony_cistatic pthread_once_t once = PTHREAD_ONCE_INIT; 786cd6a6acSopenharmony_cistatic pthread_key_t destructor_key; 796cd6a6acSopenharmony_cistatic int destructor_key_initialized = 0; 806cd6a6acSopenharmony_ci 816cd6a6acSopenharmony_cistatic void free_array_elts(void) 826cd6a6acSopenharmony_ci{ 836cd6a6acSopenharmony_ci int i; 846cd6a6acSopenharmony_ci for (i = 0; i < con_array_used; i++) 856cd6a6acSopenharmony_ci free(con_array[i]); 866cd6a6acSopenharmony_ci free(con_array); 876cd6a6acSopenharmony_ci 886cd6a6acSopenharmony_ci con_array_size = con_array_used = 0; 896cd6a6acSopenharmony_ci con_array = NULL; 906cd6a6acSopenharmony_ci} 916cd6a6acSopenharmony_ci 926cd6a6acSopenharmony_cistatic int add_array_elt(char *con) 936cd6a6acSopenharmony_ci{ 946cd6a6acSopenharmony_ci char **tmp; 956cd6a6acSopenharmony_ci if (con_array_size) { 966cd6a6acSopenharmony_ci while (con_array_used >= con_array_size) { 976cd6a6acSopenharmony_ci con_array_size *= 2; 986cd6a6acSopenharmony_ci tmp = (char **)realloc(con_array, sizeof(char*) * 996cd6a6acSopenharmony_ci con_array_size); 1006cd6a6acSopenharmony_ci if (!tmp) { 1016cd6a6acSopenharmony_ci free_array_elts(); 1026cd6a6acSopenharmony_ci return -1; 1036cd6a6acSopenharmony_ci } 1046cd6a6acSopenharmony_ci con_array = tmp; 1056cd6a6acSopenharmony_ci } 1066cd6a6acSopenharmony_ci } else { 1076cd6a6acSopenharmony_ci con_array_size = 1000; 1086cd6a6acSopenharmony_ci con_array = (char **)malloc(sizeof(char*) * con_array_size); 1096cd6a6acSopenharmony_ci if (!con_array) { 1106cd6a6acSopenharmony_ci con_array_size = con_array_used = 0; 1116cd6a6acSopenharmony_ci return -1; 1126cd6a6acSopenharmony_ci } 1136cd6a6acSopenharmony_ci } 1146cd6a6acSopenharmony_ci 1156cd6a6acSopenharmony_ci con_array[con_array_used] = strdup(con); 1166cd6a6acSopenharmony_ci if (!con_array[con_array_used]) 1176cd6a6acSopenharmony_ci return -1; 1186cd6a6acSopenharmony_ci return con_array_used++; 1196cd6a6acSopenharmony_ci} 1206cd6a6acSopenharmony_ci 1216cd6a6acSopenharmony_civoid set_matchpathcon_invalidcon(int (*f) (const char *p, unsigned l, char *c)) 1226cd6a6acSopenharmony_ci{ 1236cd6a6acSopenharmony_ci myinvalidcon = f; 1246cd6a6acSopenharmony_ci} 1256cd6a6acSopenharmony_ci 1266cd6a6acSopenharmony_cistatic int default_canoncon(const char *path, unsigned lineno, char **context) 1276cd6a6acSopenharmony_ci{ 1286cd6a6acSopenharmony_ci char *tmpcon; 1296cd6a6acSopenharmony_ci if (security_canonicalize_context_raw(*context, &tmpcon) < 0) { 1306cd6a6acSopenharmony_ci if (errno == ENOENT) 1316cd6a6acSopenharmony_ci return 0; 1326cd6a6acSopenharmony_ci if (lineno) 1336cd6a6acSopenharmony_ci myprintf("%s: line %u has invalid context %s\n", path, 1346cd6a6acSopenharmony_ci lineno, *context); 1356cd6a6acSopenharmony_ci else 1366cd6a6acSopenharmony_ci myprintf("%s: invalid context %s\n", path, *context); 1376cd6a6acSopenharmony_ci return 1; 1386cd6a6acSopenharmony_ci } 1396cd6a6acSopenharmony_ci free(*context); 1406cd6a6acSopenharmony_ci *context = tmpcon; 1416cd6a6acSopenharmony_ci return 0; 1426cd6a6acSopenharmony_ci} 1436cd6a6acSopenharmony_ci 1446cd6a6acSopenharmony_civoid set_matchpathcon_canoncon(int (*f) (const char *p, unsigned l, char **c)) 1456cd6a6acSopenharmony_ci{ 1466cd6a6acSopenharmony_ci if (f) 1476cd6a6acSopenharmony_ci mycanoncon = f; 1486cd6a6acSopenharmony_ci else 1496cd6a6acSopenharmony_ci mycanoncon = &default_canoncon; 1506cd6a6acSopenharmony_ci} 1516cd6a6acSopenharmony_ci 1526cd6a6acSopenharmony_cistatic __thread struct selinux_opt options[SELABEL_NOPT]; 1536cd6a6acSopenharmony_cistatic __thread int notrans; 1546cd6a6acSopenharmony_ci 1556cd6a6acSopenharmony_civoid set_matchpathcon_flags(unsigned int flags) 1566cd6a6acSopenharmony_ci{ 1576cd6a6acSopenharmony_ci int i; 1586cd6a6acSopenharmony_ci memset(options, 0, sizeof(options)); 1596cd6a6acSopenharmony_ci i = SELABEL_OPT_BASEONLY; 1606cd6a6acSopenharmony_ci options[i].type = i; 1616cd6a6acSopenharmony_ci options[i].value = (flags & MATCHPATHCON_BASEONLY) ? (char*)1 : NULL; 1626cd6a6acSopenharmony_ci i = SELABEL_OPT_VALIDATE; 1636cd6a6acSopenharmony_ci options[i].type = i; 1646cd6a6acSopenharmony_ci options[i].value = (flags & MATCHPATHCON_VALIDATE) ? (char*)1 : NULL; 1656cd6a6acSopenharmony_ci notrans = flags & MATCHPATHCON_NOTRANS; 1666cd6a6acSopenharmony_ci} 1676cd6a6acSopenharmony_ci 1686cd6a6acSopenharmony_ci/* 1696cd6a6acSopenharmony_ci * An association between an inode and a 1706cd6a6acSopenharmony_ci * specification. 1716cd6a6acSopenharmony_ci */ 1726cd6a6acSopenharmony_citypedef struct file_spec { 1736cd6a6acSopenharmony_ci ino_t ino; /* inode number */ 1746cd6a6acSopenharmony_ci int specind; /* index of specification in spec */ 1756cd6a6acSopenharmony_ci char *file; /* full pathname for diagnostic messages about conflicts */ 1766cd6a6acSopenharmony_ci struct file_spec *next; /* next association in hash bucket chain */ 1776cd6a6acSopenharmony_ci} file_spec_t; 1786cd6a6acSopenharmony_ci 1796cd6a6acSopenharmony_ci/* 1806cd6a6acSopenharmony_ci * The hash table of associations, hashed by inode number. 1816cd6a6acSopenharmony_ci * Chaining is used for collisions, with elements ordered 1826cd6a6acSopenharmony_ci * by inode number in each bucket. Each hash bucket has a dummy 1836cd6a6acSopenharmony_ci * header. 1846cd6a6acSopenharmony_ci */ 1856cd6a6acSopenharmony_ci#define HASH_BITS 16 1866cd6a6acSopenharmony_ci#define HASH_BUCKETS (1 << HASH_BITS) 1876cd6a6acSopenharmony_ci#define HASH_MASK (HASH_BUCKETS-1) 1886cd6a6acSopenharmony_cistatic file_spec_t *fl_head; 1896cd6a6acSopenharmony_ci 1906cd6a6acSopenharmony_ci/* 1916cd6a6acSopenharmony_ci * Try to add an association between an inode and 1926cd6a6acSopenharmony_ci * a specification. If there is already an association 1936cd6a6acSopenharmony_ci * for the inode and it conflicts with this specification, 1946cd6a6acSopenharmony_ci * then use the specification that occurs later in the 1956cd6a6acSopenharmony_ci * specification array. 1966cd6a6acSopenharmony_ci */ 1976cd6a6acSopenharmony_ciint matchpathcon_filespec_add(ino_t ino, int specind, const char *file) 1986cd6a6acSopenharmony_ci{ 1996cd6a6acSopenharmony_ci file_spec_t *prevfl, *fl; 2006cd6a6acSopenharmony_ci int h, ret; 2016cd6a6acSopenharmony_ci struct stat sb; 2026cd6a6acSopenharmony_ci 2036cd6a6acSopenharmony_ci if (!fl_head) { 2046cd6a6acSopenharmony_ci fl_head = malloc(sizeof(file_spec_t) * HASH_BUCKETS); 2056cd6a6acSopenharmony_ci if (!fl_head) 2066cd6a6acSopenharmony_ci goto oom; 2076cd6a6acSopenharmony_ci memset(fl_head, 0, sizeof(file_spec_t) * HASH_BUCKETS); 2086cd6a6acSopenharmony_ci } 2096cd6a6acSopenharmony_ci 2106cd6a6acSopenharmony_ci h = (ino + (ino >> HASH_BITS)) & HASH_MASK; 2116cd6a6acSopenharmony_ci for (prevfl = &fl_head[h], fl = fl_head[h].next; fl; 2126cd6a6acSopenharmony_ci prevfl = fl, fl = fl->next) { 2136cd6a6acSopenharmony_ci if (ino == fl->ino) { 2146cd6a6acSopenharmony_ci ret = lstat(fl->file, &sb); 2156cd6a6acSopenharmony_ci if (ret < 0 || sb.st_ino != ino) { 2166cd6a6acSopenharmony_ci fl->specind = specind; 2176cd6a6acSopenharmony_ci free(fl->file); 2186cd6a6acSopenharmony_ci fl->file = strdup(file); 2196cd6a6acSopenharmony_ci if (!fl->file) 2206cd6a6acSopenharmony_ci goto oom; 2216cd6a6acSopenharmony_ci return fl->specind; 2226cd6a6acSopenharmony_ci 2236cd6a6acSopenharmony_ci } 2246cd6a6acSopenharmony_ci 2256cd6a6acSopenharmony_ci if (!strcmp(con_array[fl->specind], 2266cd6a6acSopenharmony_ci con_array[specind])) 2276cd6a6acSopenharmony_ci return fl->specind; 2286cd6a6acSopenharmony_ci 2296cd6a6acSopenharmony_ci myprintf 2306cd6a6acSopenharmony_ci ("%s: conflicting specifications for %s and %s, using %s.\n", 2316cd6a6acSopenharmony_ci __FUNCTION__, file, fl->file, 2326cd6a6acSopenharmony_ci con_array[fl->specind]); 2336cd6a6acSopenharmony_ci free(fl->file); 2346cd6a6acSopenharmony_ci fl->file = strdup(file); 2356cd6a6acSopenharmony_ci if (!fl->file) 2366cd6a6acSopenharmony_ci goto oom; 2376cd6a6acSopenharmony_ci return fl->specind; 2386cd6a6acSopenharmony_ci } 2396cd6a6acSopenharmony_ci 2406cd6a6acSopenharmony_ci if (ino > fl->ino) 2416cd6a6acSopenharmony_ci break; 2426cd6a6acSopenharmony_ci } 2436cd6a6acSopenharmony_ci 2446cd6a6acSopenharmony_ci fl = malloc(sizeof(file_spec_t)); 2456cd6a6acSopenharmony_ci if (!fl) 2466cd6a6acSopenharmony_ci goto oom; 2476cd6a6acSopenharmony_ci fl->ino = ino; 2486cd6a6acSopenharmony_ci fl->specind = specind; 2496cd6a6acSopenharmony_ci fl->file = strdup(file); 2506cd6a6acSopenharmony_ci if (!fl->file) 2516cd6a6acSopenharmony_ci goto oom_freefl; 2526cd6a6acSopenharmony_ci fl->next = prevfl->next; 2536cd6a6acSopenharmony_ci prevfl->next = fl; 2546cd6a6acSopenharmony_ci return fl->specind; 2556cd6a6acSopenharmony_ci oom_freefl: 2566cd6a6acSopenharmony_ci free(fl); 2576cd6a6acSopenharmony_ci oom: 2586cd6a6acSopenharmony_ci myprintf("%s: insufficient memory for file label entry for %s\n", 2596cd6a6acSopenharmony_ci __FUNCTION__, file); 2606cd6a6acSopenharmony_ci return -1; 2616cd6a6acSopenharmony_ci} 2626cd6a6acSopenharmony_ci 2636cd6a6acSopenharmony_ci/* 2646cd6a6acSopenharmony_ci * Evaluate the association hash table distribution. 2656cd6a6acSopenharmony_ci */ 2666cd6a6acSopenharmony_civoid matchpathcon_filespec_eval(void) 2676cd6a6acSopenharmony_ci{ 2686cd6a6acSopenharmony_ci file_spec_t *fl; 2696cd6a6acSopenharmony_ci int h, used, nel, len, longest; 2706cd6a6acSopenharmony_ci 2716cd6a6acSopenharmony_ci if (!fl_head) 2726cd6a6acSopenharmony_ci return; 2736cd6a6acSopenharmony_ci 2746cd6a6acSopenharmony_ci used = 0; 2756cd6a6acSopenharmony_ci longest = 0; 2766cd6a6acSopenharmony_ci nel = 0; 2776cd6a6acSopenharmony_ci for (h = 0; h < HASH_BUCKETS; h++) { 2786cd6a6acSopenharmony_ci len = 0; 2796cd6a6acSopenharmony_ci for (fl = fl_head[h].next; fl; fl = fl->next) { 2806cd6a6acSopenharmony_ci len++; 2816cd6a6acSopenharmony_ci } 2826cd6a6acSopenharmony_ci if (len) 2836cd6a6acSopenharmony_ci used++; 2846cd6a6acSopenharmony_ci if (len > longest) 2856cd6a6acSopenharmony_ci longest = len; 2866cd6a6acSopenharmony_ci nel += len; 2876cd6a6acSopenharmony_ci } 2886cd6a6acSopenharmony_ci 2896cd6a6acSopenharmony_ci myprintf 2906cd6a6acSopenharmony_ci ("%s: hash table stats: %d elements, %d/%d buckets used, longest chain length %d\n", 2916cd6a6acSopenharmony_ci __FUNCTION__, nel, used, HASH_BUCKETS, longest); 2926cd6a6acSopenharmony_ci} 2936cd6a6acSopenharmony_ci 2946cd6a6acSopenharmony_ci/* 2956cd6a6acSopenharmony_ci * Destroy the association hash table. 2966cd6a6acSopenharmony_ci */ 2976cd6a6acSopenharmony_civoid matchpathcon_filespec_destroy(void) 2986cd6a6acSopenharmony_ci{ 2996cd6a6acSopenharmony_ci file_spec_t *fl, *tmp; 3006cd6a6acSopenharmony_ci int h; 3016cd6a6acSopenharmony_ci 3026cd6a6acSopenharmony_ci free_array_elts(); 3036cd6a6acSopenharmony_ci 3046cd6a6acSopenharmony_ci if (!fl_head) 3056cd6a6acSopenharmony_ci return; 3066cd6a6acSopenharmony_ci 3076cd6a6acSopenharmony_ci for (h = 0; h < HASH_BUCKETS; h++) { 3086cd6a6acSopenharmony_ci fl = fl_head[h].next; 3096cd6a6acSopenharmony_ci while (fl) { 3106cd6a6acSopenharmony_ci tmp = fl; 3116cd6a6acSopenharmony_ci fl = fl->next; 3126cd6a6acSopenharmony_ci free(tmp->file); 3136cd6a6acSopenharmony_ci free(tmp); 3146cd6a6acSopenharmony_ci } 3156cd6a6acSopenharmony_ci fl_head[h].next = NULL; 3166cd6a6acSopenharmony_ci } 3176cd6a6acSopenharmony_ci free(fl_head); 3186cd6a6acSopenharmony_ci fl_head = NULL; 3196cd6a6acSopenharmony_ci} 3206cd6a6acSopenharmony_ci 3216cd6a6acSopenharmony_cistatic void matchpathcon_fini_internal(void) 3226cd6a6acSopenharmony_ci{ 3236cd6a6acSopenharmony_ci free_array_elts(); 3246cd6a6acSopenharmony_ci 3256cd6a6acSopenharmony_ci if (hnd) { 3266cd6a6acSopenharmony_ci selabel_close(hnd); 3276cd6a6acSopenharmony_ci hnd = NULL; 3286cd6a6acSopenharmony_ci } 3296cd6a6acSopenharmony_ci} 3306cd6a6acSopenharmony_ci 3316cd6a6acSopenharmony_cistatic void matchpathcon_thread_destructor(void __attribute__((unused)) *ptr) 3326cd6a6acSopenharmony_ci{ 3336cd6a6acSopenharmony_ci matchpathcon_fini_internal(); 3346cd6a6acSopenharmony_ci} 3356cd6a6acSopenharmony_ci 3366cd6a6acSopenharmony_civoid __attribute__((destructor)) matchpathcon_lib_destructor(void); 3376cd6a6acSopenharmony_ci 3386cd6a6acSopenharmony_civoid __attribute__((destructor)) matchpathcon_lib_destructor(void) 3396cd6a6acSopenharmony_ci{ 3406cd6a6acSopenharmony_ci if (destructor_key_initialized) 3416cd6a6acSopenharmony_ci __selinux_key_delete(destructor_key); 3426cd6a6acSopenharmony_ci} 3436cd6a6acSopenharmony_ci 3446cd6a6acSopenharmony_cistatic void matchpathcon_init_once(void) 3456cd6a6acSopenharmony_ci{ 3466cd6a6acSopenharmony_ci if (__selinux_key_create(&destructor_key, matchpathcon_thread_destructor) == 0) 3476cd6a6acSopenharmony_ci destructor_key_initialized = 1; 3486cd6a6acSopenharmony_ci} 3496cd6a6acSopenharmony_ci 3506cd6a6acSopenharmony_ciint matchpathcon_init_prefix(const char *path, const char *subset) 3516cd6a6acSopenharmony_ci{ 3526cd6a6acSopenharmony_ci if (!mycanoncon) 3536cd6a6acSopenharmony_ci mycanoncon = default_canoncon; 3546cd6a6acSopenharmony_ci 3556cd6a6acSopenharmony_ci __selinux_once(once, matchpathcon_init_once); 3566cd6a6acSopenharmony_ci __selinux_setspecific(destructor_key, /* some valid address to please GCC */ &selinux_page_size); 3576cd6a6acSopenharmony_ci 3586cd6a6acSopenharmony_ci options[SELABEL_OPT_SUBSET].type = SELABEL_OPT_SUBSET; 3596cd6a6acSopenharmony_ci options[SELABEL_OPT_SUBSET].value = subset; 3606cd6a6acSopenharmony_ci options[SELABEL_OPT_PATH].type = SELABEL_OPT_PATH; 3616cd6a6acSopenharmony_ci options[SELABEL_OPT_PATH].value = path; 3626cd6a6acSopenharmony_ci 3636cd6a6acSopenharmony_ci hnd = selabel_open(SELABEL_CTX_FILE, options, SELABEL_NOPT); 3646cd6a6acSopenharmony_ci return hnd ? 0 : -1; 3656cd6a6acSopenharmony_ci} 3666cd6a6acSopenharmony_ci 3676cd6a6acSopenharmony_ci 3686cd6a6acSopenharmony_ciint matchpathcon_init(const char *path) 3696cd6a6acSopenharmony_ci{ 3706cd6a6acSopenharmony_ci return matchpathcon_init_prefix(path, NULL); 3716cd6a6acSopenharmony_ci} 3726cd6a6acSopenharmony_ci 3736cd6a6acSopenharmony_civoid matchpathcon_fini(void) 3746cd6a6acSopenharmony_ci{ 3756cd6a6acSopenharmony_ci matchpathcon_fini_internal(); 3766cd6a6acSopenharmony_ci} 3776cd6a6acSopenharmony_ci 3786cd6a6acSopenharmony_ci/* 3796cd6a6acSopenharmony_ci * We do not want to resolve a symlink to a real path if it is the final 3806cd6a6acSopenharmony_ci * component of the name. Thus we split the pathname on the last "/" and 3816cd6a6acSopenharmony_ci * determine a real path component of the first portion. We then have to 3826cd6a6acSopenharmony_ci * copy the last part back on to get the final real path. Wheww. 3836cd6a6acSopenharmony_ci */ 3846cd6a6acSopenharmony_ciint realpath_not_final(const char *name, char *resolved_path) 3856cd6a6acSopenharmony_ci{ 3866cd6a6acSopenharmony_ci char *last_component; 3876cd6a6acSopenharmony_ci char *tmp_path, *p; 3886cd6a6acSopenharmony_ci size_t len = 0; 3896cd6a6acSopenharmony_ci int rc = 0; 3906cd6a6acSopenharmony_ci 3916cd6a6acSopenharmony_ci tmp_path = strdup(name); 3926cd6a6acSopenharmony_ci if (!tmp_path) { 3936cd6a6acSopenharmony_ci myprintf("symlink_realpath(%s) strdup() failed: %m\n", 3946cd6a6acSopenharmony_ci name); 3956cd6a6acSopenharmony_ci rc = -1; 3966cd6a6acSopenharmony_ci goto out; 3976cd6a6acSopenharmony_ci } 3986cd6a6acSopenharmony_ci 3996cd6a6acSopenharmony_ci last_component = strrchr(tmp_path, '/'); 4006cd6a6acSopenharmony_ci 4016cd6a6acSopenharmony_ci if (last_component == tmp_path) { 4026cd6a6acSopenharmony_ci last_component++; 4036cd6a6acSopenharmony_ci p = strcpy(resolved_path, ""); 4046cd6a6acSopenharmony_ci } else if (last_component) { 4056cd6a6acSopenharmony_ci *last_component = '\0'; 4066cd6a6acSopenharmony_ci last_component++; 4076cd6a6acSopenharmony_ci p = realpath(tmp_path, resolved_path); 4086cd6a6acSopenharmony_ci } else { 4096cd6a6acSopenharmony_ci last_component = tmp_path; 4106cd6a6acSopenharmony_ci p = realpath("./", resolved_path); 4116cd6a6acSopenharmony_ci } 4126cd6a6acSopenharmony_ci 4136cd6a6acSopenharmony_ci if (!p) { 4146cd6a6acSopenharmony_ci myprintf("symlink_realpath(%s) realpath() failed: %m\n", 4156cd6a6acSopenharmony_ci name); 4166cd6a6acSopenharmony_ci rc = -1; 4176cd6a6acSopenharmony_ci goto out; 4186cd6a6acSopenharmony_ci } 4196cd6a6acSopenharmony_ci 4206cd6a6acSopenharmony_ci len = strlen(p); 4216cd6a6acSopenharmony_ci if (len + strlen(last_component) + 2 > PATH_MAX) { 4226cd6a6acSopenharmony_ci myprintf("symlink_realpath(%s) failed: Filename too long \n", 4236cd6a6acSopenharmony_ci name); 4246cd6a6acSopenharmony_ci errno = ENAMETOOLONG; 4256cd6a6acSopenharmony_ci rc = -1; 4266cd6a6acSopenharmony_ci goto out; 4276cd6a6acSopenharmony_ci } 4286cd6a6acSopenharmony_ci 4296cd6a6acSopenharmony_ci resolved_path += len; 4306cd6a6acSopenharmony_ci strcpy(resolved_path, "/"); 4316cd6a6acSopenharmony_ci resolved_path += 1; 4326cd6a6acSopenharmony_ci strcpy(resolved_path, last_component); 4336cd6a6acSopenharmony_ciout: 4346cd6a6acSopenharmony_ci free(tmp_path); 4356cd6a6acSopenharmony_ci return rc; 4366cd6a6acSopenharmony_ci} 4376cd6a6acSopenharmony_ci 4386cd6a6acSopenharmony_cistatic int matchpathcon_internal(const char *path, mode_t mode, char ** con) 4396cd6a6acSopenharmony_ci{ 4406cd6a6acSopenharmony_ci char stackpath[PATH_MAX + 1]; 4416cd6a6acSopenharmony_ci char *p = NULL; 4426cd6a6acSopenharmony_ci if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) 4436cd6a6acSopenharmony_ci return -1; 4446cd6a6acSopenharmony_ci 4456cd6a6acSopenharmony_ci if (S_ISLNK(mode)) { 4466cd6a6acSopenharmony_ci if (!realpath_not_final(path, stackpath)) 4476cd6a6acSopenharmony_ci path = stackpath; 4486cd6a6acSopenharmony_ci } else { 4496cd6a6acSopenharmony_ci p = realpath(path, stackpath); 4506cd6a6acSopenharmony_ci if (p) 4516cd6a6acSopenharmony_ci path = p; 4526cd6a6acSopenharmony_ci } 4536cd6a6acSopenharmony_ci 4546cd6a6acSopenharmony_ci return notrans ? 4556cd6a6acSopenharmony_ci selabel_lookup_raw(hnd, con, path, mode) : 4566cd6a6acSopenharmony_ci selabel_lookup(hnd, con, path, mode); 4576cd6a6acSopenharmony_ci} 4586cd6a6acSopenharmony_ci 4596cd6a6acSopenharmony_ciint matchpathcon(const char *path, mode_t mode, char ** con) { 4606cd6a6acSopenharmony_ci return matchpathcon_internal(path, mode, con); 4616cd6a6acSopenharmony_ci} 4626cd6a6acSopenharmony_ci 4636cd6a6acSopenharmony_ciint matchpathcon_index(const char *name, mode_t mode, char ** con) 4646cd6a6acSopenharmony_ci{ 4656cd6a6acSopenharmony_ci int i = matchpathcon_internal(name, mode, con); 4666cd6a6acSopenharmony_ci 4676cd6a6acSopenharmony_ci if (i < 0) 4686cd6a6acSopenharmony_ci return -1; 4696cd6a6acSopenharmony_ci 4706cd6a6acSopenharmony_ci return add_array_elt(*con); 4716cd6a6acSopenharmony_ci} 4726cd6a6acSopenharmony_ci 4736cd6a6acSopenharmony_civoid matchpathcon_checkmatches(char *str __attribute__((unused))) 4746cd6a6acSopenharmony_ci{ 4756cd6a6acSopenharmony_ci selabel_stats(hnd); 4766cd6a6acSopenharmony_ci} 4776cd6a6acSopenharmony_ci 4786cd6a6acSopenharmony_ci/* Compare two contexts to see if their differences are "significant", 4796cd6a6acSopenharmony_ci * or whether the only difference is in the user. */ 4806cd6a6acSopenharmony_ciint selinux_file_context_cmp(const char * a, 4816cd6a6acSopenharmony_ci const char * b) 4826cd6a6acSopenharmony_ci{ 4836cd6a6acSopenharmony_ci const char *rest_a, *rest_b; /* Rest of the context after the user */ 4846cd6a6acSopenharmony_ci if (!a && !b) 4856cd6a6acSopenharmony_ci return 0; 4866cd6a6acSopenharmony_ci if (!a) 4876cd6a6acSopenharmony_ci return -1; 4886cd6a6acSopenharmony_ci if (!b) 4896cd6a6acSopenharmony_ci return 1; 4906cd6a6acSopenharmony_ci rest_a = strchr(a, ':'); 4916cd6a6acSopenharmony_ci rest_b = strchr(b, ':'); 4926cd6a6acSopenharmony_ci if (!rest_a && !rest_b) 4936cd6a6acSopenharmony_ci return 0; 4946cd6a6acSopenharmony_ci if (!rest_a) 4956cd6a6acSopenharmony_ci return -1; 4966cd6a6acSopenharmony_ci if (!rest_b) 4976cd6a6acSopenharmony_ci return 1; 4986cd6a6acSopenharmony_ci return strcmp(rest_a, rest_b); 4996cd6a6acSopenharmony_ci} 5006cd6a6acSopenharmony_ci 5016cd6a6acSopenharmony_ciint selinux_file_context_verify(const char *path, mode_t mode) 5026cd6a6acSopenharmony_ci{ 5036cd6a6acSopenharmony_ci char * con = NULL; 5046cd6a6acSopenharmony_ci char * fcontext = NULL; 5056cd6a6acSopenharmony_ci int rc = 0; 5066cd6a6acSopenharmony_ci char stackpath[PATH_MAX + 1]; 5076cd6a6acSopenharmony_ci char *p = NULL; 5086cd6a6acSopenharmony_ci 5096cd6a6acSopenharmony_ci if (S_ISLNK(mode)) { 5106cd6a6acSopenharmony_ci if (!realpath_not_final(path, stackpath)) 5116cd6a6acSopenharmony_ci path = stackpath; 5126cd6a6acSopenharmony_ci } else { 5136cd6a6acSopenharmony_ci p = realpath(path, stackpath); 5146cd6a6acSopenharmony_ci if (p) 5156cd6a6acSopenharmony_ci path = p; 5166cd6a6acSopenharmony_ci } 5176cd6a6acSopenharmony_ci 5186cd6a6acSopenharmony_ci rc = lgetfilecon_raw(path, &con); 5196cd6a6acSopenharmony_ci if (rc == -1) { 5206cd6a6acSopenharmony_ci if (errno != ENOTSUP) 5216cd6a6acSopenharmony_ci return -1; 5226cd6a6acSopenharmony_ci else 5236cd6a6acSopenharmony_ci return 0; 5246cd6a6acSopenharmony_ci } 5256cd6a6acSopenharmony_ci 5266cd6a6acSopenharmony_ci if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) 5276cd6a6acSopenharmony_ci return -1; 5286cd6a6acSopenharmony_ci 5296cd6a6acSopenharmony_ci if (selabel_lookup_raw(hnd, &fcontext, path, mode) != 0) { 5306cd6a6acSopenharmony_ci if (errno != ENOENT) 5316cd6a6acSopenharmony_ci rc = -1; 5326cd6a6acSopenharmony_ci else 5336cd6a6acSopenharmony_ci rc = 0; 5346cd6a6acSopenharmony_ci } else { 5356cd6a6acSopenharmony_ci /* 5366cd6a6acSopenharmony_ci * Need to set errno to 0 as it can be set to ENOENT if the 5376cd6a6acSopenharmony_ci * file_contexts.subs file does not exist (see selabel_open in 5386cd6a6acSopenharmony_ci * label.c), thus causing confusion if errno is checked on return. 5396cd6a6acSopenharmony_ci */ 5406cd6a6acSopenharmony_ci errno = 0; 5416cd6a6acSopenharmony_ci rc = (selinux_file_context_cmp(fcontext, con) == 0); 5426cd6a6acSopenharmony_ci } 5436cd6a6acSopenharmony_ci 5446cd6a6acSopenharmony_ci freecon(con); 5456cd6a6acSopenharmony_ci freecon(fcontext); 5466cd6a6acSopenharmony_ci return rc; 5476cd6a6acSopenharmony_ci} 5486cd6a6acSopenharmony_ci 5496cd6a6acSopenharmony_ciint selinux_lsetfilecon_default(const char *path) 5506cd6a6acSopenharmony_ci{ 5516cd6a6acSopenharmony_ci struct stat st; 5526cd6a6acSopenharmony_ci int rc = -1; 5536cd6a6acSopenharmony_ci char * scontext = NULL; 5546cd6a6acSopenharmony_ci if (lstat(path, &st) != 0) 5556cd6a6acSopenharmony_ci return rc; 5566cd6a6acSopenharmony_ci 5576cd6a6acSopenharmony_ci if (!hnd && (matchpathcon_init_prefix(NULL, NULL) < 0)) 5586cd6a6acSopenharmony_ci return -1; 5596cd6a6acSopenharmony_ci 5606cd6a6acSopenharmony_ci /* If there's an error determining the context, or it has none, 5616cd6a6acSopenharmony_ci return to allow default context */ 5626cd6a6acSopenharmony_ci if (selabel_lookup_raw(hnd, &scontext, path, st.st_mode)) { 5636cd6a6acSopenharmony_ci if (errno == ENOENT) 5646cd6a6acSopenharmony_ci rc = 0; 5656cd6a6acSopenharmony_ci } else { 5666cd6a6acSopenharmony_ci rc = lsetfilecon_raw(path, scontext); 5676cd6a6acSopenharmony_ci freecon(scontext); 5686cd6a6acSopenharmony_ci } 5696cd6a6acSopenharmony_ci return rc; 5706cd6a6acSopenharmony_ci} 5716cd6a6acSopenharmony_ci 5726cd6a6acSopenharmony_ci#endif 573