// SPDX-License-Identifier: GPL-2.0-only /* * Simplified MAC Kernel (smack) security module * * This file contains the smack hook function implementations. * * Authors: * Casey Schaufler <[email protected]> * Jarkko Sakkinen <[email protected]> * * Copyright (C) 2007 Casey Schaufler <[email protected]> * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. * Paul Moore <[email protected]> * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2011 Intel Corporation. */ #include <linux/xattr.h> #include <linux/pagemap.h> #include <linux/mount.h> #include <linux/stat.h> #include <linux/kd.h> #include <asm/ioctls.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/udp.h> #include <linux/dccp.h> #include <linux/icmpv6.h> #include <linux/slab.h> #include <linux/mutex.h> #include <net/cipso_ipv4.h> #include <net/ip.h> #include <net/ipv6.h> #include <linux/audit.h> #include <linux/magic.h> #include <linux/dcache.h> #include <linux/personality.h> #include <linux/msg.h> #include <linux/shm.h> #include <uapi/linux/shm.h> #include <linux/binfmts.h> #include <linux/parser.h> #include <linux/fs_context.h> #include <linux/fs_parser.h> #include <linux/watch_queue.h> #include <linux/io_uring/cmd.h> #include <uapi/linux/lsm.h> #include "smack.h" #define TRANS_TRUE … #define TRANS_TRUE_SIZE … #define SMK_CONNECTING … #define SMK_RECEIVING … #define SMK_SENDING … /* * Smack uses multiple xattrs. * SMACK64 - for access control, * SMACK64TRANSMUTE - label initialization, * Not saved on files - SMACK64IPIN and SMACK64IPOUT, * Must be set explicitly - SMACK64EXEC and SMACK64MMAP */ #define SMACK_INODE_INIT_XATTRS … #ifdef SMACK_IPV6_PORT_LABELING static DEFINE_MUTEX(smack_ipv6_lock); static LIST_HEAD(smk_ipv6_port_list); #endif struct kmem_cache *smack_rule_cache; int smack_enabled __initdata; #define A … static struct { … } smk_mount_opts[] = …; #undef A static int match_opt_prefix(char *s, int l, char **arg) { … } #ifdef CONFIG_SECURITY_SMACK_BRINGUP static char *smk_bu_mess[] = …; static void smk_bu_mode(int mode, char *s) { … } #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_note(char *note, struct smack_known *sskp, struct smack_known *oskp, int mode, int rc) { … } #else #define smk_bu_note … #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_current(char *note, struct smack_known *oskp, int mode, int rc) { … } #else #define smk_bu_current … #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_task(struct task_struct *otp, int mode, int rc) { … } #else #define smk_bu_task … #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_inode(struct inode *inode, int mode, int rc) { … } #else #define smk_bu_inode … #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_file(struct file *file, int mode, int rc) { … } #else #define smk_bu_file … #endif #ifdef CONFIG_SECURITY_SMACK_BRINGUP static int smk_bu_credfile(const struct cred *cred, struct file *file, int mode, int rc) { … } #else #define smk_bu_credfile … #endif /** * smk_fetch - Fetch the smack label from a file. * @name: type of the label (attribute) * @ip: a pointer to the inode * @dp: a pointer to the dentry * * Returns a pointer to the master list entry for the Smack label, * NULL if there was no label to fetch, or an error code. */ static struct smack_known *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) { … } /** * init_inode_smack - initialize an inode security blob * @inode: inode to extract the info from * @skp: a pointer to the Smack label entry to use in the blob * */ static void init_inode_smack(struct inode *inode, struct smack_known *skp) { … } /** * init_task_smack - initialize a task security blob * @tsp: blob to initialize * @task: a pointer to the Smack label for the running task * @forked: a pointer to the Smack label for the forked task * */ static void init_task_smack(struct task_smack *tsp, struct smack_known *task, struct smack_known *forked) { … } /** * smk_copy_rules - copy a rule set * @nhead: new rules header pointer * @ohead: old rules header pointer * @gfp: type of the memory for the allocation * * Returns 0 on success, -ENOMEM on error */ static int smk_copy_rules(struct list_head *nhead, struct list_head *ohead, gfp_t gfp) { … } /** * smk_copy_relabel - copy smk_relabel labels list * @nhead: new rules header pointer * @ohead: old rules header pointer * @gfp: type of the memory for the allocation * * Returns 0 on success, -ENOMEM on error */ static int smk_copy_relabel(struct list_head *nhead, struct list_head *ohead, gfp_t gfp) { … } /** * smk_ptrace_mode - helper function for converting PTRACE_MODE_* into MAY_* * @mode: input mode in form of PTRACE_MODE_* * * Returns a converted MAY_* mode usable by smack rules */ static inline unsigned int smk_ptrace_mode(unsigned int mode) { … } /** * smk_ptrace_rule_check - helper for ptrace access * @tracer: tracer process * @tracee_known: label entry of the process that's about to be traced * @mode: ptrace attachment mode (PTRACE_MODE_*) * @func: name of the function that called us, used for audit * * Returns 0 on access granted, -error on error */ static int smk_ptrace_rule_check(struct task_struct *tracer, struct smack_known *tracee_known, unsigned int mode, const char *func) { … } /* * LSM hooks. * We he, that is fun! */ /** * smack_ptrace_access_check - Smack approval on PTRACE_ATTACH * @ctp: child task pointer * @mode: ptrace attachment mode (PTRACE_MODE_*) * * Returns 0 if access is OK, an error code otherwise * * Do the capability checks. */ static int smack_ptrace_access_check(struct task_struct *ctp, unsigned int mode) { … } /** * smack_ptrace_traceme - Smack approval on PTRACE_TRACEME * @ptp: parent task pointer * * Returns 0 if access is OK, an error code otherwise * * Do the capability checks, and require PTRACE_MODE_ATTACH. */ static int smack_ptrace_traceme(struct task_struct *ptp) { … } /** * smack_syslog - Smack approval on syslog * @typefrom_file: unused * * Returns 0 on success, error code otherwise. */ static int smack_syslog(int typefrom_file) { … } /* * Superblock Hooks. */ /** * smack_sb_alloc_security - allocate a superblock blob * @sb: the superblock getting the blob * * Returns 0 on success or -ENOMEM on error. */ static int smack_sb_alloc_security(struct super_block *sb) { … } struct smack_mnt_opts { … }; static void smack_free_mnt_opts(void *mnt_opts) { … } static int smack_add_opt(int token, const char *s, void **mnt_opts) { … } /** * smack_fs_context_submount - Initialise security data for a filesystem context * @fc: The filesystem context. * @reference: reference superblock * * Returns 0 on success or -ENOMEM on error. */ static int smack_fs_context_submount(struct fs_context *fc, struct super_block *reference) { … } /** * smack_fs_context_dup - Duplicate the security data on fs_context duplication * @fc: The new filesystem context. * @src_fc: The source filesystem context being duplicated. * * Returns 0 on success or -ENOMEM on error. */ static int smack_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) { … } static const struct fs_parameter_spec smack_fs_parameters[] = …; /** * smack_fs_context_parse_param - Parse a single mount parameter * @fc: The new filesystem context being constructed. * @param: The parameter. * * Returns 0 on success, -ENOPARAM to pass the parameter on or anything else on * error. */ static int smack_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { … } static int smack_sb_eat_lsm_opts(char *options, void **mnt_opts) { … } /** * smack_set_mnt_opts - set Smack specific mount options * @sb: the file system superblock * @mnt_opts: Smack mount options * @kern_flags: mount option from kernel space or user space * @set_kern_flags: where to store converted mount opts * * Returns 0 on success, an error code on failure * * Allow filesystems with binary mount data to explicitly set Smack mount * labels. */ static int smack_set_mnt_opts(struct super_block *sb, void *mnt_opts, unsigned long kern_flags, unsigned long *set_kern_flags) { … } /** * smack_sb_statfs - Smack check on statfs * @dentry: identifies the file system in question * * Returns 0 if current can read the floor of the filesystem, * and error code otherwise */ static int smack_sb_statfs(struct dentry *dentry) { … } /* * BPRM hooks */ /** * smack_bprm_creds_for_exec - Update bprm->cred if needed for exec * @bprm: the exec information * * Returns 0 if it gets a blob, -EPERM if exec forbidden and -ENOMEM otherwise */ static int smack_bprm_creds_for_exec(struct linux_binprm *bprm) { … } /* * Inode hooks */ /** * smack_inode_alloc_security - allocate an inode blob * @inode: the inode in need of a blob * * Returns 0 */ static int smack_inode_alloc_security(struct inode *inode) { … } /** * smack_inode_init_security - copy out the smack from an inode * @inode: the newly created inode * @dir: containing directory object * @qstr: unused * @xattrs: where to put the attributes * @xattr_count: current number of LSM-provided xattrs (updated) * * Returns 0 if it all works out, -ENOMEM if there's no memory */ static int smack_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, struct xattr *xattrs, int *xattr_count) { … } /** * smack_inode_link - Smack check on link * @old_dentry: the existing object * @dir: unused * @new_dentry: the new object * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { … } /** * smack_inode_unlink - Smack check on inode deletion * @dir: containing directory object * @dentry: file to unlink * * Returns 0 if current can write the containing directory * and the object, error code otherwise */ static int smack_inode_unlink(struct inode *dir, struct dentry *dentry) { … } /** * smack_inode_rmdir - Smack check on directory deletion * @dir: containing directory object * @dentry: directory to unlink * * Returns 0 if current can write the containing directory * and the directory, error code otherwise */ static int smack_inode_rmdir(struct inode *dir, struct dentry *dentry) { … } /** * smack_inode_rename - Smack check on rename * @old_inode: unused * @old_dentry: the old object * @new_inode: unused * @new_dentry: the new object * * Read and write access is required on both the old and * new directories. * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry) { … } /** * smack_inode_permission - Smack version of permission() * @inode: the inode in question * @mask: the access requested * * This is the important Smack hook. * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_permission(struct inode *inode, int mask) { … } /** * smack_inode_setattr - Smack check for setting attributes * @idmap: idmap of the mount * @dentry: the object * @iattr: for the force flag * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_setattr(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *iattr) { … } /** * smack_inode_getattr - Smack check for getting attributes * @path: path to extract the info from * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_getattr(const struct path *path) { … } /** * smack_inode_xattr_skipcap - Skip the xattr capability checks? * @name: name of the xattr * * Returns 1 to indicate that Smack "owns" the access control rights to xattrs * named @name; the LSM layer should avoid enforcing any traditional * capability based access controls on this xattr. Returns 0 to indicate that * Smack does not "own" the access control rights to xattrs named @name and is * deferring to the LSM layer for further access controls, including capability * based controls. */ static int smack_inode_xattr_skipcap(const char *name) { … } /** * smack_inode_setxattr - Smack check for setting xattrs * @idmap: idmap of the mount * @dentry: the object * @name: name of the attribute * @value: value of the attribute * @size: size of the value * @flags: unused * * This protects the Smack attribute explicitly. * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_setxattr(struct mnt_idmap *idmap, struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { … } /** * smack_inode_post_setxattr - Apply the Smack update approved above * @dentry: object * @name: attribute name * @value: attribute value * @size: attribute size * @flags: unused * * Set the pointer in the inode blob to the entry found * in the master label list. */ static void smack_inode_post_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { … } /** * smack_inode_getxattr - Smack check on getxattr * @dentry: the object * @name: unused * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_getxattr(struct dentry *dentry, const char *name) { … } /** * smack_inode_removexattr - Smack check on removexattr * @idmap: idmap of the mount * @dentry: the object * @name: name of the attribute * * Removing the Smack attribute requires CAP_MAC_ADMIN * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_removexattr(struct mnt_idmap *idmap, struct dentry *dentry, const char *name) { … } /** * smack_inode_set_acl - Smack check for setting posix acls * @idmap: idmap of the mnt this request came from * @dentry: the object * @acl_name: name of the posix acl * @kacl: the posix acls * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_set_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name, struct posix_acl *kacl) { … } /** * smack_inode_get_acl - Smack check for getting posix acls * @idmap: idmap of the mnt this request came from * @dentry: the object * @acl_name: name of the posix acl * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_get_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name) { … } /** * smack_inode_remove_acl - Smack check for getting posix acls * @idmap: idmap of the mnt this request came from * @dentry: the object * @acl_name: name of the posix acl * * Returns 0 if access is permitted, an error code otherwise */ static int smack_inode_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry, const char *acl_name) { … } /** * smack_inode_getsecurity - get smack xattrs * @idmap: idmap of the mount * @inode: the object * @name: attribute name * @buffer: where to put the result * @alloc: duplicate memory * * Returns the size of the attribute or an error code */ static int smack_inode_getsecurity(struct mnt_idmap *idmap, struct inode *inode, const char *name, void **buffer, bool alloc) { … } /** * smack_inode_listsecurity - list the Smack attributes * @inode: the object * @buffer: where they go * @buffer_size: size of buffer */ static int smack_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) { … } /** * smack_inode_getsecid - Extract inode's security id * @inode: inode to extract the info from * @secid: where result will be saved */ static void smack_inode_getsecid(struct inode *inode, u32 *secid) { … } /* * File Hooks */ /* * There is no smack_file_permission hook * * Should access checks be done on each read or write? * UNICOS and SELinux say yes. * Trusted Solaris, Trusted Irix, and just about everyone else says no. * * I'll say no for now. Smack does not do the frequent * label changing that SELinux does. */ /** * smack_file_alloc_security - assign a file security blob * @file: the object * * The security blob for a file is a pointer to the master * label list, so no allocation is done. * * f_security is the owner security information. It * isn't used on file access checks, it's for send_sigio. * * Returns 0 */ static int smack_file_alloc_security(struct file *file) { … } /** * smack_file_ioctl - Smack check on ioctls * @file: the object * @cmd: what to do * @arg: unused * * Relies heavily on the correct use of the ioctl command conventions. * * Returns 0 if allowed, error code otherwise */ static int smack_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { … } /** * smack_file_lock - Smack check on file locking * @file: the object * @cmd: unused * * Returns 0 if current has lock access, error code otherwise */ static int smack_file_lock(struct file *file, unsigned int cmd) { … } /** * smack_file_fcntl - Smack check on fcntl * @file: the object * @cmd: what action to check * @arg: unused * * Generally these operations are harmless. * File locking operations present an obvious mechanism * for passing information, so they require write access. * * Returns 0 if current has access, error code otherwise */ static int smack_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg) { … } /** * smack_mmap_file - Check permissions for a mmap operation. * @file: contains the file structure for file to map (may be NULL). * @reqprot: contains the protection requested by the application. * @prot: contains the protection that will be applied by the kernel. * @flags: contains the operational flags. * * The @file may be NULL, e.g. if mapping anonymous memory. * * Return 0 if permission is granted. */ static int smack_mmap_file(struct file *file, unsigned long reqprot, unsigned long prot, unsigned long flags) { … } /** * smack_file_set_fowner - set the file security blob value * @file: object in question * */ static void smack_file_set_fowner(struct file *file) { … } /** * smack_file_send_sigiotask - Smack on sigio * @tsk: The target task * @fown: the object the signal come from * @signum: unused * * Allow a privileged task to get signals even if it shouldn't * * Returns 0 if a subject with the object's smack could * write to the task, an error code otherwise. */ static int smack_file_send_sigiotask(struct task_struct *tsk, struct fown_struct *fown, int signum) { … } /** * smack_file_receive - Smack file receive check * @file: the object * * Returns 0 if current has access, error code otherwise */ static int smack_file_receive(struct file *file) { … } /** * smack_file_open - Smack dentry open processing * @file: the object * * Set the security blob in the file structure. * Allow the open only if the task has read access. There are * many read operations (e.g. fstat) that you can do with an * fd even if you have the file open write-only. * * Returns 0 if current has access, error code otherwise */ static int smack_file_open(struct file *file) { … } /* * Task hooks */ /** * smack_cred_alloc_blank - "allocate" blank task-level security credentials * @cred: the new credentials * @gfp: the atomicity of any memory allocations * * Prepare a blank set of credentials for modification. This must allocate all * the memory the LSM module might require such that cred_transfer() can * complete without error. */ static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) { … } /** * smack_cred_free - "free" task-level security credentials * @cred: the credentials in question * */ static void smack_cred_free(struct cred *cred) { … } /** * smack_cred_prepare - prepare new set of credentials for modification * @new: the new credentials * @old: the original credentials * @gfp: the atomicity of any memory allocations * * Prepare a new set of credentials for modification. */ static int smack_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { … } /** * smack_cred_transfer - Transfer the old credentials to the new credentials * @new: the new credentials * @old: the original credentials * * Fill in a set of blank credentials from another set of credentials. */ static void smack_cred_transfer(struct cred *new, const struct cred *old) { … } /** * smack_cred_getsecid - get the secid corresponding to a creds structure * @cred: the object creds * @secid: where to put the result * * Sets the secid to contain a u32 version of the smack label. */ static void smack_cred_getsecid(const struct cred *cred, u32 *secid) { … } /** * smack_kernel_act_as - Set the subjective context in a set of credentials * @new: points to the set of credentials to be modified. * @secid: specifies the security ID to be set * * Set the security data for a kernel service. */ static int smack_kernel_act_as(struct cred *new, u32 secid) { … } /** * smack_kernel_create_files_as - Set the file creation label in a set of creds * @new: points to the set of credentials to be modified * @inode: points to the inode to use as a reference * * Set the file creation context in a set of credentials to the same * as the objective context of the specified inode */ static int smack_kernel_create_files_as(struct cred *new, struct inode *inode) { … } /** * smk_curacc_on_task - helper to log task related access * @p: the task object * @access: the access requested * @caller: name of the calling function for audit * * Return 0 if access is permitted */ static int smk_curacc_on_task(struct task_struct *p, int access, const char *caller) { … } /** * smack_task_setpgid - Smack check on setting pgid * @p: the task object * @pgid: unused * * Return 0 if write access is permitted */ static int smack_task_setpgid(struct task_struct *p, pid_t pgid) { … } /** * smack_task_getpgid - Smack access check for getpgid * @p: the object task * * Returns 0 if current can read the object task, error code otherwise */ static int smack_task_getpgid(struct task_struct *p) { … } /** * smack_task_getsid - Smack access check for getsid * @p: the object task * * Returns 0 if current can read the object task, error code otherwise */ static int smack_task_getsid(struct task_struct *p) { … } /** * smack_current_getsecid_subj - get the subjective secid of the current task * @secid: where to put the result * * Sets the secid to contain a u32 version of the task's subjective smack label. */ static void smack_current_getsecid_subj(u32 *secid) { … } /** * smack_task_getsecid_obj - get the objective secid of the task * @p: the task * @secid: where to put the result * * Sets the secid to contain a u32 version of the task's objective smack label. */ static void smack_task_getsecid_obj(struct task_struct *p, u32 *secid) { … } /** * smack_task_setnice - Smack check on setting nice * @p: the task object * @nice: unused * * Return 0 if write access is permitted */ static int smack_task_setnice(struct task_struct *p, int nice) { … } /** * smack_task_setioprio - Smack check on setting ioprio * @p: the task object * @ioprio: unused * * Return 0 if write access is permitted */ static int smack_task_setioprio(struct task_struct *p, int ioprio) { … } /** * smack_task_getioprio - Smack check on reading ioprio * @p: the task object * * Return 0 if read access is permitted */ static int smack_task_getioprio(struct task_struct *p) { … } /** * smack_task_setscheduler - Smack check on setting scheduler * @p: the task object * * Return 0 if read access is permitted */ static int smack_task_setscheduler(struct task_struct *p) { … } /** * smack_task_getscheduler - Smack check on reading scheduler * @p: the task object * * Return 0 if read access is permitted */ static int smack_task_getscheduler(struct task_struct *p) { … } /** * smack_task_movememory - Smack check on moving memory * @p: the task object * * Return 0 if write access is permitted */ static int smack_task_movememory(struct task_struct *p) { … } /** * smack_task_kill - Smack check on signal delivery * @p: the task object * @info: unused * @sig: unused * @cred: identifies the cred to use in lieu of current's * * Return 0 if write access is permitted * */ static int smack_task_kill(struct task_struct *p, struct kernel_siginfo *info, int sig, const struct cred *cred) { … } /** * smack_task_to_inode - copy task smack into the inode blob * @p: task to copy from * @inode: inode to copy to * * Sets the smack pointer in the inode security blob */ static void smack_task_to_inode(struct task_struct *p, struct inode *inode) { … } /* * Socket hooks. */ /** * smack_sk_alloc_security - Allocate a socket blob * @sk: the socket * @family: unused * @gfp_flags: memory allocation flags * * Assign Smack pointers to current * * Returns 0 on success, -ENOMEM is there's no memory */ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags) { … } /** * smack_sk_free_security - Free a socket blob * @sk: the socket * * Clears the blob pointer */ static void smack_sk_free_security(struct sock *sk) { … } /** * smack_sk_clone_security - Copy security context * @sk: the old socket * @newsk: the new socket * * Copy the security context of the old socket pointer to the cloned */ static void smack_sk_clone_security(const struct sock *sk, struct sock *newsk) { … } /** * smack_ipv4host_label - check host based restrictions * @sip: the object end * * looks for host based access restrictions * * This version will only be appropriate for really small sets of single label * hosts. The caller is responsible for ensuring that the RCU read lock is * taken before calling this function. * * Returns the label of the far end or NULL if it's not special. */ static struct smack_known *smack_ipv4host_label(struct sockaddr_in *sip) { … } /* * smk_ipv6_localhost - Check for local ipv6 host address * @sip: the address * * Returns boolean true if this is the localhost address */ static bool smk_ipv6_localhost(struct sockaddr_in6 *sip) { … } /** * smack_ipv6host_label - check host based restrictions * @sip: the object end * * looks for host based access restrictions * * This version will only be appropriate for really small sets of single label * hosts. The caller is responsible for ensuring that the RCU read lock is * taken before calling this function. * * Returns the label of the far end or NULL if it's not special. */ static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip) { … } /** * smack_netlbl_add - Set the secattr on a socket * @sk: the socket * * Attach the outbound smack value (smk_out) to the socket. * * Returns 0 on success or an error code */ static int smack_netlbl_add(struct sock *sk) { … } /** * smack_netlbl_delete - Remove the secattr from a socket * @sk: the socket * * Remove the outbound smack value from a socket */ static void smack_netlbl_delete(struct sock *sk) { … } /** * smk_ipv4_check - Perform IPv4 host access checks * @sk: the socket * @sap: the destination address * * Set the correct secattr for the given socket based on the destination * address and perform any outbound access checks needed. * * Returns 0 on success or an error code. * */ static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap) { … } /** * smk_ipv6_check - check Smack access * @subject: subject Smack label * @object: object Smack label * @address: address * @act: the action being taken * * Check an IPv6 access */ static int smk_ipv6_check(struct smack_known *subject, struct smack_known *object, struct sockaddr_in6 *address, int act) { … } #ifdef SMACK_IPV6_PORT_LABELING /** * smk_ipv6_port_label - Smack port access table management * @sock: socket * @address: address * * Create or update the port list entry */ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) { struct sock *sk = sock->sk; struct sockaddr_in6 *addr6; struct socket_smack *ssp = sock->sk->sk_security; struct smk_port_label *spp; unsigned short port = 0; if (address == NULL) { /* * This operation is changing the Smack information * on the bound socket. Take the changes to the port * as well. */ rcu_read_lock(); list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (sk != spp->smk_sock) continue; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; rcu_read_unlock(); return; } /* * A NULL address is only used for updating existing * bound entries. If there isn't one, it's OK. */ rcu_read_unlock(); return; } addr6 = (struct sockaddr_in6 *)address; port = ntohs(addr6->sin6_port); /* * This is a special case that is safely ignored. */ if (port == 0) return; /* * Look for an existing port list entry. * This is an indication that a port is getting reused. */ rcu_read_lock(); list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port || spp->smk_sock_type != sock->type) continue; if (spp->smk_can_reuse != 1) { rcu_read_unlock(); return; } spp->smk_port = port; spp->smk_sock = sk; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; spp->smk_can_reuse = 0; rcu_read_unlock(); return; } rcu_read_unlock(); /* * A new port entry is required. */ spp = kzalloc(sizeof(*spp), GFP_KERNEL); if (spp == NULL) return; spp->smk_port = port; spp->smk_sock = sk; spp->smk_in = ssp->smk_in; spp->smk_out = ssp->smk_out; spp->smk_sock_type = sock->type; spp->smk_can_reuse = 0; mutex_lock(&smack_ipv6_lock); list_add_rcu(&spp->list, &smk_ipv6_port_list); mutex_unlock(&smack_ipv6_lock); return; } /** * smk_ipv6_port_check - check Smack port access * @sk: socket * @address: address * @act: the action being taken * * Create or update the port list entry */ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, int act) { struct smk_port_label *spp; struct socket_smack *ssp = sk->sk_security; struct smack_known *skp = NULL; unsigned short port; struct smack_known *object; if (act == SMK_RECEIVING) { skp = smack_ipv6host_label(address); object = ssp->smk_in; } else { skp = ssp->smk_out; object = smack_ipv6host_label(address); } /* * The other end is a single label host. */ if (skp != NULL && object != NULL) return smk_ipv6_check(skp, object, address, act); if (skp == NULL) skp = smack_net_ambient; if (object == NULL) object = smack_net_ambient; /* * It's remote, so port lookup does no good. */ if (!smk_ipv6_localhost(address)) return smk_ipv6_check(skp, object, address, act); /* * It's local so the send check has to have passed. */ if (act == SMK_RECEIVING) return 0; port = ntohs(address->sin6_port); rcu_read_lock(); list_for_each_entry_rcu(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port || spp->smk_sock_type != sk->sk_type) continue; object = spp->smk_in; if (act == SMK_CONNECTING) ssp->smk_packet = spp->smk_out; break; } rcu_read_unlock(); return smk_ipv6_check(skp, object, address, act); } #endif /** * smack_inode_setsecurity - set smack xattrs * @inode: the object * @name: attribute name * @value: attribute value * @size: size of the attribute * @flags: unused * * Sets the named attribute in the appropriate blob * * Returns 0 on success, or an error code */ static int smack_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) { … } /** * smack_socket_post_create - finish socket setup * @sock: the socket * @family: protocol family * @type: unused * @protocol: unused * @kern: unused * * Sets the netlabel information on the socket * * Returns 0 on success, and error code otherwise */ static int smack_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { … } /** * smack_socket_socketpair - create socket pair * @socka: one socket * @sockb: another socket * * Cross reference the peer labels for SO_PEERSEC * * Returns 0 */ static int smack_socket_socketpair(struct socket *socka, struct socket *sockb) { … } #ifdef SMACK_IPV6_PORT_LABELING /** * smack_socket_bind - record port binding information. * @sock: the socket * @address: the port address * @addrlen: size of the address * * Records the label bound to a port. * * Returns 0 on success, and error code otherwise */ static int smack_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) { if (addrlen < SIN6_LEN_RFC2133 || address->sa_family != AF_INET6) return -EINVAL; smk_ipv6_port_label(sock, address); } return 0; } #endif /* SMACK_IPV6_PORT_LABELING */ /** * smack_socket_connect - connect access check * @sock: the socket * @sap: the other end * @addrlen: size of sap * * Verifies that a connection may be possible * * Returns 0 on success, and error code otherwise */ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, int addrlen) { … } /** * smack_flags_to_may - convert S_ to MAY_ values * @flags: the S_ value * * Returns the equivalent MAY_ value */ static int smack_flags_to_may(int flags) { … } /** * smack_msg_msg_alloc_security - Set the security blob for msg_msg * @msg: the object * * Returns 0 */ static int smack_msg_msg_alloc_security(struct msg_msg *msg) { … } /** * smack_of_ipc - the smack pointer for the ipc * @isp: the object * * Returns a pointer to the smack value */ static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp) { … } /** * smack_ipc_alloc_security - Set the security blob for ipc * @isp: the object * * Returns 0 */ static int smack_ipc_alloc_security(struct kern_ipc_perm *isp) { … } /** * smk_curacc_shm : check if current has access on shm * @isp : the object * @access : access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smk_curacc_shm(struct kern_ipc_perm *isp, int access) { … } /** * smack_shm_associate - Smack access check for shm * @isp: the object * @shmflg: access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smack_shm_associate(struct kern_ipc_perm *isp, int shmflg) { … } /** * smack_shm_shmctl - Smack access check for shm * @isp: the object * @cmd: what it wants to do * * Returns 0 if current has the requested access, error code otherwise */ static int smack_shm_shmctl(struct kern_ipc_perm *isp, int cmd) { … } /** * smack_shm_shmat - Smack access for shmat * @isp: the object * @shmaddr: unused * @shmflg: access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smack_shm_shmat(struct kern_ipc_perm *isp, char __user *shmaddr, int shmflg) { … } /** * smk_curacc_sem : check if current has access on sem * @isp : the object * @access : access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smk_curacc_sem(struct kern_ipc_perm *isp, int access) { … } /** * smack_sem_associate - Smack access check for sem * @isp: the object * @semflg: access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smack_sem_associate(struct kern_ipc_perm *isp, int semflg) { … } /** * smack_sem_semctl - Smack access check for sem * @isp: the object * @cmd: what it wants to do * * Returns 0 if current has the requested access, error code otherwise */ static int smack_sem_semctl(struct kern_ipc_perm *isp, int cmd) { … } /** * smack_sem_semop - Smack checks of semaphore operations * @isp: the object * @sops: unused * @nsops: unused * @alter: unused * * Treated as read and write in all cases. * * Returns 0 if access is allowed, error code otherwise */ static int smack_sem_semop(struct kern_ipc_perm *isp, struct sembuf *sops, unsigned nsops, int alter) { … } /** * smk_curacc_msq : helper to check if current has access on msq * @isp : the msq * @access : access requested * * return 0 if current has access, error otherwise */ static int smk_curacc_msq(struct kern_ipc_perm *isp, int access) { … } /** * smack_msg_queue_associate - Smack access check for msg_queue * @isp: the object * @msqflg: access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smack_msg_queue_associate(struct kern_ipc_perm *isp, int msqflg) { … } /** * smack_msg_queue_msgctl - Smack access check for msg_queue * @isp: the object * @cmd: what it wants to do * * Returns 0 if current has the requested access, error code otherwise */ static int smack_msg_queue_msgctl(struct kern_ipc_perm *isp, int cmd) { … } /** * smack_msg_queue_msgsnd - Smack access check for msg_queue * @isp: the object * @msg: unused * @msqflg: access requested * * Returns 0 if current has the requested access, error code otherwise */ static int smack_msg_queue_msgsnd(struct kern_ipc_perm *isp, struct msg_msg *msg, int msqflg) { … } /** * smack_msg_queue_msgrcv - Smack access check for msg_queue * @isp: the object * @msg: unused * @target: unused * @type: unused * @mode: unused * * Returns 0 if current has read and write access, error code otherwise */ static int smack_msg_queue_msgrcv(struct kern_ipc_perm *isp, struct msg_msg *msg, struct task_struct *target, long type, int mode) { … } /** * smack_ipc_permission - Smack access for ipc_permission() * @ipp: the object permissions * @flag: access requested * * Returns 0 if current has read and write access, error code otherwise */ static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag) { … } /** * smack_ipc_getsecid - Extract smack security id * @ipp: the object permissions * @secid: where result will be saved */ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid) { … } /** * smack_d_instantiate - Make sure the blob is correct on an inode * @opt_dentry: dentry where inode will be attached * @inode: the object * * Set the inode's security blob if it hasn't been done already. */ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) { … } /** * smack_getselfattr - Smack current process attribute * @attr: which attribute to fetch * @ctx: buffer to receive the result * @size: available size in, actual size out * @flags: unused * * Fill the passed user space @ctx with the details of the requested * attribute. * * Returns the number of attributes on success, an error code otherwise. * There will only ever be one attribute. */ static int smack_getselfattr(unsigned int attr, struct lsm_ctx __user *ctx, u32 *size, u32 flags) { … } /** * smack_getprocattr - Smack process attribute access * @p: the object task * @name: the name of the attribute in /proc/.../attr * @value: where to put the result * * Places a copy of the task Smack into value * * Returns the length of the smack label or an error code */ static int smack_getprocattr(struct task_struct *p, const char *name, char **value) { … } /** * do_setattr - Smack process attribute setting * @attr: the ID of the attribute * @value: the value to set * @size: the size of the value * * Sets the Smack value of the task. Only setting self * is permitted and only with privilege * * Returns the length of the smack label or an error code */ static int do_setattr(u64 attr, void *value, size_t size) { … } /** * smack_setselfattr - Set a Smack process attribute * @attr: which attribute to set * @ctx: buffer containing the data * @size: size of @ctx * @flags: unused * * Fill the passed user space @ctx with the details of the requested * attribute. * * Returns 0 on success, an error code otherwise. */ static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx, u32 size, u32 flags) { … } /** * smack_setprocattr - Smack process attribute setting * @name: the name of the attribute in /proc/.../attr * @value: the value to set * @size: the size of the value * * Sets the Smack value of the task. Only setting self * is permitted and only with privilege * * Returns the length of the smack label or an error code */ static int smack_setprocattr(const char *name, void *value, size_t size) { … } /** * smack_unix_stream_connect - Smack access on UDS * @sock: one sock * @other: the other sock * @newsk: unused * * Return 0 if a subject with the smack of sock could access * an object with the smack of other, otherwise an error code */ static int smack_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk) { … } /** * smack_unix_may_send - Smack access on UDS * @sock: one socket * @other: the other socket * * Return 0 if a subject with the smack of sock could access * an object with the smack of other, otherwise an error code */ static int smack_unix_may_send(struct socket *sock, struct socket *other) { … } /** * smack_socket_sendmsg - Smack check based on destination host * @sock: the socket * @msg: the message * @size: the size of the message * * Return 0 if the current subject can write to the destination host. * For IPv4 this is only a question if the destination is a single label host. * For IPv6 this is a check against the label of the port. */ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { … } /** * smack_from_secattr - Convert a netlabel attr.mls.lvl/attr.mls.cat pair to smack * @sap: netlabel secattr * @ssp: socket security information * * Returns a pointer to a Smack label entry found on the label list. */ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, struct socket_smack *ssp) { … } #if IS_ENABLED(CONFIG_IPV6) static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) { … } #endif /* CONFIG_IPV6 */ /** * smack_from_skb - Smack data from the secmark in an skb * @skb: packet * * Returns smack_known of the secmark or NULL if that won't work. */ #ifdef CONFIG_NETWORK_SECMARK static struct smack_known *smack_from_skb(struct sk_buff *skb) { … } #else static inline struct smack_known *smack_from_skb(struct sk_buff *skb) { return NULL; } #endif /** * smack_from_netlbl - Smack data from the IP options in an skb * @sk: socket data came in on * @family: address family * @skb: packet * * Find the Smack label in the IP options. If it hasn't been * added to the netlabel cache, add it here. * * Returns smack_known of the IP options or NULL if that won't work. */ static struct smack_known *smack_from_netlbl(const struct sock *sk, u16 family, struct sk_buff *skb) { … } /** * smack_socket_sock_rcv_skb - Smack packet delivery access check * @sk: socket * @skb: packet * * Returns 0 if the packet should be delivered, an error code otherwise */ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) { … } /** * smack_socket_getpeersec_stream - pull in packet label * @sock: the socket * @optval: user's destination * @optlen: size thereof * @len: max thereof * * returns zero on success, an error code otherwise */ static int smack_socket_getpeersec_stream(struct socket *sock, sockptr_t optval, sockptr_t optlen, unsigned int len) { … } /** * smack_socket_getpeersec_dgram - pull in packet label * @sock: the peer socket * @skb: packet data * @secid: pointer to where to put the secid of the packet * * Sets the netlabel socket state on sk from parent */ static int smack_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { … } /** * smack_sock_graft - Initialize a newly created socket with an existing sock * @sk: child sock * @parent: parent socket * * Set the smk_{in,out} state of an existing sock based on the process that * is creating the new socket. */ static void smack_sock_graft(struct sock *sk, struct socket *parent) { … } /** * smack_inet_conn_request - Smack access check on connect * @sk: socket involved * @skb: packet * @req: unused * * Returns 0 if a task with the packet label could write to * the socket, otherwise an error code */ static int smack_inet_conn_request(const struct sock *sk, struct sk_buff *skb, struct request_sock *req) { … } /** * smack_inet_csk_clone - Copy the connection information to the new socket * @sk: the new socket * @req: the connection's request_sock * * Transfer the connection's peer label to the newly created socket. */ static void smack_inet_csk_clone(struct sock *sk, const struct request_sock *req) { … } /* * Key management security hooks * * Casey has not tested key support very heavily. * The permission check is most likely too restrictive. * If you care about keys please have a look. */ #ifdef CONFIG_KEYS /** * smack_key_alloc - Set the key security blob * @key: object * @cred: the credentials to use * @flags: unused * * No allocation required * * Returns 0 */ static int smack_key_alloc(struct key *key, const struct cred *cred, unsigned long flags) { … } /** * smack_key_free - Clear the key security blob * @key: the object * * Clear the blob pointer */ static void smack_key_free(struct key *key) { … } /** * smack_key_permission - Smack access on a key * @key_ref: gets to the object * @cred: the credentials to use * @need_perm: requested key permission * * Return 0 if the task has read and write to the object, * an error code otherwise */ static int smack_key_permission(key_ref_t key_ref, const struct cred *cred, enum key_need_perm need_perm) { … } /* * smack_key_getsecurity - Smack label tagging the key * @key points to the key to be queried * @_buffer points to a pointer that should be set to point to the * resulting string (if no label or an error occurs). * Return the length of the string (including terminating NUL) or -ve if * an error. * May also return 0 (and a NULL buffer pointer) if there is no label. */ static int smack_key_getsecurity(struct key *key, char **_buffer) { … } #ifdef CONFIG_KEY_NOTIFICATIONS /** * smack_watch_key - Smack access to watch a key for notifications. * @key: The key to be watched * * Return 0 if the @watch->cred has permission to read from the key object and * an error otherwise. */ static int smack_watch_key(struct key *key) { … } #endif /* CONFIG_KEY_NOTIFICATIONS */ #endif /* CONFIG_KEYS */ #ifdef CONFIG_WATCH_QUEUE /** * smack_post_notification - Smack access to post a notification to a queue * @w_cred: The credentials of the watcher. * @cred: The credentials of the event source (may be NULL). * @n: The notification message to be posted. */ static int smack_post_notification(const struct cred *w_cred, const struct cred *cred, struct watch_notification *n) { … } #endif /* CONFIG_WATCH_QUEUE */ /* * Smack Audit hooks * * Audit requires a unique representation of each Smack specific * rule. This unique representation is used to distinguish the * object to be audited from remaining kernel objects and also * works as a glue between the audit hooks. * * Since repository entries are added but never deleted, we'll use * the smack_known label address related to the given audit rule as * the needed unique representation. This also better fits the smack * model where nearly everything is a label. */ #ifdef CONFIG_AUDIT /** * smack_audit_rule_init - Initialize a smack audit rule * @field: audit rule fields given from user-space (audit.h) * @op: required testing operator (=, !=, >, <, ...) * @rulestr: smack label to be audited * @vrule: pointer to save our own audit rule representation * @gfp: type of the memory for the allocation * * Prepare to audit cases where (@field @op @rulestr) is true. * The label to be audited is created if necessay. */ static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule, gfp_t gfp) { … } /** * smack_audit_rule_known - Distinguish Smack audit rules * @krule: rule of interest, in Audit kernel representation format * * This is used to filter Smack rules from remaining Audit ones. * If it's proved that this rule belongs to us, the * audit_rule_match hook will be called to do the final judgement. */ static int smack_audit_rule_known(struct audit_krule *krule) { … } /** * smack_audit_rule_match - Audit given object ? * @secid: security id for identifying the object to test * @field: audit rule flags given from user-space * @op: required testing operator * @vrule: smack internal rule presentation * * The core Audit hook. It's used to take the decision of * whether to audit or not to audit a given object. */ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule) { … } /* * There is no need for a smack_audit_rule_free hook. * No memory was allocated. */ #endif /* CONFIG_AUDIT */ /** * smack_ismaclabel - check if xattr @name references a smack MAC label * @name: Full xattr name to check. */ static int smack_ismaclabel(const char *name) { … } /** * smack_secid_to_secctx - return the smack label for a secid * @secid: incoming integer * @secdata: destination * @seclen: how long it is * * Exists for networking code. */ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) { … } /** * smack_secctx_to_secid - return the secid for a smack label * @secdata: smack label * @seclen: how long result is * @secid: outgoing integer * * Exists for audit and networking code. */ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) { … } /* * There used to be a smack_release_secctx hook * that did nothing back when hooks were in a vector. * Now that there's a list such a hook adds cost. */ static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) { … } static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) { … } static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) { … } static int smack_inode_copy_up(struct dentry *dentry, struct cred **new) { … } static int smack_inode_copy_up_xattr(struct dentry *src, const char *name) { … } static int smack_dentry_create_files_as(struct dentry *dentry, int mode, struct qstr *name, const struct cred *old, struct cred *new) { … } #ifdef CONFIG_IO_URING /** * smack_uring_override_creds - Is io_uring cred override allowed? * @new: the target creds * * Check to see if the current task is allowed to override it's credentials * to service an io_uring operation. */ static int smack_uring_override_creds(const struct cred *new) { … } /** * smack_uring_sqpoll - check if a io_uring polling thread can be created * * Check to see if the current task is allowed to create a new io_uring * kernel polling thread. */ static int smack_uring_sqpoll(void) { … } /** * smack_uring_cmd - check on file operations for io_uring * @ioucmd: the command in question * * Make a best guess about whether a io_uring "command" should * be allowed. Use the same logic used for determining if the * file could be opened for read in the absence of better criteria. */ static int smack_uring_cmd(struct io_uring_cmd *ioucmd) { … } #endif /* CONFIG_IO_URING */ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = …; static const struct lsm_id smack_lsmid = …; static struct security_hook_list smack_hooks[] __ro_after_init = …; static __init void init_smack_known_list(void) { … } /** * smack_init - initialize the smack system * * Returns 0 on success, -ENOMEM is there's no memory */ static __init int smack_init(void) { … } /* * Smack requires early initialization in order to label * all processes and objects when they are created. */ DEFINE_LSM(smack) = …;