18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Simplified MAC Kernel (smack) security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains the smack hook function implementations. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Casey Schaufler <casey@schaufler-ca.com> 98c2ecf20Sopenharmony_ci * Jarkko Sakkinen <jarkko.sakkinen@intel.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> 128c2ecf20Sopenharmony_ci * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. 138c2ecf20Sopenharmony_ci * Paul Moore <paul@paul-moore.com> 148c2ecf20Sopenharmony_ci * Copyright (C) 2010 Nokia Corporation 158c2ecf20Sopenharmony_ci * Copyright (C) 2011 Intel Corporation. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/xattr.h> 198c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 208c2ecf20Sopenharmony_ci#include <linux/mount.h> 218c2ecf20Sopenharmony_ci#include <linux/stat.h> 228c2ecf20Sopenharmony_ci#include <linux/kd.h> 238c2ecf20Sopenharmony_ci#include <asm/ioctls.h> 248c2ecf20Sopenharmony_ci#include <linux/ip.h> 258c2ecf20Sopenharmony_ci#include <linux/tcp.h> 268c2ecf20Sopenharmony_ci#include <linux/udp.h> 278c2ecf20Sopenharmony_ci#include <linux/dccp.h> 288c2ecf20Sopenharmony_ci#include <linux/icmpv6.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/mutex.h> 318c2ecf20Sopenharmony_ci#include <net/cipso_ipv4.h> 328c2ecf20Sopenharmony_ci#include <net/ip.h> 338c2ecf20Sopenharmony_ci#include <net/ipv6.h> 348c2ecf20Sopenharmony_ci#include <linux/audit.h> 358c2ecf20Sopenharmony_ci#include <linux/magic.h> 368c2ecf20Sopenharmony_ci#include <linux/dcache.h> 378c2ecf20Sopenharmony_ci#include <linux/personality.h> 388c2ecf20Sopenharmony_ci#include <linux/msg.h> 398c2ecf20Sopenharmony_ci#include <linux/shm.h> 408c2ecf20Sopenharmony_ci#include <linux/binfmts.h> 418c2ecf20Sopenharmony_ci#include <linux/parser.h> 428c2ecf20Sopenharmony_ci#include <linux/fs_context.h> 438c2ecf20Sopenharmony_ci#include <linux/fs_parser.h> 448c2ecf20Sopenharmony_ci#include <linux/watch_queue.h> 458c2ecf20Sopenharmony_ci#include "smack.h" 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define TRANS_TRUE "TRUE" 488c2ecf20Sopenharmony_ci#define TRANS_TRUE_SIZE 4 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define SMK_CONNECTING 0 518c2ecf20Sopenharmony_ci#define SMK_RECEIVING 1 528c2ecf20Sopenharmony_ci#define SMK_SENDING 2 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(smack_ipv6_lock); 558c2ecf20Sopenharmony_cistatic LIST_HEAD(smk_ipv6_port_list); 568c2ecf20Sopenharmony_cistruct kmem_cache *smack_rule_cache; 578c2ecf20Sopenharmony_ciint smack_enabled; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define A(s) {"smack"#s, sizeof("smack"#s) - 1, Opt_##s} 608c2ecf20Sopenharmony_cistatic struct { 618c2ecf20Sopenharmony_ci const char *name; 628c2ecf20Sopenharmony_ci int len; 638c2ecf20Sopenharmony_ci int opt; 648c2ecf20Sopenharmony_ci} smk_mount_opts[] = { 658c2ecf20Sopenharmony_ci {"smackfsdef", sizeof("smackfsdef") - 1, Opt_fsdefault}, 668c2ecf20Sopenharmony_ci A(fsdefault), A(fsfloor), A(fshat), A(fsroot), A(fstransmute) 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci#undef A 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int match_opt_prefix(char *s, int l, char **arg) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int i; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(smk_mount_opts); i++) { 758c2ecf20Sopenharmony_ci size_t len = smk_mount_opts[i].len; 768c2ecf20Sopenharmony_ci if (len > l || memcmp(s, smk_mount_opts[i].name, len)) 778c2ecf20Sopenharmony_ci continue; 788c2ecf20Sopenharmony_ci if (len == l || s[len] != '=') 798c2ecf20Sopenharmony_ci continue; 808c2ecf20Sopenharmony_ci *arg = s + len + 1; 818c2ecf20Sopenharmony_ci return smk_mount_opts[i].opt; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci return Opt_error; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 878c2ecf20Sopenharmony_cistatic char *smk_bu_mess[] = { 888c2ecf20Sopenharmony_ci "Bringup Error", /* Unused */ 898c2ecf20Sopenharmony_ci "Bringup", /* SMACK_BRINGUP_ALLOW */ 908c2ecf20Sopenharmony_ci "Unconfined Subject", /* SMACK_UNCONFINED_SUBJECT */ 918c2ecf20Sopenharmony_ci "Unconfined Object", /* SMACK_UNCONFINED_OBJECT */ 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistatic void smk_bu_mode(int mode, char *s) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci int i = 0; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (mode & MAY_READ) 998c2ecf20Sopenharmony_ci s[i++] = 'r'; 1008c2ecf20Sopenharmony_ci if (mode & MAY_WRITE) 1018c2ecf20Sopenharmony_ci s[i++] = 'w'; 1028c2ecf20Sopenharmony_ci if (mode & MAY_EXEC) 1038c2ecf20Sopenharmony_ci s[i++] = 'x'; 1048c2ecf20Sopenharmony_ci if (mode & MAY_APPEND) 1058c2ecf20Sopenharmony_ci s[i++] = 'a'; 1068c2ecf20Sopenharmony_ci if (mode & MAY_TRANSMUTE) 1078c2ecf20Sopenharmony_ci s[i++] = 't'; 1088c2ecf20Sopenharmony_ci if (mode & MAY_LOCK) 1098c2ecf20Sopenharmony_ci s[i++] = 'l'; 1108c2ecf20Sopenharmony_ci if (i == 0) 1118c2ecf20Sopenharmony_ci s[i++] = '-'; 1128c2ecf20Sopenharmony_ci s[i] = '\0'; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci#endif 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 1178c2ecf20Sopenharmony_cistatic int smk_bu_note(char *note, struct smack_known *sskp, 1188c2ecf20Sopenharmony_ci struct smack_known *oskp, int mode, int rc) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci char acc[SMK_NUM_ACCESS_TYPE + 1]; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (rc <= 0) 1238c2ecf20Sopenharmony_ci return rc; 1248c2ecf20Sopenharmony_ci if (rc > SMACK_UNCONFINED_OBJECT) 1258c2ecf20Sopenharmony_ci rc = 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci smk_bu_mode(mode, acc); 1288c2ecf20Sopenharmony_ci pr_info("Smack %s: (%s %s %s) %s\n", smk_bu_mess[rc], 1298c2ecf20Sopenharmony_ci sskp->smk_known, oskp->smk_known, acc, note); 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci#else 1338c2ecf20Sopenharmony_ci#define smk_bu_note(note, sskp, oskp, mode, RC) (RC) 1348c2ecf20Sopenharmony_ci#endif 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 1378c2ecf20Sopenharmony_cistatic int smk_bu_current(char *note, struct smack_known *oskp, 1388c2ecf20Sopenharmony_ci int mode, int rc) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 1418c2ecf20Sopenharmony_ci char acc[SMK_NUM_ACCESS_TYPE + 1]; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (rc <= 0) 1448c2ecf20Sopenharmony_ci return rc; 1458c2ecf20Sopenharmony_ci if (rc > SMACK_UNCONFINED_OBJECT) 1468c2ecf20Sopenharmony_ci rc = 0; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci smk_bu_mode(mode, acc); 1498c2ecf20Sopenharmony_ci pr_info("Smack %s: (%s %s %s) %s %s\n", smk_bu_mess[rc], 1508c2ecf20Sopenharmony_ci tsp->smk_task->smk_known, oskp->smk_known, 1518c2ecf20Sopenharmony_ci acc, current->comm, note); 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci#else 1558c2ecf20Sopenharmony_ci#define smk_bu_current(note, oskp, mode, RC) (RC) 1568c2ecf20Sopenharmony_ci#endif 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 1598c2ecf20Sopenharmony_cistatic int smk_bu_task(struct task_struct *otp, int mode, int rc) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 1628c2ecf20Sopenharmony_ci struct smack_known *smk_task = smk_of_task_struct(otp); 1638c2ecf20Sopenharmony_ci char acc[SMK_NUM_ACCESS_TYPE + 1]; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (rc <= 0) 1668c2ecf20Sopenharmony_ci return rc; 1678c2ecf20Sopenharmony_ci if (rc > SMACK_UNCONFINED_OBJECT) 1688c2ecf20Sopenharmony_ci rc = 0; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci smk_bu_mode(mode, acc); 1718c2ecf20Sopenharmony_ci pr_info("Smack %s: (%s %s %s) %s to %s\n", smk_bu_mess[rc], 1728c2ecf20Sopenharmony_ci tsp->smk_task->smk_known, smk_task->smk_known, acc, 1738c2ecf20Sopenharmony_ci current->comm, otp->comm); 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci#else 1778c2ecf20Sopenharmony_ci#define smk_bu_task(otp, mode, RC) (RC) 1788c2ecf20Sopenharmony_ci#endif 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 1818c2ecf20Sopenharmony_cistatic int smk_bu_inode(struct inode *inode, int mode, int rc) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 1848c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(inode); 1858c2ecf20Sopenharmony_ci char acc[SMK_NUM_ACCESS_TYPE + 1]; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (isp->smk_flags & SMK_INODE_IMPURE) 1888c2ecf20Sopenharmony_ci pr_info("Smack Unconfined Corruption: inode=(%s %ld) %s\n", 1898c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, current->comm); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (rc <= 0) 1928c2ecf20Sopenharmony_ci return rc; 1938c2ecf20Sopenharmony_ci if (rc > SMACK_UNCONFINED_OBJECT) 1948c2ecf20Sopenharmony_ci rc = 0; 1958c2ecf20Sopenharmony_ci if (rc == SMACK_UNCONFINED_SUBJECT && 1968c2ecf20Sopenharmony_ci (mode & (MAY_WRITE | MAY_APPEND))) 1978c2ecf20Sopenharmony_ci isp->smk_flags |= SMK_INODE_IMPURE; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci smk_bu_mode(mode, acc); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci pr_info("Smack %s: (%s %s %s) inode=(%s %ld) %s\n", smk_bu_mess[rc], 2028c2ecf20Sopenharmony_ci tsp->smk_task->smk_known, isp->smk_inode->smk_known, acc, 2038c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, current->comm); 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci#else 2078c2ecf20Sopenharmony_ci#define smk_bu_inode(inode, mode, RC) (RC) 2088c2ecf20Sopenharmony_ci#endif 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 2118c2ecf20Sopenharmony_cistatic int smk_bu_file(struct file *file, int mode, int rc) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 2148c2ecf20Sopenharmony_ci struct smack_known *sskp = tsp->smk_task; 2158c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 2168c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(inode); 2178c2ecf20Sopenharmony_ci char acc[SMK_NUM_ACCESS_TYPE + 1]; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (isp->smk_flags & SMK_INODE_IMPURE) 2208c2ecf20Sopenharmony_ci pr_info("Smack Unconfined Corruption: inode=(%s %ld) %s\n", 2218c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, current->comm); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (rc <= 0) 2248c2ecf20Sopenharmony_ci return rc; 2258c2ecf20Sopenharmony_ci if (rc > SMACK_UNCONFINED_OBJECT) 2268c2ecf20Sopenharmony_ci rc = 0; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci smk_bu_mode(mode, acc); 2298c2ecf20Sopenharmony_ci pr_info("Smack %s: (%s %s %s) file=(%s %ld %pD) %s\n", smk_bu_mess[rc], 2308c2ecf20Sopenharmony_ci sskp->smk_known, smk_of_inode(inode)->smk_known, acc, 2318c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, file, 2328c2ecf20Sopenharmony_ci current->comm); 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci#else 2368c2ecf20Sopenharmony_ci#define smk_bu_file(file, mode, RC) (RC) 2378c2ecf20Sopenharmony_ci#endif 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_BRINGUP 2408c2ecf20Sopenharmony_cistatic int smk_bu_credfile(const struct cred *cred, struct file *file, 2418c2ecf20Sopenharmony_ci int mode, int rc) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(cred); 2448c2ecf20Sopenharmony_ci struct smack_known *sskp = tsp->smk_task; 2458c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 2468c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(inode); 2478c2ecf20Sopenharmony_ci char acc[SMK_NUM_ACCESS_TYPE + 1]; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (isp->smk_flags & SMK_INODE_IMPURE) 2508c2ecf20Sopenharmony_ci pr_info("Smack Unconfined Corruption: inode=(%s %ld) %s\n", 2518c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, current->comm); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (rc <= 0) 2548c2ecf20Sopenharmony_ci return rc; 2558c2ecf20Sopenharmony_ci if (rc > SMACK_UNCONFINED_OBJECT) 2568c2ecf20Sopenharmony_ci rc = 0; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci smk_bu_mode(mode, acc); 2598c2ecf20Sopenharmony_ci pr_info("Smack %s: (%s %s %s) file=(%s %ld %pD) %s\n", smk_bu_mess[rc], 2608c2ecf20Sopenharmony_ci sskp->smk_known, smk_of_inode(inode)->smk_known, acc, 2618c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, file, 2628c2ecf20Sopenharmony_ci current->comm); 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci#else 2668c2ecf20Sopenharmony_ci#define smk_bu_credfile(cred, file, mode, RC) (RC) 2678c2ecf20Sopenharmony_ci#endif 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/** 2708c2ecf20Sopenharmony_ci * smk_fetch - Fetch the smack label from a file. 2718c2ecf20Sopenharmony_ci * @name: type of the label (attribute) 2728c2ecf20Sopenharmony_ci * @ip: a pointer to the inode 2738c2ecf20Sopenharmony_ci * @dp: a pointer to the dentry 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * Returns a pointer to the master list entry for the Smack label, 2768c2ecf20Sopenharmony_ci * NULL if there was no label to fetch, or an error code. 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_cistatic struct smack_known *smk_fetch(const char *name, struct inode *ip, 2798c2ecf20Sopenharmony_ci struct dentry *dp) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci int rc; 2828c2ecf20Sopenharmony_ci char *buffer; 2838c2ecf20Sopenharmony_ci struct smack_known *skp = NULL; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (!(ip->i_opflags & IOP_XATTR)) 2868c2ecf20Sopenharmony_ci return ERR_PTR(-EOPNOTSUPP); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci buffer = kzalloc(SMK_LONGLABEL, GFP_NOFS); 2898c2ecf20Sopenharmony_ci if (buffer == NULL) 2908c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci rc = __vfs_getxattr(dp, ip, name, buffer, SMK_LONGLABEL); 2938c2ecf20Sopenharmony_ci if (rc < 0) 2948c2ecf20Sopenharmony_ci skp = ERR_PTR(rc); 2958c2ecf20Sopenharmony_ci else if (rc == 0) 2968c2ecf20Sopenharmony_ci skp = NULL; 2978c2ecf20Sopenharmony_ci else 2988c2ecf20Sopenharmony_ci skp = smk_import_entry(buffer, rc); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci kfree(buffer); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return skp; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci/** 3068c2ecf20Sopenharmony_ci * init_inode_smack - initialize an inode security blob 3078c2ecf20Sopenharmony_ci * @inode: inode to extract the info from 3088c2ecf20Sopenharmony_ci * @skp: a pointer to the Smack label entry to use in the blob 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic void init_inode_smack(struct inode *inode, struct smack_known *skp) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(inode); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci isp->smk_inode = skp; 3168c2ecf20Sopenharmony_ci isp->smk_flags = 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/** 3208c2ecf20Sopenharmony_ci * init_task_smack - initialize a task security blob 3218c2ecf20Sopenharmony_ci * @tsp: blob to initialize 3228c2ecf20Sopenharmony_ci * @task: a pointer to the Smack label for the running task 3238c2ecf20Sopenharmony_ci * @forked: a pointer to the Smack label for the forked task 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic void init_task_smack(struct task_smack *tsp, struct smack_known *task, 3278c2ecf20Sopenharmony_ci struct smack_known *forked) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci tsp->smk_task = task; 3308c2ecf20Sopenharmony_ci tsp->smk_forked = forked; 3318c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tsp->smk_rules); 3328c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tsp->smk_relabel); 3338c2ecf20Sopenharmony_ci mutex_init(&tsp->smk_rules_lock); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/** 3378c2ecf20Sopenharmony_ci * smk_copy_rules - copy a rule set 3388c2ecf20Sopenharmony_ci * @nhead: new rules header pointer 3398c2ecf20Sopenharmony_ci * @ohead: old rules header pointer 3408c2ecf20Sopenharmony_ci * @gfp: type of the memory for the allocation 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * Returns 0 on success, -ENOMEM on error 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_cistatic int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, 3458c2ecf20Sopenharmony_ci gfp_t gfp) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct smack_rule *nrp; 3488c2ecf20Sopenharmony_ci struct smack_rule *orp; 3498c2ecf20Sopenharmony_ci int rc = 0; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci list_for_each_entry_rcu(orp, ohead, list) { 3528c2ecf20Sopenharmony_ci nrp = kmem_cache_zalloc(smack_rule_cache, gfp); 3538c2ecf20Sopenharmony_ci if (nrp == NULL) { 3548c2ecf20Sopenharmony_ci rc = -ENOMEM; 3558c2ecf20Sopenharmony_ci break; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci *nrp = *orp; 3588c2ecf20Sopenharmony_ci list_add_rcu(&nrp->list, nhead); 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci return rc; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci/** 3648c2ecf20Sopenharmony_ci * smk_copy_relabel - copy smk_relabel labels list 3658c2ecf20Sopenharmony_ci * @nhead: new rules header pointer 3668c2ecf20Sopenharmony_ci * @ohead: old rules header pointer 3678c2ecf20Sopenharmony_ci * @gfp: type of the memory for the allocation 3688c2ecf20Sopenharmony_ci * 3698c2ecf20Sopenharmony_ci * Returns 0 on success, -ENOMEM on error 3708c2ecf20Sopenharmony_ci */ 3718c2ecf20Sopenharmony_cistatic int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead, 3728c2ecf20Sopenharmony_ci gfp_t gfp) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci struct smack_known_list_elem *nklep; 3758c2ecf20Sopenharmony_ci struct smack_known_list_elem *oklep; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci list_for_each_entry(oklep, ohead, list) { 3788c2ecf20Sopenharmony_ci nklep = kzalloc(sizeof(struct smack_known_list_elem), gfp); 3798c2ecf20Sopenharmony_ci if (nklep == NULL) { 3808c2ecf20Sopenharmony_ci smk_destroy_label_list(nhead); 3818c2ecf20Sopenharmony_ci return -ENOMEM; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci nklep->smk_label = oklep->smk_label; 3848c2ecf20Sopenharmony_ci list_add(&nklep->list, nhead); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/** 3918c2ecf20Sopenharmony_ci * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_* 3928c2ecf20Sopenharmony_ci * @mode - input mode in form of PTRACE_MODE_* 3938c2ecf20Sopenharmony_ci * 3948c2ecf20Sopenharmony_ci * Returns a converted MAY_* mode usable by smack rules 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_cistatic inline unsigned int smk_ptrace_mode(unsigned int mode) 3978c2ecf20Sopenharmony_ci{ 3988c2ecf20Sopenharmony_ci if (mode & PTRACE_MODE_ATTACH) 3998c2ecf20Sopenharmony_ci return MAY_READWRITE; 4008c2ecf20Sopenharmony_ci if (mode & PTRACE_MODE_READ) 4018c2ecf20Sopenharmony_ci return MAY_READ; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci/** 4078c2ecf20Sopenharmony_ci * smk_ptrace_rule_check - helper for ptrace access 4088c2ecf20Sopenharmony_ci * @tracer: tracer process 4098c2ecf20Sopenharmony_ci * @tracee_known: label entry of the process that's about to be traced 4108c2ecf20Sopenharmony_ci * @mode: ptrace attachment mode (PTRACE_MODE_*) 4118c2ecf20Sopenharmony_ci * @func: name of the function that called us, used for audit 4128c2ecf20Sopenharmony_ci * 4138c2ecf20Sopenharmony_ci * Returns 0 on access granted, -error on error 4148c2ecf20Sopenharmony_ci */ 4158c2ecf20Sopenharmony_cistatic int smk_ptrace_rule_check(struct task_struct *tracer, 4168c2ecf20Sopenharmony_ci struct smack_known *tracee_known, 4178c2ecf20Sopenharmony_ci unsigned int mode, const char *func) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci int rc; 4208c2ecf20Sopenharmony_ci struct smk_audit_info ad, *saip = NULL; 4218c2ecf20Sopenharmony_ci struct task_smack *tsp; 4228c2ecf20Sopenharmony_ci struct smack_known *tracer_known; 4238c2ecf20Sopenharmony_ci const struct cred *tracercred; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if ((mode & PTRACE_MODE_NOAUDIT) == 0) { 4268c2ecf20Sopenharmony_ci smk_ad_init(&ad, func, LSM_AUDIT_DATA_TASK); 4278c2ecf20Sopenharmony_ci smk_ad_setfield_u_tsk(&ad, tracer); 4288c2ecf20Sopenharmony_ci saip = &ad; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci rcu_read_lock(); 4328c2ecf20Sopenharmony_ci tracercred = __task_cred(tracer); 4338c2ecf20Sopenharmony_ci tsp = smack_cred(tracercred); 4348c2ecf20Sopenharmony_ci tracer_known = smk_of_task(tsp); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if ((mode & PTRACE_MODE_ATTACH) && 4378c2ecf20Sopenharmony_ci (smack_ptrace_rule == SMACK_PTRACE_EXACT || 4388c2ecf20Sopenharmony_ci smack_ptrace_rule == SMACK_PTRACE_DRACONIAN)) { 4398c2ecf20Sopenharmony_ci if (tracer_known->smk_known == tracee_known->smk_known) 4408c2ecf20Sopenharmony_ci rc = 0; 4418c2ecf20Sopenharmony_ci else if (smack_ptrace_rule == SMACK_PTRACE_DRACONIAN) 4428c2ecf20Sopenharmony_ci rc = -EACCES; 4438c2ecf20Sopenharmony_ci else if (smack_privileged_cred(CAP_SYS_PTRACE, tracercred)) 4448c2ecf20Sopenharmony_ci rc = 0; 4458c2ecf20Sopenharmony_ci else 4468c2ecf20Sopenharmony_ci rc = -EACCES; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (saip) 4498c2ecf20Sopenharmony_ci smack_log(tracer_known->smk_known, 4508c2ecf20Sopenharmony_ci tracee_known->smk_known, 4518c2ecf20Sopenharmony_ci 0, rc, saip); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci rcu_read_unlock(); 4548c2ecf20Sopenharmony_ci return rc; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* In case of rule==SMACK_PTRACE_DEFAULT or mode==PTRACE_MODE_READ */ 4588c2ecf20Sopenharmony_ci rc = smk_tskacc(tsp, tracee_known, smk_ptrace_mode(mode), saip); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rcu_read_unlock(); 4618c2ecf20Sopenharmony_ci return rc; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci/* 4658c2ecf20Sopenharmony_ci * LSM hooks. 4668c2ecf20Sopenharmony_ci * We he, that is fun! 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci/** 4708c2ecf20Sopenharmony_ci * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH 4718c2ecf20Sopenharmony_ci * @ctp: child task pointer 4728c2ecf20Sopenharmony_ci * @mode: ptrace attachment mode (PTRACE_MODE_*) 4738c2ecf20Sopenharmony_ci * 4748c2ecf20Sopenharmony_ci * Returns 0 if access is OK, an error code otherwise 4758c2ecf20Sopenharmony_ci * 4768c2ecf20Sopenharmony_ci * Do the capability checks. 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_cistatic int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct smack_known *skp; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci skp = smk_of_task_struct(ctp); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return smk_ptrace_rule_check(current, skp, mode, __func__); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/** 4888c2ecf20Sopenharmony_ci * smack_ptrace_traceme - Smack approval on PTRACE_TRACEME 4898c2ecf20Sopenharmony_ci * @ptp: parent task pointer 4908c2ecf20Sopenharmony_ci * 4918c2ecf20Sopenharmony_ci * Returns 0 if access is OK, an error code otherwise 4928c2ecf20Sopenharmony_ci * 4938c2ecf20Sopenharmony_ci * Do the capability checks, and require PTRACE_MODE_ATTACH. 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_cistatic int smack_ptrace_traceme(struct task_struct *ptp) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci int rc; 4988c2ecf20Sopenharmony_ci struct smack_known *skp; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci skp = smk_of_task(smack_cred(current_cred())); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__); 5038c2ecf20Sopenharmony_ci return rc; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci/** 5078c2ecf20Sopenharmony_ci * smack_syslog - Smack approval on syslog 5088c2ecf20Sopenharmony_ci * @typefrom_file: unused 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * Returns 0 on success, error code otherwise. 5118c2ecf20Sopenharmony_ci */ 5128c2ecf20Sopenharmony_cistatic int smack_syslog(int typefrom_file) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci int rc = 0; 5158c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_current(); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (smack_privileged(CAP_MAC_OVERRIDE)) 5188c2ecf20Sopenharmony_ci return 0; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (smack_syslog_label != NULL && smack_syslog_label != skp) 5218c2ecf20Sopenharmony_ci rc = -EACCES; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return rc; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci/* 5278c2ecf20Sopenharmony_ci * Superblock Hooks. 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/** 5318c2ecf20Sopenharmony_ci * smack_sb_alloc_security - allocate a superblock blob 5328c2ecf20Sopenharmony_ci * @sb: the superblock getting the blob 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * Returns 0 on success or -ENOMEM on error. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_cistatic int smack_sb_alloc_security(struct super_block *sb) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct superblock_smack *sbsp; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci sbsp = kzalloc(sizeof(struct superblock_smack), GFP_KERNEL); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (sbsp == NULL) 5438c2ecf20Sopenharmony_ci return -ENOMEM; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci sbsp->smk_root = &smack_known_floor; 5468c2ecf20Sopenharmony_ci sbsp->smk_default = &smack_known_floor; 5478c2ecf20Sopenharmony_ci sbsp->smk_floor = &smack_known_floor; 5488c2ecf20Sopenharmony_ci sbsp->smk_hat = &smack_known_hat; 5498c2ecf20Sopenharmony_ci /* 5508c2ecf20Sopenharmony_ci * SMK_SB_INITIALIZED will be zero from kzalloc. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_ci sb->s_security = sbsp; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * smack_sb_free_security - free a superblock blob 5598c2ecf20Sopenharmony_ci * @sb: the superblock getting the blob 5608c2ecf20Sopenharmony_ci * 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_cistatic void smack_sb_free_security(struct super_block *sb) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci kfree(sb->s_security); 5658c2ecf20Sopenharmony_ci sb->s_security = NULL; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistruct smack_mnt_opts { 5698c2ecf20Sopenharmony_ci const char *fsdefault, *fsfloor, *fshat, *fsroot, *fstransmute; 5708c2ecf20Sopenharmony_ci}; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_cistatic void smack_free_mnt_opts(void *mnt_opts) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct smack_mnt_opts *opts = mnt_opts; 5758c2ecf20Sopenharmony_ci kfree(opts->fsdefault); 5768c2ecf20Sopenharmony_ci kfree(opts->fsfloor); 5778c2ecf20Sopenharmony_ci kfree(opts->fshat); 5788c2ecf20Sopenharmony_ci kfree(opts->fsroot); 5798c2ecf20Sopenharmony_ci kfree(opts->fstransmute); 5808c2ecf20Sopenharmony_ci kfree(opts); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int smack_add_opt(int token, const char *s, void **mnt_opts) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct smack_mnt_opts *opts = *mnt_opts; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (!opts) { 5888c2ecf20Sopenharmony_ci opts = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); 5898c2ecf20Sopenharmony_ci if (!opts) 5908c2ecf20Sopenharmony_ci return -ENOMEM; 5918c2ecf20Sopenharmony_ci *mnt_opts = opts; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci if (!s) 5948c2ecf20Sopenharmony_ci return -ENOMEM; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci switch (token) { 5978c2ecf20Sopenharmony_ci case Opt_fsdefault: 5988c2ecf20Sopenharmony_ci if (opts->fsdefault) 5998c2ecf20Sopenharmony_ci goto out_opt_err; 6008c2ecf20Sopenharmony_ci opts->fsdefault = s; 6018c2ecf20Sopenharmony_ci break; 6028c2ecf20Sopenharmony_ci case Opt_fsfloor: 6038c2ecf20Sopenharmony_ci if (opts->fsfloor) 6048c2ecf20Sopenharmony_ci goto out_opt_err; 6058c2ecf20Sopenharmony_ci opts->fsfloor = s; 6068c2ecf20Sopenharmony_ci break; 6078c2ecf20Sopenharmony_ci case Opt_fshat: 6088c2ecf20Sopenharmony_ci if (opts->fshat) 6098c2ecf20Sopenharmony_ci goto out_opt_err; 6108c2ecf20Sopenharmony_ci opts->fshat = s; 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci case Opt_fsroot: 6138c2ecf20Sopenharmony_ci if (opts->fsroot) 6148c2ecf20Sopenharmony_ci goto out_opt_err; 6158c2ecf20Sopenharmony_ci opts->fsroot = s; 6168c2ecf20Sopenharmony_ci break; 6178c2ecf20Sopenharmony_ci case Opt_fstransmute: 6188c2ecf20Sopenharmony_ci if (opts->fstransmute) 6198c2ecf20Sopenharmony_ci goto out_opt_err; 6208c2ecf20Sopenharmony_ci opts->fstransmute = s; 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci return 0; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ciout_opt_err: 6268c2ecf20Sopenharmony_ci pr_warn("Smack: duplicate mount options\n"); 6278c2ecf20Sopenharmony_ci return -EINVAL; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/** 6318c2ecf20Sopenharmony_ci * smack_fs_context_dup - Duplicate the security data on fs_context duplication 6328c2ecf20Sopenharmony_ci * @fc: The new filesystem context. 6338c2ecf20Sopenharmony_ci * @src_fc: The source filesystem context being duplicated. 6348c2ecf20Sopenharmony_ci * 6358c2ecf20Sopenharmony_ci * Returns 0 on success or -ENOMEM on error. 6368c2ecf20Sopenharmony_ci */ 6378c2ecf20Sopenharmony_cistatic int smack_fs_context_dup(struct fs_context *fc, 6388c2ecf20Sopenharmony_ci struct fs_context *src_fc) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct smack_mnt_opts *dst, *src = src_fc->security; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!src) 6438c2ecf20Sopenharmony_ci return 0; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci fc->security = kzalloc(sizeof(struct smack_mnt_opts), GFP_KERNEL); 6468c2ecf20Sopenharmony_ci if (!fc->security) 6478c2ecf20Sopenharmony_ci return -ENOMEM; 6488c2ecf20Sopenharmony_ci dst = fc->security; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci if (src->fsdefault) { 6518c2ecf20Sopenharmony_ci dst->fsdefault = kstrdup(src->fsdefault, GFP_KERNEL); 6528c2ecf20Sopenharmony_ci if (!dst->fsdefault) 6538c2ecf20Sopenharmony_ci return -ENOMEM; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci if (src->fsfloor) { 6568c2ecf20Sopenharmony_ci dst->fsfloor = kstrdup(src->fsfloor, GFP_KERNEL); 6578c2ecf20Sopenharmony_ci if (!dst->fsfloor) 6588c2ecf20Sopenharmony_ci return -ENOMEM; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci if (src->fshat) { 6618c2ecf20Sopenharmony_ci dst->fshat = kstrdup(src->fshat, GFP_KERNEL); 6628c2ecf20Sopenharmony_ci if (!dst->fshat) 6638c2ecf20Sopenharmony_ci return -ENOMEM; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci if (src->fsroot) { 6668c2ecf20Sopenharmony_ci dst->fsroot = kstrdup(src->fsroot, GFP_KERNEL); 6678c2ecf20Sopenharmony_ci if (!dst->fsroot) 6688c2ecf20Sopenharmony_ci return -ENOMEM; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci if (src->fstransmute) { 6718c2ecf20Sopenharmony_ci dst->fstransmute = kstrdup(src->fstransmute, GFP_KERNEL); 6728c2ecf20Sopenharmony_ci if (!dst->fstransmute) 6738c2ecf20Sopenharmony_ci return -ENOMEM; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci return 0; 6768c2ecf20Sopenharmony_ci} 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec smack_fs_parameters[] = { 6798c2ecf20Sopenharmony_ci fsparam_string("smackfsdef", Opt_fsdefault), 6808c2ecf20Sopenharmony_ci fsparam_string("smackfsdefault", Opt_fsdefault), 6818c2ecf20Sopenharmony_ci fsparam_string("smackfsfloor", Opt_fsfloor), 6828c2ecf20Sopenharmony_ci fsparam_string("smackfshat", Opt_fshat), 6838c2ecf20Sopenharmony_ci fsparam_string("smackfsroot", Opt_fsroot), 6848c2ecf20Sopenharmony_ci fsparam_string("smackfstransmute", Opt_fstransmute), 6858c2ecf20Sopenharmony_ci {} 6868c2ecf20Sopenharmony_ci}; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci/** 6898c2ecf20Sopenharmony_ci * smack_fs_context_parse_param - Parse a single mount parameter 6908c2ecf20Sopenharmony_ci * @fc: The new filesystem context being constructed. 6918c2ecf20Sopenharmony_ci * @param: The parameter. 6928c2ecf20Sopenharmony_ci * 6938c2ecf20Sopenharmony_ci * Returns 0 on success, -ENOPARAM to pass the parameter on or anything else on 6948c2ecf20Sopenharmony_ci * error. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_cistatic int smack_fs_context_parse_param(struct fs_context *fc, 6978c2ecf20Sopenharmony_ci struct fs_parameter *param) 6988c2ecf20Sopenharmony_ci{ 6998c2ecf20Sopenharmony_ci struct fs_parse_result result; 7008c2ecf20Sopenharmony_ci int opt, rc; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci opt = fs_parse(fc, smack_fs_parameters, param, &result); 7038c2ecf20Sopenharmony_ci if (opt < 0) 7048c2ecf20Sopenharmony_ci return opt; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci rc = smack_add_opt(opt, param->string, &fc->security); 7078c2ecf20Sopenharmony_ci if (!rc) 7088c2ecf20Sopenharmony_ci param->string = NULL; 7098c2ecf20Sopenharmony_ci return rc; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci char *from = options, *to = options; 7158c2ecf20Sopenharmony_ci bool first = true; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci while (1) { 7188c2ecf20Sopenharmony_ci char *next = strchr(from, ','); 7198c2ecf20Sopenharmony_ci int token, len, rc; 7208c2ecf20Sopenharmony_ci char *arg = NULL; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (next) 7238c2ecf20Sopenharmony_ci len = next - from; 7248c2ecf20Sopenharmony_ci else 7258c2ecf20Sopenharmony_ci len = strlen(from); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci token = match_opt_prefix(from, len, &arg); 7288c2ecf20Sopenharmony_ci if (token != Opt_error) { 7298c2ecf20Sopenharmony_ci arg = kmemdup_nul(arg, from + len - arg, GFP_KERNEL); 7308c2ecf20Sopenharmony_ci rc = smack_add_opt(token, arg, mnt_opts); 7318c2ecf20Sopenharmony_ci if (unlikely(rc)) { 7328c2ecf20Sopenharmony_ci kfree(arg); 7338c2ecf20Sopenharmony_ci if (*mnt_opts) 7348c2ecf20Sopenharmony_ci smack_free_mnt_opts(*mnt_opts); 7358c2ecf20Sopenharmony_ci *mnt_opts = NULL; 7368c2ecf20Sopenharmony_ci return rc; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci } else { 7398c2ecf20Sopenharmony_ci if (!first) { // copy with preceding comma 7408c2ecf20Sopenharmony_ci from--; 7418c2ecf20Sopenharmony_ci len++; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci if (to != from) 7448c2ecf20Sopenharmony_ci memmove(to, from, len); 7458c2ecf20Sopenharmony_ci to += len; 7468c2ecf20Sopenharmony_ci first = false; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci if (!from[len]) 7498c2ecf20Sopenharmony_ci break; 7508c2ecf20Sopenharmony_ci from += len + 1; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci *to = '\0'; 7538c2ecf20Sopenharmony_ci return 0; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci/** 7578c2ecf20Sopenharmony_ci * smack_set_mnt_opts - set Smack specific mount options 7588c2ecf20Sopenharmony_ci * @sb: the file system superblock 7598c2ecf20Sopenharmony_ci * @mnt_opts: Smack mount options 7608c2ecf20Sopenharmony_ci * @kern_flags: mount option from kernel space or user space 7618c2ecf20Sopenharmony_ci * @set_kern_flags: where to store converted mount opts 7628c2ecf20Sopenharmony_ci * 7638c2ecf20Sopenharmony_ci * Returns 0 on success, an error code on failure 7648c2ecf20Sopenharmony_ci * 7658c2ecf20Sopenharmony_ci * Allow filesystems with binary mount data to explicitly set Smack mount 7668c2ecf20Sopenharmony_ci * labels. 7678c2ecf20Sopenharmony_ci */ 7688c2ecf20Sopenharmony_cistatic int smack_set_mnt_opts(struct super_block *sb, 7698c2ecf20Sopenharmony_ci void *mnt_opts, 7708c2ecf20Sopenharmony_ci unsigned long kern_flags, 7718c2ecf20Sopenharmony_ci unsigned long *set_kern_flags) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct dentry *root = sb->s_root; 7748c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(root); 7758c2ecf20Sopenharmony_ci struct superblock_smack *sp = sb->s_security; 7768c2ecf20Sopenharmony_ci struct inode_smack *isp; 7778c2ecf20Sopenharmony_ci struct smack_known *skp; 7788c2ecf20Sopenharmony_ci struct smack_mnt_opts *opts = mnt_opts; 7798c2ecf20Sopenharmony_ci bool transmute = false; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (sp->smk_flags & SMK_SB_INITIALIZED) 7828c2ecf20Sopenharmony_ci return 0; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (inode->i_security == NULL) { 7858c2ecf20Sopenharmony_ci int rc = lsm_inode_alloc(inode); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (rc) 7888c2ecf20Sopenharmony_ci return rc; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci if (!smack_privileged(CAP_MAC_ADMIN)) { 7928c2ecf20Sopenharmony_ci /* 7938c2ecf20Sopenharmony_ci * Unprivileged mounts don't get to specify Smack values. 7948c2ecf20Sopenharmony_ci */ 7958c2ecf20Sopenharmony_ci if (opts) 7968c2ecf20Sopenharmony_ci return -EPERM; 7978c2ecf20Sopenharmony_ci /* 7988c2ecf20Sopenharmony_ci * Unprivileged mounts get root and default from the caller. 7998c2ecf20Sopenharmony_ci */ 8008c2ecf20Sopenharmony_ci skp = smk_of_current(); 8018c2ecf20Sopenharmony_ci sp->smk_root = skp; 8028c2ecf20Sopenharmony_ci sp->smk_default = skp; 8038c2ecf20Sopenharmony_ci /* 8048c2ecf20Sopenharmony_ci * For a handful of fs types with no user-controlled 8058c2ecf20Sopenharmony_ci * backing store it's okay to trust security labels 8068c2ecf20Sopenharmony_ci * in the filesystem. The rest are untrusted. 8078c2ecf20Sopenharmony_ci */ 8088c2ecf20Sopenharmony_ci if (sb->s_user_ns != &init_user_ns && 8098c2ecf20Sopenharmony_ci sb->s_magic != SYSFS_MAGIC && sb->s_magic != TMPFS_MAGIC && 8108c2ecf20Sopenharmony_ci sb->s_magic != RAMFS_MAGIC) { 8118c2ecf20Sopenharmony_ci transmute = true; 8128c2ecf20Sopenharmony_ci sp->smk_flags |= SMK_SB_UNTRUSTED; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci sp->smk_flags |= SMK_SB_INITIALIZED; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (opts) { 8198c2ecf20Sopenharmony_ci if (opts->fsdefault) { 8208c2ecf20Sopenharmony_ci skp = smk_import_entry(opts->fsdefault, 0); 8218c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 8228c2ecf20Sopenharmony_ci return PTR_ERR(skp); 8238c2ecf20Sopenharmony_ci sp->smk_default = skp; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci if (opts->fsfloor) { 8268c2ecf20Sopenharmony_ci skp = smk_import_entry(opts->fsfloor, 0); 8278c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 8288c2ecf20Sopenharmony_ci return PTR_ERR(skp); 8298c2ecf20Sopenharmony_ci sp->smk_floor = skp; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci if (opts->fshat) { 8328c2ecf20Sopenharmony_ci skp = smk_import_entry(opts->fshat, 0); 8338c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 8348c2ecf20Sopenharmony_ci return PTR_ERR(skp); 8358c2ecf20Sopenharmony_ci sp->smk_hat = skp; 8368c2ecf20Sopenharmony_ci } 8378c2ecf20Sopenharmony_ci if (opts->fsroot) { 8388c2ecf20Sopenharmony_ci skp = smk_import_entry(opts->fsroot, 0); 8398c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 8408c2ecf20Sopenharmony_ci return PTR_ERR(skp); 8418c2ecf20Sopenharmony_ci sp->smk_root = skp; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci if (opts->fstransmute) { 8448c2ecf20Sopenharmony_ci skp = smk_import_entry(opts->fstransmute, 0); 8458c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 8468c2ecf20Sopenharmony_ci return PTR_ERR(skp); 8478c2ecf20Sopenharmony_ci sp->smk_root = skp; 8488c2ecf20Sopenharmony_ci transmute = true; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* 8538c2ecf20Sopenharmony_ci * Initialize the root inode. 8548c2ecf20Sopenharmony_ci */ 8558c2ecf20Sopenharmony_ci init_inode_smack(inode, sp->smk_root); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (transmute) { 8588c2ecf20Sopenharmony_ci isp = smack_inode(inode); 8598c2ecf20Sopenharmony_ci isp->smk_flags |= SMK_INODE_TRANSMUTE; 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci return 0; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci/** 8668c2ecf20Sopenharmony_ci * smack_sb_statfs - Smack check on statfs 8678c2ecf20Sopenharmony_ci * @dentry: identifies the file system in question 8688c2ecf20Sopenharmony_ci * 8698c2ecf20Sopenharmony_ci * Returns 0 if current can read the floor of the filesystem, 8708c2ecf20Sopenharmony_ci * and error code otherwise 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_cistatic int smack_sb_statfs(struct dentry *dentry) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct superblock_smack *sbp = dentry->d_sb->s_security; 8758c2ecf20Sopenharmony_ci int rc; 8768c2ecf20Sopenharmony_ci struct smk_audit_info ad; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 8798c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci rc = smk_curacc(sbp->smk_floor, MAY_READ, &ad); 8828c2ecf20Sopenharmony_ci rc = smk_bu_current("statfs", sbp->smk_floor, MAY_READ, rc); 8838c2ecf20Sopenharmony_ci return rc; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci/* 8878c2ecf20Sopenharmony_ci * BPRM hooks 8888c2ecf20Sopenharmony_ci */ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci/** 8918c2ecf20Sopenharmony_ci * smack_bprm_creds_for_exec - Update bprm->cred if needed for exec 8928c2ecf20Sopenharmony_ci * @bprm: the exec information 8938c2ecf20Sopenharmony_ci * 8948c2ecf20Sopenharmony_ci * Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_cistatic int smack_bprm_creds_for_exec(struct linux_binprm *bprm) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci struct inode *inode = file_inode(bprm->file); 8998c2ecf20Sopenharmony_ci struct task_smack *bsp = smack_cred(bprm->cred); 9008c2ecf20Sopenharmony_ci struct inode_smack *isp; 9018c2ecf20Sopenharmony_ci struct superblock_smack *sbsp; 9028c2ecf20Sopenharmony_ci int rc; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci isp = smack_inode(inode); 9058c2ecf20Sopenharmony_ci if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task) 9068c2ecf20Sopenharmony_ci return 0; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci sbsp = inode->i_sb->s_security; 9098c2ecf20Sopenharmony_ci if ((sbsp->smk_flags & SMK_SB_UNTRUSTED) && 9108c2ecf20Sopenharmony_ci isp->smk_task != sbsp->smk_root) 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (bprm->unsafe & LSM_UNSAFE_PTRACE) { 9148c2ecf20Sopenharmony_ci struct task_struct *tracer; 9158c2ecf20Sopenharmony_ci rc = 0; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci rcu_read_lock(); 9188c2ecf20Sopenharmony_ci tracer = ptrace_parent(current); 9198c2ecf20Sopenharmony_ci if (likely(tracer != NULL)) 9208c2ecf20Sopenharmony_ci rc = smk_ptrace_rule_check(tracer, 9218c2ecf20Sopenharmony_ci isp->smk_task, 9228c2ecf20Sopenharmony_ci PTRACE_MODE_ATTACH, 9238c2ecf20Sopenharmony_ci __func__); 9248c2ecf20Sopenharmony_ci rcu_read_unlock(); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (rc != 0) 9278c2ecf20Sopenharmony_ci return rc; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci if (bprm->unsafe & ~LSM_UNSAFE_PTRACE) 9308c2ecf20Sopenharmony_ci return -EPERM; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci bsp->smk_task = isp->smk_task; 9338c2ecf20Sopenharmony_ci bprm->per_clear |= PER_CLEAR_ON_SETID; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci /* Decide if this is a secure exec. */ 9368c2ecf20Sopenharmony_ci if (bsp->smk_task != bsp->smk_forked) 9378c2ecf20Sopenharmony_ci bprm->secureexec = 1; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci return 0; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/* 9438c2ecf20Sopenharmony_ci * Inode hooks 9448c2ecf20Sopenharmony_ci */ 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci/** 9478c2ecf20Sopenharmony_ci * smack_inode_alloc_security - allocate an inode blob 9488c2ecf20Sopenharmony_ci * @inode: the inode in need of a blob 9498c2ecf20Sopenharmony_ci * 9508c2ecf20Sopenharmony_ci * Returns 0 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_cistatic int smack_inode_alloc_security(struct inode *inode) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_current(); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci init_inode_smack(inode, skp); 9578c2ecf20Sopenharmony_ci return 0; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci/** 9618c2ecf20Sopenharmony_ci * smack_inode_init_security - copy out the smack from an inode 9628c2ecf20Sopenharmony_ci * @inode: the newly created inode 9638c2ecf20Sopenharmony_ci * @dir: containing directory object 9648c2ecf20Sopenharmony_ci * @qstr: unused 9658c2ecf20Sopenharmony_ci * @name: where to put the attribute name 9668c2ecf20Sopenharmony_ci * @value: where to put the attribute value 9678c2ecf20Sopenharmony_ci * @len: where to put the length of the attribute 9688c2ecf20Sopenharmony_ci * 9698c2ecf20Sopenharmony_ci * Returns 0 if it all works out, -ENOMEM if there's no memory 9708c2ecf20Sopenharmony_ci */ 9718c2ecf20Sopenharmony_cistatic int smack_inode_init_security(struct inode *inode, struct inode *dir, 9728c2ecf20Sopenharmony_ci const struct qstr *qstr, const char **name, 9738c2ecf20Sopenharmony_ci void **value, size_t *len) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 9768c2ecf20Sopenharmony_ci struct inode_smack *issp = smack_inode(inode); 9778c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_task(tsp); 9788c2ecf20Sopenharmony_ci struct smack_known *isp = smk_of_inode(inode); 9798c2ecf20Sopenharmony_ci struct smack_known *dsp = smk_of_inode(dir); 9808c2ecf20Sopenharmony_ci int may; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (name) 9838c2ecf20Sopenharmony_ci *name = XATTR_SMACK_SUFFIX; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (value && len) { 9868c2ecf20Sopenharmony_ci /* 9878c2ecf20Sopenharmony_ci * If equal, transmuting already occurred in 9888c2ecf20Sopenharmony_ci * smack_dentry_create_files_as(). No need to check again. 9898c2ecf20Sopenharmony_ci */ 9908c2ecf20Sopenharmony_ci if (tsp->smk_task != tsp->smk_transmuted) { 9918c2ecf20Sopenharmony_ci rcu_read_lock(); 9928c2ecf20Sopenharmony_ci may = smk_access_entry(skp->smk_known, dsp->smk_known, 9938c2ecf20Sopenharmony_ci &skp->smk_rules); 9948c2ecf20Sopenharmony_ci rcu_read_unlock(); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci /* 9988c2ecf20Sopenharmony_ci * In addition to having smk_task equal to smk_transmuted, 9998c2ecf20Sopenharmony_ci * if the access rule allows transmutation and the directory 10008c2ecf20Sopenharmony_ci * requests transmutation then by all means transmute. 10018c2ecf20Sopenharmony_ci * Mark the inode as changed. 10028c2ecf20Sopenharmony_ci */ 10038c2ecf20Sopenharmony_ci if ((tsp->smk_task == tsp->smk_transmuted) || 10048c2ecf20Sopenharmony_ci (may > 0 && ((may & MAY_TRANSMUTE) != 0) && 10058c2ecf20Sopenharmony_ci smk_inode_transmutable(dir))) { 10068c2ecf20Sopenharmony_ci /* 10078c2ecf20Sopenharmony_ci * The caller of smack_dentry_create_files_as() 10088c2ecf20Sopenharmony_ci * should have overridden the current cred, so the 10098c2ecf20Sopenharmony_ci * inode label was already set correctly in 10108c2ecf20Sopenharmony_ci * smack_inode_alloc_security(). 10118c2ecf20Sopenharmony_ci */ 10128c2ecf20Sopenharmony_ci if (tsp->smk_task != tsp->smk_transmuted) 10138c2ecf20Sopenharmony_ci isp = dsp; 10148c2ecf20Sopenharmony_ci issp->smk_flags |= SMK_INODE_CHANGED; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci *value = kstrdup(isp->smk_known, GFP_NOFS); 10188c2ecf20Sopenharmony_ci if (*value == NULL) 10198c2ecf20Sopenharmony_ci return -ENOMEM; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci *len = strlen(isp->smk_known); 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci/** 10288c2ecf20Sopenharmony_ci * smack_inode_link - Smack check on link 10298c2ecf20Sopenharmony_ci * @old_dentry: the existing object 10308c2ecf20Sopenharmony_ci * @dir: unused 10318c2ecf20Sopenharmony_ci * @new_dentry: the new object 10328c2ecf20Sopenharmony_ci * 10338c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 10348c2ecf20Sopenharmony_ci */ 10358c2ecf20Sopenharmony_cistatic int smack_inode_link(struct dentry *old_dentry, struct inode *dir, 10368c2ecf20Sopenharmony_ci struct dentry *new_dentry) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct smack_known *isp; 10398c2ecf20Sopenharmony_ci struct smk_audit_info ad; 10408c2ecf20Sopenharmony_ci int rc; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 10438c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci isp = smk_of_inode(d_backing_inode(old_dentry)); 10468c2ecf20Sopenharmony_ci rc = smk_curacc(isp, MAY_WRITE, &ad); 10478c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_WRITE, rc); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if (rc == 0 && d_is_positive(new_dentry)) { 10508c2ecf20Sopenharmony_ci isp = smk_of_inode(d_backing_inode(new_dentry)); 10518c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); 10528c2ecf20Sopenharmony_ci rc = smk_curacc(isp, MAY_WRITE, &ad); 10538c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_WRITE, rc); 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci return rc; 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci/** 10608c2ecf20Sopenharmony_ci * smack_inode_unlink - Smack check on inode deletion 10618c2ecf20Sopenharmony_ci * @dir: containing directory object 10628c2ecf20Sopenharmony_ci * @dentry: file to unlink 10638c2ecf20Sopenharmony_ci * 10648c2ecf20Sopenharmony_ci * Returns 0 if current can write the containing directory 10658c2ecf20Sopenharmony_ci * and the object, error code otherwise 10668c2ecf20Sopenharmony_ci */ 10678c2ecf20Sopenharmony_cistatic int smack_inode_unlink(struct inode *dir, struct dentry *dentry) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci struct inode *ip = d_backing_inode(dentry); 10708c2ecf20Sopenharmony_ci struct smk_audit_info ad; 10718c2ecf20Sopenharmony_ci int rc; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 10748c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* 10778c2ecf20Sopenharmony_ci * You need write access to the thing you're unlinking 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(ip), MAY_WRITE, &ad); 10808c2ecf20Sopenharmony_ci rc = smk_bu_inode(ip, MAY_WRITE, rc); 10818c2ecf20Sopenharmony_ci if (rc == 0) { 10828c2ecf20Sopenharmony_ci /* 10838c2ecf20Sopenharmony_ci * You also need write access to the containing directory 10848c2ecf20Sopenharmony_ci */ 10858c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); 10868c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_inode(&ad, dir); 10878c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); 10888c2ecf20Sopenharmony_ci rc = smk_bu_inode(dir, MAY_WRITE, rc); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci return rc; 10918c2ecf20Sopenharmony_ci} 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci/** 10948c2ecf20Sopenharmony_ci * smack_inode_rmdir - Smack check on directory deletion 10958c2ecf20Sopenharmony_ci * @dir: containing directory object 10968c2ecf20Sopenharmony_ci * @dentry: directory to unlink 10978c2ecf20Sopenharmony_ci * 10988c2ecf20Sopenharmony_ci * Returns 0 if current can write the containing directory 10998c2ecf20Sopenharmony_ci * and the directory, error code otherwise 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_cistatic int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) 11028c2ecf20Sopenharmony_ci{ 11038c2ecf20Sopenharmony_ci struct smk_audit_info ad; 11048c2ecf20Sopenharmony_ci int rc; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 11078c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* 11108c2ecf20Sopenharmony_ci * You need write access to the thing you're removing 11118c2ecf20Sopenharmony_ci */ 11128c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); 11138c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); 11148c2ecf20Sopenharmony_ci if (rc == 0) { 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * You also need write access to the containing directory 11178c2ecf20Sopenharmony_ci */ 11188c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); 11198c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_inode(&ad, dir); 11208c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(dir), MAY_WRITE, &ad); 11218c2ecf20Sopenharmony_ci rc = smk_bu_inode(dir, MAY_WRITE, rc); 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci return rc; 11258c2ecf20Sopenharmony_ci} 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci/** 11288c2ecf20Sopenharmony_ci * smack_inode_rename - Smack check on rename 11298c2ecf20Sopenharmony_ci * @old_inode: unused 11308c2ecf20Sopenharmony_ci * @old_dentry: the old object 11318c2ecf20Sopenharmony_ci * @new_inode: unused 11328c2ecf20Sopenharmony_ci * @new_dentry: the new object 11338c2ecf20Sopenharmony_ci * 11348c2ecf20Sopenharmony_ci * Read and write access is required on both the old and 11358c2ecf20Sopenharmony_ci * new directories. 11368c2ecf20Sopenharmony_ci * 11378c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 11388c2ecf20Sopenharmony_ci */ 11398c2ecf20Sopenharmony_cistatic int smack_inode_rename(struct inode *old_inode, 11408c2ecf20Sopenharmony_ci struct dentry *old_dentry, 11418c2ecf20Sopenharmony_ci struct inode *new_inode, 11428c2ecf20Sopenharmony_ci struct dentry *new_dentry) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci int rc; 11458c2ecf20Sopenharmony_ci struct smack_known *isp; 11468c2ecf20Sopenharmony_ci struct smk_audit_info ad; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 11498c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, old_dentry); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci isp = smk_of_inode(d_backing_inode(old_dentry)); 11528c2ecf20Sopenharmony_ci rc = smk_curacc(isp, MAY_READWRITE, &ad); 11538c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(old_dentry), MAY_READWRITE, rc); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci if (rc == 0 && d_is_positive(new_dentry)) { 11568c2ecf20Sopenharmony_ci isp = smk_of_inode(d_backing_inode(new_dentry)); 11578c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, new_dentry); 11588c2ecf20Sopenharmony_ci rc = smk_curacc(isp, MAY_READWRITE, &ad); 11598c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(new_dentry), MAY_READWRITE, rc); 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci return rc; 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci/** 11658c2ecf20Sopenharmony_ci * smack_inode_permission - Smack version of permission() 11668c2ecf20Sopenharmony_ci * @inode: the inode in question 11678c2ecf20Sopenharmony_ci * @mask: the access requested 11688c2ecf20Sopenharmony_ci * 11698c2ecf20Sopenharmony_ci * This is the important Smack hook. 11708c2ecf20Sopenharmony_ci * 11718c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 11728c2ecf20Sopenharmony_ci */ 11738c2ecf20Sopenharmony_cistatic int smack_inode_permission(struct inode *inode, int mask) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci struct superblock_smack *sbsp = inode->i_sb->s_security; 11768c2ecf20Sopenharmony_ci struct smk_audit_info ad; 11778c2ecf20Sopenharmony_ci int no_block = mask & MAY_NOT_BLOCK; 11788c2ecf20Sopenharmony_ci int rc; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); 11818c2ecf20Sopenharmony_ci /* 11828c2ecf20Sopenharmony_ci * No permission to check. Existence test. Yup, it's there. 11838c2ecf20Sopenharmony_ci */ 11848c2ecf20Sopenharmony_ci if (mask == 0) 11858c2ecf20Sopenharmony_ci return 0; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci if (sbsp->smk_flags & SMK_SB_UNTRUSTED) { 11888c2ecf20Sopenharmony_ci if (smk_of_inode(inode) != sbsp->smk_root) 11898c2ecf20Sopenharmony_ci return -EACCES; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* May be droppable after audit */ 11938c2ecf20Sopenharmony_ci if (no_block) 11948c2ecf20Sopenharmony_ci return -ECHILD; 11958c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_INODE); 11968c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_inode(&ad, inode); 11978c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), mask, &ad); 11988c2ecf20Sopenharmony_ci rc = smk_bu_inode(inode, mask, rc); 11998c2ecf20Sopenharmony_ci return rc; 12008c2ecf20Sopenharmony_ci} 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci/** 12038c2ecf20Sopenharmony_ci * smack_inode_setattr - Smack check for setting attributes 12048c2ecf20Sopenharmony_ci * @dentry: the object 12058c2ecf20Sopenharmony_ci * @iattr: for the force flag 12068c2ecf20Sopenharmony_ci * 12078c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 12088c2ecf20Sopenharmony_ci */ 12098c2ecf20Sopenharmony_cistatic int smack_inode_setattr(struct dentry *dentry, struct iattr *iattr) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci struct smk_audit_info ad; 12128c2ecf20Sopenharmony_ci int rc; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* 12158c2ecf20Sopenharmony_ci * Need to allow for clearing the setuid bit. 12168c2ecf20Sopenharmony_ci */ 12178c2ecf20Sopenharmony_ci if (iattr->ia_valid & ATTR_FORCE) 12188c2ecf20Sopenharmony_ci return 0; 12198c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 12208c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); 12238c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); 12248c2ecf20Sopenharmony_ci return rc; 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci/** 12288c2ecf20Sopenharmony_ci * smack_inode_getattr - Smack check for getting attributes 12298c2ecf20Sopenharmony_ci * @path: path to extract the info from 12308c2ecf20Sopenharmony_ci * 12318c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_cistatic int smack_inode_getattr(const struct path *path) 12348c2ecf20Sopenharmony_ci{ 12358c2ecf20Sopenharmony_ci struct smk_audit_info ad; 12368c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(path->dentry); 12378c2ecf20Sopenharmony_ci int rc; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 12408c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, *path); 12418c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); 12428c2ecf20Sopenharmony_ci rc = smk_bu_inode(inode, MAY_READ, rc); 12438c2ecf20Sopenharmony_ci return rc; 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci/** 12478c2ecf20Sopenharmony_ci * smack_inode_setxattr - Smack check for setting xattrs 12488c2ecf20Sopenharmony_ci * @dentry: the object 12498c2ecf20Sopenharmony_ci * @name: name of the attribute 12508c2ecf20Sopenharmony_ci * @value: value of the attribute 12518c2ecf20Sopenharmony_ci * @size: size of the value 12528c2ecf20Sopenharmony_ci * @flags: unused 12538c2ecf20Sopenharmony_ci * 12548c2ecf20Sopenharmony_ci * This protects the Smack attribute explicitly. 12558c2ecf20Sopenharmony_ci * 12568c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 12578c2ecf20Sopenharmony_ci */ 12588c2ecf20Sopenharmony_cistatic int smack_inode_setxattr(struct dentry *dentry, const char *name, 12598c2ecf20Sopenharmony_ci const void *value, size_t size, int flags) 12608c2ecf20Sopenharmony_ci{ 12618c2ecf20Sopenharmony_ci struct smk_audit_info ad; 12628c2ecf20Sopenharmony_ci struct smack_known *skp; 12638c2ecf20Sopenharmony_ci int check_priv = 0; 12648c2ecf20Sopenharmony_ci int check_import = 0; 12658c2ecf20Sopenharmony_ci int check_star = 0; 12668c2ecf20Sopenharmony_ci int rc = 0; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* 12698c2ecf20Sopenharmony_ci * Check label validity here so import won't fail in post_setxattr 12708c2ecf20Sopenharmony_ci */ 12718c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SMACK) == 0 || 12728c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || 12738c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) { 12748c2ecf20Sopenharmony_ci check_priv = 1; 12758c2ecf20Sopenharmony_ci check_import = 1; 12768c2ecf20Sopenharmony_ci } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || 12778c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { 12788c2ecf20Sopenharmony_ci check_priv = 1; 12798c2ecf20Sopenharmony_ci check_import = 1; 12808c2ecf20Sopenharmony_ci check_star = 1; 12818c2ecf20Sopenharmony_ci } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { 12828c2ecf20Sopenharmony_ci check_priv = 1; 12838c2ecf20Sopenharmony_ci if (size != TRANS_TRUE_SIZE || 12848c2ecf20Sopenharmony_ci strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0) 12858c2ecf20Sopenharmony_ci rc = -EINVAL; 12868c2ecf20Sopenharmony_ci } else 12878c2ecf20Sopenharmony_ci rc = cap_inode_setxattr(dentry, name, value, size, flags); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci if (check_priv && !smack_privileged(CAP_MAC_ADMIN)) 12908c2ecf20Sopenharmony_ci rc = -EPERM; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci if (rc == 0 && check_import) { 12938c2ecf20Sopenharmony_ci skp = size ? smk_import_entry(value, size) : NULL; 12948c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 12958c2ecf20Sopenharmony_ci rc = PTR_ERR(skp); 12968c2ecf20Sopenharmony_ci else if (skp == NULL || (check_star && 12978c2ecf20Sopenharmony_ci (skp == &smack_known_star || skp == &smack_known_web))) 12988c2ecf20Sopenharmony_ci rc = -EINVAL; 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 13028c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (rc == 0) { 13058c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); 13068c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci return rc; 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci/** 13138c2ecf20Sopenharmony_ci * smack_inode_post_setxattr - Apply the Smack update approved above 13148c2ecf20Sopenharmony_ci * @dentry: object 13158c2ecf20Sopenharmony_ci * @name: attribute name 13168c2ecf20Sopenharmony_ci * @value: attribute value 13178c2ecf20Sopenharmony_ci * @size: attribute size 13188c2ecf20Sopenharmony_ci * @flags: unused 13198c2ecf20Sopenharmony_ci * 13208c2ecf20Sopenharmony_ci * Set the pointer in the inode blob to the entry found 13218c2ecf20Sopenharmony_ci * in the master label list. 13228c2ecf20Sopenharmony_ci */ 13238c2ecf20Sopenharmony_cistatic void smack_inode_post_setxattr(struct dentry *dentry, const char *name, 13248c2ecf20Sopenharmony_ci const void *value, size_t size, int flags) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci struct smack_known *skp; 13278c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(d_backing_inode(dentry)); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { 13308c2ecf20Sopenharmony_ci isp->smk_flags |= SMK_INODE_TRANSMUTE; 13318c2ecf20Sopenharmony_ci return; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SMACK) == 0) { 13358c2ecf20Sopenharmony_ci skp = smk_import_entry(value, size); 13368c2ecf20Sopenharmony_ci if (!IS_ERR(skp)) 13378c2ecf20Sopenharmony_ci isp->smk_inode = skp; 13388c2ecf20Sopenharmony_ci } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) { 13398c2ecf20Sopenharmony_ci skp = smk_import_entry(value, size); 13408c2ecf20Sopenharmony_ci if (!IS_ERR(skp)) 13418c2ecf20Sopenharmony_ci isp->smk_task = skp; 13428c2ecf20Sopenharmony_ci } else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { 13438c2ecf20Sopenharmony_ci skp = smk_import_entry(value, size); 13448c2ecf20Sopenharmony_ci if (!IS_ERR(skp)) 13458c2ecf20Sopenharmony_ci isp->smk_mmap = skp; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci return; 13498c2ecf20Sopenharmony_ci} 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci/** 13528c2ecf20Sopenharmony_ci * smack_inode_getxattr - Smack check on getxattr 13538c2ecf20Sopenharmony_ci * @dentry: the object 13548c2ecf20Sopenharmony_ci * @name: unused 13558c2ecf20Sopenharmony_ci * 13568c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_cistatic int smack_inode_getxattr(struct dentry *dentry, const char *name) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci struct smk_audit_info ad; 13618c2ecf20Sopenharmony_ci int rc; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 13648c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_READ, &ad); 13678c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(dentry), MAY_READ, rc); 13688c2ecf20Sopenharmony_ci return rc; 13698c2ecf20Sopenharmony_ci} 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci/** 13728c2ecf20Sopenharmony_ci * smack_inode_removexattr - Smack check on removexattr 13738c2ecf20Sopenharmony_ci * @dentry: the object 13748c2ecf20Sopenharmony_ci * @name: name of the attribute 13758c2ecf20Sopenharmony_ci * 13768c2ecf20Sopenharmony_ci * Removing the Smack attribute requires CAP_MAC_ADMIN 13778c2ecf20Sopenharmony_ci * 13788c2ecf20Sopenharmony_ci * Returns 0 if access is permitted, an error code otherwise 13798c2ecf20Sopenharmony_ci */ 13808c2ecf20Sopenharmony_cistatic int smack_inode_removexattr(struct dentry *dentry, const char *name) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci struct inode_smack *isp; 13838c2ecf20Sopenharmony_ci struct smk_audit_info ad; 13848c2ecf20Sopenharmony_ci int rc = 0; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SMACK) == 0 || 13878c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKIPIN) == 0 || 13888c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 || 13898c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKEXEC) == 0 || 13908c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0 || 13918c2ecf20Sopenharmony_ci strcmp(name, XATTR_NAME_SMACKMMAP) == 0) { 13928c2ecf20Sopenharmony_ci if (!smack_privileged(CAP_MAC_ADMIN)) 13938c2ecf20Sopenharmony_ci rc = -EPERM; 13948c2ecf20Sopenharmony_ci } else 13958c2ecf20Sopenharmony_ci rc = cap_inode_removexattr(dentry, name); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (rc != 0) 13988c2ecf20Sopenharmony_ci return rc; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY); 14018c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path_dentry(&ad, dentry); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(d_backing_inode(dentry)), MAY_WRITE, &ad); 14048c2ecf20Sopenharmony_ci rc = smk_bu_inode(d_backing_inode(dentry), MAY_WRITE, rc); 14058c2ecf20Sopenharmony_ci if (rc != 0) 14068c2ecf20Sopenharmony_ci return rc; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci isp = smack_inode(d_backing_inode(dentry)); 14098c2ecf20Sopenharmony_ci /* 14108c2ecf20Sopenharmony_ci * Don't do anything special for these. 14118c2ecf20Sopenharmony_ci * XATTR_NAME_SMACKIPIN 14128c2ecf20Sopenharmony_ci * XATTR_NAME_SMACKIPOUT 14138c2ecf20Sopenharmony_ci */ 14148c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SMACK) == 0) { 14158c2ecf20Sopenharmony_ci struct super_block *sbp = dentry->d_sb; 14168c2ecf20Sopenharmony_ci struct superblock_smack *sbsp = sbp->s_security; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci isp->smk_inode = sbsp->smk_default; 14198c2ecf20Sopenharmony_ci } else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0) 14208c2ecf20Sopenharmony_ci isp->smk_task = NULL; 14218c2ecf20Sopenharmony_ci else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0) 14228c2ecf20Sopenharmony_ci isp->smk_mmap = NULL; 14238c2ecf20Sopenharmony_ci else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) 14248c2ecf20Sopenharmony_ci isp->smk_flags &= ~SMK_INODE_TRANSMUTE; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return 0; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci/** 14308c2ecf20Sopenharmony_ci * smack_inode_getsecurity - get smack xattrs 14318c2ecf20Sopenharmony_ci * @inode: the object 14328c2ecf20Sopenharmony_ci * @name: attribute name 14338c2ecf20Sopenharmony_ci * @buffer: where to put the result 14348c2ecf20Sopenharmony_ci * @alloc: duplicate memory 14358c2ecf20Sopenharmony_ci * 14368c2ecf20Sopenharmony_ci * Returns the size of the attribute or an error code 14378c2ecf20Sopenharmony_ci */ 14388c2ecf20Sopenharmony_cistatic int smack_inode_getsecurity(struct inode *inode, 14398c2ecf20Sopenharmony_ci const char *name, void **buffer, 14408c2ecf20Sopenharmony_ci bool alloc) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci struct socket_smack *ssp; 14438c2ecf20Sopenharmony_ci struct socket *sock; 14448c2ecf20Sopenharmony_ci struct super_block *sbp; 14458c2ecf20Sopenharmony_ci struct inode *ip = (struct inode *)inode; 14468c2ecf20Sopenharmony_ci struct smack_known *isp; 14478c2ecf20Sopenharmony_ci struct inode_smack *ispp; 14488c2ecf20Sopenharmony_ci size_t label_len; 14498c2ecf20Sopenharmony_ci char *label = NULL; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { 14528c2ecf20Sopenharmony_ci isp = smk_of_inode(inode); 14538c2ecf20Sopenharmony_ci } else if (strcmp(name, XATTR_SMACK_TRANSMUTE) == 0) { 14548c2ecf20Sopenharmony_ci ispp = smack_inode(inode); 14558c2ecf20Sopenharmony_ci if (ispp->smk_flags & SMK_INODE_TRANSMUTE) 14568c2ecf20Sopenharmony_ci label = TRANS_TRUE; 14578c2ecf20Sopenharmony_ci else 14588c2ecf20Sopenharmony_ci label = ""; 14598c2ecf20Sopenharmony_ci } else { 14608c2ecf20Sopenharmony_ci /* 14618c2ecf20Sopenharmony_ci * The rest of the Smack xattrs are only on sockets. 14628c2ecf20Sopenharmony_ci */ 14638c2ecf20Sopenharmony_ci sbp = ip->i_sb; 14648c2ecf20Sopenharmony_ci if (sbp->s_magic != SOCKFS_MAGIC) 14658c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci sock = SOCKET_I(ip); 14688c2ecf20Sopenharmony_ci if (sock == NULL || sock->sk == NULL) 14698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci ssp = sock->sk->sk_security; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_SMACK_IPIN) == 0) 14748c2ecf20Sopenharmony_ci isp = ssp->smk_in; 14758c2ecf20Sopenharmony_ci else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) 14768c2ecf20Sopenharmony_ci isp = ssp->smk_out; 14778c2ecf20Sopenharmony_ci else 14788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14798c2ecf20Sopenharmony_ci } 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (!label) 14828c2ecf20Sopenharmony_ci label = isp->smk_known; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci label_len = strlen(label); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (alloc) { 14878c2ecf20Sopenharmony_ci *buffer = kstrdup(label, GFP_KERNEL); 14888c2ecf20Sopenharmony_ci if (*buffer == NULL) 14898c2ecf20Sopenharmony_ci return -ENOMEM; 14908c2ecf20Sopenharmony_ci } 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return label_len; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci/** 14978c2ecf20Sopenharmony_ci * smack_inode_listsecurity - list the Smack attributes 14988c2ecf20Sopenharmony_ci * @inode: the object 14998c2ecf20Sopenharmony_ci * @buffer: where they go 15008c2ecf20Sopenharmony_ci * @buffer_size: size of buffer 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_cistatic int smack_inode_listsecurity(struct inode *inode, char *buffer, 15038c2ecf20Sopenharmony_ci size_t buffer_size) 15048c2ecf20Sopenharmony_ci{ 15058c2ecf20Sopenharmony_ci int len = sizeof(XATTR_NAME_SMACK); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci if (buffer != NULL && len <= buffer_size) 15088c2ecf20Sopenharmony_ci memcpy(buffer, XATTR_NAME_SMACK, len); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci return len; 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci/** 15148c2ecf20Sopenharmony_ci * smack_inode_getsecid - Extract inode's security id 15158c2ecf20Sopenharmony_ci * @inode: inode to extract the info from 15168c2ecf20Sopenharmony_ci * @secid: where result will be saved 15178c2ecf20Sopenharmony_ci */ 15188c2ecf20Sopenharmony_cistatic void smack_inode_getsecid(struct inode *inode, u32 *secid) 15198c2ecf20Sopenharmony_ci{ 15208c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_inode(inode); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci *secid = skp->smk_secid; 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci/* 15268c2ecf20Sopenharmony_ci * File Hooks 15278c2ecf20Sopenharmony_ci */ 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci/* 15308c2ecf20Sopenharmony_ci * There is no smack_file_permission hook 15318c2ecf20Sopenharmony_ci * 15328c2ecf20Sopenharmony_ci * Should access checks be done on each read or write? 15338c2ecf20Sopenharmony_ci * UNICOS and SELinux say yes. 15348c2ecf20Sopenharmony_ci * Trusted Solaris, Trusted Irix, and just about everyone else says no. 15358c2ecf20Sopenharmony_ci * 15368c2ecf20Sopenharmony_ci * I'll say no for now. Smack does not do the frequent 15378c2ecf20Sopenharmony_ci * label changing that SELinux does. 15388c2ecf20Sopenharmony_ci */ 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci/** 15418c2ecf20Sopenharmony_ci * smack_file_alloc_security - assign a file security blob 15428c2ecf20Sopenharmony_ci * @file: the object 15438c2ecf20Sopenharmony_ci * 15448c2ecf20Sopenharmony_ci * The security blob for a file is a pointer to the master 15458c2ecf20Sopenharmony_ci * label list, so no allocation is done. 15468c2ecf20Sopenharmony_ci * 15478c2ecf20Sopenharmony_ci * f_security is the owner security information. It 15488c2ecf20Sopenharmony_ci * isn't used on file access checks, it's for send_sigio. 15498c2ecf20Sopenharmony_ci * 15508c2ecf20Sopenharmony_ci * Returns 0 15518c2ecf20Sopenharmony_ci */ 15528c2ecf20Sopenharmony_cistatic int smack_file_alloc_security(struct file *file) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci struct smack_known **blob = smack_file(file); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_ci *blob = smk_of_current(); 15578c2ecf20Sopenharmony_ci return 0; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci/** 15618c2ecf20Sopenharmony_ci * smack_file_ioctl - Smack check on ioctls 15628c2ecf20Sopenharmony_ci * @file: the object 15638c2ecf20Sopenharmony_ci * @cmd: what to do 15648c2ecf20Sopenharmony_ci * @arg: unused 15658c2ecf20Sopenharmony_ci * 15668c2ecf20Sopenharmony_ci * Relies heavily on the correct use of the ioctl command conventions. 15678c2ecf20Sopenharmony_ci * 15688c2ecf20Sopenharmony_ci * Returns 0 if allowed, error code otherwise 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_cistatic int smack_file_ioctl(struct file *file, unsigned int cmd, 15718c2ecf20Sopenharmony_ci unsigned long arg) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci int rc = 0; 15748c2ecf20Sopenharmony_ci struct smk_audit_info ad; 15758c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 15818c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, file->f_path); 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (_IOC_DIR(cmd) & _IOC_WRITE) { 15848c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); 15858c2ecf20Sopenharmony_ci rc = smk_bu_file(file, MAY_WRITE, rc); 15868c2ecf20Sopenharmony_ci } 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci if (rc == 0 && (_IOC_DIR(cmd) & _IOC_READ)) { 15898c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), MAY_READ, &ad); 15908c2ecf20Sopenharmony_ci rc = smk_bu_file(file, MAY_READ, rc); 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci return rc; 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci/** 15978c2ecf20Sopenharmony_ci * smack_file_lock - Smack check on file locking 15988c2ecf20Sopenharmony_ci * @file: the object 15998c2ecf20Sopenharmony_ci * @cmd: unused 16008c2ecf20Sopenharmony_ci * 16018c2ecf20Sopenharmony_ci * Returns 0 if current has lock access, error code otherwise 16028c2ecf20Sopenharmony_ci */ 16038c2ecf20Sopenharmony_cistatic int smack_file_lock(struct file *file, unsigned int cmd) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct smk_audit_info ad; 16068c2ecf20Sopenharmony_ci int rc; 16078c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 16108c2ecf20Sopenharmony_ci return 0; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 16138c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, file->f_path); 16148c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); 16158c2ecf20Sopenharmony_ci rc = smk_bu_file(file, MAY_LOCK, rc); 16168c2ecf20Sopenharmony_ci return rc; 16178c2ecf20Sopenharmony_ci} 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci/** 16208c2ecf20Sopenharmony_ci * smack_file_fcntl - Smack check on fcntl 16218c2ecf20Sopenharmony_ci * @file: the object 16228c2ecf20Sopenharmony_ci * @cmd: what action to check 16238c2ecf20Sopenharmony_ci * @arg: unused 16248c2ecf20Sopenharmony_ci * 16258c2ecf20Sopenharmony_ci * Generally these operations are harmless. 16268c2ecf20Sopenharmony_ci * File locking operations present an obvious mechanism 16278c2ecf20Sopenharmony_ci * for passing information, so they require write access. 16288c2ecf20Sopenharmony_ci * 16298c2ecf20Sopenharmony_ci * Returns 0 if current has access, error code otherwise 16308c2ecf20Sopenharmony_ci */ 16318c2ecf20Sopenharmony_cistatic int smack_file_fcntl(struct file *file, unsigned int cmd, 16328c2ecf20Sopenharmony_ci unsigned long arg) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci struct smk_audit_info ad; 16358c2ecf20Sopenharmony_ci int rc = 0; 16368c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 16398c2ecf20Sopenharmony_ci return 0; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci switch (cmd) { 16428c2ecf20Sopenharmony_ci case F_GETLK: 16438c2ecf20Sopenharmony_ci break; 16448c2ecf20Sopenharmony_ci case F_SETLK: 16458c2ecf20Sopenharmony_ci case F_SETLKW: 16468c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 16478c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, file->f_path); 16488c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), MAY_LOCK, &ad); 16498c2ecf20Sopenharmony_ci rc = smk_bu_file(file, MAY_LOCK, rc); 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci case F_SETOWN: 16528c2ecf20Sopenharmony_ci case F_SETSIG: 16538c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 16548c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, file->f_path); 16558c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), MAY_WRITE, &ad); 16568c2ecf20Sopenharmony_ci rc = smk_bu_file(file, MAY_WRITE, rc); 16578c2ecf20Sopenharmony_ci break; 16588c2ecf20Sopenharmony_ci default: 16598c2ecf20Sopenharmony_ci break; 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci return rc; 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci/** 16668c2ecf20Sopenharmony_ci * smack_mmap_file : 16678c2ecf20Sopenharmony_ci * Check permissions for a mmap operation. The @file may be NULL, e.g. 16688c2ecf20Sopenharmony_ci * if mapping anonymous memory. 16698c2ecf20Sopenharmony_ci * @file contains the file structure for file to map (may be NULL). 16708c2ecf20Sopenharmony_ci * @reqprot contains the protection requested by the application. 16718c2ecf20Sopenharmony_ci * @prot contains the protection that will be applied by the kernel. 16728c2ecf20Sopenharmony_ci * @flags contains the operational flags. 16738c2ecf20Sopenharmony_ci * Return 0 if permission is granted. 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_cistatic int smack_mmap_file(struct file *file, 16768c2ecf20Sopenharmony_ci unsigned long reqprot, unsigned long prot, 16778c2ecf20Sopenharmony_ci unsigned long flags) 16788c2ecf20Sopenharmony_ci{ 16798c2ecf20Sopenharmony_ci struct smack_known *skp; 16808c2ecf20Sopenharmony_ci struct smack_known *mkp; 16818c2ecf20Sopenharmony_ci struct smack_rule *srp; 16828c2ecf20Sopenharmony_ci struct task_smack *tsp; 16838c2ecf20Sopenharmony_ci struct smack_known *okp; 16848c2ecf20Sopenharmony_ci struct inode_smack *isp; 16858c2ecf20Sopenharmony_ci struct superblock_smack *sbsp; 16868c2ecf20Sopenharmony_ci int may; 16878c2ecf20Sopenharmony_ci int mmay; 16888c2ecf20Sopenharmony_ci int tmay; 16898c2ecf20Sopenharmony_ci int rc; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (file == NULL) 16928c2ecf20Sopenharmony_ci return 0; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(file_inode(file)))) 16958c2ecf20Sopenharmony_ci return 0; 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci isp = smack_inode(file_inode(file)); 16988c2ecf20Sopenharmony_ci if (isp->smk_mmap == NULL) 16998c2ecf20Sopenharmony_ci return 0; 17008c2ecf20Sopenharmony_ci sbsp = file_inode(file)->i_sb->s_security; 17018c2ecf20Sopenharmony_ci if (sbsp->smk_flags & SMK_SB_UNTRUSTED && 17028c2ecf20Sopenharmony_ci isp->smk_mmap != sbsp->smk_root) 17038c2ecf20Sopenharmony_ci return -EACCES; 17048c2ecf20Sopenharmony_ci mkp = isp->smk_mmap; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci tsp = smack_cred(current_cred()); 17078c2ecf20Sopenharmony_ci skp = smk_of_current(); 17088c2ecf20Sopenharmony_ci rc = 0; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci rcu_read_lock(); 17118c2ecf20Sopenharmony_ci /* 17128c2ecf20Sopenharmony_ci * For each Smack rule associated with the subject 17138c2ecf20Sopenharmony_ci * label verify that the SMACK64MMAP also has access 17148c2ecf20Sopenharmony_ci * to that rule's object label. 17158c2ecf20Sopenharmony_ci */ 17168c2ecf20Sopenharmony_ci list_for_each_entry_rcu(srp, &skp->smk_rules, list) { 17178c2ecf20Sopenharmony_ci okp = srp->smk_object; 17188c2ecf20Sopenharmony_ci /* 17198c2ecf20Sopenharmony_ci * Matching labels always allows access. 17208c2ecf20Sopenharmony_ci */ 17218c2ecf20Sopenharmony_ci if (mkp->smk_known == okp->smk_known) 17228c2ecf20Sopenharmony_ci continue; 17238c2ecf20Sopenharmony_ci /* 17248c2ecf20Sopenharmony_ci * If there is a matching local rule take 17258c2ecf20Sopenharmony_ci * that into account as well. 17268c2ecf20Sopenharmony_ci */ 17278c2ecf20Sopenharmony_ci may = smk_access_entry(srp->smk_subject->smk_known, 17288c2ecf20Sopenharmony_ci okp->smk_known, 17298c2ecf20Sopenharmony_ci &tsp->smk_rules); 17308c2ecf20Sopenharmony_ci if (may == -ENOENT) 17318c2ecf20Sopenharmony_ci may = srp->smk_access; 17328c2ecf20Sopenharmony_ci else 17338c2ecf20Sopenharmony_ci may &= srp->smk_access; 17348c2ecf20Sopenharmony_ci /* 17358c2ecf20Sopenharmony_ci * If may is zero the SMACK64MMAP subject can't 17368c2ecf20Sopenharmony_ci * possibly have less access. 17378c2ecf20Sopenharmony_ci */ 17388c2ecf20Sopenharmony_ci if (may == 0) 17398c2ecf20Sopenharmony_ci continue; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci /* 17428c2ecf20Sopenharmony_ci * Fetch the global list entry. 17438c2ecf20Sopenharmony_ci * If there isn't one a SMACK64MMAP subject 17448c2ecf20Sopenharmony_ci * can't have as much access as current. 17458c2ecf20Sopenharmony_ci */ 17468c2ecf20Sopenharmony_ci mmay = smk_access_entry(mkp->smk_known, okp->smk_known, 17478c2ecf20Sopenharmony_ci &mkp->smk_rules); 17488c2ecf20Sopenharmony_ci if (mmay == -ENOENT) { 17498c2ecf20Sopenharmony_ci rc = -EACCES; 17508c2ecf20Sopenharmony_ci break; 17518c2ecf20Sopenharmony_ci } 17528c2ecf20Sopenharmony_ci /* 17538c2ecf20Sopenharmony_ci * If there is a local entry it modifies the 17548c2ecf20Sopenharmony_ci * potential access, too. 17558c2ecf20Sopenharmony_ci */ 17568c2ecf20Sopenharmony_ci tmay = smk_access_entry(mkp->smk_known, okp->smk_known, 17578c2ecf20Sopenharmony_ci &tsp->smk_rules); 17588c2ecf20Sopenharmony_ci if (tmay != -ENOENT) 17598c2ecf20Sopenharmony_ci mmay &= tmay; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* 17628c2ecf20Sopenharmony_ci * If there is any access available to current that is 17638c2ecf20Sopenharmony_ci * not available to a SMACK64MMAP subject 17648c2ecf20Sopenharmony_ci * deny access. 17658c2ecf20Sopenharmony_ci */ 17668c2ecf20Sopenharmony_ci if ((may | mmay) != mmay) { 17678c2ecf20Sopenharmony_ci rc = -EACCES; 17688c2ecf20Sopenharmony_ci break; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci } 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci rcu_read_unlock(); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci return rc; 17758c2ecf20Sopenharmony_ci} 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci/** 17788c2ecf20Sopenharmony_ci * smack_file_set_fowner - set the file security blob value 17798c2ecf20Sopenharmony_ci * @file: object in question 17808c2ecf20Sopenharmony_ci * 17818c2ecf20Sopenharmony_ci */ 17828c2ecf20Sopenharmony_cistatic void smack_file_set_fowner(struct file *file) 17838c2ecf20Sopenharmony_ci{ 17848c2ecf20Sopenharmony_ci struct smack_known **blob = smack_file(file); 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci *blob = smk_of_current(); 17878c2ecf20Sopenharmony_ci} 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci/** 17908c2ecf20Sopenharmony_ci * smack_file_send_sigiotask - Smack on sigio 17918c2ecf20Sopenharmony_ci * @tsk: The target task 17928c2ecf20Sopenharmony_ci * @fown: the object the signal come from 17938c2ecf20Sopenharmony_ci * @signum: unused 17948c2ecf20Sopenharmony_ci * 17958c2ecf20Sopenharmony_ci * Allow a privileged task to get signals even if it shouldn't 17968c2ecf20Sopenharmony_ci * 17978c2ecf20Sopenharmony_ci * Returns 0 if a subject with the object's smack could 17988c2ecf20Sopenharmony_ci * write to the task, an error code otherwise. 17998c2ecf20Sopenharmony_ci */ 18008c2ecf20Sopenharmony_cistatic int smack_file_send_sigiotask(struct task_struct *tsk, 18018c2ecf20Sopenharmony_ci struct fown_struct *fown, int signum) 18028c2ecf20Sopenharmony_ci{ 18038c2ecf20Sopenharmony_ci struct smack_known **blob; 18048c2ecf20Sopenharmony_ci struct smack_known *skp; 18058c2ecf20Sopenharmony_ci struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred)); 18068c2ecf20Sopenharmony_ci const struct cred *tcred; 18078c2ecf20Sopenharmony_ci struct file *file; 18088c2ecf20Sopenharmony_ci int rc; 18098c2ecf20Sopenharmony_ci struct smk_audit_info ad; 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci /* 18128c2ecf20Sopenharmony_ci * struct fown_struct is never outside the context of a struct file 18138c2ecf20Sopenharmony_ci */ 18148c2ecf20Sopenharmony_ci file = container_of(fown, struct file, f_owner); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* we don't log here as rc can be overriden */ 18178c2ecf20Sopenharmony_ci blob = smack_file(file); 18188c2ecf20Sopenharmony_ci skp = *blob; 18198c2ecf20Sopenharmony_ci rc = smk_access(skp, tkp, MAY_DELIVER, NULL); 18208c2ecf20Sopenharmony_ci rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc); 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci rcu_read_lock(); 18238c2ecf20Sopenharmony_ci tcred = __task_cred(tsk); 18248c2ecf20Sopenharmony_ci if (rc != 0 && smack_privileged_cred(CAP_MAC_OVERRIDE, tcred)) 18258c2ecf20Sopenharmony_ci rc = 0; 18268c2ecf20Sopenharmony_ci rcu_read_unlock(); 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); 18298c2ecf20Sopenharmony_ci smk_ad_setfield_u_tsk(&ad, tsk); 18308c2ecf20Sopenharmony_ci smack_log(skp->smk_known, tkp->smk_known, MAY_DELIVER, rc, &ad); 18318c2ecf20Sopenharmony_ci return rc; 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci/** 18358c2ecf20Sopenharmony_ci * smack_file_receive - Smack file receive check 18368c2ecf20Sopenharmony_ci * @file: the object 18378c2ecf20Sopenharmony_ci * 18388c2ecf20Sopenharmony_ci * Returns 0 if current has access, error code otherwise 18398c2ecf20Sopenharmony_ci */ 18408c2ecf20Sopenharmony_cistatic int smack_file_receive(struct file *file) 18418c2ecf20Sopenharmony_ci{ 18428c2ecf20Sopenharmony_ci int rc; 18438c2ecf20Sopenharmony_ci int may = 0; 18448c2ecf20Sopenharmony_ci struct smk_audit_info ad; 18458c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 18468c2ecf20Sopenharmony_ci struct socket *sock; 18478c2ecf20Sopenharmony_ci struct task_smack *tsp; 18488c2ecf20Sopenharmony_ci struct socket_smack *ssp; 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 18518c2ecf20Sopenharmony_ci return 0; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 18548c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, file->f_path); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci if (inode->i_sb->s_magic == SOCKFS_MAGIC) { 18578c2ecf20Sopenharmony_ci sock = SOCKET_I(inode); 18588c2ecf20Sopenharmony_ci ssp = sock->sk->sk_security; 18598c2ecf20Sopenharmony_ci tsp = smack_cred(current_cred()); 18608c2ecf20Sopenharmony_ci /* 18618c2ecf20Sopenharmony_ci * If the receiving process can't write to the 18628c2ecf20Sopenharmony_ci * passed socket or if the passed socket can't 18638c2ecf20Sopenharmony_ci * write to the receiving process don't accept 18648c2ecf20Sopenharmony_ci * the passed socket. 18658c2ecf20Sopenharmony_ci */ 18668c2ecf20Sopenharmony_ci rc = smk_access(tsp->smk_task, ssp->smk_out, MAY_WRITE, &ad); 18678c2ecf20Sopenharmony_ci rc = smk_bu_file(file, may, rc); 18688c2ecf20Sopenharmony_ci if (rc < 0) 18698c2ecf20Sopenharmony_ci return rc; 18708c2ecf20Sopenharmony_ci rc = smk_access(ssp->smk_in, tsp->smk_task, MAY_WRITE, &ad); 18718c2ecf20Sopenharmony_ci rc = smk_bu_file(file, may, rc); 18728c2ecf20Sopenharmony_ci return rc; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci /* 18758c2ecf20Sopenharmony_ci * This code relies on bitmasks. 18768c2ecf20Sopenharmony_ci */ 18778c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_READ) 18788c2ecf20Sopenharmony_ci may = MAY_READ; 18798c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_WRITE) 18808c2ecf20Sopenharmony_ci may |= MAY_WRITE; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci rc = smk_curacc(smk_of_inode(inode), may, &ad); 18838c2ecf20Sopenharmony_ci rc = smk_bu_file(file, may, rc); 18848c2ecf20Sopenharmony_ci return rc; 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci/** 18888c2ecf20Sopenharmony_ci * smack_file_open - Smack dentry open processing 18898c2ecf20Sopenharmony_ci * @file: the object 18908c2ecf20Sopenharmony_ci * 18918c2ecf20Sopenharmony_ci * Set the security blob in the file structure. 18928c2ecf20Sopenharmony_ci * Allow the open only if the task has read access. There are 18938c2ecf20Sopenharmony_ci * many read operations (e.g. fstat) that you can do with an 18948c2ecf20Sopenharmony_ci * fd even if you have the file open write-only. 18958c2ecf20Sopenharmony_ci * 18968c2ecf20Sopenharmony_ci * Returns 0 if current has access, error code otherwise 18978c2ecf20Sopenharmony_ci */ 18988c2ecf20Sopenharmony_cistatic int smack_file_open(struct file *file) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(file->f_cred); 19018c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 19028c2ecf20Sopenharmony_ci struct smk_audit_info ad; 19038c2ecf20Sopenharmony_ci int rc; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH); 19068c2ecf20Sopenharmony_ci smk_ad_setfield_u_fs_path(&ad, file->f_path); 19078c2ecf20Sopenharmony_ci rc = smk_tskacc(tsp, smk_of_inode(inode), MAY_READ, &ad); 19088c2ecf20Sopenharmony_ci rc = smk_bu_credfile(file->f_cred, file, MAY_READ, rc); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci return rc; 19118c2ecf20Sopenharmony_ci} 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci/* 19148c2ecf20Sopenharmony_ci * Task hooks 19158c2ecf20Sopenharmony_ci */ 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci/** 19188c2ecf20Sopenharmony_ci * smack_cred_alloc_blank - "allocate" blank task-level security credentials 19198c2ecf20Sopenharmony_ci * @cred: the new credentials 19208c2ecf20Sopenharmony_ci * @gfp: the atomicity of any memory allocations 19218c2ecf20Sopenharmony_ci * 19228c2ecf20Sopenharmony_ci * Prepare a blank set of credentials for modification. This must allocate all 19238c2ecf20Sopenharmony_ci * the memory the LSM module might require such that cred_transfer() can 19248c2ecf20Sopenharmony_ci * complete without error. 19258c2ecf20Sopenharmony_ci */ 19268c2ecf20Sopenharmony_cistatic int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) 19278c2ecf20Sopenharmony_ci{ 19288c2ecf20Sopenharmony_ci init_task_smack(smack_cred(cred), NULL, NULL); 19298c2ecf20Sopenharmony_ci return 0; 19308c2ecf20Sopenharmony_ci} 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci/** 19348c2ecf20Sopenharmony_ci * smack_cred_free - "free" task-level security credentials 19358c2ecf20Sopenharmony_ci * @cred: the credentials in question 19368c2ecf20Sopenharmony_ci * 19378c2ecf20Sopenharmony_ci */ 19388c2ecf20Sopenharmony_cistatic void smack_cred_free(struct cred *cred) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(cred); 19418c2ecf20Sopenharmony_ci struct smack_rule *rp; 19428c2ecf20Sopenharmony_ci struct list_head *l; 19438c2ecf20Sopenharmony_ci struct list_head *n; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci smk_destroy_label_list(&tsp->smk_relabel); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci list_for_each_safe(l, n, &tsp->smk_rules) { 19488c2ecf20Sopenharmony_ci rp = list_entry(l, struct smack_rule, list); 19498c2ecf20Sopenharmony_ci list_del(&rp->list); 19508c2ecf20Sopenharmony_ci kmem_cache_free(smack_rule_cache, rp); 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci} 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci/** 19558c2ecf20Sopenharmony_ci * smack_cred_prepare - prepare new set of credentials for modification 19568c2ecf20Sopenharmony_ci * @new: the new credentials 19578c2ecf20Sopenharmony_ci * @old: the original credentials 19588c2ecf20Sopenharmony_ci * @gfp: the atomicity of any memory allocations 19598c2ecf20Sopenharmony_ci * 19608c2ecf20Sopenharmony_ci * Prepare a new set of credentials for modification. 19618c2ecf20Sopenharmony_ci */ 19628c2ecf20Sopenharmony_cistatic int smack_cred_prepare(struct cred *new, const struct cred *old, 19638c2ecf20Sopenharmony_ci gfp_t gfp) 19648c2ecf20Sopenharmony_ci{ 19658c2ecf20Sopenharmony_ci struct task_smack *old_tsp = smack_cred(old); 19668c2ecf20Sopenharmony_ci struct task_smack *new_tsp = smack_cred(new); 19678c2ecf20Sopenharmony_ci int rc; 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task); 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); 19728c2ecf20Sopenharmony_ci if (rc != 0) 19738c2ecf20Sopenharmony_ci return rc; 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel, 19768c2ecf20Sopenharmony_ci gfp); 19778c2ecf20Sopenharmony_ci return rc; 19788c2ecf20Sopenharmony_ci} 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci/** 19818c2ecf20Sopenharmony_ci * smack_cred_transfer - Transfer the old credentials to the new credentials 19828c2ecf20Sopenharmony_ci * @new: the new credentials 19838c2ecf20Sopenharmony_ci * @old: the original credentials 19848c2ecf20Sopenharmony_ci * 19858c2ecf20Sopenharmony_ci * Fill in a set of blank credentials from another set of credentials. 19868c2ecf20Sopenharmony_ci */ 19878c2ecf20Sopenharmony_cistatic void smack_cred_transfer(struct cred *new, const struct cred *old) 19888c2ecf20Sopenharmony_ci{ 19898c2ecf20Sopenharmony_ci struct task_smack *old_tsp = smack_cred(old); 19908c2ecf20Sopenharmony_ci struct task_smack *new_tsp = smack_cred(new); 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci new_tsp->smk_task = old_tsp->smk_task; 19938c2ecf20Sopenharmony_ci new_tsp->smk_forked = old_tsp->smk_task; 19948c2ecf20Sopenharmony_ci mutex_init(&new_tsp->smk_rules_lock); 19958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&new_tsp->smk_rules); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci /* cbs copy rule list */ 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci/** 20018c2ecf20Sopenharmony_ci * smack_cred_getsecid - get the secid corresponding to a creds structure 20028c2ecf20Sopenharmony_ci * @cred: the object creds 20038c2ecf20Sopenharmony_ci * @secid: where to put the result 20048c2ecf20Sopenharmony_ci * 20058c2ecf20Sopenharmony_ci * Sets the secid to contain a u32 version of the smack label. 20068c2ecf20Sopenharmony_ci */ 20078c2ecf20Sopenharmony_cistatic void smack_cred_getsecid(const struct cred *cred, u32 *secid) 20088c2ecf20Sopenharmony_ci{ 20098c2ecf20Sopenharmony_ci struct smack_known *skp; 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci rcu_read_lock(); 20128c2ecf20Sopenharmony_ci skp = smk_of_task(smack_cred(cred)); 20138c2ecf20Sopenharmony_ci *secid = skp->smk_secid; 20148c2ecf20Sopenharmony_ci rcu_read_unlock(); 20158c2ecf20Sopenharmony_ci} 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci/** 20188c2ecf20Sopenharmony_ci * smack_kernel_act_as - Set the subjective context in a set of credentials 20198c2ecf20Sopenharmony_ci * @new: points to the set of credentials to be modified. 20208c2ecf20Sopenharmony_ci * @secid: specifies the security ID to be set 20218c2ecf20Sopenharmony_ci * 20228c2ecf20Sopenharmony_ci * Set the security data for a kernel service. 20238c2ecf20Sopenharmony_ci */ 20248c2ecf20Sopenharmony_cistatic int smack_kernel_act_as(struct cred *new, u32 secid) 20258c2ecf20Sopenharmony_ci{ 20268c2ecf20Sopenharmony_ci struct task_smack *new_tsp = smack_cred(new); 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci new_tsp->smk_task = smack_from_secid(secid); 20298c2ecf20Sopenharmony_ci return 0; 20308c2ecf20Sopenharmony_ci} 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci/** 20338c2ecf20Sopenharmony_ci * smack_kernel_create_files_as - Set the file creation label in a set of creds 20348c2ecf20Sopenharmony_ci * @new: points to the set of credentials to be modified 20358c2ecf20Sopenharmony_ci * @inode: points to the inode to use as a reference 20368c2ecf20Sopenharmony_ci * 20378c2ecf20Sopenharmony_ci * Set the file creation context in a set of credentials to the same 20388c2ecf20Sopenharmony_ci * as the objective context of the specified inode 20398c2ecf20Sopenharmony_ci */ 20408c2ecf20Sopenharmony_cistatic int smack_kernel_create_files_as(struct cred *new, 20418c2ecf20Sopenharmony_ci struct inode *inode) 20428c2ecf20Sopenharmony_ci{ 20438c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(inode); 20448c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(new); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci tsp->smk_forked = isp->smk_inode; 20478c2ecf20Sopenharmony_ci tsp->smk_task = tsp->smk_forked; 20488c2ecf20Sopenharmony_ci return 0; 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci/** 20528c2ecf20Sopenharmony_ci * smk_curacc_on_task - helper to log task related access 20538c2ecf20Sopenharmony_ci * @p: the task object 20548c2ecf20Sopenharmony_ci * @access: the access requested 20558c2ecf20Sopenharmony_ci * @caller: name of the calling function for audit 20568c2ecf20Sopenharmony_ci * 20578c2ecf20Sopenharmony_ci * Return 0 if access is permitted 20588c2ecf20Sopenharmony_ci */ 20598c2ecf20Sopenharmony_cistatic int smk_curacc_on_task(struct task_struct *p, int access, 20608c2ecf20Sopenharmony_ci const char *caller) 20618c2ecf20Sopenharmony_ci{ 20628c2ecf20Sopenharmony_ci struct smk_audit_info ad; 20638c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_task_struct(p); 20648c2ecf20Sopenharmony_ci int rc; 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_ci smk_ad_init(&ad, caller, LSM_AUDIT_DATA_TASK); 20678c2ecf20Sopenharmony_ci smk_ad_setfield_u_tsk(&ad, p); 20688c2ecf20Sopenharmony_ci rc = smk_curacc(skp, access, &ad); 20698c2ecf20Sopenharmony_ci rc = smk_bu_task(p, access, rc); 20708c2ecf20Sopenharmony_ci return rc; 20718c2ecf20Sopenharmony_ci} 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci/** 20748c2ecf20Sopenharmony_ci * smack_task_setpgid - Smack check on setting pgid 20758c2ecf20Sopenharmony_ci * @p: the task object 20768c2ecf20Sopenharmony_ci * @pgid: unused 20778c2ecf20Sopenharmony_ci * 20788c2ecf20Sopenharmony_ci * Return 0 if write access is permitted 20798c2ecf20Sopenharmony_ci */ 20808c2ecf20Sopenharmony_cistatic int smack_task_setpgid(struct task_struct *p, pid_t pgid) 20818c2ecf20Sopenharmony_ci{ 20828c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_WRITE, __func__); 20838c2ecf20Sopenharmony_ci} 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci/** 20868c2ecf20Sopenharmony_ci * smack_task_getpgid - Smack access check for getpgid 20878c2ecf20Sopenharmony_ci * @p: the object task 20888c2ecf20Sopenharmony_ci * 20898c2ecf20Sopenharmony_ci * Returns 0 if current can read the object task, error code otherwise 20908c2ecf20Sopenharmony_ci */ 20918c2ecf20Sopenharmony_cistatic int smack_task_getpgid(struct task_struct *p) 20928c2ecf20Sopenharmony_ci{ 20938c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_READ, __func__); 20948c2ecf20Sopenharmony_ci} 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci/** 20978c2ecf20Sopenharmony_ci * smack_task_getsid - Smack access check for getsid 20988c2ecf20Sopenharmony_ci * @p: the object task 20998c2ecf20Sopenharmony_ci * 21008c2ecf20Sopenharmony_ci * Returns 0 if current can read the object task, error code otherwise 21018c2ecf20Sopenharmony_ci */ 21028c2ecf20Sopenharmony_cistatic int smack_task_getsid(struct task_struct *p) 21038c2ecf20Sopenharmony_ci{ 21048c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_READ, __func__); 21058c2ecf20Sopenharmony_ci} 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci/** 21088c2ecf20Sopenharmony_ci * smack_task_getsecid - get the secid of the task 21098c2ecf20Sopenharmony_ci * @p: the object task 21108c2ecf20Sopenharmony_ci * @secid: where to put the result 21118c2ecf20Sopenharmony_ci * 21128c2ecf20Sopenharmony_ci * Sets the secid to contain a u32 version of the smack label. 21138c2ecf20Sopenharmony_ci */ 21148c2ecf20Sopenharmony_cistatic void smack_task_getsecid(struct task_struct *p, u32 *secid) 21158c2ecf20Sopenharmony_ci{ 21168c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_task_struct(p); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci *secid = skp->smk_secid; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci/** 21228c2ecf20Sopenharmony_ci * smack_task_setnice - Smack check on setting nice 21238c2ecf20Sopenharmony_ci * @p: the task object 21248c2ecf20Sopenharmony_ci * @nice: unused 21258c2ecf20Sopenharmony_ci * 21268c2ecf20Sopenharmony_ci * Return 0 if write access is permitted 21278c2ecf20Sopenharmony_ci */ 21288c2ecf20Sopenharmony_cistatic int smack_task_setnice(struct task_struct *p, int nice) 21298c2ecf20Sopenharmony_ci{ 21308c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_WRITE, __func__); 21318c2ecf20Sopenharmony_ci} 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci/** 21348c2ecf20Sopenharmony_ci * smack_task_setioprio - Smack check on setting ioprio 21358c2ecf20Sopenharmony_ci * @p: the task object 21368c2ecf20Sopenharmony_ci * @ioprio: unused 21378c2ecf20Sopenharmony_ci * 21388c2ecf20Sopenharmony_ci * Return 0 if write access is permitted 21398c2ecf20Sopenharmony_ci */ 21408c2ecf20Sopenharmony_cistatic int smack_task_setioprio(struct task_struct *p, int ioprio) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_WRITE, __func__); 21438c2ecf20Sopenharmony_ci} 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci/** 21468c2ecf20Sopenharmony_ci * smack_task_getioprio - Smack check on reading ioprio 21478c2ecf20Sopenharmony_ci * @p: the task object 21488c2ecf20Sopenharmony_ci * 21498c2ecf20Sopenharmony_ci * Return 0 if read access is permitted 21508c2ecf20Sopenharmony_ci */ 21518c2ecf20Sopenharmony_cistatic int smack_task_getioprio(struct task_struct *p) 21528c2ecf20Sopenharmony_ci{ 21538c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_READ, __func__); 21548c2ecf20Sopenharmony_ci} 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci/** 21578c2ecf20Sopenharmony_ci * smack_task_setscheduler - Smack check on setting scheduler 21588c2ecf20Sopenharmony_ci * @p: the task object 21598c2ecf20Sopenharmony_ci * 21608c2ecf20Sopenharmony_ci * Return 0 if read access is permitted 21618c2ecf20Sopenharmony_ci */ 21628c2ecf20Sopenharmony_cistatic int smack_task_setscheduler(struct task_struct *p) 21638c2ecf20Sopenharmony_ci{ 21648c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_WRITE, __func__); 21658c2ecf20Sopenharmony_ci} 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci/** 21688c2ecf20Sopenharmony_ci * smack_task_getscheduler - Smack check on reading scheduler 21698c2ecf20Sopenharmony_ci * @p: the task object 21708c2ecf20Sopenharmony_ci * 21718c2ecf20Sopenharmony_ci * Return 0 if read access is permitted 21728c2ecf20Sopenharmony_ci */ 21738c2ecf20Sopenharmony_cistatic int smack_task_getscheduler(struct task_struct *p) 21748c2ecf20Sopenharmony_ci{ 21758c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_READ, __func__); 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci/** 21798c2ecf20Sopenharmony_ci * smack_task_movememory - Smack check on moving memory 21808c2ecf20Sopenharmony_ci * @p: the task object 21818c2ecf20Sopenharmony_ci * 21828c2ecf20Sopenharmony_ci * Return 0 if write access is permitted 21838c2ecf20Sopenharmony_ci */ 21848c2ecf20Sopenharmony_cistatic int smack_task_movememory(struct task_struct *p) 21858c2ecf20Sopenharmony_ci{ 21868c2ecf20Sopenharmony_ci return smk_curacc_on_task(p, MAY_WRITE, __func__); 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci/** 21908c2ecf20Sopenharmony_ci * smack_task_kill - Smack check on signal delivery 21918c2ecf20Sopenharmony_ci * @p: the task object 21928c2ecf20Sopenharmony_ci * @info: unused 21938c2ecf20Sopenharmony_ci * @sig: unused 21948c2ecf20Sopenharmony_ci * @cred: identifies the cred to use in lieu of current's 21958c2ecf20Sopenharmony_ci * 21968c2ecf20Sopenharmony_ci * Return 0 if write access is permitted 21978c2ecf20Sopenharmony_ci * 21988c2ecf20Sopenharmony_ci */ 21998c2ecf20Sopenharmony_cistatic int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, 22008c2ecf20Sopenharmony_ci int sig, const struct cred *cred) 22018c2ecf20Sopenharmony_ci{ 22028c2ecf20Sopenharmony_ci struct smk_audit_info ad; 22038c2ecf20Sopenharmony_ci struct smack_known *skp; 22048c2ecf20Sopenharmony_ci struct smack_known *tkp = smk_of_task_struct(p); 22058c2ecf20Sopenharmony_ci int rc; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci if (!sig) 22088c2ecf20Sopenharmony_ci return 0; /* null signal; existence test */ 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK); 22118c2ecf20Sopenharmony_ci smk_ad_setfield_u_tsk(&ad, p); 22128c2ecf20Sopenharmony_ci /* 22138c2ecf20Sopenharmony_ci * Sending a signal requires that the sender 22148c2ecf20Sopenharmony_ci * can write the receiver. 22158c2ecf20Sopenharmony_ci */ 22168c2ecf20Sopenharmony_ci if (cred == NULL) { 22178c2ecf20Sopenharmony_ci rc = smk_curacc(tkp, MAY_DELIVER, &ad); 22188c2ecf20Sopenharmony_ci rc = smk_bu_task(p, MAY_DELIVER, rc); 22198c2ecf20Sopenharmony_ci return rc; 22208c2ecf20Sopenharmony_ci } 22218c2ecf20Sopenharmony_ci /* 22228c2ecf20Sopenharmony_ci * If the cred isn't NULL we're dealing with some USB IO 22238c2ecf20Sopenharmony_ci * specific behavior. This is not clean. For one thing 22248c2ecf20Sopenharmony_ci * we can't take privilege into account. 22258c2ecf20Sopenharmony_ci */ 22268c2ecf20Sopenharmony_ci skp = smk_of_task(smack_cred(cred)); 22278c2ecf20Sopenharmony_ci rc = smk_access(skp, tkp, MAY_DELIVER, &ad); 22288c2ecf20Sopenharmony_ci rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc); 22298c2ecf20Sopenharmony_ci return rc; 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci/** 22338c2ecf20Sopenharmony_ci * smack_task_to_inode - copy task smack into the inode blob 22348c2ecf20Sopenharmony_ci * @p: task to copy from 22358c2ecf20Sopenharmony_ci * @inode: inode to copy to 22368c2ecf20Sopenharmony_ci * 22378c2ecf20Sopenharmony_ci * Sets the smack pointer in the inode security blob 22388c2ecf20Sopenharmony_ci */ 22398c2ecf20Sopenharmony_cistatic void smack_task_to_inode(struct task_struct *p, struct inode *inode) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci struct inode_smack *isp = smack_inode(inode); 22428c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_task_struct(p); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci isp->smk_inode = skp; 22458c2ecf20Sopenharmony_ci isp->smk_flags |= SMK_INODE_INSTANT; 22468c2ecf20Sopenharmony_ci} 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci/* 22498c2ecf20Sopenharmony_ci * Socket hooks. 22508c2ecf20Sopenharmony_ci */ 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci/** 22538c2ecf20Sopenharmony_ci * smack_sk_alloc_security - Allocate a socket blob 22548c2ecf20Sopenharmony_ci * @sk: the socket 22558c2ecf20Sopenharmony_ci * @family: unused 22568c2ecf20Sopenharmony_ci * @gfp_flags: memory allocation flags 22578c2ecf20Sopenharmony_ci * 22588c2ecf20Sopenharmony_ci * Assign Smack pointers to current 22598c2ecf20Sopenharmony_ci * 22608c2ecf20Sopenharmony_ci * Returns 0 on success, -ENOMEM is there's no memory 22618c2ecf20Sopenharmony_ci */ 22628c2ecf20Sopenharmony_cistatic int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) 22638c2ecf20Sopenharmony_ci{ 22648c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_current(); 22658c2ecf20Sopenharmony_ci struct socket_smack *ssp; 22668c2ecf20Sopenharmony_ci 22678c2ecf20Sopenharmony_ci ssp = kzalloc(sizeof(struct socket_smack), gfp_flags); 22688c2ecf20Sopenharmony_ci if (ssp == NULL) 22698c2ecf20Sopenharmony_ci return -ENOMEM; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci /* 22728c2ecf20Sopenharmony_ci * Sockets created by kernel threads receive web label. 22738c2ecf20Sopenharmony_ci */ 22748c2ecf20Sopenharmony_ci if (unlikely(current->flags & PF_KTHREAD)) { 22758c2ecf20Sopenharmony_ci ssp->smk_in = &smack_known_web; 22768c2ecf20Sopenharmony_ci ssp->smk_out = &smack_known_web; 22778c2ecf20Sopenharmony_ci } else { 22788c2ecf20Sopenharmony_ci ssp->smk_in = skp; 22798c2ecf20Sopenharmony_ci ssp->smk_out = skp; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci ssp->smk_packet = NULL; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci sk->sk_security = ssp; 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci return 0; 22868c2ecf20Sopenharmony_ci} 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_ci/** 22898c2ecf20Sopenharmony_ci * smack_sk_free_security - Free a socket blob 22908c2ecf20Sopenharmony_ci * @sk: the socket 22918c2ecf20Sopenharmony_ci * 22928c2ecf20Sopenharmony_ci * Clears the blob pointer 22938c2ecf20Sopenharmony_ci */ 22948c2ecf20Sopenharmony_cistatic void smack_sk_free_security(struct sock *sk) 22958c2ecf20Sopenharmony_ci{ 22968c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 22978c2ecf20Sopenharmony_ci struct smk_port_label *spp; 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (sk->sk_family == PF_INET6) { 23008c2ecf20Sopenharmony_ci rcu_read_lock(); 23018c2ecf20Sopenharmony_ci list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { 23028c2ecf20Sopenharmony_ci if (spp->smk_sock != sk) 23038c2ecf20Sopenharmony_ci continue; 23048c2ecf20Sopenharmony_ci spp->smk_can_reuse = 1; 23058c2ecf20Sopenharmony_ci break; 23068c2ecf20Sopenharmony_ci } 23078c2ecf20Sopenharmony_ci rcu_read_unlock(); 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci#endif 23108c2ecf20Sopenharmony_ci kfree(sk->sk_security); 23118c2ecf20Sopenharmony_ci} 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci/** 23148c2ecf20Sopenharmony_ci* smack_ipv4host_label - check host based restrictions 23158c2ecf20Sopenharmony_ci* @sip: the object end 23168c2ecf20Sopenharmony_ci* 23178c2ecf20Sopenharmony_ci* looks for host based access restrictions 23188c2ecf20Sopenharmony_ci* 23198c2ecf20Sopenharmony_ci* This version will only be appropriate for really small sets of single label 23208c2ecf20Sopenharmony_ci* hosts. The caller is responsible for ensuring that the RCU read lock is 23218c2ecf20Sopenharmony_ci* taken before calling this function. 23228c2ecf20Sopenharmony_ci* 23238c2ecf20Sopenharmony_ci* Returns the label of the far end or NULL if it's not special. 23248c2ecf20Sopenharmony_ci*/ 23258c2ecf20Sopenharmony_cistatic struct smack_known *smack_ipv4host_label(struct sockaddr_in *sip) 23268c2ecf20Sopenharmony_ci{ 23278c2ecf20Sopenharmony_ci struct smk_net4addr *snp; 23288c2ecf20Sopenharmony_ci struct in_addr *siap = &sip->sin_addr; 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci if (siap->s_addr == 0) 23318c2ecf20Sopenharmony_ci return NULL; 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci list_for_each_entry_rcu(snp, &smk_net4addr_list, list) 23348c2ecf20Sopenharmony_ci /* 23358c2ecf20Sopenharmony_ci * we break after finding the first match because 23368c2ecf20Sopenharmony_ci * the list is sorted from longest to shortest mask 23378c2ecf20Sopenharmony_ci * so we have found the most specific match 23388c2ecf20Sopenharmony_ci */ 23398c2ecf20Sopenharmony_ci if (snp->smk_host.s_addr == 23408c2ecf20Sopenharmony_ci (siap->s_addr & snp->smk_mask.s_addr)) 23418c2ecf20Sopenharmony_ci return snp->smk_label; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci return NULL; 23448c2ecf20Sopenharmony_ci} 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci/* 23478c2ecf20Sopenharmony_ci * smk_ipv6_localhost - Check for local ipv6 host address 23488c2ecf20Sopenharmony_ci * @sip: the address 23498c2ecf20Sopenharmony_ci * 23508c2ecf20Sopenharmony_ci * Returns boolean true if this is the localhost address 23518c2ecf20Sopenharmony_ci */ 23528c2ecf20Sopenharmony_cistatic bool smk_ipv6_localhost(struct sockaddr_in6 *sip) 23538c2ecf20Sopenharmony_ci{ 23548c2ecf20Sopenharmony_ci __be16 *be16p = (__be16 *)&sip->sin6_addr; 23558c2ecf20Sopenharmony_ci __be32 *be32p = (__be32 *)&sip->sin6_addr; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci if (be32p[0] == 0 && be32p[1] == 0 && be32p[2] == 0 && be16p[6] == 0 && 23588c2ecf20Sopenharmony_ci ntohs(be16p[7]) == 1) 23598c2ecf20Sopenharmony_ci return true; 23608c2ecf20Sopenharmony_ci return false; 23618c2ecf20Sopenharmony_ci} 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci/** 23648c2ecf20Sopenharmony_ci* smack_ipv6host_label - check host based restrictions 23658c2ecf20Sopenharmony_ci* @sip: the object end 23668c2ecf20Sopenharmony_ci* 23678c2ecf20Sopenharmony_ci* looks for host based access restrictions 23688c2ecf20Sopenharmony_ci* 23698c2ecf20Sopenharmony_ci* This version will only be appropriate for really small sets of single label 23708c2ecf20Sopenharmony_ci* hosts. The caller is responsible for ensuring that the RCU read lock is 23718c2ecf20Sopenharmony_ci* taken before calling this function. 23728c2ecf20Sopenharmony_ci* 23738c2ecf20Sopenharmony_ci* Returns the label of the far end or NULL if it's not special. 23748c2ecf20Sopenharmony_ci*/ 23758c2ecf20Sopenharmony_cistatic struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip) 23768c2ecf20Sopenharmony_ci{ 23778c2ecf20Sopenharmony_ci struct smk_net6addr *snp; 23788c2ecf20Sopenharmony_ci struct in6_addr *sap = &sip->sin6_addr; 23798c2ecf20Sopenharmony_ci int i; 23808c2ecf20Sopenharmony_ci int found = 0; 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci /* 23838c2ecf20Sopenharmony_ci * It's local. Don't look for a host label. 23848c2ecf20Sopenharmony_ci */ 23858c2ecf20Sopenharmony_ci if (smk_ipv6_localhost(sip)) 23868c2ecf20Sopenharmony_ci return NULL; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci list_for_each_entry_rcu(snp, &smk_net6addr_list, list) { 23898c2ecf20Sopenharmony_ci /* 23908c2ecf20Sopenharmony_ci * If the label is NULL the entry has 23918c2ecf20Sopenharmony_ci * been renounced. Ignore it. 23928c2ecf20Sopenharmony_ci */ 23938c2ecf20Sopenharmony_ci if (snp->smk_label == NULL) 23948c2ecf20Sopenharmony_ci continue; 23958c2ecf20Sopenharmony_ci /* 23968c2ecf20Sopenharmony_ci * we break after finding the first match because 23978c2ecf20Sopenharmony_ci * the list is sorted from longest to shortest mask 23988c2ecf20Sopenharmony_ci * so we have found the most specific match 23998c2ecf20Sopenharmony_ci */ 24008c2ecf20Sopenharmony_ci for (found = 1, i = 0; i < 8; i++) { 24018c2ecf20Sopenharmony_ci if ((sap->s6_addr16[i] & snp->smk_mask.s6_addr16[i]) != 24028c2ecf20Sopenharmony_ci snp->smk_host.s6_addr16[i]) { 24038c2ecf20Sopenharmony_ci found = 0; 24048c2ecf20Sopenharmony_ci break; 24058c2ecf20Sopenharmony_ci } 24068c2ecf20Sopenharmony_ci } 24078c2ecf20Sopenharmony_ci if (found) 24088c2ecf20Sopenharmony_ci return snp->smk_label; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci return NULL; 24128c2ecf20Sopenharmony_ci} 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci/** 24158c2ecf20Sopenharmony_ci * smack_netlbl_add - Set the secattr on a socket 24168c2ecf20Sopenharmony_ci * @sk: the socket 24178c2ecf20Sopenharmony_ci * 24188c2ecf20Sopenharmony_ci * Attach the outbound smack value (smk_out) to the socket. 24198c2ecf20Sopenharmony_ci * 24208c2ecf20Sopenharmony_ci * Returns 0 on success or an error code 24218c2ecf20Sopenharmony_ci */ 24228c2ecf20Sopenharmony_cistatic int smack_netlbl_add(struct sock *sk) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 24258c2ecf20Sopenharmony_ci struct smack_known *skp = ssp->smk_out; 24268c2ecf20Sopenharmony_ci int rc; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci local_bh_disable(); 24298c2ecf20Sopenharmony_ci bh_lock_sock_nested(sk); 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_ci rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); 24328c2ecf20Sopenharmony_ci switch (rc) { 24338c2ecf20Sopenharmony_ci case 0: 24348c2ecf20Sopenharmony_ci ssp->smk_state = SMK_NETLBL_LABELED; 24358c2ecf20Sopenharmony_ci break; 24368c2ecf20Sopenharmony_ci case -EDESTADDRREQ: 24378c2ecf20Sopenharmony_ci ssp->smk_state = SMK_NETLBL_REQSKB; 24388c2ecf20Sopenharmony_ci rc = 0; 24398c2ecf20Sopenharmony_ci break; 24408c2ecf20Sopenharmony_ci } 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 24438c2ecf20Sopenharmony_ci local_bh_enable(); 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci return rc; 24468c2ecf20Sopenharmony_ci} 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci/** 24498c2ecf20Sopenharmony_ci * smack_netlbl_delete - Remove the secattr from a socket 24508c2ecf20Sopenharmony_ci * @sk: the socket 24518c2ecf20Sopenharmony_ci * 24528c2ecf20Sopenharmony_ci * Remove the outbound smack value from a socket 24538c2ecf20Sopenharmony_ci */ 24548c2ecf20Sopenharmony_cistatic void smack_netlbl_delete(struct sock *sk) 24558c2ecf20Sopenharmony_ci{ 24568c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci /* 24598c2ecf20Sopenharmony_ci * Take the label off the socket if one is set. 24608c2ecf20Sopenharmony_ci */ 24618c2ecf20Sopenharmony_ci if (ssp->smk_state != SMK_NETLBL_LABELED) 24628c2ecf20Sopenharmony_ci return; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci local_bh_disable(); 24658c2ecf20Sopenharmony_ci bh_lock_sock_nested(sk); 24668c2ecf20Sopenharmony_ci netlbl_sock_delattr(sk); 24678c2ecf20Sopenharmony_ci bh_unlock_sock(sk); 24688c2ecf20Sopenharmony_ci local_bh_enable(); 24698c2ecf20Sopenharmony_ci ssp->smk_state = SMK_NETLBL_UNLABELED; 24708c2ecf20Sopenharmony_ci} 24718c2ecf20Sopenharmony_ci 24728c2ecf20Sopenharmony_ci/** 24738c2ecf20Sopenharmony_ci * smk_ipv4_check - Perform IPv4 host access checks 24748c2ecf20Sopenharmony_ci * @sk: the socket 24758c2ecf20Sopenharmony_ci * @sap: the destination address 24768c2ecf20Sopenharmony_ci * 24778c2ecf20Sopenharmony_ci * Set the correct secattr for the given socket based on the destination 24788c2ecf20Sopenharmony_ci * address and perform any outbound access checks needed. 24798c2ecf20Sopenharmony_ci * 24808c2ecf20Sopenharmony_ci * Returns 0 on success or an error code. 24818c2ecf20Sopenharmony_ci * 24828c2ecf20Sopenharmony_ci */ 24838c2ecf20Sopenharmony_cistatic int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap) 24848c2ecf20Sopenharmony_ci{ 24858c2ecf20Sopenharmony_ci struct smack_known *skp; 24868c2ecf20Sopenharmony_ci int rc = 0; 24878c2ecf20Sopenharmony_ci struct smack_known *hkp; 24888c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 24898c2ecf20Sopenharmony_ci struct smk_audit_info ad; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci rcu_read_lock(); 24928c2ecf20Sopenharmony_ci hkp = smack_ipv4host_label(sap); 24938c2ecf20Sopenharmony_ci if (hkp != NULL) { 24948c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 24958c2ecf20Sopenharmony_ci struct lsm_network_audit net; 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 24988c2ecf20Sopenharmony_ci ad.a.u.net->family = sap->sin_family; 24998c2ecf20Sopenharmony_ci ad.a.u.net->dport = sap->sin_port; 25008c2ecf20Sopenharmony_ci ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr; 25018c2ecf20Sopenharmony_ci#endif 25028c2ecf20Sopenharmony_ci skp = ssp->smk_out; 25038c2ecf20Sopenharmony_ci rc = smk_access(skp, hkp, MAY_WRITE, &ad); 25048c2ecf20Sopenharmony_ci rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc); 25058c2ecf20Sopenharmony_ci /* 25068c2ecf20Sopenharmony_ci * Clear the socket netlabel if it's set. 25078c2ecf20Sopenharmony_ci */ 25088c2ecf20Sopenharmony_ci if (!rc) 25098c2ecf20Sopenharmony_ci smack_netlbl_delete(sk); 25108c2ecf20Sopenharmony_ci } 25118c2ecf20Sopenharmony_ci rcu_read_unlock(); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci return rc; 25148c2ecf20Sopenharmony_ci} 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci/** 25178c2ecf20Sopenharmony_ci * smk_ipv6_check - check Smack access 25188c2ecf20Sopenharmony_ci * @subject: subject Smack label 25198c2ecf20Sopenharmony_ci * @object: object Smack label 25208c2ecf20Sopenharmony_ci * @address: address 25218c2ecf20Sopenharmony_ci * @act: the action being taken 25228c2ecf20Sopenharmony_ci * 25238c2ecf20Sopenharmony_ci * Check an IPv6 access 25248c2ecf20Sopenharmony_ci */ 25258c2ecf20Sopenharmony_cistatic int smk_ipv6_check(struct smack_known *subject, 25268c2ecf20Sopenharmony_ci struct smack_known *object, 25278c2ecf20Sopenharmony_ci struct sockaddr_in6 *address, int act) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 25308c2ecf20Sopenharmony_ci struct lsm_network_audit net; 25318c2ecf20Sopenharmony_ci#endif 25328c2ecf20Sopenharmony_ci struct smk_audit_info ad; 25338c2ecf20Sopenharmony_ci int rc; 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 25368c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 25378c2ecf20Sopenharmony_ci ad.a.u.net->family = PF_INET6; 25388c2ecf20Sopenharmony_ci ad.a.u.net->dport = address->sin6_port; 25398c2ecf20Sopenharmony_ci if (act == SMK_RECEIVING) 25408c2ecf20Sopenharmony_ci ad.a.u.net->v6info.saddr = address->sin6_addr; 25418c2ecf20Sopenharmony_ci else 25428c2ecf20Sopenharmony_ci ad.a.u.net->v6info.daddr = address->sin6_addr; 25438c2ecf20Sopenharmony_ci#endif 25448c2ecf20Sopenharmony_ci rc = smk_access(subject, object, MAY_WRITE, &ad); 25458c2ecf20Sopenharmony_ci rc = smk_bu_note("IPv6 check", subject, object, MAY_WRITE, rc); 25468c2ecf20Sopenharmony_ci return rc; 25478c2ecf20Sopenharmony_ci} 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 25508c2ecf20Sopenharmony_ci/** 25518c2ecf20Sopenharmony_ci * smk_ipv6_port_label - Smack port access table management 25528c2ecf20Sopenharmony_ci * @sock: socket 25538c2ecf20Sopenharmony_ci * @address: address 25548c2ecf20Sopenharmony_ci * 25558c2ecf20Sopenharmony_ci * Create or update the port list entry 25568c2ecf20Sopenharmony_ci */ 25578c2ecf20Sopenharmony_cistatic void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) 25588c2ecf20Sopenharmony_ci{ 25598c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 25608c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6; 25618c2ecf20Sopenharmony_ci struct socket_smack *ssp = sock->sk->sk_security; 25628c2ecf20Sopenharmony_ci struct smk_port_label *spp; 25638c2ecf20Sopenharmony_ci unsigned short port = 0; 25648c2ecf20Sopenharmony_ci 25658c2ecf20Sopenharmony_ci if (address == NULL) { 25668c2ecf20Sopenharmony_ci /* 25678c2ecf20Sopenharmony_ci * This operation is changing the Smack information 25688c2ecf20Sopenharmony_ci * on the bound socket. Take the changes to the port 25698c2ecf20Sopenharmony_ci * as well. 25708c2ecf20Sopenharmony_ci */ 25718c2ecf20Sopenharmony_ci rcu_read_lock(); 25728c2ecf20Sopenharmony_ci list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { 25738c2ecf20Sopenharmony_ci if (sk != spp->smk_sock) 25748c2ecf20Sopenharmony_ci continue; 25758c2ecf20Sopenharmony_ci spp->smk_in = ssp->smk_in; 25768c2ecf20Sopenharmony_ci spp->smk_out = ssp->smk_out; 25778c2ecf20Sopenharmony_ci rcu_read_unlock(); 25788c2ecf20Sopenharmony_ci return; 25798c2ecf20Sopenharmony_ci } 25808c2ecf20Sopenharmony_ci /* 25818c2ecf20Sopenharmony_ci * A NULL address is only used for updating existing 25828c2ecf20Sopenharmony_ci * bound entries. If there isn't one, it's OK. 25838c2ecf20Sopenharmony_ci */ 25848c2ecf20Sopenharmony_ci rcu_read_unlock(); 25858c2ecf20Sopenharmony_ci return; 25868c2ecf20Sopenharmony_ci } 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)address; 25898c2ecf20Sopenharmony_ci port = ntohs(addr6->sin6_port); 25908c2ecf20Sopenharmony_ci /* 25918c2ecf20Sopenharmony_ci * This is a special case that is safely ignored. 25928c2ecf20Sopenharmony_ci */ 25938c2ecf20Sopenharmony_ci if (port == 0) 25948c2ecf20Sopenharmony_ci return; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci /* 25978c2ecf20Sopenharmony_ci * Look for an existing port list entry. 25988c2ecf20Sopenharmony_ci * This is an indication that a port is getting reused. 25998c2ecf20Sopenharmony_ci */ 26008c2ecf20Sopenharmony_ci rcu_read_lock(); 26018c2ecf20Sopenharmony_ci list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { 26028c2ecf20Sopenharmony_ci if (spp->smk_port != port || spp->smk_sock_type != sock->type) 26038c2ecf20Sopenharmony_ci continue; 26048c2ecf20Sopenharmony_ci if (spp->smk_can_reuse != 1) { 26058c2ecf20Sopenharmony_ci rcu_read_unlock(); 26068c2ecf20Sopenharmony_ci return; 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci spp->smk_port = port; 26098c2ecf20Sopenharmony_ci spp->smk_sock = sk; 26108c2ecf20Sopenharmony_ci spp->smk_in = ssp->smk_in; 26118c2ecf20Sopenharmony_ci spp->smk_out = ssp->smk_out; 26128c2ecf20Sopenharmony_ci spp->smk_can_reuse = 0; 26138c2ecf20Sopenharmony_ci rcu_read_unlock(); 26148c2ecf20Sopenharmony_ci return; 26158c2ecf20Sopenharmony_ci } 26168c2ecf20Sopenharmony_ci rcu_read_unlock(); 26178c2ecf20Sopenharmony_ci /* 26188c2ecf20Sopenharmony_ci * A new port entry is required. 26198c2ecf20Sopenharmony_ci */ 26208c2ecf20Sopenharmony_ci spp = kzalloc(sizeof(*spp), GFP_KERNEL); 26218c2ecf20Sopenharmony_ci if (spp == NULL) 26228c2ecf20Sopenharmony_ci return; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci spp->smk_port = port; 26258c2ecf20Sopenharmony_ci spp->smk_sock = sk; 26268c2ecf20Sopenharmony_ci spp->smk_in = ssp->smk_in; 26278c2ecf20Sopenharmony_ci spp->smk_out = ssp->smk_out; 26288c2ecf20Sopenharmony_ci spp->smk_sock_type = sock->type; 26298c2ecf20Sopenharmony_ci spp->smk_can_reuse = 0; 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci mutex_lock(&smack_ipv6_lock); 26328c2ecf20Sopenharmony_ci list_add_rcu(&spp->list, &smk_ipv6_port_list); 26338c2ecf20Sopenharmony_ci mutex_unlock(&smack_ipv6_lock); 26348c2ecf20Sopenharmony_ci return; 26358c2ecf20Sopenharmony_ci} 26368c2ecf20Sopenharmony_ci#endif 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci/** 26398c2ecf20Sopenharmony_ci * smk_ipv6_port_check - check Smack port access 26408c2ecf20Sopenharmony_ci * @sk: socket 26418c2ecf20Sopenharmony_ci * @address: address 26428c2ecf20Sopenharmony_ci * @act: the action being taken 26438c2ecf20Sopenharmony_ci * 26448c2ecf20Sopenharmony_ci * Create or update the port list entry 26458c2ecf20Sopenharmony_ci */ 26468c2ecf20Sopenharmony_cistatic int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, 26478c2ecf20Sopenharmony_ci int act) 26488c2ecf20Sopenharmony_ci{ 26498c2ecf20Sopenharmony_ci struct smk_port_label *spp; 26508c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 26518c2ecf20Sopenharmony_ci struct smack_known *skp = NULL; 26528c2ecf20Sopenharmony_ci unsigned short port; 26538c2ecf20Sopenharmony_ci struct smack_known *object; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci if (act == SMK_RECEIVING) { 26568c2ecf20Sopenharmony_ci skp = smack_ipv6host_label(address); 26578c2ecf20Sopenharmony_ci object = ssp->smk_in; 26588c2ecf20Sopenharmony_ci } else { 26598c2ecf20Sopenharmony_ci skp = ssp->smk_out; 26608c2ecf20Sopenharmony_ci object = smack_ipv6host_label(address); 26618c2ecf20Sopenharmony_ci } 26628c2ecf20Sopenharmony_ci 26638c2ecf20Sopenharmony_ci /* 26648c2ecf20Sopenharmony_ci * The other end is a single label host. 26658c2ecf20Sopenharmony_ci */ 26668c2ecf20Sopenharmony_ci if (skp != NULL && object != NULL) 26678c2ecf20Sopenharmony_ci return smk_ipv6_check(skp, object, address, act); 26688c2ecf20Sopenharmony_ci if (skp == NULL) 26698c2ecf20Sopenharmony_ci skp = smack_net_ambient; 26708c2ecf20Sopenharmony_ci if (object == NULL) 26718c2ecf20Sopenharmony_ci object = smack_net_ambient; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci /* 26748c2ecf20Sopenharmony_ci * It's remote, so port lookup does no good. 26758c2ecf20Sopenharmony_ci */ 26768c2ecf20Sopenharmony_ci if (!smk_ipv6_localhost(address)) 26778c2ecf20Sopenharmony_ci return smk_ipv6_check(skp, object, address, act); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci /* 26808c2ecf20Sopenharmony_ci * It's local so the send check has to have passed. 26818c2ecf20Sopenharmony_ci */ 26828c2ecf20Sopenharmony_ci if (act == SMK_RECEIVING) 26838c2ecf20Sopenharmony_ci return 0; 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci port = ntohs(address->sin6_port); 26868c2ecf20Sopenharmony_ci rcu_read_lock(); 26878c2ecf20Sopenharmony_ci list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { 26888c2ecf20Sopenharmony_ci if (spp->smk_port != port || spp->smk_sock_type != sk->sk_type) 26898c2ecf20Sopenharmony_ci continue; 26908c2ecf20Sopenharmony_ci object = spp->smk_in; 26918c2ecf20Sopenharmony_ci if (act == SMK_CONNECTING) 26928c2ecf20Sopenharmony_ci ssp->smk_packet = spp->smk_out; 26938c2ecf20Sopenharmony_ci break; 26948c2ecf20Sopenharmony_ci } 26958c2ecf20Sopenharmony_ci rcu_read_unlock(); 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci return smk_ipv6_check(skp, object, address, act); 26988c2ecf20Sopenharmony_ci} 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci/** 27018c2ecf20Sopenharmony_ci * smack_inode_setsecurity - set smack xattrs 27028c2ecf20Sopenharmony_ci * @inode: the object 27038c2ecf20Sopenharmony_ci * @name: attribute name 27048c2ecf20Sopenharmony_ci * @value: attribute value 27058c2ecf20Sopenharmony_ci * @size: size of the attribute 27068c2ecf20Sopenharmony_ci * @flags: unused 27078c2ecf20Sopenharmony_ci * 27088c2ecf20Sopenharmony_ci * Sets the named attribute in the appropriate blob 27098c2ecf20Sopenharmony_ci * 27108c2ecf20Sopenharmony_ci * Returns 0 on success, or an error code 27118c2ecf20Sopenharmony_ci */ 27128c2ecf20Sopenharmony_cistatic int smack_inode_setsecurity(struct inode *inode, const char *name, 27138c2ecf20Sopenharmony_ci const void *value, size_t size, int flags) 27148c2ecf20Sopenharmony_ci{ 27158c2ecf20Sopenharmony_ci struct smack_known *skp; 27168c2ecf20Sopenharmony_ci struct inode_smack *nsp = smack_inode(inode); 27178c2ecf20Sopenharmony_ci struct socket_smack *ssp; 27188c2ecf20Sopenharmony_ci struct socket *sock; 27198c2ecf20Sopenharmony_ci int rc = 0; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci if (value == NULL || size > SMK_LONGLABEL || size == 0) 27228c2ecf20Sopenharmony_ci return -EINVAL; 27238c2ecf20Sopenharmony_ci 27248c2ecf20Sopenharmony_ci skp = smk_import_entry(value, size); 27258c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 27268c2ecf20Sopenharmony_ci return PTR_ERR(skp); 27278c2ecf20Sopenharmony_ci 27288c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_SMACK_SUFFIX) == 0) { 27298c2ecf20Sopenharmony_ci nsp->smk_inode = skp; 27308c2ecf20Sopenharmony_ci nsp->smk_flags |= SMK_INODE_INSTANT; 27318c2ecf20Sopenharmony_ci return 0; 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci /* 27348c2ecf20Sopenharmony_ci * The rest of the Smack xattrs are only on sockets. 27358c2ecf20Sopenharmony_ci */ 27368c2ecf20Sopenharmony_ci if (inode->i_sb->s_magic != SOCKFS_MAGIC) 27378c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci sock = SOCKET_I(inode); 27408c2ecf20Sopenharmony_ci if (sock == NULL || sock->sk == NULL) 27418c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci ssp = sock->sk->sk_security; 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_SMACK_IPIN) == 0) 27468c2ecf20Sopenharmony_ci ssp->smk_in = skp; 27478c2ecf20Sopenharmony_ci else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { 27488c2ecf20Sopenharmony_ci ssp->smk_out = skp; 27498c2ecf20Sopenharmony_ci if (sock->sk->sk_family == PF_INET) { 27508c2ecf20Sopenharmony_ci rc = smack_netlbl_add(sock->sk); 27518c2ecf20Sopenharmony_ci if (rc != 0) 27528c2ecf20Sopenharmony_ci printk(KERN_WARNING 27538c2ecf20Sopenharmony_ci "Smack: \"%s\" netlbl error %d.\n", 27548c2ecf20Sopenharmony_ci __func__, -rc); 27558c2ecf20Sopenharmony_ci } 27568c2ecf20Sopenharmony_ci } else 27578c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 27608c2ecf20Sopenharmony_ci if (sock->sk->sk_family == PF_INET6) 27618c2ecf20Sopenharmony_ci smk_ipv6_port_label(sock, NULL); 27628c2ecf20Sopenharmony_ci#endif 27638c2ecf20Sopenharmony_ci 27648c2ecf20Sopenharmony_ci return 0; 27658c2ecf20Sopenharmony_ci} 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci/** 27688c2ecf20Sopenharmony_ci * smack_socket_post_create - finish socket setup 27698c2ecf20Sopenharmony_ci * @sock: the socket 27708c2ecf20Sopenharmony_ci * @family: protocol family 27718c2ecf20Sopenharmony_ci * @type: unused 27728c2ecf20Sopenharmony_ci * @protocol: unused 27738c2ecf20Sopenharmony_ci * @kern: unused 27748c2ecf20Sopenharmony_ci * 27758c2ecf20Sopenharmony_ci * Sets the netlabel information on the socket 27768c2ecf20Sopenharmony_ci * 27778c2ecf20Sopenharmony_ci * Returns 0 on success, and error code otherwise 27788c2ecf20Sopenharmony_ci */ 27798c2ecf20Sopenharmony_cistatic int smack_socket_post_create(struct socket *sock, int family, 27808c2ecf20Sopenharmony_ci int type, int protocol, int kern) 27818c2ecf20Sopenharmony_ci{ 27828c2ecf20Sopenharmony_ci struct socket_smack *ssp; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci if (sock->sk == NULL) 27858c2ecf20Sopenharmony_ci return 0; 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci /* 27888c2ecf20Sopenharmony_ci * Sockets created by kernel threads receive web label. 27898c2ecf20Sopenharmony_ci */ 27908c2ecf20Sopenharmony_ci if (unlikely(current->flags & PF_KTHREAD)) { 27918c2ecf20Sopenharmony_ci ssp = sock->sk->sk_security; 27928c2ecf20Sopenharmony_ci ssp->smk_in = &smack_known_web; 27938c2ecf20Sopenharmony_ci ssp->smk_out = &smack_known_web; 27948c2ecf20Sopenharmony_ci } 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci if (family != PF_INET) 27978c2ecf20Sopenharmony_ci return 0; 27988c2ecf20Sopenharmony_ci /* 27998c2ecf20Sopenharmony_ci * Set the outbound netlbl. 28008c2ecf20Sopenharmony_ci */ 28018c2ecf20Sopenharmony_ci return smack_netlbl_add(sock->sk); 28028c2ecf20Sopenharmony_ci} 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_ci/** 28058c2ecf20Sopenharmony_ci * smack_socket_socketpair - create socket pair 28068c2ecf20Sopenharmony_ci * @socka: one socket 28078c2ecf20Sopenharmony_ci * @sockb: another socket 28088c2ecf20Sopenharmony_ci * 28098c2ecf20Sopenharmony_ci * Cross reference the peer labels for SO_PEERSEC 28108c2ecf20Sopenharmony_ci * 28118c2ecf20Sopenharmony_ci * Returns 0 28128c2ecf20Sopenharmony_ci */ 28138c2ecf20Sopenharmony_cistatic int smack_socket_socketpair(struct socket *socka, 28148c2ecf20Sopenharmony_ci struct socket *sockb) 28158c2ecf20Sopenharmony_ci{ 28168c2ecf20Sopenharmony_ci struct socket_smack *asp = socka->sk->sk_security; 28178c2ecf20Sopenharmony_ci struct socket_smack *bsp = sockb->sk->sk_security; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci asp->smk_packet = bsp->smk_out; 28208c2ecf20Sopenharmony_ci bsp->smk_packet = asp->smk_out; 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci return 0; 28238c2ecf20Sopenharmony_ci} 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 28268c2ecf20Sopenharmony_ci/** 28278c2ecf20Sopenharmony_ci * smack_socket_bind - record port binding information. 28288c2ecf20Sopenharmony_ci * @sock: the socket 28298c2ecf20Sopenharmony_ci * @address: the port address 28308c2ecf20Sopenharmony_ci * @addrlen: size of the address 28318c2ecf20Sopenharmony_ci * 28328c2ecf20Sopenharmony_ci * Records the label bound to a port. 28338c2ecf20Sopenharmony_ci * 28348c2ecf20Sopenharmony_ci * Returns 0 on success, and error code otherwise 28358c2ecf20Sopenharmony_ci */ 28368c2ecf20Sopenharmony_cistatic int smack_socket_bind(struct socket *sock, struct sockaddr *address, 28378c2ecf20Sopenharmony_ci int addrlen) 28388c2ecf20Sopenharmony_ci{ 28398c2ecf20Sopenharmony_ci if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) { 28408c2ecf20Sopenharmony_ci if (addrlen < SIN6_LEN_RFC2133 || 28418c2ecf20Sopenharmony_ci address->sa_family != AF_INET6) 28428c2ecf20Sopenharmony_ci return -EINVAL; 28438c2ecf20Sopenharmony_ci smk_ipv6_port_label(sock, address); 28448c2ecf20Sopenharmony_ci } 28458c2ecf20Sopenharmony_ci return 0; 28468c2ecf20Sopenharmony_ci} 28478c2ecf20Sopenharmony_ci#endif /* SMACK_IPV6_PORT_LABELING */ 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci/** 28508c2ecf20Sopenharmony_ci * smack_socket_connect - connect access check 28518c2ecf20Sopenharmony_ci * @sock: the socket 28528c2ecf20Sopenharmony_ci * @sap: the other end 28538c2ecf20Sopenharmony_ci * @addrlen: size of sap 28548c2ecf20Sopenharmony_ci * 28558c2ecf20Sopenharmony_ci * Verifies that a connection may be possible 28568c2ecf20Sopenharmony_ci * 28578c2ecf20Sopenharmony_ci * Returns 0 on success, and error code otherwise 28588c2ecf20Sopenharmony_ci */ 28598c2ecf20Sopenharmony_cistatic int smack_socket_connect(struct socket *sock, struct sockaddr *sap, 28608c2ecf20Sopenharmony_ci int addrlen) 28618c2ecf20Sopenharmony_ci{ 28628c2ecf20Sopenharmony_ci int rc = 0; 28638c2ecf20Sopenharmony_ci 28648c2ecf20Sopenharmony_ci if (sock->sk == NULL) 28658c2ecf20Sopenharmony_ci return 0; 28668c2ecf20Sopenharmony_ci if (sock->sk->sk_family != PF_INET && 28678c2ecf20Sopenharmony_ci (!IS_ENABLED(CONFIG_IPV6) || sock->sk->sk_family != PF_INET6)) 28688c2ecf20Sopenharmony_ci return 0; 28698c2ecf20Sopenharmony_ci if (addrlen < offsetofend(struct sockaddr, sa_family)) 28708c2ecf20Sopenharmony_ci return 0; 28718c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_IPV6) && sap->sa_family == AF_INET6) { 28728c2ecf20Sopenharmony_ci struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap; 28738c2ecf20Sopenharmony_ci struct smack_known *rsp = NULL; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci if (addrlen < SIN6_LEN_RFC2133) 28768c2ecf20Sopenharmony_ci return 0; 28778c2ecf20Sopenharmony_ci if (__is_defined(SMACK_IPV6_SECMARK_LABELING)) 28788c2ecf20Sopenharmony_ci rsp = smack_ipv6host_label(sip); 28798c2ecf20Sopenharmony_ci if (rsp != NULL) { 28808c2ecf20Sopenharmony_ci struct socket_smack *ssp = sock->sk->sk_security; 28818c2ecf20Sopenharmony_ci 28828c2ecf20Sopenharmony_ci rc = smk_ipv6_check(ssp->smk_out, rsp, sip, 28838c2ecf20Sopenharmony_ci SMK_CONNECTING); 28848c2ecf20Sopenharmony_ci } 28858c2ecf20Sopenharmony_ci if (__is_defined(SMACK_IPV6_PORT_LABELING)) 28868c2ecf20Sopenharmony_ci rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING); 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci return rc; 28898c2ecf20Sopenharmony_ci } 28908c2ecf20Sopenharmony_ci if (sap->sa_family != AF_INET || addrlen < sizeof(struct sockaddr_in)) 28918c2ecf20Sopenharmony_ci return 0; 28928c2ecf20Sopenharmony_ci rc = smk_ipv4_check(sock->sk, (struct sockaddr_in *)sap); 28938c2ecf20Sopenharmony_ci return rc; 28948c2ecf20Sopenharmony_ci} 28958c2ecf20Sopenharmony_ci 28968c2ecf20Sopenharmony_ci/** 28978c2ecf20Sopenharmony_ci * smack_flags_to_may - convert S_ to MAY_ values 28988c2ecf20Sopenharmony_ci * @flags: the S_ value 28998c2ecf20Sopenharmony_ci * 29008c2ecf20Sopenharmony_ci * Returns the equivalent MAY_ value 29018c2ecf20Sopenharmony_ci */ 29028c2ecf20Sopenharmony_cistatic int smack_flags_to_may(int flags) 29038c2ecf20Sopenharmony_ci{ 29048c2ecf20Sopenharmony_ci int may = 0; 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci if (flags & S_IRUGO) 29078c2ecf20Sopenharmony_ci may |= MAY_READ; 29088c2ecf20Sopenharmony_ci if (flags & S_IWUGO) 29098c2ecf20Sopenharmony_ci may |= MAY_WRITE; 29108c2ecf20Sopenharmony_ci if (flags & S_IXUGO) 29118c2ecf20Sopenharmony_ci may |= MAY_EXEC; 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci return may; 29148c2ecf20Sopenharmony_ci} 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci/** 29178c2ecf20Sopenharmony_ci * smack_msg_msg_alloc_security - Set the security blob for msg_msg 29188c2ecf20Sopenharmony_ci * @msg: the object 29198c2ecf20Sopenharmony_ci * 29208c2ecf20Sopenharmony_ci * Returns 0 29218c2ecf20Sopenharmony_ci */ 29228c2ecf20Sopenharmony_cistatic int smack_msg_msg_alloc_security(struct msg_msg *msg) 29238c2ecf20Sopenharmony_ci{ 29248c2ecf20Sopenharmony_ci struct smack_known **blob = smack_msg_msg(msg); 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci *blob = smk_of_current(); 29278c2ecf20Sopenharmony_ci return 0; 29288c2ecf20Sopenharmony_ci} 29298c2ecf20Sopenharmony_ci 29308c2ecf20Sopenharmony_ci/** 29318c2ecf20Sopenharmony_ci * smack_of_ipc - the smack pointer for the ipc 29328c2ecf20Sopenharmony_ci * @isp: the object 29338c2ecf20Sopenharmony_ci * 29348c2ecf20Sopenharmony_ci * Returns a pointer to the smack value 29358c2ecf20Sopenharmony_ci */ 29368c2ecf20Sopenharmony_cistatic struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp) 29378c2ecf20Sopenharmony_ci{ 29388c2ecf20Sopenharmony_ci struct smack_known **blob = smack_ipc(isp); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci return *blob; 29418c2ecf20Sopenharmony_ci} 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci/** 29448c2ecf20Sopenharmony_ci * smack_ipc_alloc_security - Set the security blob for ipc 29458c2ecf20Sopenharmony_ci * @isp: the object 29468c2ecf20Sopenharmony_ci * 29478c2ecf20Sopenharmony_ci * Returns 0 29488c2ecf20Sopenharmony_ci */ 29498c2ecf20Sopenharmony_cistatic int smack_ipc_alloc_security(struct kern_ipc_perm *isp) 29508c2ecf20Sopenharmony_ci{ 29518c2ecf20Sopenharmony_ci struct smack_known **blob = smack_ipc(isp); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci *blob = smk_of_current(); 29548c2ecf20Sopenharmony_ci return 0; 29558c2ecf20Sopenharmony_ci} 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci/** 29588c2ecf20Sopenharmony_ci * smk_curacc_shm : check if current has access on shm 29598c2ecf20Sopenharmony_ci * @isp : the object 29608c2ecf20Sopenharmony_ci * @access : access requested 29618c2ecf20Sopenharmony_ci * 29628c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 29638c2ecf20Sopenharmony_ci */ 29648c2ecf20Sopenharmony_cistatic int smk_curacc_shm(struct kern_ipc_perm *isp, int access) 29658c2ecf20Sopenharmony_ci{ 29668c2ecf20Sopenharmony_ci struct smack_known *ssp = smack_of_ipc(isp); 29678c2ecf20Sopenharmony_ci struct smk_audit_info ad; 29688c2ecf20Sopenharmony_ci int rc; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 29718c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); 29728c2ecf20Sopenharmony_ci ad.a.u.ipc_id = isp->id; 29738c2ecf20Sopenharmony_ci#endif 29748c2ecf20Sopenharmony_ci rc = smk_curacc(ssp, access, &ad); 29758c2ecf20Sopenharmony_ci rc = smk_bu_current("shm", ssp, access, rc); 29768c2ecf20Sopenharmony_ci return rc; 29778c2ecf20Sopenharmony_ci} 29788c2ecf20Sopenharmony_ci 29798c2ecf20Sopenharmony_ci/** 29808c2ecf20Sopenharmony_ci * smack_shm_associate - Smack access check for shm 29818c2ecf20Sopenharmony_ci * @isp: the object 29828c2ecf20Sopenharmony_ci * @shmflg: access requested 29838c2ecf20Sopenharmony_ci * 29848c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 29858c2ecf20Sopenharmony_ci */ 29868c2ecf20Sopenharmony_cistatic int smack_shm_associate(struct kern_ipc_perm *isp, int shmflg) 29878c2ecf20Sopenharmony_ci{ 29888c2ecf20Sopenharmony_ci int may; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci may = smack_flags_to_may(shmflg); 29918c2ecf20Sopenharmony_ci return smk_curacc_shm(isp, may); 29928c2ecf20Sopenharmony_ci} 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_ci/** 29958c2ecf20Sopenharmony_ci * smack_shm_shmctl - Smack access check for shm 29968c2ecf20Sopenharmony_ci * @isp: the object 29978c2ecf20Sopenharmony_ci * @cmd: what it wants to do 29988c2ecf20Sopenharmony_ci * 29998c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 30008c2ecf20Sopenharmony_ci */ 30018c2ecf20Sopenharmony_cistatic int smack_shm_shmctl(struct kern_ipc_perm *isp, int cmd) 30028c2ecf20Sopenharmony_ci{ 30038c2ecf20Sopenharmony_ci int may; 30048c2ecf20Sopenharmony_ci 30058c2ecf20Sopenharmony_ci switch (cmd) { 30068c2ecf20Sopenharmony_ci case IPC_STAT: 30078c2ecf20Sopenharmony_ci case SHM_STAT: 30088c2ecf20Sopenharmony_ci case SHM_STAT_ANY: 30098c2ecf20Sopenharmony_ci may = MAY_READ; 30108c2ecf20Sopenharmony_ci break; 30118c2ecf20Sopenharmony_ci case IPC_SET: 30128c2ecf20Sopenharmony_ci case SHM_LOCK: 30138c2ecf20Sopenharmony_ci case SHM_UNLOCK: 30148c2ecf20Sopenharmony_ci case IPC_RMID: 30158c2ecf20Sopenharmony_ci may = MAY_READWRITE; 30168c2ecf20Sopenharmony_ci break; 30178c2ecf20Sopenharmony_ci case IPC_INFO: 30188c2ecf20Sopenharmony_ci case SHM_INFO: 30198c2ecf20Sopenharmony_ci /* 30208c2ecf20Sopenharmony_ci * System level information. 30218c2ecf20Sopenharmony_ci */ 30228c2ecf20Sopenharmony_ci return 0; 30238c2ecf20Sopenharmony_ci default: 30248c2ecf20Sopenharmony_ci return -EINVAL; 30258c2ecf20Sopenharmony_ci } 30268c2ecf20Sopenharmony_ci return smk_curacc_shm(isp, may); 30278c2ecf20Sopenharmony_ci} 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci/** 30308c2ecf20Sopenharmony_ci * smack_shm_shmat - Smack access for shmat 30318c2ecf20Sopenharmony_ci * @isp: the object 30328c2ecf20Sopenharmony_ci * @shmaddr: unused 30338c2ecf20Sopenharmony_ci * @shmflg: access requested 30348c2ecf20Sopenharmony_ci * 30358c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 30368c2ecf20Sopenharmony_ci */ 30378c2ecf20Sopenharmony_cistatic int smack_shm_shmat(struct kern_ipc_perm *isp, char __user *shmaddr, 30388c2ecf20Sopenharmony_ci int shmflg) 30398c2ecf20Sopenharmony_ci{ 30408c2ecf20Sopenharmony_ci int may; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci may = smack_flags_to_may(shmflg); 30438c2ecf20Sopenharmony_ci return smk_curacc_shm(isp, may); 30448c2ecf20Sopenharmony_ci} 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci/** 30478c2ecf20Sopenharmony_ci * smk_curacc_sem : check if current has access on sem 30488c2ecf20Sopenharmony_ci * @isp : the object 30498c2ecf20Sopenharmony_ci * @access : access requested 30508c2ecf20Sopenharmony_ci * 30518c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 30528c2ecf20Sopenharmony_ci */ 30538c2ecf20Sopenharmony_cistatic int smk_curacc_sem(struct kern_ipc_perm *isp, int access) 30548c2ecf20Sopenharmony_ci{ 30558c2ecf20Sopenharmony_ci struct smack_known *ssp = smack_of_ipc(isp); 30568c2ecf20Sopenharmony_ci struct smk_audit_info ad; 30578c2ecf20Sopenharmony_ci int rc; 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 30608c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); 30618c2ecf20Sopenharmony_ci ad.a.u.ipc_id = isp->id; 30628c2ecf20Sopenharmony_ci#endif 30638c2ecf20Sopenharmony_ci rc = smk_curacc(ssp, access, &ad); 30648c2ecf20Sopenharmony_ci rc = smk_bu_current("sem", ssp, access, rc); 30658c2ecf20Sopenharmony_ci return rc; 30668c2ecf20Sopenharmony_ci} 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci/** 30698c2ecf20Sopenharmony_ci * smack_sem_associate - Smack access check for sem 30708c2ecf20Sopenharmony_ci * @isp: the object 30718c2ecf20Sopenharmony_ci * @semflg: access requested 30728c2ecf20Sopenharmony_ci * 30738c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 30748c2ecf20Sopenharmony_ci */ 30758c2ecf20Sopenharmony_cistatic int smack_sem_associate(struct kern_ipc_perm *isp, int semflg) 30768c2ecf20Sopenharmony_ci{ 30778c2ecf20Sopenharmony_ci int may; 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci may = smack_flags_to_may(semflg); 30808c2ecf20Sopenharmony_ci return smk_curacc_sem(isp, may); 30818c2ecf20Sopenharmony_ci} 30828c2ecf20Sopenharmony_ci 30838c2ecf20Sopenharmony_ci/** 30848c2ecf20Sopenharmony_ci * smack_sem_shmctl - Smack access check for sem 30858c2ecf20Sopenharmony_ci * @isp: the object 30868c2ecf20Sopenharmony_ci * @cmd: what it wants to do 30878c2ecf20Sopenharmony_ci * 30888c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 30898c2ecf20Sopenharmony_ci */ 30908c2ecf20Sopenharmony_cistatic int smack_sem_semctl(struct kern_ipc_perm *isp, int cmd) 30918c2ecf20Sopenharmony_ci{ 30928c2ecf20Sopenharmony_ci int may; 30938c2ecf20Sopenharmony_ci 30948c2ecf20Sopenharmony_ci switch (cmd) { 30958c2ecf20Sopenharmony_ci case GETPID: 30968c2ecf20Sopenharmony_ci case GETNCNT: 30978c2ecf20Sopenharmony_ci case GETZCNT: 30988c2ecf20Sopenharmony_ci case GETVAL: 30998c2ecf20Sopenharmony_ci case GETALL: 31008c2ecf20Sopenharmony_ci case IPC_STAT: 31018c2ecf20Sopenharmony_ci case SEM_STAT: 31028c2ecf20Sopenharmony_ci case SEM_STAT_ANY: 31038c2ecf20Sopenharmony_ci may = MAY_READ; 31048c2ecf20Sopenharmony_ci break; 31058c2ecf20Sopenharmony_ci case SETVAL: 31068c2ecf20Sopenharmony_ci case SETALL: 31078c2ecf20Sopenharmony_ci case IPC_RMID: 31088c2ecf20Sopenharmony_ci case IPC_SET: 31098c2ecf20Sopenharmony_ci may = MAY_READWRITE; 31108c2ecf20Sopenharmony_ci break; 31118c2ecf20Sopenharmony_ci case IPC_INFO: 31128c2ecf20Sopenharmony_ci case SEM_INFO: 31138c2ecf20Sopenharmony_ci /* 31148c2ecf20Sopenharmony_ci * System level information 31158c2ecf20Sopenharmony_ci */ 31168c2ecf20Sopenharmony_ci return 0; 31178c2ecf20Sopenharmony_ci default: 31188c2ecf20Sopenharmony_ci return -EINVAL; 31198c2ecf20Sopenharmony_ci } 31208c2ecf20Sopenharmony_ci 31218c2ecf20Sopenharmony_ci return smk_curacc_sem(isp, may); 31228c2ecf20Sopenharmony_ci} 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci/** 31258c2ecf20Sopenharmony_ci * smack_sem_semop - Smack checks of semaphore operations 31268c2ecf20Sopenharmony_ci * @isp: the object 31278c2ecf20Sopenharmony_ci * @sops: unused 31288c2ecf20Sopenharmony_ci * @nsops: unused 31298c2ecf20Sopenharmony_ci * @alter: unused 31308c2ecf20Sopenharmony_ci * 31318c2ecf20Sopenharmony_ci * Treated as read and write in all cases. 31328c2ecf20Sopenharmony_ci * 31338c2ecf20Sopenharmony_ci * Returns 0 if access is allowed, error code otherwise 31348c2ecf20Sopenharmony_ci */ 31358c2ecf20Sopenharmony_cistatic int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops, 31368c2ecf20Sopenharmony_ci unsigned nsops, int alter) 31378c2ecf20Sopenharmony_ci{ 31388c2ecf20Sopenharmony_ci return smk_curacc_sem(isp, MAY_READWRITE); 31398c2ecf20Sopenharmony_ci} 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci/** 31428c2ecf20Sopenharmony_ci * smk_curacc_msq : helper to check if current has access on msq 31438c2ecf20Sopenharmony_ci * @isp : the msq 31448c2ecf20Sopenharmony_ci * @access : access requested 31458c2ecf20Sopenharmony_ci * 31468c2ecf20Sopenharmony_ci * return 0 if current has access, error otherwise 31478c2ecf20Sopenharmony_ci */ 31488c2ecf20Sopenharmony_cistatic int smk_curacc_msq(struct kern_ipc_perm *isp, int access) 31498c2ecf20Sopenharmony_ci{ 31508c2ecf20Sopenharmony_ci struct smack_known *msp = smack_of_ipc(isp); 31518c2ecf20Sopenharmony_ci struct smk_audit_info ad; 31528c2ecf20Sopenharmony_ci int rc; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 31558c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); 31568c2ecf20Sopenharmony_ci ad.a.u.ipc_id = isp->id; 31578c2ecf20Sopenharmony_ci#endif 31588c2ecf20Sopenharmony_ci rc = smk_curacc(msp, access, &ad); 31598c2ecf20Sopenharmony_ci rc = smk_bu_current("msq", msp, access, rc); 31608c2ecf20Sopenharmony_ci return rc; 31618c2ecf20Sopenharmony_ci} 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_ci/** 31648c2ecf20Sopenharmony_ci * smack_msg_queue_associate - Smack access check for msg_queue 31658c2ecf20Sopenharmony_ci * @isp: the object 31668c2ecf20Sopenharmony_ci * @msqflg: access requested 31678c2ecf20Sopenharmony_ci * 31688c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 31698c2ecf20Sopenharmony_ci */ 31708c2ecf20Sopenharmony_cistatic int smack_msg_queue_associate(struct kern_ipc_perm *isp, int msqflg) 31718c2ecf20Sopenharmony_ci{ 31728c2ecf20Sopenharmony_ci int may; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci may = smack_flags_to_may(msqflg); 31758c2ecf20Sopenharmony_ci return smk_curacc_msq(isp, may); 31768c2ecf20Sopenharmony_ci} 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci/** 31798c2ecf20Sopenharmony_ci * smack_msg_queue_msgctl - Smack access check for msg_queue 31808c2ecf20Sopenharmony_ci * @isp: the object 31818c2ecf20Sopenharmony_ci * @cmd: what it wants to do 31828c2ecf20Sopenharmony_ci * 31838c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 31848c2ecf20Sopenharmony_ci */ 31858c2ecf20Sopenharmony_cistatic int smack_msg_queue_msgctl(struct kern_ipc_perm *isp, int cmd) 31868c2ecf20Sopenharmony_ci{ 31878c2ecf20Sopenharmony_ci int may; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci switch (cmd) { 31908c2ecf20Sopenharmony_ci case IPC_STAT: 31918c2ecf20Sopenharmony_ci case MSG_STAT: 31928c2ecf20Sopenharmony_ci case MSG_STAT_ANY: 31938c2ecf20Sopenharmony_ci may = MAY_READ; 31948c2ecf20Sopenharmony_ci break; 31958c2ecf20Sopenharmony_ci case IPC_SET: 31968c2ecf20Sopenharmony_ci case IPC_RMID: 31978c2ecf20Sopenharmony_ci may = MAY_READWRITE; 31988c2ecf20Sopenharmony_ci break; 31998c2ecf20Sopenharmony_ci case IPC_INFO: 32008c2ecf20Sopenharmony_ci case MSG_INFO: 32018c2ecf20Sopenharmony_ci /* 32028c2ecf20Sopenharmony_ci * System level information 32038c2ecf20Sopenharmony_ci */ 32048c2ecf20Sopenharmony_ci return 0; 32058c2ecf20Sopenharmony_ci default: 32068c2ecf20Sopenharmony_ci return -EINVAL; 32078c2ecf20Sopenharmony_ci } 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_ci return smk_curacc_msq(isp, may); 32108c2ecf20Sopenharmony_ci} 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci/** 32138c2ecf20Sopenharmony_ci * smack_msg_queue_msgsnd - Smack access check for msg_queue 32148c2ecf20Sopenharmony_ci * @isp: the object 32158c2ecf20Sopenharmony_ci * @msg: unused 32168c2ecf20Sopenharmony_ci * @msqflg: access requested 32178c2ecf20Sopenharmony_ci * 32188c2ecf20Sopenharmony_ci * Returns 0 if current has the requested access, error code otherwise 32198c2ecf20Sopenharmony_ci */ 32208c2ecf20Sopenharmony_cistatic int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg, 32218c2ecf20Sopenharmony_ci int msqflg) 32228c2ecf20Sopenharmony_ci{ 32238c2ecf20Sopenharmony_ci int may; 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci may = smack_flags_to_may(msqflg); 32268c2ecf20Sopenharmony_ci return smk_curacc_msq(isp, may); 32278c2ecf20Sopenharmony_ci} 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci/** 32308c2ecf20Sopenharmony_ci * smack_msg_queue_msgsnd - Smack access check for msg_queue 32318c2ecf20Sopenharmony_ci * @isp: the object 32328c2ecf20Sopenharmony_ci * @msg: unused 32338c2ecf20Sopenharmony_ci * @target: unused 32348c2ecf20Sopenharmony_ci * @type: unused 32358c2ecf20Sopenharmony_ci * @mode: unused 32368c2ecf20Sopenharmony_ci * 32378c2ecf20Sopenharmony_ci * Returns 0 if current has read and write access, error code otherwise 32388c2ecf20Sopenharmony_ci */ 32398c2ecf20Sopenharmony_cistatic int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp, struct msg_msg *msg, 32408c2ecf20Sopenharmony_ci struct task_struct *target, long type, int mode) 32418c2ecf20Sopenharmony_ci{ 32428c2ecf20Sopenharmony_ci return smk_curacc_msq(isp, MAY_READWRITE); 32438c2ecf20Sopenharmony_ci} 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci/** 32468c2ecf20Sopenharmony_ci * smack_ipc_permission - Smack access for ipc_permission() 32478c2ecf20Sopenharmony_ci * @ipp: the object permissions 32488c2ecf20Sopenharmony_ci * @flag: access requested 32498c2ecf20Sopenharmony_ci * 32508c2ecf20Sopenharmony_ci * Returns 0 if current has read and write access, error code otherwise 32518c2ecf20Sopenharmony_ci */ 32528c2ecf20Sopenharmony_cistatic int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) 32538c2ecf20Sopenharmony_ci{ 32548c2ecf20Sopenharmony_ci struct smack_known **blob = smack_ipc(ipp); 32558c2ecf20Sopenharmony_ci struct smack_known *iskp = *blob; 32568c2ecf20Sopenharmony_ci int may = smack_flags_to_may(flag); 32578c2ecf20Sopenharmony_ci struct smk_audit_info ad; 32588c2ecf20Sopenharmony_ci int rc; 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 32618c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_IPC); 32628c2ecf20Sopenharmony_ci ad.a.u.ipc_id = ipp->id; 32638c2ecf20Sopenharmony_ci#endif 32648c2ecf20Sopenharmony_ci rc = smk_curacc(iskp, may, &ad); 32658c2ecf20Sopenharmony_ci rc = smk_bu_current("svipc", iskp, may, rc); 32668c2ecf20Sopenharmony_ci return rc; 32678c2ecf20Sopenharmony_ci} 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci/** 32708c2ecf20Sopenharmony_ci * smack_ipc_getsecid - Extract smack security id 32718c2ecf20Sopenharmony_ci * @ipp: the object permissions 32728c2ecf20Sopenharmony_ci * @secid: where result will be saved 32738c2ecf20Sopenharmony_ci */ 32748c2ecf20Sopenharmony_cistatic void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) 32758c2ecf20Sopenharmony_ci{ 32768c2ecf20Sopenharmony_ci struct smack_known **blob = smack_ipc(ipp); 32778c2ecf20Sopenharmony_ci struct smack_known *iskp = *blob; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci *secid = iskp->smk_secid; 32808c2ecf20Sopenharmony_ci} 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci/** 32838c2ecf20Sopenharmony_ci * smack_d_instantiate - Make sure the blob is correct on an inode 32848c2ecf20Sopenharmony_ci * @opt_dentry: dentry where inode will be attached 32858c2ecf20Sopenharmony_ci * @inode: the object 32868c2ecf20Sopenharmony_ci * 32878c2ecf20Sopenharmony_ci * Set the inode's security blob if it hasn't been done already. 32888c2ecf20Sopenharmony_ci */ 32898c2ecf20Sopenharmony_cistatic void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) 32908c2ecf20Sopenharmony_ci{ 32918c2ecf20Sopenharmony_ci struct super_block *sbp; 32928c2ecf20Sopenharmony_ci struct superblock_smack *sbsp; 32938c2ecf20Sopenharmony_ci struct inode_smack *isp; 32948c2ecf20Sopenharmony_ci struct smack_known *skp; 32958c2ecf20Sopenharmony_ci struct smack_known *ckp = smk_of_current(); 32968c2ecf20Sopenharmony_ci struct smack_known *final; 32978c2ecf20Sopenharmony_ci char trattr[TRANS_TRUE_SIZE]; 32988c2ecf20Sopenharmony_ci int transflag = 0; 32998c2ecf20Sopenharmony_ci int rc; 33008c2ecf20Sopenharmony_ci struct dentry *dp; 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci if (inode == NULL) 33038c2ecf20Sopenharmony_ci return; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci isp = smack_inode(inode); 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ci /* 33088c2ecf20Sopenharmony_ci * If the inode is already instantiated 33098c2ecf20Sopenharmony_ci * take the quick way out 33108c2ecf20Sopenharmony_ci */ 33118c2ecf20Sopenharmony_ci if (isp->smk_flags & SMK_INODE_INSTANT) 33128c2ecf20Sopenharmony_ci return; 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci sbp = inode->i_sb; 33158c2ecf20Sopenharmony_ci sbsp = sbp->s_security; 33168c2ecf20Sopenharmony_ci /* 33178c2ecf20Sopenharmony_ci * We're going to use the superblock default label 33188c2ecf20Sopenharmony_ci * if there's no label on the file. 33198c2ecf20Sopenharmony_ci */ 33208c2ecf20Sopenharmony_ci final = sbsp->smk_default; 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci /* 33238c2ecf20Sopenharmony_ci * If this is the root inode the superblock 33248c2ecf20Sopenharmony_ci * may be in the process of initialization. 33258c2ecf20Sopenharmony_ci * If that is the case use the root value out 33268c2ecf20Sopenharmony_ci * of the superblock. 33278c2ecf20Sopenharmony_ci */ 33288c2ecf20Sopenharmony_ci if (opt_dentry->d_parent == opt_dentry) { 33298c2ecf20Sopenharmony_ci switch (sbp->s_magic) { 33308c2ecf20Sopenharmony_ci case CGROUP_SUPER_MAGIC: 33318c2ecf20Sopenharmony_ci case CGROUP2_SUPER_MAGIC: 33328c2ecf20Sopenharmony_ci /* 33338c2ecf20Sopenharmony_ci * The cgroup filesystem is never mounted, 33348c2ecf20Sopenharmony_ci * so there's no opportunity to set the mount 33358c2ecf20Sopenharmony_ci * options. 33368c2ecf20Sopenharmony_ci */ 33378c2ecf20Sopenharmony_ci sbsp->smk_root = &smack_known_star; 33388c2ecf20Sopenharmony_ci sbsp->smk_default = &smack_known_star; 33398c2ecf20Sopenharmony_ci isp->smk_inode = sbsp->smk_root; 33408c2ecf20Sopenharmony_ci break; 33418c2ecf20Sopenharmony_ci case TMPFS_MAGIC: 33428c2ecf20Sopenharmony_ci /* 33438c2ecf20Sopenharmony_ci * What about shmem/tmpfs anonymous files with dentry 33448c2ecf20Sopenharmony_ci * obtained from d_alloc_pseudo()? 33458c2ecf20Sopenharmony_ci */ 33468c2ecf20Sopenharmony_ci isp->smk_inode = smk_of_current(); 33478c2ecf20Sopenharmony_ci break; 33488c2ecf20Sopenharmony_ci case PIPEFS_MAGIC: 33498c2ecf20Sopenharmony_ci isp->smk_inode = smk_of_current(); 33508c2ecf20Sopenharmony_ci break; 33518c2ecf20Sopenharmony_ci case SOCKFS_MAGIC: 33528c2ecf20Sopenharmony_ci /* 33538c2ecf20Sopenharmony_ci * Socket access is controlled by the socket 33548c2ecf20Sopenharmony_ci * structures associated with the task involved. 33558c2ecf20Sopenharmony_ci */ 33568c2ecf20Sopenharmony_ci isp->smk_inode = &smack_known_star; 33578c2ecf20Sopenharmony_ci break; 33588c2ecf20Sopenharmony_ci default: 33598c2ecf20Sopenharmony_ci isp->smk_inode = sbsp->smk_root; 33608c2ecf20Sopenharmony_ci break; 33618c2ecf20Sopenharmony_ci } 33628c2ecf20Sopenharmony_ci isp->smk_flags |= SMK_INODE_INSTANT; 33638c2ecf20Sopenharmony_ci return; 33648c2ecf20Sopenharmony_ci } 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_ci /* 33678c2ecf20Sopenharmony_ci * This is pretty hackish. 33688c2ecf20Sopenharmony_ci * Casey says that we shouldn't have to do 33698c2ecf20Sopenharmony_ci * file system specific code, but it does help 33708c2ecf20Sopenharmony_ci * with keeping it simple. 33718c2ecf20Sopenharmony_ci */ 33728c2ecf20Sopenharmony_ci switch (sbp->s_magic) { 33738c2ecf20Sopenharmony_ci case SMACK_MAGIC: 33748c2ecf20Sopenharmony_ci case CGROUP_SUPER_MAGIC: 33758c2ecf20Sopenharmony_ci case CGROUP2_SUPER_MAGIC: 33768c2ecf20Sopenharmony_ci /* 33778c2ecf20Sopenharmony_ci * Casey says that it's a little embarrassing 33788c2ecf20Sopenharmony_ci * that the smack file system doesn't do 33798c2ecf20Sopenharmony_ci * extended attributes. 33808c2ecf20Sopenharmony_ci * 33818c2ecf20Sopenharmony_ci * Cgroupfs is special 33828c2ecf20Sopenharmony_ci */ 33838c2ecf20Sopenharmony_ci final = &smack_known_star; 33848c2ecf20Sopenharmony_ci break; 33858c2ecf20Sopenharmony_ci case DEVPTS_SUPER_MAGIC: 33868c2ecf20Sopenharmony_ci /* 33878c2ecf20Sopenharmony_ci * devpts seems content with the label of the task. 33888c2ecf20Sopenharmony_ci * Programs that change smack have to treat the 33898c2ecf20Sopenharmony_ci * pty with respect. 33908c2ecf20Sopenharmony_ci */ 33918c2ecf20Sopenharmony_ci final = ckp; 33928c2ecf20Sopenharmony_ci break; 33938c2ecf20Sopenharmony_ci case PROC_SUPER_MAGIC: 33948c2ecf20Sopenharmony_ci /* 33958c2ecf20Sopenharmony_ci * Casey says procfs appears not to care. 33968c2ecf20Sopenharmony_ci * The superblock default suffices. 33978c2ecf20Sopenharmony_ci */ 33988c2ecf20Sopenharmony_ci break; 33998c2ecf20Sopenharmony_ci case TMPFS_MAGIC: 34008c2ecf20Sopenharmony_ci /* 34018c2ecf20Sopenharmony_ci * Device labels should come from the filesystem, 34028c2ecf20Sopenharmony_ci * but watch out, because they're volitile, 34038c2ecf20Sopenharmony_ci * getting recreated on every reboot. 34048c2ecf20Sopenharmony_ci */ 34058c2ecf20Sopenharmony_ci final = &smack_known_star; 34068c2ecf20Sopenharmony_ci /* 34078c2ecf20Sopenharmony_ci * If a smack value has been set we want to use it, 34088c2ecf20Sopenharmony_ci * but since tmpfs isn't giving us the opportunity 34098c2ecf20Sopenharmony_ci * to set mount options simulate setting the 34108c2ecf20Sopenharmony_ci * superblock default. 34118c2ecf20Sopenharmony_ci */ 34128c2ecf20Sopenharmony_ci fallthrough; 34138c2ecf20Sopenharmony_ci default: 34148c2ecf20Sopenharmony_ci /* 34158c2ecf20Sopenharmony_ci * This isn't an understood special case. 34168c2ecf20Sopenharmony_ci * Get the value from the xattr. 34178c2ecf20Sopenharmony_ci */ 34188c2ecf20Sopenharmony_ci 34198c2ecf20Sopenharmony_ci /* 34208c2ecf20Sopenharmony_ci * UNIX domain sockets use lower level socket data. 34218c2ecf20Sopenharmony_ci */ 34228c2ecf20Sopenharmony_ci if (S_ISSOCK(inode->i_mode)) { 34238c2ecf20Sopenharmony_ci final = &smack_known_star; 34248c2ecf20Sopenharmony_ci break; 34258c2ecf20Sopenharmony_ci } 34268c2ecf20Sopenharmony_ci /* 34278c2ecf20Sopenharmony_ci * No xattr support means, alas, no SMACK label. 34288c2ecf20Sopenharmony_ci * Use the aforeapplied default. 34298c2ecf20Sopenharmony_ci * It would be curious if the label of the task 34308c2ecf20Sopenharmony_ci * does not match that assigned. 34318c2ecf20Sopenharmony_ci */ 34328c2ecf20Sopenharmony_ci if (!(inode->i_opflags & IOP_XATTR)) 34338c2ecf20Sopenharmony_ci break; 34348c2ecf20Sopenharmony_ci /* 34358c2ecf20Sopenharmony_ci * Get the dentry for xattr. 34368c2ecf20Sopenharmony_ci */ 34378c2ecf20Sopenharmony_ci dp = dget(opt_dentry); 34388c2ecf20Sopenharmony_ci skp = smk_fetch(XATTR_NAME_SMACK, inode, dp); 34398c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(skp)) 34408c2ecf20Sopenharmony_ci final = skp; 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci /* 34438c2ecf20Sopenharmony_ci * Transmuting directory 34448c2ecf20Sopenharmony_ci */ 34458c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 34468c2ecf20Sopenharmony_ci /* 34478c2ecf20Sopenharmony_ci * If this is a new directory and the label was 34488c2ecf20Sopenharmony_ci * transmuted when the inode was initialized 34498c2ecf20Sopenharmony_ci * set the transmute attribute on the directory 34508c2ecf20Sopenharmony_ci * and mark the inode. 34518c2ecf20Sopenharmony_ci * 34528c2ecf20Sopenharmony_ci * If there is a transmute attribute on the 34538c2ecf20Sopenharmony_ci * directory mark the inode. 34548c2ecf20Sopenharmony_ci */ 34558c2ecf20Sopenharmony_ci if (isp->smk_flags & SMK_INODE_CHANGED) { 34568c2ecf20Sopenharmony_ci isp->smk_flags &= ~SMK_INODE_CHANGED; 34578c2ecf20Sopenharmony_ci rc = __vfs_setxattr(dp, inode, 34588c2ecf20Sopenharmony_ci XATTR_NAME_SMACKTRANSMUTE, 34598c2ecf20Sopenharmony_ci TRANS_TRUE, TRANS_TRUE_SIZE, 34608c2ecf20Sopenharmony_ci 0); 34618c2ecf20Sopenharmony_ci } else { 34628c2ecf20Sopenharmony_ci rc = __vfs_getxattr(dp, inode, 34638c2ecf20Sopenharmony_ci XATTR_NAME_SMACKTRANSMUTE, trattr, 34648c2ecf20Sopenharmony_ci TRANS_TRUE_SIZE); 34658c2ecf20Sopenharmony_ci if (rc >= 0 && strncmp(trattr, TRANS_TRUE, 34668c2ecf20Sopenharmony_ci TRANS_TRUE_SIZE) != 0) 34678c2ecf20Sopenharmony_ci rc = -EINVAL; 34688c2ecf20Sopenharmony_ci } 34698c2ecf20Sopenharmony_ci if (rc >= 0) 34708c2ecf20Sopenharmony_ci transflag = SMK_INODE_TRANSMUTE; 34718c2ecf20Sopenharmony_ci } 34728c2ecf20Sopenharmony_ci /* 34738c2ecf20Sopenharmony_ci * Don't let the exec or mmap label be "*" or "@". 34748c2ecf20Sopenharmony_ci */ 34758c2ecf20Sopenharmony_ci skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); 34768c2ecf20Sopenharmony_ci if (IS_ERR(skp) || skp == &smack_known_star || 34778c2ecf20Sopenharmony_ci skp == &smack_known_web) 34788c2ecf20Sopenharmony_ci skp = NULL; 34798c2ecf20Sopenharmony_ci isp->smk_task = skp; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); 34828c2ecf20Sopenharmony_ci if (IS_ERR(skp) || skp == &smack_known_star || 34838c2ecf20Sopenharmony_ci skp == &smack_known_web) 34848c2ecf20Sopenharmony_ci skp = NULL; 34858c2ecf20Sopenharmony_ci isp->smk_mmap = skp; 34868c2ecf20Sopenharmony_ci 34878c2ecf20Sopenharmony_ci dput(dp); 34888c2ecf20Sopenharmony_ci break; 34898c2ecf20Sopenharmony_ci } 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci if (final == NULL) 34928c2ecf20Sopenharmony_ci isp->smk_inode = ckp; 34938c2ecf20Sopenharmony_ci else 34948c2ecf20Sopenharmony_ci isp->smk_inode = final; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci isp->smk_flags |= (SMK_INODE_INSTANT | transflag); 34978c2ecf20Sopenharmony_ci 34988c2ecf20Sopenharmony_ci return; 34998c2ecf20Sopenharmony_ci} 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci/** 35028c2ecf20Sopenharmony_ci * smack_getprocattr - Smack process attribute access 35038c2ecf20Sopenharmony_ci * @p: the object task 35048c2ecf20Sopenharmony_ci * @name: the name of the attribute in /proc/.../attr 35058c2ecf20Sopenharmony_ci * @value: where to put the result 35068c2ecf20Sopenharmony_ci * 35078c2ecf20Sopenharmony_ci * Places a copy of the task Smack into value 35088c2ecf20Sopenharmony_ci * 35098c2ecf20Sopenharmony_ci * Returns the length of the smack label or an error code 35108c2ecf20Sopenharmony_ci */ 35118c2ecf20Sopenharmony_cistatic int smack_getprocattr(struct task_struct *p, char *name, char **value) 35128c2ecf20Sopenharmony_ci{ 35138c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_task_struct(p); 35148c2ecf20Sopenharmony_ci char *cp; 35158c2ecf20Sopenharmony_ci int slen; 35168c2ecf20Sopenharmony_ci 35178c2ecf20Sopenharmony_ci if (strcmp(name, "current") != 0) 35188c2ecf20Sopenharmony_ci return -EINVAL; 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_ci cp = kstrdup(skp->smk_known, GFP_KERNEL); 35218c2ecf20Sopenharmony_ci if (cp == NULL) 35228c2ecf20Sopenharmony_ci return -ENOMEM; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci slen = strlen(cp); 35258c2ecf20Sopenharmony_ci *value = cp; 35268c2ecf20Sopenharmony_ci return slen; 35278c2ecf20Sopenharmony_ci} 35288c2ecf20Sopenharmony_ci 35298c2ecf20Sopenharmony_ci/** 35308c2ecf20Sopenharmony_ci * smack_setprocattr - Smack process attribute setting 35318c2ecf20Sopenharmony_ci * @name: the name of the attribute in /proc/.../attr 35328c2ecf20Sopenharmony_ci * @value: the value to set 35338c2ecf20Sopenharmony_ci * @size: the size of the value 35348c2ecf20Sopenharmony_ci * 35358c2ecf20Sopenharmony_ci * Sets the Smack value of the task. Only setting self 35368c2ecf20Sopenharmony_ci * is permitted and only with privilege 35378c2ecf20Sopenharmony_ci * 35388c2ecf20Sopenharmony_ci * Returns the length of the smack label or an error code 35398c2ecf20Sopenharmony_ci */ 35408c2ecf20Sopenharmony_cistatic int smack_setprocattr(const char *name, void *value, size_t size) 35418c2ecf20Sopenharmony_ci{ 35428c2ecf20Sopenharmony_ci struct task_smack *tsp = smack_cred(current_cred()); 35438c2ecf20Sopenharmony_ci struct cred *new; 35448c2ecf20Sopenharmony_ci struct smack_known *skp; 35458c2ecf20Sopenharmony_ci struct smack_known_list_elem *sklep; 35468c2ecf20Sopenharmony_ci int rc; 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_ci if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel)) 35498c2ecf20Sopenharmony_ci return -EPERM; 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci if (value == NULL || size == 0 || size >= SMK_LONGLABEL) 35528c2ecf20Sopenharmony_ci return -EINVAL; 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ci if (strcmp(name, "current") != 0) 35558c2ecf20Sopenharmony_ci return -EINVAL; 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci skp = smk_import_entry(value, size); 35588c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 35598c2ecf20Sopenharmony_ci return PTR_ERR(skp); 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci /* 35628c2ecf20Sopenharmony_ci * No process is ever allowed the web ("@") label 35638c2ecf20Sopenharmony_ci * and the star ("*") label. 35648c2ecf20Sopenharmony_ci */ 35658c2ecf20Sopenharmony_ci if (skp == &smack_known_web || skp == &smack_known_star) 35668c2ecf20Sopenharmony_ci return -EINVAL; 35678c2ecf20Sopenharmony_ci 35688c2ecf20Sopenharmony_ci if (!smack_privileged(CAP_MAC_ADMIN)) { 35698c2ecf20Sopenharmony_ci rc = -EPERM; 35708c2ecf20Sopenharmony_ci list_for_each_entry(sklep, &tsp->smk_relabel, list) 35718c2ecf20Sopenharmony_ci if (sklep->smk_label == skp) { 35728c2ecf20Sopenharmony_ci rc = 0; 35738c2ecf20Sopenharmony_ci break; 35748c2ecf20Sopenharmony_ci } 35758c2ecf20Sopenharmony_ci if (rc) 35768c2ecf20Sopenharmony_ci return rc; 35778c2ecf20Sopenharmony_ci } 35788c2ecf20Sopenharmony_ci 35798c2ecf20Sopenharmony_ci new = prepare_creds(); 35808c2ecf20Sopenharmony_ci if (new == NULL) 35818c2ecf20Sopenharmony_ci return -ENOMEM; 35828c2ecf20Sopenharmony_ci 35838c2ecf20Sopenharmony_ci tsp = smack_cred(new); 35848c2ecf20Sopenharmony_ci tsp->smk_task = skp; 35858c2ecf20Sopenharmony_ci /* 35868c2ecf20Sopenharmony_ci * process can change its label only once 35878c2ecf20Sopenharmony_ci */ 35888c2ecf20Sopenharmony_ci smk_destroy_label_list(&tsp->smk_relabel); 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci commit_creds(new); 35918c2ecf20Sopenharmony_ci return size; 35928c2ecf20Sopenharmony_ci} 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci/** 35958c2ecf20Sopenharmony_ci * smack_unix_stream_connect - Smack access on UDS 35968c2ecf20Sopenharmony_ci * @sock: one sock 35978c2ecf20Sopenharmony_ci * @other: the other sock 35988c2ecf20Sopenharmony_ci * @newsk: unused 35998c2ecf20Sopenharmony_ci * 36008c2ecf20Sopenharmony_ci * Return 0 if a subject with the smack of sock could access 36018c2ecf20Sopenharmony_ci * an object with the smack of other, otherwise an error code 36028c2ecf20Sopenharmony_ci */ 36038c2ecf20Sopenharmony_cistatic int smack_unix_stream_connect(struct sock *sock, 36048c2ecf20Sopenharmony_ci struct sock *other, struct sock *newsk) 36058c2ecf20Sopenharmony_ci{ 36068c2ecf20Sopenharmony_ci struct smack_known *skp; 36078c2ecf20Sopenharmony_ci struct smack_known *okp; 36088c2ecf20Sopenharmony_ci struct socket_smack *ssp = sock->sk_security; 36098c2ecf20Sopenharmony_ci struct socket_smack *osp = other->sk_security; 36108c2ecf20Sopenharmony_ci struct socket_smack *nsp = newsk->sk_security; 36118c2ecf20Sopenharmony_ci struct smk_audit_info ad; 36128c2ecf20Sopenharmony_ci int rc = 0; 36138c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 36148c2ecf20Sopenharmony_ci struct lsm_network_audit net; 36158c2ecf20Sopenharmony_ci#endif 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci if (!smack_privileged(CAP_MAC_OVERRIDE)) { 36188c2ecf20Sopenharmony_ci skp = ssp->smk_out; 36198c2ecf20Sopenharmony_ci okp = osp->smk_in; 36208c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 36218c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 36228c2ecf20Sopenharmony_ci smk_ad_setfield_u_net_sk(&ad, other); 36238c2ecf20Sopenharmony_ci#endif 36248c2ecf20Sopenharmony_ci rc = smk_access(skp, okp, MAY_WRITE, &ad); 36258c2ecf20Sopenharmony_ci rc = smk_bu_note("UDS connect", skp, okp, MAY_WRITE, rc); 36268c2ecf20Sopenharmony_ci if (rc == 0) { 36278c2ecf20Sopenharmony_ci okp = osp->smk_out; 36288c2ecf20Sopenharmony_ci skp = ssp->smk_in; 36298c2ecf20Sopenharmony_ci rc = smk_access(okp, skp, MAY_WRITE, &ad); 36308c2ecf20Sopenharmony_ci rc = smk_bu_note("UDS connect", okp, skp, 36318c2ecf20Sopenharmony_ci MAY_WRITE, rc); 36328c2ecf20Sopenharmony_ci } 36338c2ecf20Sopenharmony_ci } 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci /* 36368c2ecf20Sopenharmony_ci * Cross reference the peer labels for SO_PEERSEC. 36378c2ecf20Sopenharmony_ci */ 36388c2ecf20Sopenharmony_ci if (rc == 0) { 36398c2ecf20Sopenharmony_ci nsp->smk_packet = ssp->smk_out; 36408c2ecf20Sopenharmony_ci ssp->smk_packet = osp->smk_out; 36418c2ecf20Sopenharmony_ci } 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci return rc; 36448c2ecf20Sopenharmony_ci} 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci/** 36478c2ecf20Sopenharmony_ci * smack_unix_may_send - Smack access on UDS 36488c2ecf20Sopenharmony_ci * @sock: one socket 36498c2ecf20Sopenharmony_ci * @other: the other socket 36508c2ecf20Sopenharmony_ci * 36518c2ecf20Sopenharmony_ci * Return 0 if a subject with the smack of sock could access 36528c2ecf20Sopenharmony_ci * an object with the smack of other, otherwise an error code 36538c2ecf20Sopenharmony_ci */ 36548c2ecf20Sopenharmony_cistatic int smack_unix_may_send(struct socket *sock, struct socket *other) 36558c2ecf20Sopenharmony_ci{ 36568c2ecf20Sopenharmony_ci struct socket_smack *ssp = sock->sk->sk_security; 36578c2ecf20Sopenharmony_ci struct socket_smack *osp = other->sk->sk_security; 36588c2ecf20Sopenharmony_ci struct smk_audit_info ad; 36598c2ecf20Sopenharmony_ci int rc; 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 36628c2ecf20Sopenharmony_ci struct lsm_network_audit net; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 36658c2ecf20Sopenharmony_ci smk_ad_setfield_u_net_sk(&ad, other->sk); 36668c2ecf20Sopenharmony_ci#endif 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci if (smack_privileged(CAP_MAC_OVERRIDE)) 36698c2ecf20Sopenharmony_ci return 0; 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci rc = smk_access(ssp->smk_out, osp->smk_in, MAY_WRITE, &ad); 36728c2ecf20Sopenharmony_ci rc = smk_bu_note("UDS send", ssp->smk_out, osp->smk_in, MAY_WRITE, rc); 36738c2ecf20Sopenharmony_ci return rc; 36748c2ecf20Sopenharmony_ci} 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci/** 36778c2ecf20Sopenharmony_ci * smack_socket_sendmsg - Smack check based on destination host 36788c2ecf20Sopenharmony_ci * @sock: the socket 36798c2ecf20Sopenharmony_ci * @msg: the message 36808c2ecf20Sopenharmony_ci * @size: the size of the message 36818c2ecf20Sopenharmony_ci * 36828c2ecf20Sopenharmony_ci * Return 0 if the current subject can write to the destination host. 36838c2ecf20Sopenharmony_ci * For IPv4 this is only a question if the destination is a single label host. 36848c2ecf20Sopenharmony_ci * For IPv6 this is a check against the label of the port. 36858c2ecf20Sopenharmony_ci */ 36868c2ecf20Sopenharmony_cistatic int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, 36878c2ecf20Sopenharmony_ci int size) 36888c2ecf20Sopenharmony_ci{ 36898c2ecf20Sopenharmony_ci struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; 36908c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 36918c2ecf20Sopenharmony_ci struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; 36928c2ecf20Sopenharmony_ci#endif 36938c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_SECMARK_LABELING 36948c2ecf20Sopenharmony_ci struct socket_smack *ssp = sock->sk->sk_security; 36958c2ecf20Sopenharmony_ci struct smack_known *rsp; 36968c2ecf20Sopenharmony_ci#endif 36978c2ecf20Sopenharmony_ci int rc = 0; 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_ci /* 37008c2ecf20Sopenharmony_ci * Perfectly reasonable for this to be NULL 37018c2ecf20Sopenharmony_ci */ 37028c2ecf20Sopenharmony_ci if (sip == NULL) 37038c2ecf20Sopenharmony_ci return 0; 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci switch (sock->sk->sk_family) { 37068c2ecf20Sopenharmony_ci case AF_INET: 37078c2ecf20Sopenharmony_ci if (msg->msg_namelen < sizeof(struct sockaddr_in) || 37088c2ecf20Sopenharmony_ci sip->sin_family != AF_INET) 37098c2ecf20Sopenharmony_ci return -EINVAL; 37108c2ecf20Sopenharmony_ci rc = smk_ipv4_check(sock->sk, sip); 37118c2ecf20Sopenharmony_ci break; 37128c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 37138c2ecf20Sopenharmony_ci case AF_INET6: 37148c2ecf20Sopenharmony_ci if (msg->msg_namelen < SIN6_LEN_RFC2133 || 37158c2ecf20Sopenharmony_ci sap->sin6_family != AF_INET6) 37168c2ecf20Sopenharmony_ci return -EINVAL; 37178c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_SECMARK_LABELING 37188c2ecf20Sopenharmony_ci rsp = smack_ipv6host_label(sap); 37198c2ecf20Sopenharmony_ci if (rsp != NULL) 37208c2ecf20Sopenharmony_ci rc = smk_ipv6_check(ssp->smk_out, rsp, sap, 37218c2ecf20Sopenharmony_ci SMK_CONNECTING); 37228c2ecf20Sopenharmony_ci#endif 37238c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 37248c2ecf20Sopenharmony_ci rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); 37258c2ecf20Sopenharmony_ci#endif 37268c2ecf20Sopenharmony_ci#endif /* IS_ENABLED(CONFIG_IPV6) */ 37278c2ecf20Sopenharmony_ci break; 37288c2ecf20Sopenharmony_ci } 37298c2ecf20Sopenharmony_ci return rc; 37308c2ecf20Sopenharmony_ci} 37318c2ecf20Sopenharmony_ci 37328c2ecf20Sopenharmony_ci/** 37338c2ecf20Sopenharmony_ci * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack 37348c2ecf20Sopenharmony_ci * @sap: netlabel secattr 37358c2ecf20Sopenharmony_ci * @ssp: socket security information 37368c2ecf20Sopenharmony_ci * 37378c2ecf20Sopenharmony_ci * Returns a pointer to a Smack label entry found on the label list. 37388c2ecf20Sopenharmony_ci */ 37398c2ecf20Sopenharmony_cistatic struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, 37408c2ecf20Sopenharmony_ci struct socket_smack *ssp) 37418c2ecf20Sopenharmony_ci{ 37428c2ecf20Sopenharmony_ci struct smack_known *skp; 37438c2ecf20Sopenharmony_ci int found = 0; 37448c2ecf20Sopenharmony_ci int acat; 37458c2ecf20Sopenharmony_ci int kcat; 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci /* 37488c2ecf20Sopenharmony_ci * Netlabel found it in the cache. 37498c2ecf20Sopenharmony_ci */ 37508c2ecf20Sopenharmony_ci if ((sap->flags & NETLBL_SECATTR_CACHE) != 0) 37518c2ecf20Sopenharmony_ci return (struct smack_known *)sap->cache->data; 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci if ((sap->flags & NETLBL_SECATTR_SECID) != 0) 37548c2ecf20Sopenharmony_ci /* 37558c2ecf20Sopenharmony_ci * Looks like a fallback, which gives us a secid. 37568c2ecf20Sopenharmony_ci */ 37578c2ecf20Sopenharmony_ci return smack_from_secid(sap->attr.secid); 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { 37608c2ecf20Sopenharmony_ci /* 37618c2ecf20Sopenharmony_ci * Looks like a CIPSO packet. 37628c2ecf20Sopenharmony_ci * If there are flags but no level netlabel isn't 37638c2ecf20Sopenharmony_ci * behaving the way we expect it to. 37648c2ecf20Sopenharmony_ci * 37658c2ecf20Sopenharmony_ci * Look it up in the label table 37668c2ecf20Sopenharmony_ci * Without guidance regarding the smack value 37678c2ecf20Sopenharmony_ci * for the packet fall back on the network 37688c2ecf20Sopenharmony_ci * ambient value. 37698c2ecf20Sopenharmony_ci */ 37708c2ecf20Sopenharmony_ci rcu_read_lock(); 37718c2ecf20Sopenharmony_ci list_for_each_entry_rcu(skp, &smack_known_list, list) { 37728c2ecf20Sopenharmony_ci if (sap->attr.mls.lvl != skp->smk_netlabel.attr.mls.lvl) 37738c2ecf20Sopenharmony_ci continue; 37748c2ecf20Sopenharmony_ci /* 37758c2ecf20Sopenharmony_ci * Compare the catsets. Use the netlbl APIs. 37768c2ecf20Sopenharmony_ci */ 37778c2ecf20Sopenharmony_ci if ((sap->flags & NETLBL_SECATTR_MLS_CAT) == 0) { 37788c2ecf20Sopenharmony_ci if ((skp->smk_netlabel.flags & 37798c2ecf20Sopenharmony_ci NETLBL_SECATTR_MLS_CAT) == 0) 37808c2ecf20Sopenharmony_ci found = 1; 37818c2ecf20Sopenharmony_ci break; 37828c2ecf20Sopenharmony_ci } 37838c2ecf20Sopenharmony_ci for (acat = -1, kcat = -1; acat == kcat; ) { 37848c2ecf20Sopenharmony_ci acat = netlbl_catmap_walk(sap->attr.mls.cat, 37858c2ecf20Sopenharmony_ci acat + 1); 37868c2ecf20Sopenharmony_ci kcat = netlbl_catmap_walk( 37878c2ecf20Sopenharmony_ci skp->smk_netlabel.attr.mls.cat, 37888c2ecf20Sopenharmony_ci kcat + 1); 37898c2ecf20Sopenharmony_ci if (acat < 0 || kcat < 0) 37908c2ecf20Sopenharmony_ci break; 37918c2ecf20Sopenharmony_ci } 37928c2ecf20Sopenharmony_ci if (acat == kcat) { 37938c2ecf20Sopenharmony_ci found = 1; 37948c2ecf20Sopenharmony_ci break; 37958c2ecf20Sopenharmony_ci } 37968c2ecf20Sopenharmony_ci } 37978c2ecf20Sopenharmony_ci rcu_read_unlock(); 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci if (found) 38008c2ecf20Sopenharmony_ci return skp; 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci if (ssp != NULL && ssp->smk_in == &smack_known_star) 38038c2ecf20Sopenharmony_ci return &smack_known_web; 38048c2ecf20Sopenharmony_ci return &smack_known_star; 38058c2ecf20Sopenharmony_ci } 38068c2ecf20Sopenharmony_ci /* 38078c2ecf20Sopenharmony_ci * Without guidance regarding the smack value 38088c2ecf20Sopenharmony_ci * for the packet fall back on the network 38098c2ecf20Sopenharmony_ci * ambient value. 38108c2ecf20Sopenharmony_ci */ 38118c2ecf20Sopenharmony_ci return smack_net_ambient; 38128c2ecf20Sopenharmony_ci} 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 38158c2ecf20Sopenharmony_cistatic int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) 38168c2ecf20Sopenharmony_ci{ 38178c2ecf20Sopenharmony_ci u8 nexthdr; 38188c2ecf20Sopenharmony_ci int offset; 38198c2ecf20Sopenharmony_ci int proto = -EINVAL; 38208c2ecf20Sopenharmony_ci struct ipv6hdr _ipv6h; 38218c2ecf20Sopenharmony_ci struct ipv6hdr *ip6; 38228c2ecf20Sopenharmony_ci __be16 frag_off; 38238c2ecf20Sopenharmony_ci struct tcphdr _tcph, *th; 38248c2ecf20Sopenharmony_ci struct udphdr _udph, *uh; 38258c2ecf20Sopenharmony_ci struct dccp_hdr _dccph, *dh; 38268c2ecf20Sopenharmony_ci 38278c2ecf20Sopenharmony_ci sip->sin6_port = 0; 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci offset = skb_network_offset(skb); 38308c2ecf20Sopenharmony_ci ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); 38318c2ecf20Sopenharmony_ci if (ip6 == NULL) 38328c2ecf20Sopenharmony_ci return -EINVAL; 38338c2ecf20Sopenharmony_ci sip->sin6_addr = ip6->saddr; 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci nexthdr = ip6->nexthdr; 38368c2ecf20Sopenharmony_ci offset += sizeof(_ipv6h); 38378c2ecf20Sopenharmony_ci offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); 38388c2ecf20Sopenharmony_ci if (offset < 0) 38398c2ecf20Sopenharmony_ci return -EINVAL; 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci proto = nexthdr; 38428c2ecf20Sopenharmony_ci switch (proto) { 38438c2ecf20Sopenharmony_ci case IPPROTO_TCP: 38448c2ecf20Sopenharmony_ci th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 38458c2ecf20Sopenharmony_ci if (th != NULL) 38468c2ecf20Sopenharmony_ci sip->sin6_port = th->source; 38478c2ecf20Sopenharmony_ci break; 38488c2ecf20Sopenharmony_ci case IPPROTO_UDP: 38498c2ecf20Sopenharmony_ci case IPPROTO_UDPLITE: 38508c2ecf20Sopenharmony_ci uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 38518c2ecf20Sopenharmony_ci if (uh != NULL) 38528c2ecf20Sopenharmony_ci sip->sin6_port = uh->source; 38538c2ecf20Sopenharmony_ci break; 38548c2ecf20Sopenharmony_ci case IPPROTO_DCCP: 38558c2ecf20Sopenharmony_ci dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 38568c2ecf20Sopenharmony_ci if (dh != NULL) 38578c2ecf20Sopenharmony_ci sip->sin6_port = dh->dccph_sport; 38588c2ecf20Sopenharmony_ci break; 38598c2ecf20Sopenharmony_ci } 38608c2ecf20Sopenharmony_ci return proto; 38618c2ecf20Sopenharmony_ci} 38628c2ecf20Sopenharmony_ci#endif /* CONFIG_IPV6 */ 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci/** 38658c2ecf20Sopenharmony_ci * smack_from_skb - Smack data from the secmark in an skb 38668c2ecf20Sopenharmony_ci * @skb: packet 38678c2ecf20Sopenharmony_ci * 38688c2ecf20Sopenharmony_ci * Returns smack_known of the secmark or NULL if that won't work. 38698c2ecf20Sopenharmony_ci */ 38708c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 38718c2ecf20Sopenharmony_cistatic struct smack_known *smack_from_skb(struct sk_buff *skb) 38728c2ecf20Sopenharmony_ci{ 38738c2ecf20Sopenharmony_ci if (skb == NULL || skb->secmark == 0) 38748c2ecf20Sopenharmony_ci return NULL; 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci return smack_from_secid(skb->secmark); 38778c2ecf20Sopenharmony_ci} 38788c2ecf20Sopenharmony_ci#else 38798c2ecf20Sopenharmony_cistatic inline struct smack_known *smack_from_skb(struct sk_buff *skb) 38808c2ecf20Sopenharmony_ci{ 38818c2ecf20Sopenharmony_ci return NULL; 38828c2ecf20Sopenharmony_ci} 38838c2ecf20Sopenharmony_ci#endif 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci/** 38868c2ecf20Sopenharmony_ci * smack_from_netlbl - Smack data from the IP options in an skb 38878c2ecf20Sopenharmony_ci * @sk: socket data came in on 38888c2ecf20Sopenharmony_ci * @family: address family 38898c2ecf20Sopenharmony_ci * @skb: packet 38908c2ecf20Sopenharmony_ci * 38918c2ecf20Sopenharmony_ci * Find the Smack label in the IP options. If it hasn't been 38928c2ecf20Sopenharmony_ci * added to the netlabel cache, add it here. 38938c2ecf20Sopenharmony_ci * 38948c2ecf20Sopenharmony_ci * Returns smack_known of the IP options or NULL if that won't work. 38958c2ecf20Sopenharmony_ci */ 38968c2ecf20Sopenharmony_cistatic struct smack_known *smack_from_netlbl(struct sock *sk, u16 family, 38978c2ecf20Sopenharmony_ci struct sk_buff *skb) 38988c2ecf20Sopenharmony_ci{ 38998c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr secattr; 39008c2ecf20Sopenharmony_ci struct socket_smack *ssp = NULL; 39018c2ecf20Sopenharmony_ci struct smack_known *skp = NULL; 39028c2ecf20Sopenharmony_ci int rc; 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_ci netlbl_secattr_init(&secattr); 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci if (sk) 39078c2ecf20Sopenharmony_ci ssp = sk->sk_security; 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ci if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) { 39108c2ecf20Sopenharmony_ci skp = smack_from_secattr(&secattr, ssp); 39118c2ecf20Sopenharmony_ci if (secattr.flags & NETLBL_SECATTR_CACHEABLE) 39128c2ecf20Sopenharmony_ci rc = netlbl_cache_add(skb, family, &skp->smk_netlabel); 39138c2ecf20Sopenharmony_ci } 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci netlbl_secattr_destroy(&secattr); 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci return skp; 39188c2ecf20Sopenharmony_ci} 39198c2ecf20Sopenharmony_ci 39208c2ecf20Sopenharmony_ci/** 39218c2ecf20Sopenharmony_ci * smack_socket_sock_rcv_skb - Smack packet delivery access check 39228c2ecf20Sopenharmony_ci * @sk: socket 39238c2ecf20Sopenharmony_ci * @skb: packet 39248c2ecf20Sopenharmony_ci * 39258c2ecf20Sopenharmony_ci * Returns 0 if the packet should be delivered, an error code otherwise 39268c2ecf20Sopenharmony_ci */ 39278c2ecf20Sopenharmony_cistatic int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 39288c2ecf20Sopenharmony_ci{ 39298c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 39308c2ecf20Sopenharmony_ci struct smack_known *skp = NULL; 39318c2ecf20Sopenharmony_ci int rc = 0; 39328c2ecf20Sopenharmony_ci struct smk_audit_info ad; 39338c2ecf20Sopenharmony_ci u16 family = sk->sk_family; 39348c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 39358c2ecf20Sopenharmony_ci struct lsm_network_audit net; 39368c2ecf20Sopenharmony_ci#endif 39378c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 39388c2ecf20Sopenharmony_ci struct sockaddr_in6 sadd; 39398c2ecf20Sopenharmony_ci int proto; 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 39428c2ecf20Sopenharmony_ci family = PF_INET; 39438c2ecf20Sopenharmony_ci#endif /* CONFIG_IPV6 */ 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci switch (family) { 39468c2ecf20Sopenharmony_ci case PF_INET: 39478c2ecf20Sopenharmony_ci /* 39488c2ecf20Sopenharmony_ci * If there is a secmark use it rather than the CIPSO label. 39498c2ecf20Sopenharmony_ci * If there is no secmark fall back to CIPSO. 39508c2ecf20Sopenharmony_ci * The secmark is assumed to reflect policy better. 39518c2ecf20Sopenharmony_ci */ 39528c2ecf20Sopenharmony_ci skp = smack_from_skb(skb); 39538c2ecf20Sopenharmony_ci if (skp == NULL) { 39548c2ecf20Sopenharmony_ci skp = smack_from_netlbl(sk, family, skb); 39558c2ecf20Sopenharmony_ci if (skp == NULL) 39568c2ecf20Sopenharmony_ci skp = smack_net_ambient; 39578c2ecf20Sopenharmony_ci } 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 39608c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 39618c2ecf20Sopenharmony_ci ad.a.u.net->family = family; 39628c2ecf20Sopenharmony_ci ad.a.u.net->netif = skb->skb_iif; 39638c2ecf20Sopenharmony_ci ipv4_skb_to_auditdata(skb, &ad.a, NULL); 39648c2ecf20Sopenharmony_ci#endif 39658c2ecf20Sopenharmony_ci /* 39668c2ecf20Sopenharmony_ci * Receiving a packet requires that the other end 39678c2ecf20Sopenharmony_ci * be able to write here. Read access is not required. 39688c2ecf20Sopenharmony_ci * This is the simplist possible security model 39698c2ecf20Sopenharmony_ci * for networking. 39708c2ecf20Sopenharmony_ci */ 39718c2ecf20Sopenharmony_ci rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); 39728c2ecf20Sopenharmony_ci rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in, 39738c2ecf20Sopenharmony_ci MAY_WRITE, rc); 39748c2ecf20Sopenharmony_ci if (rc != 0) 39758c2ecf20Sopenharmony_ci netlbl_skbuff_err(skb, family, rc, 0); 39768c2ecf20Sopenharmony_ci break; 39778c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 39788c2ecf20Sopenharmony_ci case PF_INET6: 39798c2ecf20Sopenharmony_ci proto = smk_skb_to_addr_ipv6(skb, &sadd); 39808c2ecf20Sopenharmony_ci if (proto != IPPROTO_UDP && proto != IPPROTO_UDPLITE && 39818c2ecf20Sopenharmony_ci proto != IPPROTO_TCP && proto != IPPROTO_DCCP) 39828c2ecf20Sopenharmony_ci break; 39838c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_SECMARK_LABELING 39848c2ecf20Sopenharmony_ci skp = smack_from_skb(skb); 39858c2ecf20Sopenharmony_ci if (skp == NULL) { 39868c2ecf20Sopenharmony_ci if (smk_ipv6_localhost(&sadd)) 39878c2ecf20Sopenharmony_ci break; 39888c2ecf20Sopenharmony_ci skp = smack_ipv6host_label(&sadd); 39898c2ecf20Sopenharmony_ci if (skp == NULL) 39908c2ecf20Sopenharmony_ci skp = smack_net_ambient; 39918c2ecf20Sopenharmony_ci } 39928c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 39938c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 39948c2ecf20Sopenharmony_ci ad.a.u.net->family = family; 39958c2ecf20Sopenharmony_ci ad.a.u.net->netif = skb->skb_iif; 39968c2ecf20Sopenharmony_ci ipv6_skb_to_auditdata(skb, &ad.a, NULL); 39978c2ecf20Sopenharmony_ci#endif /* CONFIG_AUDIT */ 39988c2ecf20Sopenharmony_ci rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); 39998c2ecf20Sopenharmony_ci rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, 40008c2ecf20Sopenharmony_ci MAY_WRITE, rc); 40018c2ecf20Sopenharmony_ci#endif /* SMACK_IPV6_SECMARK_LABELING */ 40028c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 40038c2ecf20Sopenharmony_ci rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); 40048c2ecf20Sopenharmony_ci#endif /* SMACK_IPV6_PORT_LABELING */ 40058c2ecf20Sopenharmony_ci if (rc != 0) 40068c2ecf20Sopenharmony_ci icmpv6_send(skb, ICMPV6_DEST_UNREACH, 40078c2ecf20Sopenharmony_ci ICMPV6_ADM_PROHIBITED, 0); 40088c2ecf20Sopenharmony_ci break; 40098c2ecf20Sopenharmony_ci#endif /* CONFIG_IPV6 */ 40108c2ecf20Sopenharmony_ci } 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci return rc; 40138c2ecf20Sopenharmony_ci} 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci/** 40168c2ecf20Sopenharmony_ci * smack_socket_getpeersec_stream - pull in packet label 40178c2ecf20Sopenharmony_ci * @sock: the socket 40188c2ecf20Sopenharmony_ci * @optval: user's destination 40198c2ecf20Sopenharmony_ci * @optlen: size thereof 40208c2ecf20Sopenharmony_ci * @len: max thereof 40218c2ecf20Sopenharmony_ci * 40228c2ecf20Sopenharmony_ci * returns zero on success, an error code otherwise 40238c2ecf20Sopenharmony_ci */ 40248c2ecf20Sopenharmony_cistatic int smack_socket_getpeersec_stream(struct socket *sock, 40258c2ecf20Sopenharmony_ci char __user *optval, 40268c2ecf20Sopenharmony_ci int __user *optlen, unsigned len) 40278c2ecf20Sopenharmony_ci{ 40288c2ecf20Sopenharmony_ci struct socket_smack *ssp; 40298c2ecf20Sopenharmony_ci char *rcp = ""; 40308c2ecf20Sopenharmony_ci int slen = 1; 40318c2ecf20Sopenharmony_ci int rc = 0; 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci ssp = sock->sk->sk_security; 40348c2ecf20Sopenharmony_ci if (ssp->smk_packet != NULL) { 40358c2ecf20Sopenharmony_ci rcp = ssp->smk_packet->smk_known; 40368c2ecf20Sopenharmony_ci slen = strlen(rcp) + 1; 40378c2ecf20Sopenharmony_ci } 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci if (slen > len) 40408c2ecf20Sopenharmony_ci rc = -ERANGE; 40418c2ecf20Sopenharmony_ci else if (copy_to_user(optval, rcp, slen) != 0) 40428c2ecf20Sopenharmony_ci rc = -EFAULT; 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci if (put_user(slen, optlen) != 0) 40458c2ecf20Sopenharmony_ci rc = -EFAULT; 40468c2ecf20Sopenharmony_ci 40478c2ecf20Sopenharmony_ci return rc; 40488c2ecf20Sopenharmony_ci} 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci/** 40528c2ecf20Sopenharmony_ci * smack_socket_getpeersec_dgram - pull in packet label 40538c2ecf20Sopenharmony_ci * @sock: the peer socket 40548c2ecf20Sopenharmony_ci * @skb: packet data 40558c2ecf20Sopenharmony_ci * @secid: pointer to where to put the secid of the packet 40568c2ecf20Sopenharmony_ci * 40578c2ecf20Sopenharmony_ci * Sets the netlabel socket state on sk from parent 40588c2ecf20Sopenharmony_ci */ 40598c2ecf20Sopenharmony_cistatic int smack_socket_getpeersec_dgram(struct socket *sock, 40608c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 *secid) 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci{ 40638c2ecf20Sopenharmony_ci struct socket_smack *ssp = NULL; 40648c2ecf20Sopenharmony_ci struct smack_known *skp; 40658c2ecf20Sopenharmony_ci struct sock *sk = NULL; 40668c2ecf20Sopenharmony_ci int family = PF_UNSPEC; 40678c2ecf20Sopenharmony_ci u32 s = 0; /* 0 is the invalid secid */ 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci if (skb != NULL) { 40708c2ecf20Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) 40718c2ecf20Sopenharmony_ci family = PF_INET; 40728c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 40738c2ecf20Sopenharmony_ci else if (skb->protocol == htons(ETH_P_IPV6)) 40748c2ecf20Sopenharmony_ci family = PF_INET6; 40758c2ecf20Sopenharmony_ci#endif /* CONFIG_IPV6 */ 40768c2ecf20Sopenharmony_ci } 40778c2ecf20Sopenharmony_ci if (family == PF_UNSPEC && sock != NULL) 40788c2ecf20Sopenharmony_ci family = sock->sk->sk_family; 40798c2ecf20Sopenharmony_ci 40808c2ecf20Sopenharmony_ci switch (family) { 40818c2ecf20Sopenharmony_ci case PF_UNIX: 40828c2ecf20Sopenharmony_ci ssp = sock->sk->sk_security; 40838c2ecf20Sopenharmony_ci s = ssp->smk_out->smk_secid; 40848c2ecf20Sopenharmony_ci break; 40858c2ecf20Sopenharmony_ci case PF_INET: 40868c2ecf20Sopenharmony_ci skp = smack_from_skb(skb); 40878c2ecf20Sopenharmony_ci if (skp) { 40888c2ecf20Sopenharmony_ci s = skp->smk_secid; 40898c2ecf20Sopenharmony_ci break; 40908c2ecf20Sopenharmony_ci } 40918c2ecf20Sopenharmony_ci /* 40928c2ecf20Sopenharmony_ci * Translate what netlabel gave us. 40938c2ecf20Sopenharmony_ci */ 40948c2ecf20Sopenharmony_ci if (sock != NULL) 40958c2ecf20Sopenharmony_ci sk = sock->sk; 40968c2ecf20Sopenharmony_ci skp = smack_from_netlbl(sk, family, skb); 40978c2ecf20Sopenharmony_ci if (skp != NULL) 40988c2ecf20Sopenharmony_ci s = skp->smk_secid; 40998c2ecf20Sopenharmony_ci break; 41008c2ecf20Sopenharmony_ci case PF_INET6: 41018c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_SECMARK_LABELING 41028c2ecf20Sopenharmony_ci skp = smack_from_skb(skb); 41038c2ecf20Sopenharmony_ci if (skp) 41048c2ecf20Sopenharmony_ci s = skp->smk_secid; 41058c2ecf20Sopenharmony_ci#endif 41068c2ecf20Sopenharmony_ci break; 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci *secid = s; 41098c2ecf20Sopenharmony_ci if (s == 0) 41108c2ecf20Sopenharmony_ci return -EINVAL; 41118c2ecf20Sopenharmony_ci return 0; 41128c2ecf20Sopenharmony_ci} 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci/** 41158c2ecf20Sopenharmony_ci * smack_sock_graft - Initialize a newly created socket with an existing sock 41168c2ecf20Sopenharmony_ci * @sk: child sock 41178c2ecf20Sopenharmony_ci * @parent: parent socket 41188c2ecf20Sopenharmony_ci * 41198c2ecf20Sopenharmony_ci * Set the smk_{in,out} state of an existing sock based on the process that 41208c2ecf20Sopenharmony_ci * is creating the new socket. 41218c2ecf20Sopenharmony_ci */ 41228c2ecf20Sopenharmony_cistatic void smack_sock_graft(struct sock *sk, struct socket *parent) 41238c2ecf20Sopenharmony_ci{ 41248c2ecf20Sopenharmony_ci struct socket_smack *ssp; 41258c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_current(); 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci if (sk == NULL || 41288c2ecf20Sopenharmony_ci (sk->sk_family != PF_INET && sk->sk_family != PF_INET6)) 41298c2ecf20Sopenharmony_ci return; 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci ssp = sk->sk_security; 41328c2ecf20Sopenharmony_ci ssp->smk_in = skp; 41338c2ecf20Sopenharmony_ci ssp->smk_out = skp; 41348c2ecf20Sopenharmony_ci /* cssp->smk_packet is already set in smack_inet_csk_clone() */ 41358c2ecf20Sopenharmony_ci} 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ci/** 41388c2ecf20Sopenharmony_ci * smack_inet_conn_request - Smack access check on connect 41398c2ecf20Sopenharmony_ci * @sk: socket involved 41408c2ecf20Sopenharmony_ci * @skb: packet 41418c2ecf20Sopenharmony_ci * @req: unused 41428c2ecf20Sopenharmony_ci * 41438c2ecf20Sopenharmony_ci * Returns 0 if a task with the packet label could write to 41448c2ecf20Sopenharmony_ci * the socket, otherwise an error code 41458c2ecf20Sopenharmony_ci */ 41468c2ecf20Sopenharmony_cistatic int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, 41478c2ecf20Sopenharmony_ci struct request_sock *req) 41488c2ecf20Sopenharmony_ci{ 41498c2ecf20Sopenharmony_ci u16 family = sk->sk_family; 41508c2ecf20Sopenharmony_ci struct smack_known *skp; 41518c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 41528c2ecf20Sopenharmony_ci struct sockaddr_in addr; 41538c2ecf20Sopenharmony_ci struct iphdr *hdr; 41548c2ecf20Sopenharmony_ci struct smack_known *hskp; 41558c2ecf20Sopenharmony_ci int rc; 41568c2ecf20Sopenharmony_ci struct smk_audit_info ad; 41578c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 41588c2ecf20Sopenharmony_ci struct lsm_network_audit net; 41598c2ecf20Sopenharmony_ci#endif 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 41628c2ecf20Sopenharmony_ci if (family == PF_INET6) { 41638c2ecf20Sopenharmony_ci /* 41648c2ecf20Sopenharmony_ci * Handle mapped IPv4 packets arriving 41658c2ecf20Sopenharmony_ci * via IPv6 sockets. Don't set up netlabel 41668c2ecf20Sopenharmony_ci * processing on IPv6. 41678c2ecf20Sopenharmony_ci */ 41688c2ecf20Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) 41698c2ecf20Sopenharmony_ci family = PF_INET; 41708c2ecf20Sopenharmony_ci else 41718c2ecf20Sopenharmony_ci return 0; 41728c2ecf20Sopenharmony_ci } 41738c2ecf20Sopenharmony_ci#endif /* CONFIG_IPV6 */ 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci /* 41768c2ecf20Sopenharmony_ci * If there is a secmark use it rather than the CIPSO label. 41778c2ecf20Sopenharmony_ci * If there is no secmark fall back to CIPSO. 41788c2ecf20Sopenharmony_ci * The secmark is assumed to reflect policy better. 41798c2ecf20Sopenharmony_ci */ 41808c2ecf20Sopenharmony_ci skp = smack_from_skb(skb); 41818c2ecf20Sopenharmony_ci if (skp == NULL) { 41828c2ecf20Sopenharmony_ci skp = smack_from_netlbl(sk, family, skb); 41838c2ecf20Sopenharmony_ci if (skp == NULL) 41848c2ecf20Sopenharmony_ci skp = &smack_known_huh; 41858c2ecf20Sopenharmony_ci } 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 41888c2ecf20Sopenharmony_ci smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); 41898c2ecf20Sopenharmony_ci ad.a.u.net->family = family; 41908c2ecf20Sopenharmony_ci ad.a.u.net->netif = skb->skb_iif; 41918c2ecf20Sopenharmony_ci ipv4_skb_to_auditdata(skb, &ad.a, NULL); 41928c2ecf20Sopenharmony_ci#endif 41938c2ecf20Sopenharmony_ci /* 41948c2ecf20Sopenharmony_ci * Receiving a packet requires that the other end be able to write 41958c2ecf20Sopenharmony_ci * here. Read access is not required. 41968c2ecf20Sopenharmony_ci */ 41978c2ecf20Sopenharmony_ci rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); 41988c2ecf20Sopenharmony_ci rc = smk_bu_note("IPv4 connect", skp, ssp->smk_in, MAY_WRITE, rc); 41998c2ecf20Sopenharmony_ci if (rc != 0) 42008c2ecf20Sopenharmony_ci return rc; 42018c2ecf20Sopenharmony_ci 42028c2ecf20Sopenharmony_ci /* 42038c2ecf20Sopenharmony_ci * Save the peer's label in the request_sock so we can later setup 42048c2ecf20Sopenharmony_ci * smk_packet in the child socket so that SO_PEERCRED can report it. 42058c2ecf20Sopenharmony_ci */ 42068c2ecf20Sopenharmony_ci req->peer_secid = skp->smk_secid; 42078c2ecf20Sopenharmony_ci 42088c2ecf20Sopenharmony_ci /* 42098c2ecf20Sopenharmony_ci * We need to decide if we want to label the incoming connection here 42108c2ecf20Sopenharmony_ci * if we do we only need to label the request_sock and the stack will 42118c2ecf20Sopenharmony_ci * propagate the wire-label to the sock when it is created. 42128c2ecf20Sopenharmony_ci */ 42138c2ecf20Sopenharmony_ci hdr = ip_hdr(skb); 42148c2ecf20Sopenharmony_ci addr.sin_addr.s_addr = hdr->saddr; 42158c2ecf20Sopenharmony_ci rcu_read_lock(); 42168c2ecf20Sopenharmony_ci hskp = smack_ipv4host_label(&addr); 42178c2ecf20Sopenharmony_ci rcu_read_unlock(); 42188c2ecf20Sopenharmony_ci 42198c2ecf20Sopenharmony_ci if (hskp == NULL) 42208c2ecf20Sopenharmony_ci rc = netlbl_req_setattr(req, &skp->smk_netlabel); 42218c2ecf20Sopenharmony_ci else 42228c2ecf20Sopenharmony_ci netlbl_req_delattr(req); 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_ci return rc; 42258c2ecf20Sopenharmony_ci} 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_ci/** 42288c2ecf20Sopenharmony_ci * smack_inet_csk_clone - Copy the connection information to the new socket 42298c2ecf20Sopenharmony_ci * @sk: the new socket 42308c2ecf20Sopenharmony_ci * @req: the connection's request_sock 42318c2ecf20Sopenharmony_ci * 42328c2ecf20Sopenharmony_ci * Transfer the connection's peer label to the newly created socket. 42338c2ecf20Sopenharmony_ci */ 42348c2ecf20Sopenharmony_cistatic void smack_inet_csk_clone(struct sock *sk, 42358c2ecf20Sopenharmony_ci const struct request_sock *req) 42368c2ecf20Sopenharmony_ci{ 42378c2ecf20Sopenharmony_ci struct socket_smack *ssp = sk->sk_security; 42388c2ecf20Sopenharmony_ci struct smack_known *skp; 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci if (req->peer_secid != 0) { 42418c2ecf20Sopenharmony_ci skp = smack_from_secid(req->peer_secid); 42428c2ecf20Sopenharmony_ci ssp->smk_packet = skp; 42438c2ecf20Sopenharmony_ci } else 42448c2ecf20Sopenharmony_ci ssp->smk_packet = NULL; 42458c2ecf20Sopenharmony_ci} 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci/* 42488c2ecf20Sopenharmony_ci * Key management security hooks 42498c2ecf20Sopenharmony_ci * 42508c2ecf20Sopenharmony_ci * Casey has not tested key support very heavily. 42518c2ecf20Sopenharmony_ci * The permission check is most likely too restrictive. 42528c2ecf20Sopenharmony_ci * If you care about keys please have a look. 42538c2ecf20Sopenharmony_ci */ 42548c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci/** 42578c2ecf20Sopenharmony_ci * smack_key_alloc - Set the key security blob 42588c2ecf20Sopenharmony_ci * @key: object 42598c2ecf20Sopenharmony_ci * @cred: the credentials to use 42608c2ecf20Sopenharmony_ci * @flags: unused 42618c2ecf20Sopenharmony_ci * 42628c2ecf20Sopenharmony_ci * No allocation required 42638c2ecf20Sopenharmony_ci * 42648c2ecf20Sopenharmony_ci * Returns 0 42658c2ecf20Sopenharmony_ci */ 42668c2ecf20Sopenharmony_cistatic int smack_key_alloc(struct key *key, const struct cred *cred, 42678c2ecf20Sopenharmony_ci unsigned long flags) 42688c2ecf20Sopenharmony_ci{ 42698c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_task(smack_cred(cred)); 42708c2ecf20Sopenharmony_ci 42718c2ecf20Sopenharmony_ci key->security = skp; 42728c2ecf20Sopenharmony_ci return 0; 42738c2ecf20Sopenharmony_ci} 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_ci/** 42768c2ecf20Sopenharmony_ci * smack_key_free - Clear the key security blob 42778c2ecf20Sopenharmony_ci * @key: the object 42788c2ecf20Sopenharmony_ci * 42798c2ecf20Sopenharmony_ci * Clear the blob pointer 42808c2ecf20Sopenharmony_ci */ 42818c2ecf20Sopenharmony_cistatic void smack_key_free(struct key *key) 42828c2ecf20Sopenharmony_ci{ 42838c2ecf20Sopenharmony_ci key->security = NULL; 42848c2ecf20Sopenharmony_ci} 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci/** 42878c2ecf20Sopenharmony_ci * smack_key_permission - Smack access on a key 42888c2ecf20Sopenharmony_ci * @key_ref: gets to the object 42898c2ecf20Sopenharmony_ci * @cred: the credentials to use 42908c2ecf20Sopenharmony_ci * @need_perm: requested key permission 42918c2ecf20Sopenharmony_ci * 42928c2ecf20Sopenharmony_ci * Return 0 if the task has read and write to the object, 42938c2ecf20Sopenharmony_ci * an error code otherwise 42948c2ecf20Sopenharmony_ci */ 42958c2ecf20Sopenharmony_cistatic int smack_key_permission(key_ref_t key_ref, 42968c2ecf20Sopenharmony_ci const struct cred *cred, 42978c2ecf20Sopenharmony_ci enum key_need_perm need_perm) 42988c2ecf20Sopenharmony_ci{ 42998c2ecf20Sopenharmony_ci struct key *keyp; 43008c2ecf20Sopenharmony_ci struct smk_audit_info ad; 43018c2ecf20Sopenharmony_ci struct smack_known *tkp = smk_of_task(smack_cred(cred)); 43028c2ecf20Sopenharmony_ci int request = 0; 43038c2ecf20Sopenharmony_ci int rc; 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci /* 43068c2ecf20Sopenharmony_ci * Validate requested permissions 43078c2ecf20Sopenharmony_ci */ 43088c2ecf20Sopenharmony_ci switch (need_perm) { 43098c2ecf20Sopenharmony_ci case KEY_NEED_READ: 43108c2ecf20Sopenharmony_ci case KEY_NEED_SEARCH: 43118c2ecf20Sopenharmony_ci case KEY_NEED_VIEW: 43128c2ecf20Sopenharmony_ci request |= MAY_READ; 43138c2ecf20Sopenharmony_ci break; 43148c2ecf20Sopenharmony_ci case KEY_NEED_WRITE: 43158c2ecf20Sopenharmony_ci case KEY_NEED_LINK: 43168c2ecf20Sopenharmony_ci case KEY_NEED_SETATTR: 43178c2ecf20Sopenharmony_ci request |= MAY_WRITE; 43188c2ecf20Sopenharmony_ci break; 43198c2ecf20Sopenharmony_ci case KEY_NEED_UNSPECIFIED: 43208c2ecf20Sopenharmony_ci case KEY_NEED_UNLINK: 43218c2ecf20Sopenharmony_ci case KEY_SYSADMIN_OVERRIDE: 43228c2ecf20Sopenharmony_ci case KEY_AUTHTOKEN_OVERRIDE: 43238c2ecf20Sopenharmony_ci case KEY_DEFER_PERM_CHECK: 43248c2ecf20Sopenharmony_ci return 0; 43258c2ecf20Sopenharmony_ci default: 43268c2ecf20Sopenharmony_ci return -EINVAL; 43278c2ecf20Sopenharmony_ci } 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci keyp = key_ref_to_ptr(key_ref); 43308c2ecf20Sopenharmony_ci if (keyp == NULL) 43318c2ecf20Sopenharmony_ci return -EINVAL; 43328c2ecf20Sopenharmony_ci /* 43338c2ecf20Sopenharmony_ci * If the key hasn't been initialized give it access so that 43348c2ecf20Sopenharmony_ci * it may do so. 43358c2ecf20Sopenharmony_ci */ 43368c2ecf20Sopenharmony_ci if (keyp->security == NULL) 43378c2ecf20Sopenharmony_ci return 0; 43388c2ecf20Sopenharmony_ci /* 43398c2ecf20Sopenharmony_ci * This should not occur 43408c2ecf20Sopenharmony_ci */ 43418c2ecf20Sopenharmony_ci if (tkp == NULL) 43428c2ecf20Sopenharmony_ci return -EACCES; 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci if (smack_privileged(CAP_MAC_OVERRIDE)) 43458c2ecf20Sopenharmony_ci return 0; 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 43488c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); 43498c2ecf20Sopenharmony_ci ad.a.u.key_struct.key = keyp->serial; 43508c2ecf20Sopenharmony_ci ad.a.u.key_struct.key_desc = keyp->description; 43518c2ecf20Sopenharmony_ci#endif 43528c2ecf20Sopenharmony_ci rc = smk_access(tkp, keyp->security, request, &ad); 43538c2ecf20Sopenharmony_ci rc = smk_bu_note("key access", tkp, keyp->security, request, rc); 43548c2ecf20Sopenharmony_ci return rc; 43558c2ecf20Sopenharmony_ci} 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci/* 43588c2ecf20Sopenharmony_ci * smack_key_getsecurity - Smack label tagging the key 43598c2ecf20Sopenharmony_ci * @key points to the key to be queried 43608c2ecf20Sopenharmony_ci * @_buffer points to a pointer that should be set to point to the 43618c2ecf20Sopenharmony_ci * resulting string (if no label or an error occurs). 43628c2ecf20Sopenharmony_ci * Return the length of the string (including terminating NUL) or -ve if 43638c2ecf20Sopenharmony_ci * an error. 43648c2ecf20Sopenharmony_ci * May also return 0 (and a NULL buffer pointer) if there is no label. 43658c2ecf20Sopenharmony_ci */ 43668c2ecf20Sopenharmony_cistatic int smack_key_getsecurity(struct key *key, char **_buffer) 43678c2ecf20Sopenharmony_ci{ 43688c2ecf20Sopenharmony_ci struct smack_known *skp = key->security; 43698c2ecf20Sopenharmony_ci size_t length; 43708c2ecf20Sopenharmony_ci char *copy; 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_ci if (key->security == NULL) { 43738c2ecf20Sopenharmony_ci *_buffer = NULL; 43748c2ecf20Sopenharmony_ci return 0; 43758c2ecf20Sopenharmony_ci } 43768c2ecf20Sopenharmony_ci 43778c2ecf20Sopenharmony_ci copy = kstrdup(skp->smk_known, GFP_KERNEL); 43788c2ecf20Sopenharmony_ci if (copy == NULL) 43798c2ecf20Sopenharmony_ci return -ENOMEM; 43808c2ecf20Sopenharmony_ci length = strlen(copy) + 1; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci *_buffer = copy; 43838c2ecf20Sopenharmony_ci return length; 43848c2ecf20Sopenharmony_ci} 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci 43878c2ecf20Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS 43888c2ecf20Sopenharmony_ci/** 43898c2ecf20Sopenharmony_ci * smack_watch_key - Smack access to watch a key for notifications. 43908c2ecf20Sopenharmony_ci * @key: The key to be watched 43918c2ecf20Sopenharmony_ci * 43928c2ecf20Sopenharmony_ci * Return 0 if the @watch->cred has permission to read from the key object and 43938c2ecf20Sopenharmony_ci * an error otherwise. 43948c2ecf20Sopenharmony_ci */ 43958c2ecf20Sopenharmony_cistatic int smack_watch_key(struct key *key) 43968c2ecf20Sopenharmony_ci{ 43978c2ecf20Sopenharmony_ci struct smk_audit_info ad; 43988c2ecf20Sopenharmony_ci struct smack_known *tkp = smk_of_current(); 43998c2ecf20Sopenharmony_ci int rc; 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci if (key == NULL) 44028c2ecf20Sopenharmony_ci return -EINVAL; 44038c2ecf20Sopenharmony_ci /* 44048c2ecf20Sopenharmony_ci * If the key hasn't been initialized give it access so that 44058c2ecf20Sopenharmony_ci * it may do so. 44068c2ecf20Sopenharmony_ci */ 44078c2ecf20Sopenharmony_ci if (key->security == NULL) 44088c2ecf20Sopenharmony_ci return 0; 44098c2ecf20Sopenharmony_ci /* 44108c2ecf20Sopenharmony_ci * This should not occur 44118c2ecf20Sopenharmony_ci */ 44128c2ecf20Sopenharmony_ci if (tkp == NULL) 44138c2ecf20Sopenharmony_ci return -EACCES; 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_ci if (smack_privileged_cred(CAP_MAC_OVERRIDE, current_cred())) 44168c2ecf20Sopenharmony_ci return 0; 44178c2ecf20Sopenharmony_ci 44188c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 44198c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_KEY); 44208c2ecf20Sopenharmony_ci ad.a.u.key_struct.key = key->serial; 44218c2ecf20Sopenharmony_ci ad.a.u.key_struct.key_desc = key->description; 44228c2ecf20Sopenharmony_ci#endif 44238c2ecf20Sopenharmony_ci rc = smk_access(tkp, key->security, MAY_READ, &ad); 44248c2ecf20Sopenharmony_ci rc = smk_bu_note("key watch", tkp, key->security, MAY_READ, rc); 44258c2ecf20Sopenharmony_ci return rc; 44268c2ecf20Sopenharmony_ci} 44278c2ecf20Sopenharmony_ci#endif /* CONFIG_KEY_NOTIFICATIONS */ 44288c2ecf20Sopenharmony_ci#endif /* CONFIG_KEYS */ 44298c2ecf20Sopenharmony_ci 44308c2ecf20Sopenharmony_ci#ifdef CONFIG_WATCH_QUEUE 44318c2ecf20Sopenharmony_ci/** 44328c2ecf20Sopenharmony_ci * smack_post_notification - Smack access to post a notification to a queue 44338c2ecf20Sopenharmony_ci * @w_cred: The credentials of the watcher. 44348c2ecf20Sopenharmony_ci * @cred: The credentials of the event source (may be NULL). 44358c2ecf20Sopenharmony_ci * @n: The notification message to be posted. 44368c2ecf20Sopenharmony_ci */ 44378c2ecf20Sopenharmony_cistatic int smack_post_notification(const struct cred *w_cred, 44388c2ecf20Sopenharmony_ci const struct cred *cred, 44398c2ecf20Sopenharmony_ci struct watch_notification *n) 44408c2ecf20Sopenharmony_ci{ 44418c2ecf20Sopenharmony_ci struct smk_audit_info ad; 44428c2ecf20Sopenharmony_ci struct smack_known *subj, *obj; 44438c2ecf20Sopenharmony_ci int rc; 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci /* Always let maintenance notifications through. */ 44468c2ecf20Sopenharmony_ci if (n->type == WATCH_TYPE_META) 44478c2ecf20Sopenharmony_ci return 0; 44488c2ecf20Sopenharmony_ci 44498c2ecf20Sopenharmony_ci if (!cred) 44508c2ecf20Sopenharmony_ci return 0; 44518c2ecf20Sopenharmony_ci subj = smk_of_task(smack_cred(cred)); 44528c2ecf20Sopenharmony_ci obj = smk_of_task(smack_cred(w_cred)); 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_NOTIFICATION); 44558c2ecf20Sopenharmony_ci rc = smk_access(subj, obj, MAY_WRITE, &ad); 44568c2ecf20Sopenharmony_ci rc = smk_bu_note("notification", subj, obj, MAY_WRITE, rc); 44578c2ecf20Sopenharmony_ci return rc; 44588c2ecf20Sopenharmony_ci} 44598c2ecf20Sopenharmony_ci#endif /* CONFIG_WATCH_QUEUE */ 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci/* 44628c2ecf20Sopenharmony_ci * Smack Audit hooks 44638c2ecf20Sopenharmony_ci * 44648c2ecf20Sopenharmony_ci * Audit requires a unique representation of each Smack specific 44658c2ecf20Sopenharmony_ci * rule. This unique representation is used to distinguish the 44668c2ecf20Sopenharmony_ci * object to be audited from remaining kernel objects and also 44678c2ecf20Sopenharmony_ci * works as a glue between the audit hooks. 44688c2ecf20Sopenharmony_ci * 44698c2ecf20Sopenharmony_ci * Since repository entries are added but never deleted, we'll use 44708c2ecf20Sopenharmony_ci * the smack_known label address related to the given audit rule as 44718c2ecf20Sopenharmony_ci * the needed unique representation. This also better fits the smack 44728c2ecf20Sopenharmony_ci * model where nearly everything is a label. 44738c2ecf20Sopenharmony_ci */ 44748c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 44758c2ecf20Sopenharmony_ci 44768c2ecf20Sopenharmony_ci/** 44778c2ecf20Sopenharmony_ci * smack_audit_rule_init - Initialize a smack audit rule 44788c2ecf20Sopenharmony_ci * @field: audit rule fields given from user-space (audit.h) 44798c2ecf20Sopenharmony_ci * @op: required testing operator (=, !=, >, <, ...) 44808c2ecf20Sopenharmony_ci * @rulestr: smack label to be audited 44818c2ecf20Sopenharmony_ci * @vrule: pointer to save our own audit rule representation 44828c2ecf20Sopenharmony_ci * 44838c2ecf20Sopenharmony_ci * Prepare to audit cases where (@field @op @rulestr) is true. 44848c2ecf20Sopenharmony_ci * The label to be audited is created if necessay. 44858c2ecf20Sopenharmony_ci */ 44868c2ecf20Sopenharmony_cistatic int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 44878c2ecf20Sopenharmony_ci{ 44888c2ecf20Sopenharmony_ci struct smack_known *skp; 44898c2ecf20Sopenharmony_ci char **rule = (char **)vrule; 44908c2ecf20Sopenharmony_ci *rule = NULL; 44918c2ecf20Sopenharmony_ci 44928c2ecf20Sopenharmony_ci if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) 44938c2ecf20Sopenharmony_ci return -EINVAL; 44948c2ecf20Sopenharmony_ci 44958c2ecf20Sopenharmony_ci if (op != Audit_equal && op != Audit_not_equal) 44968c2ecf20Sopenharmony_ci return -EINVAL; 44978c2ecf20Sopenharmony_ci 44988c2ecf20Sopenharmony_ci skp = smk_import_entry(rulestr, 0); 44998c2ecf20Sopenharmony_ci if (IS_ERR(skp)) 45008c2ecf20Sopenharmony_ci return PTR_ERR(skp); 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci *rule = skp->smk_known; 45038c2ecf20Sopenharmony_ci 45048c2ecf20Sopenharmony_ci return 0; 45058c2ecf20Sopenharmony_ci} 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci/** 45088c2ecf20Sopenharmony_ci * smack_audit_rule_known - Distinguish Smack audit rules 45098c2ecf20Sopenharmony_ci * @krule: rule of interest, in Audit kernel representation format 45108c2ecf20Sopenharmony_ci * 45118c2ecf20Sopenharmony_ci * This is used to filter Smack rules from remaining Audit ones. 45128c2ecf20Sopenharmony_ci * If it's proved that this rule belongs to us, the 45138c2ecf20Sopenharmony_ci * audit_rule_match hook will be called to do the final judgement. 45148c2ecf20Sopenharmony_ci */ 45158c2ecf20Sopenharmony_cistatic int smack_audit_rule_known(struct audit_krule *krule) 45168c2ecf20Sopenharmony_ci{ 45178c2ecf20Sopenharmony_ci struct audit_field *f; 45188c2ecf20Sopenharmony_ci int i; 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci for (i = 0; i < krule->field_count; i++) { 45218c2ecf20Sopenharmony_ci f = &krule->fields[i]; 45228c2ecf20Sopenharmony_ci 45238c2ecf20Sopenharmony_ci if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER) 45248c2ecf20Sopenharmony_ci return 1; 45258c2ecf20Sopenharmony_ci } 45268c2ecf20Sopenharmony_ci 45278c2ecf20Sopenharmony_ci return 0; 45288c2ecf20Sopenharmony_ci} 45298c2ecf20Sopenharmony_ci 45308c2ecf20Sopenharmony_ci/** 45318c2ecf20Sopenharmony_ci * smack_audit_rule_match - Audit given object ? 45328c2ecf20Sopenharmony_ci * @secid: security id for identifying the object to test 45338c2ecf20Sopenharmony_ci * @field: audit rule flags given from user-space 45348c2ecf20Sopenharmony_ci * @op: required testing operator 45358c2ecf20Sopenharmony_ci * @vrule: smack internal rule presentation 45368c2ecf20Sopenharmony_ci * 45378c2ecf20Sopenharmony_ci * The core Audit hook. It's used to take the decision of 45388c2ecf20Sopenharmony_ci * whether to audit or not to audit a given object. 45398c2ecf20Sopenharmony_ci */ 45408c2ecf20Sopenharmony_cistatic int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule) 45418c2ecf20Sopenharmony_ci{ 45428c2ecf20Sopenharmony_ci struct smack_known *skp; 45438c2ecf20Sopenharmony_ci char *rule = vrule; 45448c2ecf20Sopenharmony_ci 45458c2ecf20Sopenharmony_ci if (unlikely(!rule)) { 45468c2ecf20Sopenharmony_ci WARN_ONCE(1, "Smack: missing rule\n"); 45478c2ecf20Sopenharmony_ci return -ENOENT; 45488c2ecf20Sopenharmony_ci } 45498c2ecf20Sopenharmony_ci 45508c2ecf20Sopenharmony_ci if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER) 45518c2ecf20Sopenharmony_ci return 0; 45528c2ecf20Sopenharmony_ci 45538c2ecf20Sopenharmony_ci skp = smack_from_secid(secid); 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci /* 45568c2ecf20Sopenharmony_ci * No need to do string comparisons. If a match occurs, 45578c2ecf20Sopenharmony_ci * both pointers will point to the same smack_known 45588c2ecf20Sopenharmony_ci * label. 45598c2ecf20Sopenharmony_ci */ 45608c2ecf20Sopenharmony_ci if (op == Audit_equal) 45618c2ecf20Sopenharmony_ci return (rule == skp->smk_known); 45628c2ecf20Sopenharmony_ci if (op == Audit_not_equal) 45638c2ecf20Sopenharmony_ci return (rule != skp->smk_known); 45648c2ecf20Sopenharmony_ci 45658c2ecf20Sopenharmony_ci return 0; 45668c2ecf20Sopenharmony_ci} 45678c2ecf20Sopenharmony_ci 45688c2ecf20Sopenharmony_ci/* 45698c2ecf20Sopenharmony_ci * There is no need for a smack_audit_rule_free hook. 45708c2ecf20Sopenharmony_ci * No memory was allocated. 45718c2ecf20Sopenharmony_ci */ 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci#endif /* CONFIG_AUDIT */ 45748c2ecf20Sopenharmony_ci 45758c2ecf20Sopenharmony_ci/** 45768c2ecf20Sopenharmony_ci * smack_ismaclabel - check if xattr @name references a smack MAC label 45778c2ecf20Sopenharmony_ci * @name: Full xattr name to check. 45788c2ecf20Sopenharmony_ci */ 45798c2ecf20Sopenharmony_cistatic int smack_ismaclabel(const char *name) 45808c2ecf20Sopenharmony_ci{ 45818c2ecf20Sopenharmony_ci return (strcmp(name, XATTR_SMACK_SUFFIX) == 0); 45828c2ecf20Sopenharmony_ci} 45838c2ecf20Sopenharmony_ci 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci/** 45868c2ecf20Sopenharmony_ci * smack_secid_to_secctx - return the smack label for a secid 45878c2ecf20Sopenharmony_ci * @secid: incoming integer 45888c2ecf20Sopenharmony_ci * @secdata: destination 45898c2ecf20Sopenharmony_ci * @seclen: how long it is 45908c2ecf20Sopenharmony_ci * 45918c2ecf20Sopenharmony_ci * Exists for networking code. 45928c2ecf20Sopenharmony_ci */ 45938c2ecf20Sopenharmony_cistatic int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 45948c2ecf20Sopenharmony_ci{ 45958c2ecf20Sopenharmony_ci struct smack_known *skp = smack_from_secid(secid); 45968c2ecf20Sopenharmony_ci 45978c2ecf20Sopenharmony_ci if (secdata) 45988c2ecf20Sopenharmony_ci *secdata = skp->smk_known; 45998c2ecf20Sopenharmony_ci *seclen = strlen(skp->smk_known); 46008c2ecf20Sopenharmony_ci return 0; 46018c2ecf20Sopenharmony_ci} 46028c2ecf20Sopenharmony_ci 46038c2ecf20Sopenharmony_ci/** 46048c2ecf20Sopenharmony_ci * smack_secctx_to_secid - return the secid for a smack label 46058c2ecf20Sopenharmony_ci * @secdata: smack label 46068c2ecf20Sopenharmony_ci * @seclen: how long result is 46078c2ecf20Sopenharmony_ci * @secid: outgoing integer 46088c2ecf20Sopenharmony_ci * 46098c2ecf20Sopenharmony_ci * Exists for audit and networking code. 46108c2ecf20Sopenharmony_ci */ 46118c2ecf20Sopenharmony_cistatic int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) 46128c2ecf20Sopenharmony_ci{ 46138c2ecf20Sopenharmony_ci struct smack_known *skp = smk_find_entry(secdata); 46148c2ecf20Sopenharmony_ci 46158c2ecf20Sopenharmony_ci if (skp) 46168c2ecf20Sopenharmony_ci *secid = skp->smk_secid; 46178c2ecf20Sopenharmony_ci else 46188c2ecf20Sopenharmony_ci *secid = 0; 46198c2ecf20Sopenharmony_ci return 0; 46208c2ecf20Sopenharmony_ci} 46218c2ecf20Sopenharmony_ci 46228c2ecf20Sopenharmony_ci/* 46238c2ecf20Sopenharmony_ci * There used to be a smack_release_secctx hook 46248c2ecf20Sopenharmony_ci * that did nothing back when hooks were in a vector. 46258c2ecf20Sopenharmony_ci * Now that there's a list such a hook adds cost. 46268c2ecf20Sopenharmony_ci */ 46278c2ecf20Sopenharmony_ci 46288c2ecf20Sopenharmony_cistatic int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) 46298c2ecf20Sopenharmony_ci{ 46308c2ecf20Sopenharmony_ci return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0); 46318c2ecf20Sopenharmony_ci} 46328c2ecf20Sopenharmony_ci 46338c2ecf20Sopenharmony_cistatic int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) 46348c2ecf20Sopenharmony_ci{ 46358c2ecf20Sopenharmony_ci return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0); 46368c2ecf20Sopenharmony_ci} 46378c2ecf20Sopenharmony_ci 46388c2ecf20Sopenharmony_cistatic int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) 46398c2ecf20Sopenharmony_ci{ 46408c2ecf20Sopenharmony_ci struct smack_known *skp = smk_of_inode(inode); 46418c2ecf20Sopenharmony_ci 46428c2ecf20Sopenharmony_ci *ctx = skp->smk_known; 46438c2ecf20Sopenharmony_ci *ctxlen = strlen(skp->smk_known); 46448c2ecf20Sopenharmony_ci return 0; 46458c2ecf20Sopenharmony_ci} 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_cistatic int smack_inode_copy_up(struct dentry *dentry, struct cred **new) 46488c2ecf20Sopenharmony_ci{ 46498c2ecf20Sopenharmony_ci 46508c2ecf20Sopenharmony_ci struct task_smack *tsp; 46518c2ecf20Sopenharmony_ci struct smack_known *skp; 46528c2ecf20Sopenharmony_ci struct inode_smack *isp; 46538c2ecf20Sopenharmony_ci struct cred *new_creds = *new; 46548c2ecf20Sopenharmony_ci 46558c2ecf20Sopenharmony_ci if (new_creds == NULL) { 46568c2ecf20Sopenharmony_ci new_creds = prepare_creds(); 46578c2ecf20Sopenharmony_ci if (new_creds == NULL) 46588c2ecf20Sopenharmony_ci return -ENOMEM; 46598c2ecf20Sopenharmony_ci } 46608c2ecf20Sopenharmony_ci 46618c2ecf20Sopenharmony_ci tsp = smack_cred(new_creds); 46628c2ecf20Sopenharmony_ci 46638c2ecf20Sopenharmony_ci /* 46648c2ecf20Sopenharmony_ci * Get label from overlay inode and set it in create_sid 46658c2ecf20Sopenharmony_ci */ 46668c2ecf20Sopenharmony_ci isp = smack_inode(d_inode(dentry)); 46678c2ecf20Sopenharmony_ci skp = isp->smk_inode; 46688c2ecf20Sopenharmony_ci tsp->smk_task = skp; 46698c2ecf20Sopenharmony_ci *new = new_creds; 46708c2ecf20Sopenharmony_ci return 0; 46718c2ecf20Sopenharmony_ci} 46728c2ecf20Sopenharmony_ci 46738c2ecf20Sopenharmony_cistatic int smack_inode_copy_up_xattr(const char *name) 46748c2ecf20Sopenharmony_ci{ 46758c2ecf20Sopenharmony_ci /* 46768c2ecf20Sopenharmony_ci * Return 1 if this is the smack access Smack attribute. 46778c2ecf20Sopenharmony_ci */ 46788c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SMACK) == 0) 46798c2ecf20Sopenharmony_ci return 1; 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 46828c2ecf20Sopenharmony_ci} 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_cistatic int smack_dentry_create_files_as(struct dentry *dentry, int mode, 46858c2ecf20Sopenharmony_ci struct qstr *name, 46868c2ecf20Sopenharmony_ci const struct cred *old, 46878c2ecf20Sopenharmony_ci struct cred *new) 46888c2ecf20Sopenharmony_ci{ 46898c2ecf20Sopenharmony_ci struct task_smack *otsp = smack_cred(old); 46908c2ecf20Sopenharmony_ci struct task_smack *ntsp = smack_cred(new); 46918c2ecf20Sopenharmony_ci struct inode_smack *isp; 46928c2ecf20Sopenharmony_ci int may; 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci /* 46958c2ecf20Sopenharmony_ci * Use the process credential unless all of 46968c2ecf20Sopenharmony_ci * the transmuting criteria are met 46978c2ecf20Sopenharmony_ci */ 46988c2ecf20Sopenharmony_ci ntsp->smk_task = otsp->smk_task; 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci /* 47018c2ecf20Sopenharmony_ci * the attribute of the containing directory 47028c2ecf20Sopenharmony_ci */ 47038c2ecf20Sopenharmony_ci isp = smack_inode(d_inode(dentry->d_parent)); 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_ci if (isp->smk_flags & SMK_INODE_TRANSMUTE) { 47068c2ecf20Sopenharmony_ci rcu_read_lock(); 47078c2ecf20Sopenharmony_ci may = smk_access_entry(otsp->smk_task->smk_known, 47088c2ecf20Sopenharmony_ci isp->smk_inode->smk_known, 47098c2ecf20Sopenharmony_ci &otsp->smk_task->smk_rules); 47108c2ecf20Sopenharmony_ci rcu_read_unlock(); 47118c2ecf20Sopenharmony_ci 47128c2ecf20Sopenharmony_ci /* 47138c2ecf20Sopenharmony_ci * If the directory is transmuting and the rule 47148c2ecf20Sopenharmony_ci * providing access is transmuting use the containing 47158c2ecf20Sopenharmony_ci * directory label instead of the process label. 47168c2ecf20Sopenharmony_ci */ 47178c2ecf20Sopenharmony_ci if (may > 0 && (may & MAY_TRANSMUTE)) { 47188c2ecf20Sopenharmony_ci ntsp->smk_task = isp->smk_inode; 47198c2ecf20Sopenharmony_ci ntsp->smk_transmuted = ntsp->smk_task; 47208c2ecf20Sopenharmony_ci } 47218c2ecf20Sopenharmony_ci } 47228c2ecf20Sopenharmony_ci return 0; 47238c2ecf20Sopenharmony_ci} 47248c2ecf20Sopenharmony_ci 47258c2ecf20Sopenharmony_cistruct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { 47268c2ecf20Sopenharmony_ci .lbs_cred = sizeof(struct task_smack), 47278c2ecf20Sopenharmony_ci .lbs_file = sizeof(struct smack_known *), 47288c2ecf20Sopenharmony_ci .lbs_inode = sizeof(struct inode_smack), 47298c2ecf20Sopenharmony_ci .lbs_ipc = sizeof(struct smack_known *), 47308c2ecf20Sopenharmony_ci .lbs_msg_msg = sizeof(struct smack_known *), 47318c2ecf20Sopenharmony_ci}; 47328c2ecf20Sopenharmony_ci 47338c2ecf20Sopenharmony_cistatic struct security_hook_list smack_hooks[] __lsm_ro_after_init = { 47348c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), 47358c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), 47368c2ecf20Sopenharmony_ci LSM_HOOK_INIT(syslog, smack_syslog), 47378c2ecf20Sopenharmony_ci 47388c2ecf20Sopenharmony_ci LSM_HOOK_INIT(fs_context_dup, smack_fs_context_dup), 47398c2ecf20Sopenharmony_ci LSM_HOOK_INIT(fs_context_parse_param, smack_fs_context_parse_param), 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_alloc_security, smack_sb_alloc_security), 47428c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_free_security, smack_sb_free_security), 47438c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_free_mnt_opts, smack_free_mnt_opts), 47448c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_eat_lsm_opts, smack_sb_eat_lsm_opts), 47458c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), 47468c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), 47478c2ecf20Sopenharmony_ci 47488c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bprm_creds_for_exec, smack_bprm_creds_for_exec), 47498c2ecf20Sopenharmony_ci 47508c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security), 47518c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_init_security, smack_inode_init_security), 47528c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_link, smack_inode_link), 47538c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_unlink, smack_inode_unlink), 47548c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_rmdir, smack_inode_rmdir), 47558c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_rename, smack_inode_rename), 47568c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_permission, smack_inode_permission), 47578c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setattr, smack_inode_setattr), 47588c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getattr, smack_inode_getattr), 47598c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setxattr, smack_inode_setxattr), 47608c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_post_setxattr, smack_inode_post_setxattr), 47618c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getxattr, smack_inode_getxattr), 47628c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_removexattr, smack_inode_removexattr), 47638c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getsecurity, smack_inode_getsecurity), 47648c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setsecurity, smack_inode_setsecurity), 47658c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_listsecurity, smack_inode_listsecurity), 47668c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid), 47678c2ecf20Sopenharmony_ci 47688c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security), 47698c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_ioctl, smack_file_ioctl), 47708c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_ioctl_compat, smack_file_ioctl), 47718c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_lock, smack_file_lock), 47728c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_fcntl, smack_file_fcntl), 47738c2ecf20Sopenharmony_ci LSM_HOOK_INIT(mmap_file, smack_mmap_file), 47748c2ecf20Sopenharmony_ci LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), 47758c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_set_fowner, smack_file_set_fowner), 47768c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_send_sigiotask, smack_file_send_sigiotask), 47778c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_receive, smack_file_receive), 47788c2ecf20Sopenharmony_ci 47798c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_open, smack_file_open), 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_alloc_blank, smack_cred_alloc_blank), 47828c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_free, smack_cred_free), 47838c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_prepare, smack_cred_prepare), 47848c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_transfer, smack_cred_transfer), 47858c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_getsecid, smack_cred_getsecid), 47868c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_act_as, smack_kernel_act_as), 47878c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_create_files_as, smack_kernel_create_files_as), 47888c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setpgid, smack_task_setpgid), 47898c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getpgid, smack_task_getpgid), 47908c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getsid, smack_task_getsid), 47918c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getsecid, smack_task_getsecid), 47928c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setnice, smack_task_setnice), 47938c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setioprio, smack_task_setioprio), 47948c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getioprio, smack_task_getioprio), 47958c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setscheduler, smack_task_setscheduler), 47968c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getscheduler, smack_task_getscheduler), 47978c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_movememory, smack_task_movememory), 47988c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_kill, smack_task_kill), 47998c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_to_inode, smack_task_to_inode), 48008c2ecf20Sopenharmony_ci 48018c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ipc_permission, smack_ipc_permission), 48028c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid), 48038c2ecf20Sopenharmony_ci 48048c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security), 48058c2ecf20Sopenharmony_ci 48068c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security), 48078c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate), 48088c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl), 48098c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd), 48108c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv), 48118c2ecf20Sopenharmony_ci 48128c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security), 48138c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_associate, smack_shm_associate), 48148c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl), 48158c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_shmat, smack_shm_shmat), 48168c2ecf20Sopenharmony_ci 48178c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security), 48188c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_associate, smack_sem_associate), 48198c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_semctl, smack_sem_semctl), 48208c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_semop, smack_sem_semop), 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci LSM_HOOK_INIT(d_instantiate, smack_d_instantiate), 48238c2ecf20Sopenharmony_ci 48248c2ecf20Sopenharmony_ci LSM_HOOK_INIT(getprocattr, smack_getprocattr), 48258c2ecf20Sopenharmony_ci LSM_HOOK_INIT(setprocattr, smack_setprocattr), 48268c2ecf20Sopenharmony_ci 48278c2ecf20Sopenharmony_ci LSM_HOOK_INIT(unix_stream_connect, smack_unix_stream_connect), 48288c2ecf20Sopenharmony_ci LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), 48298c2ecf20Sopenharmony_ci 48308c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), 48318c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_socketpair, smack_socket_socketpair), 48328c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 48338c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_bind, smack_socket_bind), 48348c2ecf20Sopenharmony_ci#endif 48358c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_connect, smack_socket_connect), 48368c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg), 48378c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb), 48388c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream), 48398c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram), 48408c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security), 48418c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sk_free_security, smack_sk_free_security), 48428c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sock_graft, smack_sock_graft), 48438c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request), 48448c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inet_csk_clone, smack_inet_csk_clone), 48458c2ecf20Sopenharmony_ci 48468c2ecf20Sopenharmony_ci /* key management security hooks */ 48478c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 48488c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_alloc, smack_key_alloc), 48498c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_free, smack_key_free), 48508c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_permission, smack_key_permission), 48518c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_getsecurity, smack_key_getsecurity), 48528c2ecf20Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS 48538c2ecf20Sopenharmony_ci LSM_HOOK_INIT(watch_key, smack_watch_key), 48548c2ecf20Sopenharmony_ci#endif 48558c2ecf20Sopenharmony_ci#endif /* CONFIG_KEYS */ 48568c2ecf20Sopenharmony_ci 48578c2ecf20Sopenharmony_ci#ifdef CONFIG_WATCH_QUEUE 48588c2ecf20Sopenharmony_ci LSM_HOOK_INIT(post_notification, smack_post_notification), 48598c2ecf20Sopenharmony_ci#endif 48608c2ecf20Sopenharmony_ci 48618c2ecf20Sopenharmony_ci /* Audit hooks */ 48628c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 48638c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_init, smack_audit_rule_init), 48648c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_known, smack_audit_rule_known), 48658c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_match, smack_audit_rule_match), 48668c2ecf20Sopenharmony_ci#endif /* CONFIG_AUDIT */ 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ismaclabel, smack_ismaclabel), 48698c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secid_to_secctx, smack_secid_to_secctx), 48708c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secctx_to_secid, smack_secctx_to_secid), 48718c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx), 48728c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx), 48738c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx), 48748c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_copy_up, smack_inode_copy_up), 48758c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_copy_up_xattr, smack_inode_copy_up_xattr), 48768c2ecf20Sopenharmony_ci LSM_HOOK_INIT(dentry_create_files_as, smack_dentry_create_files_as), 48778c2ecf20Sopenharmony_ci}; 48788c2ecf20Sopenharmony_ci 48798c2ecf20Sopenharmony_ci 48808c2ecf20Sopenharmony_cistatic __init void init_smack_known_list(void) 48818c2ecf20Sopenharmony_ci{ 48828c2ecf20Sopenharmony_ci /* 48838c2ecf20Sopenharmony_ci * Initialize rule list locks 48848c2ecf20Sopenharmony_ci */ 48858c2ecf20Sopenharmony_ci mutex_init(&smack_known_huh.smk_rules_lock); 48868c2ecf20Sopenharmony_ci mutex_init(&smack_known_hat.smk_rules_lock); 48878c2ecf20Sopenharmony_ci mutex_init(&smack_known_floor.smk_rules_lock); 48888c2ecf20Sopenharmony_ci mutex_init(&smack_known_star.smk_rules_lock); 48898c2ecf20Sopenharmony_ci mutex_init(&smack_known_web.smk_rules_lock); 48908c2ecf20Sopenharmony_ci /* 48918c2ecf20Sopenharmony_ci * Initialize rule lists 48928c2ecf20Sopenharmony_ci */ 48938c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&smack_known_huh.smk_rules); 48948c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&smack_known_hat.smk_rules); 48958c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&smack_known_star.smk_rules); 48968c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&smack_known_floor.smk_rules); 48978c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&smack_known_web.smk_rules); 48988c2ecf20Sopenharmony_ci /* 48998c2ecf20Sopenharmony_ci * Create the known labels list 49008c2ecf20Sopenharmony_ci */ 49018c2ecf20Sopenharmony_ci smk_insert_entry(&smack_known_huh); 49028c2ecf20Sopenharmony_ci smk_insert_entry(&smack_known_hat); 49038c2ecf20Sopenharmony_ci smk_insert_entry(&smack_known_star); 49048c2ecf20Sopenharmony_ci smk_insert_entry(&smack_known_floor); 49058c2ecf20Sopenharmony_ci smk_insert_entry(&smack_known_web); 49068c2ecf20Sopenharmony_ci} 49078c2ecf20Sopenharmony_ci 49088c2ecf20Sopenharmony_ci/** 49098c2ecf20Sopenharmony_ci * smack_init - initialize the smack system 49108c2ecf20Sopenharmony_ci * 49118c2ecf20Sopenharmony_ci * Returns 0 on success, -ENOMEM is there's no memory 49128c2ecf20Sopenharmony_ci */ 49138c2ecf20Sopenharmony_cistatic __init int smack_init(void) 49148c2ecf20Sopenharmony_ci{ 49158c2ecf20Sopenharmony_ci struct cred *cred = (struct cred *) current->cred; 49168c2ecf20Sopenharmony_ci struct task_smack *tsp; 49178c2ecf20Sopenharmony_ci 49188c2ecf20Sopenharmony_ci smack_rule_cache = KMEM_CACHE(smack_rule, 0); 49198c2ecf20Sopenharmony_ci if (!smack_rule_cache) 49208c2ecf20Sopenharmony_ci return -ENOMEM; 49218c2ecf20Sopenharmony_ci 49228c2ecf20Sopenharmony_ci /* 49238c2ecf20Sopenharmony_ci * Set the security state for the initial task. 49248c2ecf20Sopenharmony_ci */ 49258c2ecf20Sopenharmony_ci tsp = smack_cred(cred); 49268c2ecf20Sopenharmony_ci init_task_smack(tsp, &smack_known_floor, &smack_known_floor); 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_ci /* 49298c2ecf20Sopenharmony_ci * Register with LSM 49308c2ecf20Sopenharmony_ci */ 49318c2ecf20Sopenharmony_ci security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); 49328c2ecf20Sopenharmony_ci smack_enabled = 1; 49338c2ecf20Sopenharmony_ci 49348c2ecf20Sopenharmony_ci pr_info("Smack: Initializing.\n"); 49358c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SMACK_NETFILTER 49368c2ecf20Sopenharmony_ci pr_info("Smack: Netfilter enabled.\n"); 49378c2ecf20Sopenharmony_ci#endif 49388c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_PORT_LABELING 49398c2ecf20Sopenharmony_ci pr_info("Smack: IPv6 port labeling enabled.\n"); 49408c2ecf20Sopenharmony_ci#endif 49418c2ecf20Sopenharmony_ci#ifdef SMACK_IPV6_SECMARK_LABELING 49428c2ecf20Sopenharmony_ci pr_info("Smack: IPv6 Netfilter enabled.\n"); 49438c2ecf20Sopenharmony_ci#endif 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci /* initialize the smack_known_list */ 49468c2ecf20Sopenharmony_ci init_smack_known_list(); 49478c2ecf20Sopenharmony_ci 49488c2ecf20Sopenharmony_ci return 0; 49498c2ecf20Sopenharmony_ci} 49508c2ecf20Sopenharmony_ci 49518c2ecf20Sopenharmony_ci/* 49528c2ecf20Sopenharmony_ci * Smack requires early initialization in order to label 49538c2ecf20Sopenharmony_ci * all processes and objects when they are created. 49548c2ecf20Sopenharmony_ci */ 49558c2ecf20Sopenharmony_ciDEFINE_LSM(smack) = { 49568c2ecf20Sopenharmony_ci .name = "smack", 49578c2ecf20Sopenharmony_ci .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 49588c2ecf20Sopenharmony_ci .blobs = &smack_blob_sizes, 49598c2ecf20Sopenharmony_ci .init = smack_init, 49608c2ecf20Sopenharmony_ci}; 4961