18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: 68c2ecf20Sopenharmony_ci * Casey Schaufler <casey@schaufler-ca.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/types.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/fs.h> 128c2ecf20Sopenharmony_ci#include <linux/sched.h> 138c2ecf20Sopenharmony_ci#include "smack.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct smack_known smack_known_huh = { 168c2ecf20Sopenharmony_ci .smk_known = "?", 178c2ecf20Sopenharmony_ci .smk_secid = 2, 188c2ecf20Sopenharmony_ci}; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct smack_known smack_known_hat = { 218c2ecf20Sopenharmony_ci .smk_known = "^", 228c2ecf20Sopenharmony_ci .smk_secid = 3, 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct smack_known smack_known_star = { 268c2ecf20Sopenharmony_ci .smk_known = "*", 278c2ecf20Sopenharmony_ci .smk_secid = 4, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct smack_known smack_known_floor = { 318c2ecf20Sopenharmony_ci .smk_known = "_", 328c2ecf20Sopenharmony_ci .smk_secid = 5, 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct smack_known smack_known_web = { 368c2ecf20Sopenharmony_ci .smk_known = "@", 378c2ecf20Sopenharmony_ci .smk_secid = 7, 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciLIST_HEAD(smack_known_list); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * The initial value needs to be bigger than any of the 448c2ecf20Sopenharmony_ci * known values above. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_cistatic u32 smack_next_secid = 10; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * what events do we log 508c2ecf20Sopenharmony_ci * can be overwritten at run-time by /smack/logging 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ciint log_policy = SMACK_AUDIT_DENIED; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * smk_access_entry - look up matching access rule 568c2ecf20Sopenharmony_ci * @subject_label: a pointer to the subject's Smack label 578c2ecf20Sopenharmony_ci * @object_label: a pointer to the object's Smack label 588c2ecf20Sopenharmony_ci * @rule_list: the list of rules to search 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * This function looks up the subject/object pair in the 618c2ecf20Sopenharmony_ci * access rule list and returns the access mode. If no 628c2ecf20Sopenharmony_ci * entry is found returns -ENOENT. 638c2ecf20Sopenharmony_ci * 648c2ecf20Sopenharmony_ci * NOTE: 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * Earlier versions of this function allowed for labels that 678c2ecf20Sopenharmony_ci * were not on the label list. This was done to allow for 688c2ecf20Sopenharmony_ci * labels to come over the network that had never been seen 698c2ecf20Sopenharmony_ci * before on this host. Unless the receiving socket has the 708c2ecf20Sopenharmony_ci * star label this will always result in a failure check. The 718c2ecf20Sopenharmony_ci * star labeled socket case is now handled in the networking 728c2ecf20Sopenharmony_ci * hooks so there is no case where the label is not on the 738c2ecf20Sopenharmony_ci * label list. Checking to see if the address of two labels 748c2ecf20Sopenharmony_ci * is the same is now a reliable test. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * Do the object check first because that is more 778c2ecf20Sopenharmony_ci * likely to differ. 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * Allowing write access implies allowing locking. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ciint smk_access_entry(char *subject_label, char *object_label, 828c2ecf20Sopenharmony_ci struct list_head *rule_list) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci struct smack_rule *srp; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci list_for_each_entry_rcu(srp, rule_list, list) { 878c2ecf20Sopenharmony_ci if (srp->smk_object->smk_known == object_label && 888c2ecf20Sopenharmony_ci srp->smk_subject->smk_known == subject_label) { 898c2ecf20Sopenharmony_ci int may = srp->smk_access; 908c2ecf20Sopenharmony_ci /* 918c2ecf20Sopenharmony_ci * MAY_WRITE implies MAY_LOCK. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci if ((may & MAY_WRITE) == MAY_WRITE) 948c2ecf20Sopenharmony_ci may |= MAY_LOCK; 958c2ecf20Sopenharmony_ci return may; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return -ENOENT; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/** 1038c2ecf20Sopenharmony_ci * smk_access - determine if a subject has a specific access to an object 1048c2ecf20Sopenharmony_ci * @subject: a pointer to the subject's Smack label entry 1058c2ecf20Sopenharmony_ci * @object: a pointer to the object's Smack label entry 1068c2ecf20Sopenharmony_ci * @request: the access requested, in "MAY" format 1078c2ecf20Sopenharmony_ci * @a : a pointer to the audit data 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * This function looks up the subject/object pair in the 1108c2ecf20Sopenharmony_ci * access rule list and returns 0 if the access is permitted, 1118c2ecf20Sopenharmony_ci * non zero otherwise. 1128c2ecf20Sopenharmony_ci * 1138c2ecf20Sopenharmony_ci * Smack labels are shared on smack_list 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ciint smk_access(struct smack_known *subject, struct smack_known *object, 1168c2ecf20Sopenharmony_ci int request, struct smk_audit_info *a) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci int may = MAY_NOT; 1198c2ecf20Sopenharmony_ci int rc = 0; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * Hardcoded comparisons. 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * A star subject can't access any object. 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci if (subject == &smack_known_star) { 1288c2ecf20Sopenharmony_ci rc = -EACCES; 1298c2ecf20Sopenharmony_ci goto out_audit; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * An internet object can be accessed by any subject. 1338c2ecf20Sopenharmony_ci * Tasks cannot be assigned the internet label. 1348c2ecf20Sopenharmony_ci * An internet subject can access any object. 1358c2ecf20Sopenharmony_ci */ 1368c2ecf20Sopenharmony_ci if (object == &smack_known_web || subject == &smack_known_web) 1378c2ecf20Sopenharmony_ci goto out_audit; 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * A star object can be accessed by any subject. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ci if (object == &smack_known_star) 1428c2ecf20Sopenharmony_ci goto out_audit; 1438c2ecf20Sopenharmony_ci /* 1448c2ecf20Sopenharmony_ci * An object can be accessed in any way by a subject 1458c2ecf20Sopenharmony_ci * with the same label. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (subject->smk_known == object->smk_known) 1488c2ecf20Sopenharmony_ci goto out_audit; 1498c2ecf20Sopenharmony_ci /* 1508c2ecf20Sopenharmony_ci * A hat subject can read or lock any object. 1518c2ecf20Sopenharmony_ci * A floor object can be read or locked by any subject. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_ci if ((request & MAY_ANYREAD) == request || 1548c2ecf20Sopenharmony_ci (request & MAY_LOCK) == request) { 1558c2ecf20Sopenharmony_ci if (object == &smack_known_floor) 1568c2ecf20Sopenharmony_ci goto out_audit; 1578c2ecf20Sopenharmony_ci if (subject == &smack_known_hat) 1588c2ecf20Sopenharmony_ci goto out_audit; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * Beyond here an explicit relationship is required. 1628c2ecf20Sopenharmony_ci * If the requested access is contained in the available 1638c2ecf20Sopenharmony_ci * access (e.g. read is included in readwrite) it's 1648c2ecf20Sopenharmony_ci * good. A negative response from smk_access_entry() 1658c2ecf20Sopenharmony_ci * indicates there is no entry for this pair. 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci rcu_read_lock(); 1688c2ecf20Sopenharmony_ci may = smk_access_entry(subject->smk_known, object->smk_known, 1698c2ecf20Sopenharmony_ci &subject->smk_rules); 1708c2ecf20Sopenharmony_ci rcu_read_unlock(); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (may <= 0 || (request & may) != request) { 1738c2ecf20Sopenharmony_ci rc = -EACCES; 1748c2ecf20Sopenharmony_ci goto out_audit; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * Return a positive value if using bringup mode. 1798c2ecf20Sopenharmony_ci * This allows the hooks to identify checks that 1808c2ecf20Sopenharmony_ci * succeed because of "b" rules. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci if (may & MAY_BRINGUP) 1838c2ecf20Sopenharmony_ci rc = SMACK_BRINGUP_ALLOW; 1848c2ecf20Sopenharmony_ci#endif 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ciout_audit: 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 1898c2ecf20Sopenharmony_ci if (rc < 0) { 1908c2ecf20Sopenharmony_ci if (object == smack_unconfined) 1918c2ecf20Sopenharmony_ci rc = SMACK_UNCONFINED_OBJECT; 1928c2ecf20Sopenharmony_ci if (subject == smack_unconfined) 1938c2ecf20Sopenharmony_ci rc = SMACK_UNCONFINED_SUBJECT; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci#endif 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 1988c2ecf20Sopenharmony_ci if (a) 1998c2ecf20Sopenharmony_ci smack_log(subject->smk_known, object->smk_known, 2008c2ecf20Sopenharmony_ci request, rc, a); 2018c2ecf20Sopenharmony_ci#endif 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return rc; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/** 2078c2ecf20Sopenharmony_ci * smk_tskacc - determine if a task has a specific access to an object 2088c2ecf20Sopenharmony_ci * @tsp: a pointer to the subject's task 2098c2ecf20Sopenharmony_ci * @obj_known: a pointer to the object's label entry 2108c2ecf20Sopenharmony_ci * @mode: the access requested, in "MAY" format 2118c2ecf20Sopenharmony_ci * @a : common audit data 2128c2ecf20Sopenharmony_ci * 2138c2ecf20Sopenharmony_ci * This function checks the subject task's label/object label pair 2148c2ecf20Sopenharmony_ci * in the access rule list and returns 0 if the access is permitted, 2158c2ecf20Sopenharmony_ci * non zero otherwise. It allows that the task may have the capability 2168c2ecf20Sopenharmony_ci * to override the rules. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ciint smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known, 2198c2ecf20Sopenharmony_ci u32 mode, struct smk_audit_info *a) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct smack_known *sbj_known = smk_of_task(tsp); 2228c2ecf20Sopenharmony_ci int may; 2238c2ecf20Sopenharmony_ci int rc; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * Check the global rule list 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci rc = smk_access(sbj_known, obj_known, mode, NULL); 2298c2ecf20Sopenharmony_ci if (rc >= 0) { 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * If there is an entry in the task's rule list 2328c2ecf20Sopenharmony_ci * it can further restrict access. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci may = smk_access_entry(sbj_known->smk_known, 2358c2ecf20Sopenharmony_ci obj_known->smk_known, 2368c2ecf20Sopenharmony_ci &tsp->smk_rules); 2378c2ecf20Sopenharmony_ci if (may < 0) 2388c2ecf20Sopenharmony_ci goto out_audit; 2398c2ecf20Sopenharmony_ci if ((mode & may) == mode) 2408c2ecf20Sopenharmony_ci goto out_audit; 2418c2ecf20Sopenharmony_ci rc = -EACCES; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* 2458c2ecf20Sopenharmony_ci * Allow for priviliged to override policy. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE)) 2488c2ecf20Sopenharmony_ci rc = 0; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ciout_audit: 2518c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 2528c2ecf20Sopenharmony_ci if (a) 2538c2ecf20Sopenharmony_ci smack_log(sbj_known->smk_known, obj_known->smk_known, 2548c2ecf20Sopenharmony_ci mode, rc, a); 2558c2ecf20Sopenharmony_ci#endif 2568c2ecf20Sopenharmony_ci return rc; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci/** 2608c2ecf20Sopenharmony_ci * smk_curacc - determine if current has a specific access to an object 2618c2ecf20Sopenharmony_ci * @obj_known: a pointer to the object's Smack label entry 2628c2ecf20Sopenharmony_ci * @mode: the access requested, in "MAY" format 2638c2ecf20Sopenharmony_ci * @a : common audit data 2648c2ecf20Sopenharmony_ci * 2658c2ecf20Sopenharmony_ci * This function checks the current subject label/object label pair 2668c2ecf20Sopenharmony_ci * in the access rule list and returns 0 if the access is permitted, 2678c2ecf20Sopenharmony_ci * non zero otherwise. It allows that current may have the capability 2688c2ecf20Sopenharmony_ci * to override the rules. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ciint smk_curacc(struct smack_known *obj_known, 2718c2ecf20Sopenharmony_ci u32 mode, struct smk_audit_info *a) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return smk_tskacc(tsp, obj_known, mode, a); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 2798c2ecf20Sopenharmony_ci/** 2808c2ecf20Sopenharmony_ci * smack_str_from_perm : helper to transalate an int to a 2818c2ecf20Sopenharmony_ci * readable string 2828c2ecf20Sopenharmony_ci * @string : the string to fill 2838c2ecf20Sopenharmony_ci * @access : the int 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_cistatic inline void smack_str_from_perm(char *string, int access) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci int i = 0; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (access & MAY_READ) 2918c2ecf20Sopenharmony_ci string[i++] = 'r'; 2928c2ecf20Sopenharmony_ci if (access & MAY_WRITE) 2938c2ecf20Sopenharmony_ci string[i++] = 'w'; 2948c2ecf20Sopenharmony_ci if (access & MAY_EXEC) 2958c2ecf20Sopenharmony_ci string[i++] = 'x'; 2968c2ecf20Sopenharmony_ci if (access & MAY_APPEND) 2978c2ecf20Sopenharmony_ci string[i++] = 'a'; 2988c2ecf20Sopenharmony_ci if (access & MAY_TRANSMUTE) 2998c2ecf20Sopenharmony_ci string[i++] = 't'; 3008c2ecf20Sopenharmony_ci if (access & MAY_LOCK) 3018c2ecf20Sopenharmony_ci string[i++] = 'l'; 3028c2ecf20Sopenharmony_ci string[i] = '\0'; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci/** 3058c2ecf20Sopenharmony_ci * smack_log_callback - SMACK specific information 3068c2ecf20Sopenharmony_ci * will be called by generic audit code 3078c2ecf20Sopenharmony_ci * @ab : the audit_buffer 3088c2ecf20Sopenharmony_ci * @a : audit_data 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic void smack_log_callback(struct audit_buffer *ab, void *a) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct common_audit_data *ad = a; 3148c2ecf20Sopenharmony_ci struct smack_audit_data *sad = ad->smack_audit_data; 3158c2ecf20Sopenharmony_ci audit_log_format(ab, "lsm=SMACK fn=%s action=%s", 3168c2ecf20Sopenharmony_ci ad->smack_audit_data->function, 3178c2ecf20Sopenharmony_ci sad->result ? "denied" : "granted"); 3188c2ecf20Sopenharmony_ci audit_log_format(ab, " subject="); 3198c2ecf20Sopenharmony_ci audit_log_untrustedstring(ab, sad->subject); 3208c2ecf20Sopenharmony_ci audit_log_format(ab, " object="); 3218c2ecf20Sopenharmony_ci audit_log_untrustedstring(ab, sad->object); 3228c2ecf20Sopenharmony_ci if (sad->request[0] == '\0') 3238c2ecf20Sopenharmony_ci audit_log_format(ab, " labels_differ"); 3248c2ecf20Sopenharmony_ci else 3258c2ecf20Sopenharmony_ci audit_log_format(ab, " requested=%s", sad->request); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/** 3298c2ecf20Sopenharmony_ci * smack_log - Audit the granting or denial of permissions. 3308c2ecf20Sopenharmony_ci * @subject_label : smack label of the requester 3318c2ecf20Sopenharmony_ci * @object_label : smack label of the object being accessed 3328c2ecf20Sopenharmony_ci * @request: requested permissions 3338c2ecf20Sopenharmony_ci * @result: result from smk_access 3348c2ecf20Sopenharmony_ci * @a: auxiliary audit data 3358c2ecf20Sopenharmony_ci * 3368c2ecf20Sopenharmony_ci * Audit the granting or denial of permissions in accordance 3378c2ecf20Sopenharmony_ci * with the policy. 3388c2ecf20Sopenharmony_ci */ 3398c2ecf20Sopenharmony_civoid smack_log(char *subject_label, char *object_label, int request, 3408c2ecf20Sopenharmony_ci int result, struct smk_audit_info *ad) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 3438c2ecf20Sopenharmony_ci char request_buffer[SMK_NUM_ACCESS_TYPE + 5]; 3448c2ecf20Sopenharmony_ci#else 3458c2ecf20Sopenharmony_ci char request_buffer[SMK_NUM_ACCESS_TYPE + 1]; 3468c2ecf20Sopenharmony_ci#endif 3478c2ecf20Sopenharmony_ci struct smack_audit_data *sad; 3488c2ecf20Sopenharmony_ci struct common_audit_data *a = &ad->a; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci /* check if we have to log the current event */ 3518c2ecf20Sopenharmony_ci if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) 3528c2ecf20Sopenharmony_ci return; 3538c2ecf20Sopenharmony_ci if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) 3548c2ecf20Sopenharmony_ci return; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci sad = a->smack_audit_data; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (sad->function == NULL) 3598c2ecf20Sopenharmony_ci sad->function = "unknown"; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* end preparing the audit data */ 3628c2ecf20Sopenharmony_ci smack_str_from_perm(request_buffer, request); 3638c2ecf20Sopenharmony_ci sad->subject = subject_label; 3648c2ecf20Sopenharmony_ci sad->object = object_label; 3658c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 3668c2ecf20Sopenharmony_ci /* 3678c2ecf20Sopenharmony_ci * The result may be positive in bringup mode. 3688c2ecf20Sopenharmony_ci * A positive result is an allow, but not for normal reasons. 3698c2ecf20Sopenharmony_ci * Mark it as successful, but don't filter it out even if 3708c2ecf20Sopenharmony_ci * the logging policy says to do so. 3718c2ecf20Sopenharmony_ci */ 3728c2ecf20Sopenharmony_ci if (result == SMACK_UNCONFINED_SUBJECT) 3738c2ecf20Sopenharmony_ci strcat(request_buffer, "(US)"); 3748c2ecf20Sopenharmony_ci else if (result == SMACK_UNCONFINED_OBJECT) 3758c2ecf20Sopenharmony_ci strcat(request_buffer, "(UO)"); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (result > 0) 3788c2ecf20Sopenharmony_ci result = 0; 3798c2ecf20Sopenharmony_ci#endif 3808c2ecf20Sopenharmony_ci sad->request = request_buffer; 3818c2ecf20Sopenharmony_ci sad->result = result; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci common_lsm_audit(a, smack_log_callback, NULL); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci#else /* #ifdef CONFIG_AUDIT */ 3868c2ecf20Sopenharmony_civoid smack_log(char *subject_label, char *object_label, int request, 3878c2ecf20Sopenharmony_ci int result, struct smk_audit_info *ad) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci#endif 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ciDEFINE_MUTEX(smack_known_lock); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistruct hlist_head smack_known_hash[SMACK_HASH_SLOTS]; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci/** 3978c2ecf20Sopenharmony_ci * smk_insert_entry - insert a smack label into a hash map, 3988c2ecf20Sopenharmony_ci * 3998c2ecf20Sopenharmony_ci * this function must be called under smack_known_lock 4008c2ecf20Sopenharmony_ci */ 4018c2ecf20Sopenharmony_civoid smk_insert_entry(struct smack_known *skp) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci unsigned int hash; 4048c2ecf20Sopenharmony_ci struct hlist_head *head; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known)); 4078c2ecf20Sopenharmony_ci head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci hlist_add_head_rcu(&skp->smk_hashed, head); 4108c2ecf20Sopenharmony_ci list_add_rcu(&skp->list, &smack_known_list); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/** 4148c2ecf20Sopenharmony_ci * smk_find_entry - find a label on the list, return the list entry 4158c2ecf20Sopenharmony_ci * @string: a text string that might be a Smack label 4168c2ecf20Sopenharmony_ci * 4178c2ecf20Sopenharmony_ci * Returns a pointer to the entry in the label list that 4188c2ecf20Sopenharmony_ci * matches the passed string or NULL if not found. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_cistruct smack_known *smk_find_entry(const char *string) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci unsigned int hash; 4238c2ecf20Sopenharmony_ci struct hlist_head *head; 4248c2ecf20Sopenharmony_ci struct smack_known *skp; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci hash = full_name_hash(NULL, string, strlen(string)); 4278c2ecf20Sopenharmony_ci head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)]; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci hlist_for_each_entry_rcu(skp, head, smk_hashed) 4308c2ecf20Sopenharmony_ci if (strcmp(skp->smk_known, string) == 0) 4318c2ecf20Sopenharmony_ci return skp; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci return NULL; 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/** 4378c2ecf20Sopenharmony_ci * smk_parse_smack - parse smack label from a text string 4388c2ecf20Sopenharmony_ci * @string: a text string that might contain a Smack label 4398c2ecf20Sopenharmony_ci * @len: the maximum size, or zero if it is NULL terminated. 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * Returns a pointer to the clean label or an error code. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_cichar *smk_parse_smack(const char *string, int len) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci char *smack; 4468c2ecf20Sopenharmony_ci int i; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (len <= 0) 4498c2ecf20Sopenharmony_ci len = strlen(string) + 1; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci /* 4528c2ecf20Sopenharmony_ci * Reserve a leading '-' as an indicator that 4538c2ecf20Sopenharmony_ci * this isn't a label, but an option to interfaces 4548c2ecf20Sopenharmony_ci * including /smack/cipso and /smack/cipso2 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci if (string[0] == '-') 4578c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 4608c2ecf20Sopenharmony_ci if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || 4618c2ecf20Sopenharmony_ci string[i] == '"' || string[i] == '\\' || string[i] == '\'') 4628c2ecf20Sopenharmony_ci break; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (i == 0 || i >= SMK_LONGLABEL) 4658c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci smack = kzalloc(i + 1, GFP_NOFS); 4688c2ecf20Sopenharmony_ci if (smack == NULL) 4698c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci strncpy(smack, string, i); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return smack; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci/** 4778c2ecf20Sopenharmony_ci * smk_netlbl_mls - convert a catset to netlabel mls categories 4788c2ecf20Sopenharmony_ci * @catset: the Smack categories 4798c2ecf20Sopenharmony_ci * @sap: where to put the netlabel categories 4808c2ecf20Sopenharmony_ci * 4818c2ecf20Sopenharmony_ci * Allocates and fills attr.mls 4828c2ecf20Sopenharmony_ci * Returns 0 on success, error code on failure. 4838c2ecf20Sopenharmony_ci */ 4848c2ecf20Sopenharmony_ciint smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, 4858c2ecf20Sopenharmony_ci int len) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci unsigned char *cp; 4888c2ecf20Sopenharmony_ci unsigned char m; 4898c2ecf20Sopenharmony_ci int cat; 4908c2ecf20Sopenharmony_ci int rc; 4918c2ecf20Sopenharmony_ci int byte; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci sap->flags |= NETLBL_SECATTR_MLS_CAT; 4948c2ecf20Sopenharmony_ci sap->attr.mls.lvl = level; 4958c2ecf20Sopenharmony_ci sap->attr.mls.cat = NULL; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) 4988c2ecf20Sopenharmony_ci for (m = 0x80; m != 0; m >>= 1, cat++) { 4998c2ecf20Sopenharmony_ci if ((m & *cp) == 0) 5008c2ecf20Sopenharmony_ci continue; 5018c2ecf20Sopenharmony_ci rc = netlbl_catmap_setbit(&sap->attr.mls.cat, 5028c2ecf20Sopenharmony_ci cat, GFP_NOFS); 5038c2ecf20Sopenharmony_ci if (rc < 0) { 5048c2ecf20Sopenharmony_ci netlbl_catmap_free(sap->attr.mls.cat); 5058c2ecf20Sopenharmony_ci return rc; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci/** 5138c2ecf20Sopenharmony_ci * smack_populate_secattr - fill in the smack_known netlabel information 5148c2ecf20Sopenharmony_ci * @skp: pointer to the structure to fill 5158c2ecf20Sopenharmony_ci * 5168c2ecf20Sopenharmony_ci * Populate the netlabel secattr structure for a Smack label. 5178c2ecf20Sopenharmony_ci * 5188c2ecf20Sopenharmony_ci * Returns 0 unless creating the category mapping fails 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ciint smack_populate_secattr(struct smack_known *skp) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci int slen; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci skp->smk_netlabel.attr.secid = skp->smk_secid; 5258c2ecf20Sopenharmony_ci skp->smk_netlabel.domain = skp->smk_known; 5268c2ecf20Sopenharmony_ci skp->smk_netlabel.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 5278c2ecf20Sopenharmony_ci if (skp->smk_netlabel.cache != NULL) { 5288c2ecf20Sopenharmony_ci skp->smk_netlabel.flags |= NETLBL_SECATTR_CACHE; 5298c2ecf20Sopenharmony_ci skp->smk_netlabel.cache->free = NULL; 5308c2ecf20Sopenharmony_ci skp->smk_netlabel.cache->data = skp; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci skp->smk_netlabel.flags |= NETLBL_SECATTR_SECID | 5338c2ecf20Sopenharmony_ci NETLBL_SECATTR_MLS_LVL | 5348c2ecf20Sopenharmony_ci NETLBL_SECATTR_DOMAIN; 5358c2ecf20Sopenharmony_ci /* 5368c2ecf20Sopenharmony_ci * If direct labeling works use it. 5378c2ecf20Sopenharmony_ci * Otherwise use mapped labeling. 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_ci slen = strlen(skp->smk_known); 5408c2ecf20Sopenharmony_ci if (slen < SMK_CIPSOLEN) 5418c2ecf20Sopenharmony_ci return smk_netlbl_mls(smack_cipso_direct, skp->smk_known, 5428c2ecf20Sopenharmony_ci &skp->smk_netlabel, slen); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid, 5458c2ecf20Sopenharmony_ci &skp->smk_netlabel, sizeof(skp->smk_secid)); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci/** 5498c2ecf20Sopenharmony_ci * smk_import_entry - import a label, return the list entry 5508c2ecf20Sopenharmony_ci * @string: a text string that might be a Smack label 5518c2ecf20Sopenharmony_ci * @len: the maximum size, or zero if it is NULL terminated. 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * Returns a pointer to the entry in the label list that 5548c2ecf20Sopenharmony_ci * matches the passed string, adding it if necessary, 5558c2ecf20Sopenharmony_ci * or an error code. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_cistruct smack_known *smk_import_entry(const char *string, int len) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct smack_known *skp; 5608c2ecf20Sopenharmony_ci char *smack; 5618c2ecf20Sopenharmony_ci int rc; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci smack = smk_parse_smack(string, len); 5648c2ecf20Sopenharmony_ci if (IS_ERR(smack)) 5658c2ecf20Sopenharmony_ci return ERR_CAST(smack); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci mutex_lock(&smack_known_lock); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci skp = smk_find_entry(smack); 5708c2ecf20Sopenharmony_ci if (skp != NULL) 5718c2ecf20Sopenharmony_ci goto freeout; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci skp = kzalloc(sizeof(*skp), GFP_NOFS); 5748c2ecf20Sopenharmony_ci if (skp == NULL) { 5758c2ecf20Sopenharmony_ci skp = ERR_PTR(-ENOMEM); 5768c2ecf20Sopenharmony_ci goto freeout; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci skp->smk_known = smack; 5808c2ecf20Sopenharmony_ci skp->smk_secid = smack_next_secid++; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci rc = smack_populate_secattr(skp); 5838c2ecf20Sopenharmony_ci if (rc >= 0) { 5848c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&skp->smk_rules); 5858c2ecf20Sopenharmony_ci mutex_init(&skp->smk_rules_lock); 5868c2ecf20Sopenharmony_ci /* 5878c2ecf20Sopenharmony_ci * Make sure that the entry is actually 5888c2ecf20Sopenharmony_ci * filled before putting it on the list. 5898c2ecf20Sopenharmony_ci */ 5908c2ecf20Sopenharmony_ci smk_insert_entry(skp); 5918c2ecf20Sopenharmony_ci goto unlockout; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci kfree(skp); 5948c2ecf20Sopenharmony_ci skp = ERR_PTR(rc); 5958c2ecf20Sopenharmony_cifreeout: 5968c2ecf20Sopenharmony_ci kfree(smack); 5978c2ecf20Sopenharmony_ciunlockout: 5988c2ecf20Sopenharmony_ci mutex_unlock(&smack_known_lock); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return skp; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci/** 6048c2ecf20Sopenharmony_ci * smack_from_secid - find the Smack label associated with a secid 6058c2ecf20Sopenharmony_ci * @secid: an integer that might be associated with a Smack label 6068c2ecf20Sopenharmony_ci * 6078c2ecf20Sopenharmony_ci * Returns a pointer to the appropriate Smack label entry if there is one, 6088c2ecf20Sopenharmony_ci * otherwise a pointer to the invalid Smack label. 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_cistruct smack_known *smack_from_secid(const u32 secid) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct smack_known *skp; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci rcu_read_lock(); 6158c2ecf20Sopenharmony_ci list_for_each_entry_rcu(skp, &smack_known_list, list) { 6168c2ecf20Sopenharmony_ci if (skp->smk_secid == secid) { 6178c2ecf20Sopenharmony_ci rcu_read_unlock(); 6188c2ecf20Sopenharmony_ci return skp; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* 6238c2ecf20Sopenharmony_ci * If we got this far someone asked for the translation 6248c2ecf20Sopenharmony_ci * of a secid that is not on the list. 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_ci rcu_read_unlock(); 6278c2ecf20Sopenharmony_ci return &smack_known_huh; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/* 6318c2ecf20Sopenharmony_ci * Unless a process is running with one of these labels 6328c2ecf20Sopenharmony_ci * even having CAP_MAC_OVERRIDE isn't enough to grant 6338c2ecf20Sopenharmony_ci * privilege to violate MAC policy. If no labels are 6348c2ecf20Sopenharmony_ci * designated (the empty list case) capabilities apply to 6358c2ecf20Sopenharmony_ci * everyone. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_ciLIST_HEAD(smack_onlycap_list); 6388c2ecf20Sopenharmony_ciDEFINE_MUTEX(smack_onlycap_lock); 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci/** 6418c2ecf20Sopenharmony_ci * smack_privileged_cred - are all privilege requirements met by cred 6428c2ecf20Sopenharmony_ci * @cap: The requested capability 6438c2ecf20Sopenharmony_ci * @cred: the credential to use 6448c2ecf20Sopenharmony_ci * 6458c2ecf20Sopenharmony_ci * Is the task privileged and allowed to be privileged 6468c2ecf20Sopenharmony_ci * by the onlycap rule. 6478c2ecf20Sopenharmony_ci * 6488c2ecf20Sopenharmony_ci * Returns true if the task is allowed to be privileged, false if it's not. 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_cibool smack_privileged_cred(int cap, const struct cred *cred) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(cred); 6538c2ecf20Sopenharmony_ci struct smack_known *skp = tsp->smk_task; 6548c2ecf20Sopenharmony_ci struct smack_known_list_elem *sklep; 6558c2ecf20Sopenharmony_ci int rc; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE); 6588c2ecf20Sopenharmony_ci if (rc) 6598c2ecf20Sopenharmony_ci return false; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci rcu_read_lock(); 6628c2ecf20Sopenharmony_ci if (list_empty(&smack_onlycap_list)) { 6638c2ecf20Sopenharmony_ci rcu_read_unlock(); 6648c2ecf20Sopenharmony_ci return true; 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) { 6688c2ecf20Sopenharmony_ci if (sklep->smk_label == skp) { 6698c2ecf20Sopenharmony_ci rcu_read_unlock(); 6708c2ecf20Sopenharmony_ci return true; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci rcu_read_unlock(); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci return false; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci/** 6798c2ecf20Sopenharmony_ci * smack_privileged - are all privilege requirements met 6808c2ecf20Sopenharmony_ci * @cap: The requested capability 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * Is the task privileged and allowed to be privileged 6838c2ecf20Sopenharmony_ci * by the onlycap rule. 6848c2ecf20Sopenharmony_ci * 6858c2ecf20Sopenharmony_ci * Returns true if the task is allowed to be privileged, false if it's not. 6868c2ecf20Sopenharmony_ci */ 6878c2ecf20Sopenharmony_cibool smack_privileged(int cap) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci /* 6908c2ecf20Sopenharmony_ci * Kernel threads may not have credentials we can use. 6918c2ecf20Sopenharmony_ci * The io_uring kernel threads do have reliable credentials. 6928c2ecf20Sopenharmony_ci */ 6938c2ecf20Sopenharmony_ci if ((current->flags & (PF_KTHREAD | PF_IO_WORKER)) == PF_KTHREAD) 6948c2ecf20Sopenharmony_ci return true; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return smack_privileged_cred(cap, current_cred()); 6978c2ecf20Sopenharmony_ci} 698