diff options
Diffstat (limited to 'security/security.c')
| -rw-r--r-- | security/security.c | 2730 |
1 files changed, 2628 insertions, 102 deletions
diff --git a/security/security.c b/security/security.c index f4e45992472e..d5ff7ff45b77 100644 --- a/security/security.c +++ b/security/security.c @@ -6,6 +6,7 @@ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> * Copyright (C) 2001 Networks Associates Technology, Inc <ssmalley@nai.com> * Copyright (C) 2016 Mellanox Technologies + * Copyright (C) 2023 Microsoft Corporation <paul@paul-moore.com> */ #define pr_fmt(fmt) "LSM: " fmt @@ -41,7 +42,7 @@ * all security modules to use the same descriptions for auditing * purposes. */ -const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { +const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = { [LOCKDOWN_NONE] = "none", [LOCKDOWN_MODULE_SIGNATURE] = "unsigned module loading", [LOCKDOWN_DEV_MEM] = "/dev/mem,kmem,port", @@ -87,7 +88,7 @@ static struct lsm_blob_sizes blob_sizes __ro_after_init; static __initdata const char *chosen_lsm_order; static __initdata const char *chosen_major_lsm; -static __initconst const char * const builtin_lsm_order = CONFIG_LSM; +static __initconst const char *const builtin_lsm_order = CONFIG_LSM; /* Ordered list of LSMs to initialize. */ static __initdata struct lsm_info **ordered_lsms; @@ -284,9 +285,9 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) bool found = false; for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { - if (lsm->order == LSM_ORDER_MUTABLE && - strcmp(lsm->name, name) == 0) { - append_ordered_lsm(lsm, origin); + if (strcmp(lsm->name, name) == 0) { + if (lsm->order == LSM_ORDER_MUTABLE) + append_ordered_lsm(lsm, origin); found = true; } } @@ -306,6 +307,12 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) } } + /* LSM_ORDER_LAST is always last. */ + for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { + if (lsm->order == LSM_ORDER_LAST) + append_ordered_lsm(lsm, " last"); + } + /* Disable all LSMs not in the ordered list. */ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) { if (exists_ordered_lsm(lsm)) @@ -331,7 +338,8 @@ static void __init report_lsm_order(void) pr_info("initializing lsm="); /* Report each enabled LSM name, comma separated. */ - for (early = __start_early_lsm_info; early < __end_early_lsm_info; early++) + for (early = __start_early_lsm_info; + early < __end_early_lsm_info; early++) if (is_enabled(early)) pr_cont("%s%s", first++ == 0 ? "" : ",", early->name); for (lsm = ordered_lsms; *lsm; lsm++) @@ -346,7 +354,7 @@ static void __init ordered_lsm_init(void) struct lsm_info **lsm; ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms), - GFP_KERNEL); + GFP_KERNEL); if (chosen_lsm_order) { if (chosen_major_lsm) { @@ -419,9 +427,9 @@ int __init security_init(void) { struct lsm_info *lsm; - init_debug("legacy security=%s\n", chosen_major_lsm ?: " *unspecified*"); + init_debug("legacy security=%s\n", chosen_major_lsm ? : " *unspecified*"); init_debug(" CONFIG_LSM=%s\n", builtin_lsm_order); - init_debug("boot arg lsm=%s\n", chosen_lsm_order ?: " *unspecified*"); + init_debug("boot arg lsm=%s\n", chosen_lsm_order ? : " *unspecified*"); /* * Append the names of the early LSM modules now that kmalloc() is @@ -509,7 +517,7 @@ static int lsm_append(const char *new, char **result) * Each LSM has to register its hooks with the infrastructure. */ void __init security_add_hooks(struct security_hook_list *hooks, int count, - const char *lsm) + const char *lsm) { int i; @@ -778,57 +786,157 @@ static int lsm_superblock_alloc(struct super_block *sb) /* Security operations */ +/** + * security_binder_set_context_mgr() - Check if becoming binder ctx mgr is ok + * @mgr: task credentials of current binder process + * + * Check whether @mgr is allowed to be the binder context manager. + * + * Return: Return 0 if permission is granted. + */ int security_binder_set_context_mgr(const struct cred *mgr) { return call_int_hook(binder_set_context_mgr, 0, mgr); } +/** + * security_binder_transaction() - Check if a binder transaction is allowed + * @from: sending process + * @to: receiving process + * + * Check whether @from is allowed to invoke a binder transaction call to @to. + * + * Return: Returns 0 if permission is granted. + */ int security_binder_transaction(const struct cred *from, const struct cred *to) { return call_int_hook(binder_transaction, 0, from, to); } +/** + * security_binder_transfer_binder() - Check if a binder transfer is allowed + * @from: sending process + * @to: receiving process + * + * Check whether @from is allowed to transfer a binder reference to @to. + * + * Return: Returns 0 if permission is granted. + */ int security_binder_transfer_binder(const struct cred *from, const struct cred *to) { return call_int_hook(binder_transfer_binder, 0, from, to); } +/** + * security_binder_transfer_file() - Check if a binder file xfer is allowed + * @from: sending process + * @to: receiving process + * @file: file being transferred + * + * Check whether @from is allowed to transfer @file to @to. + * + * Return: Returns 0 if permission is granted. + */ int security_binder_transfer_file(const struct cred *from, const struct cred *to, struct file *file) { return call_int_hook(binder_transfer_file, 0, from, to, file); } +/** + * security_ptrace_access_check() - Check if tracing is allowed + * @child: target process + * @mode: PTRACE_MODE flags + * + * Check permission before allowing the current process to trace the @child + * process. Security modules may also want to perform a process tracing check + * during an execve in the set_security or apply_creds hooks of tracing check + * during an execve in the bprm_set_creds hook of binprm_security_ops if the + * process is being traced and its security attributes would be changed by the + * execve. + * + * Return: Returns 0 if permission is granted. + */ int security_ptrace_access_check(struct task_struct *child, unsigned int mode) { return call_int_hook(ptrace_access_check, 0, child, mode); } +/** + * security_ptrace_traceme() - Check if tracing is allowed + * @parent: tracing process + * + * Check that the @parent process has sufficient permission to trace the + * current process before allowing the current process to present itself to the + * @parent process for tracing. + * + * Return: Returns 0 if permission is granted. + */ int security_ptrace_traceme(struct task_struct *parent) { return call_int_hook(ptrace_traceme, 0, parent); } +/** + * security_capget() - Get the capability sets for a process + * @target: target process + * @effective: effective capability set + * @inheritable: inheritable capability set + * @permitted: permitted capability set + * + * Get the @effective, @inheritable, and @permitted capability sets for the + * @target process. The hook may also perform permission checking to determine + * if the current process is allowed to see the capability sets of the @target + * process. + * + * Return: Returns 0 if the capability sets were successfully obtained. + */ int security_capget(struct task_struct *target, - kernel_cap_t *effective, - kernel_cap_t *inheritable, - kernel_cap_t *permitted) + kernel_cap_t *effective, + kernel_cap_t *inheritable, + kernel_cap_t *permitted) { return call_int_hook(capget, 0, target, - effective, inheritable, permitted); + effective, inheritable, permitted); } +/** + * security_capset() - Set the capability sets for a process + * @new: new credentials for the target process + * @old: current credentials of the target process + * @effective: effective capability set + * @inheritable: inheritable capability set + * @permitted: permitted capability set + * + * Set the @effective, @inheritable, and @permitted capability sets for the + * current process. + * + * Return: Returns 0 and update @new if permission is granted. + */ int security_capset(struct cred *new, const struct cred *old, const kernel_cap_t *effective, const kernel_cap_t *inheritable, const kernel_cap_t *permitted) { return call_int_hook(capset, 0, new, old, - effective, inheritable, permitted); + effective, inheritable, permitted); } +/** + * security_capable() - Check if a process has the necessary capability + * @cred: credentials to examine + * @ns: user namespace + * @cap: capability requested + * @opts: capability check options + * + * Check whether the @tsk process has the @cap capability in the indicated + * credentials. @cap contains the capability <include/linux/capability.h>. + * @opts contains options for the capable check <include/linux/security.h>. + * + * Return: Returns 0 if the capability is granted. + */ int security_capable(const struct cred *cred, struct user_namespace *ns, int cap, @@ -837,26 +945,78 @@ int security_capable(const struct cred *cred, return call_int_hook(capable, 0, cred, ns, cap, opts); } +/** + * security_quotactl() - Check if a quotactl() syscall is allowed for this fs + * @cmds: commands + * @type: type + * @id: id + * @sb: filesystem + * + * Check whether the quotactl syscall is allowed for this @sb. + * + * Return: Returns 0 if permission is granted. + */ int security_quotactl(int cmds, int type, int id, struct super_block *sb) { return call_int_hook(quotactl, 0, cmds, type, id, sb); } +/** + * security_quota_on() - Check if QUOTAON is allowed for a dentry + * @dentry: dentry + * + * Check whether QUOTAON is allowed for @dentry. + * + * Return: Returns 0 if permission is granted. + */ int security_quota_on(struct dentry *dentry) { return call_int_hook(quota_on, 0, dentry); } +/** + * security_syslog() - Check if accessing the kernel message ring is allowed + * @type: SYSLOG_ACTION_* type + * + * Check permission before accessing the kernel message ring or changing + * logging to the console. See the syslog(2) manual page for an explanation of + * the @type values. + * + * Return: Return 0 if permission is granted. + */ int security_syslog(int type) { return call_int_hook(syslog, 0, type); } +/** + * security_settime64() - Check if changing the system time is allowed + * @ts: new time + * @tz: timezone + * + * Check permission to change the system time, struct timespec64 is defined in + * <include/linux/time64.h> and timezone is defined in <include/linux/time.h>. + * + * Return: Returns 0 if permission is granted. + */ int security_settime64(const struct timespec64 *ts, const struct timezone *tz) { return call_int_hook(settime, 0, ts, tz); } +/** + * security_vm_enough_memory_mm() - Check if allocating a new mem map is allowed + * @mm: mm struct + * @pages: number of pages + * + * Check permissions for allocating a new virtual mapping. If all LSMs return + * a positive value, __vm_enough_memory() will be called with cap_sys_admin + * set. If at least one LSM returns 0 or negative, __vm_enough_memory() will be + * called with cap_sys_admin cleared. + * + * Return: Returns 0 if permission is granted by the LSM infrastructure to the + * caller. + */ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { struct security_hook_list *hp; @@ -880,16 +1040,61 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) return __vm_enough_memory(mm, pages, cap_sys_admin); } +/** + * security_bprm_creds_for_exec() - Prepare the credentials for exec() + * @bprm: binary program information + * + * If the setup in prepare_exec_creds did not setup @bprm->cred->security + * properly for executing @bprm->file, update the LSM's portion of + * @bprm->cred->security to be what commit_creds needs to install for the new + * program. This hook may also optionally check permissions (e.g. for + * transitions between security domains). The hook must set @bprm->secureexec + * to 1 if AT_SECURE should be set to request libc enable secure mode. @bprm + * contains the linux_binprm structure. + * + * Return: Returns 0 if the hook is successful and permission is granted. + */ int security_bprm_creds_for_exec(struct linux_binprm *bprm) { return call_int_hook(bprm_creds_for_exec, 0, bprm); } +/** + * security_bprm_creds_from_file() - Update linux_binprm creds based on file + * @bprm: binary program information + * @file: associated file + * + * If @file is setpcap, suid, sgid or otherwise marked to change privilege upon + * exec, update @bprm->cred to reflect that change. This is called after + * finding the binary that will be executed without an interpreter. This + * ensures that the credentials will not be derived from a script that the + * binary will need to reopen, which when reopend may end up being a completely + * different file. This hook may also optionally check permissions (e.g. for + * transitions between security domains). The hook must set @bprm->secureexec + * to 1 if AT_SECURE should be set to request libc enable secure mode. The + * hook must add to @bprm->per_clear any personality flags that should be + * cleared from current->personality. @bprm contains the linux_binprm + * structure. + * + * Return: Returns 0 if the hook is successful and permission is granted. + */ int security_bprm_creds_from_file(struct linux_binprm *bprm, struct file *file) { return call_int_hook(bprm_creds_from_file, 0, bprm, file); } +/** + * security_bprm_check() - Mediate binary handler search + * @bprm: binary program information + * + * This hook mediates the point when a search for a binary handler will begin. + * It allows a check against the @bprm->cred->security value which was set in + * the preceding creds_for_exec call. The argv list and envp list are reliably + * available in @bprm. This hook may be called multiple times during a single + * execve. @bprm contains the linux_binprm structure. + * + * Return: Returns 0 if the hook is successful and permission is granted. + */ int security_bprm_check(struct linux_binprm *bprm) { int ret; @@ -900,21 +1105,67 @@ int security_bprm_check(struct linux_binprm *bprm) return ima_bprm_check(bprm); } +/** + * security_bprm_committing_creds() - Install creds for a process during exec() + * @bprm: binary program information + * + * Prepare to install the new security attributes of a process being + * transformed by an execve operation, based on the old credentials pointed to + * by @current->cred and the information set in @bprm->cred by the + * bprm_creds_for_exec hook. @bprm points to the linux_binprm structure. This + * hook is a good place to perform state changes on the process such as closing + * open file descriptors to which access will no longer be granted when the + * attributes are changed. This is called immediately before commit_creds(). + */ void security_bprm_committing_creds(struct linux_binprm *bprm) { call_void_hook(bprm_committing_creds, bprm); } +/** + * security_bprm_committed_creds() - Tidy up after cred install during exec() + * @bprm: binary program information + * + * Tidy up after the installation of the new security attributes of a process + * being transformed by an execve operation. The new credentials have, by this + * point, been set to @current->cred. @bprm points to the linux_binprm + * structure. This hook is a good place to perform state changes on the + * process such as clearing out non-inheritable signal state. This is called + * immediately after commit_creds(). + */ void security_bprm_committed_creds(struct linux_binprm *bprm) { call_void_hook(bprm_committed_creds, bprm); } +/** + * security_fs_context_dup() - Duplicate a fs_context LSM blob + * @fc: destination filesystem context + * @src_fc: source filesystem context + * + * Allocate and attach a security structure to sc->security. This pointer is + * initialised to NULL by the caller. @fc indicates the new filesystem context. + * @src_fc indicates the original filesystem context. + * + * Return: Returns 0 on success or a negative error code on failure. + */ int security_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc) { return call_int_hook(fs_context_dup, 0, fc, src_fc); } +/** + * security_fs_context_parse_param() - Configure a filesystem context + * @fc: filesystem context + * @param: filesystem parameter + * + * Userspace provided a parameter to configure a superblock. The LSM can + * consume the parameter or return it to the caller for use elsewhere. + * + * Return: If the parameter is used by the LSM it should return 0, if it is + * returned to the caller -ENOPARAM is returned, otherwise a negative + * error code is returned. + */ int security_fs_context_parse_param(struct fs_context *fc, struct fs_parameter *param) { @@ -933,6 +1184,16 @@ int security_fs_context_parse_param(struct fs_context *fc, return rc; } +/** + * security_sb_alloc() - Allocate a super_block LSM blob + * @sb: filesystem superblock + * + * Allocate and attach a security structure to the sb->s_security field. The + * s_security field is initialized to NULL when the structure is allocated. + * @sb contains the super_block structure to be modified. + * + * Return: Returns 0 if operation was successful. + */ int security_sb_alloc(struct super_block *sb) { int rc = lsm_superblock_alloc(sb); @@ -945,11 +1206,25 @@ int security_sb_alloc(struct super_block *sb) return rc; } +/** + * security_sb_delete() - Release super_block LSM associated objects + * @sb: filesystem superblock + * + * Release objects tied to a superblock (e.g. inodes). @sb contains the + * super_block structure being released. + */ void security_sb_delete(struct super_block *sb) { call_void_hook(sb_delete, sb); } +/** + * security_sb_free() - Free a super_block LSM blob + * @sb: filesystem superblock + * + * Deallocate and clear the sb->s_security field. @sb contains the super_block + * structure to be modified. + */ void security_sb_free(struct super_block *sb) { call_void_hook(sb_free_security, sb); @@ -957,6 +1232,12 @@ void security_sb_free(struct super_block *sb) sb->s_security = NULL; } +/** + * security_free_mnt_opts() - Free memory associated with mount options + * @mnt_opts: LSM processed mount options + * + * Free memory associated with @mnt_ops. + */ void security_free_mnt_opts(void **mnt_opts) { if (!*mnt_opts) @@ -966,12 +1247,31 @@ void security_free_mnt_opts(void **mnt_opts) } EXPORT_SYMBOL(security_free_mnt_opts); +/** + * security_sb_eat_lsm_opts() - Consume LSM mount options + * @options: mount options + * @mnt_opts: LSM processed mount options + * + * Eat (scan @options) and save them in @mnt_opts. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_sb_eat_lsm_opts(char *options, void **mnt_opts) { return call_int_hook(sb_eat_lsm_opts, 0, options, mnt_opts); } EXPORT_SYMBOL(security_sb_eat_lsm_opts); +/** + * security_sb_mnt_opts_compat() - Check if new mount options are allowed + * @sb: filesystem superblock + * @mnt_opts: new mount options + * + * Determine if the new mount options in @mnt_opts are allowed given the + * existing mounted filesystem at @sb. @sb superblock being compared. + * + * Return: Returns 0 if options are compatible. + */ int security_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts) { @@ -979,6 +1279,16 @@ int security_sb_mnt_opts_compat(struct super_block *sb, } EXPORT_SYMBOL(security_sb_mnt_opts_compat); +/** + * security_sb_remount() - Verify no incompatible mount changes during remount + * @sb: filesystem superblock + * @mnt_opts: (re)mount options + * + * Extracts security system specific mount options and verifies no changes are + * being made to those options. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_remount(struct super_block *sb, void *mnt_opts) { @@ -986,69 +1296,184 @@ int security_sb_remount(struct super_block *sb, } EXPORT_SYMBOL(security_sb_remount); +/** + * security_sb_kern_mount() - Check if a kernel mount is allowed + * @sb: filesystem superblock + * + * Mount this @sb if allowed by permissions. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_kern_mount(struct super_block *sb) { return call_int_hook(sb_kern_mount, 0, sb); } +/** + * security_sb_show_options() - Output the mount options for a superblock + * @m: output file + * @sb: filesystem superblock + * + * Show (print on @m) mount options for this @sb. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_sb_show_options(struct seq_file *m, struct super_block *sb) { return call_int_hook(sb_show_options, 0, m, sb); } +/** + * security_sb_statfs() - Check if accessing fs stats is allowed + * @dentry: superblock handle + * + * Check permission before obtaining filesystem statistics for the @mnt + * mountpoint. @dentry is a handle on the superblock for the filesystem. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_statfs(struct dentry *dentry) { return call_int_hook(sb_statfs, 0, dentry); } +/** + * security_sb_mount() - Check permission for mounting a filesystem + * @dev_name: filesystem backing device + * @path: mount point + * @type: filesystem type + * @flags: mount flags + * @data: filesystem specific data + * + * Check permission before an object specified by @dev_name is mounted on the + * mount point named by @nd. For an ordinary mount, @dev_name identifies a + * device if the file system type requires a device. For a remount + * (@flags & MS_REMOUNT), @dev_name is irrelevant. For a loopback/bind mount + * (@flags & MS_BIND), @dev_name identifies the pathname of the object being + * mounted. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data) + const char *type, unsigned long flags, void *data) { return call_int_hook(sb_mount, 0, dev_name, path, type, flags, data); } +/** + * security_sb_umount() - Check permission for unmounting a filesystem + * @mnt: mounted filesystem + * @flags: unmount flags + * + * Check permission before the @mnt file system is unmounted. + * + * Return: Returns 0 if permission is granted. + */ int security_sb_umount(struct vfsmount *mnt, int flags) { return call_int_hook(sb_umount, 0, mnt, flags); } -int security_sb_pivotroot(const struct path *old_path, const struct path *new_path) +/** + * security_sb_pivotroot() - Check permissions for pivoting the rootfs + * @old_path: new location for current rootfs + * @new_path: location of the new rootfs + * + * Check permission before pivoting the root filesystem. + * + * Return: Returns 0 if permission is granted. + */ +int security_sb_pivotroot(const struct path *old_path, + const struct path *new_path) { return call_int_hook(sb_pivotroot, 0, old_path, new_path); } +/** + * security_sb_set_mnt_opts() - Set the mount options for a filesystem + * @sb: filesystem superblock + * @mnt_opts: binary mount options + * @kern_flags: kernel flags (in) + * @set_kern_flags: kernel flags (out) + * + * Set the security relevant mount options used for a superblock. + * + * Return: Returns 0 on success, error on failure. + */ int security_sb_set_mnt_opts(struct super_block *sb, - void *mnt_opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) + void *mnt_opts, + unsigned long kern_flags, + unsigned long *set_kern_flags) { return call_int_hook(sb_set_mnt_opts, - mnt_opts ? -EOPNOTSUPP : 0, sb, - mnt_opts, kern_flags, set_kern_flags); + mnt_opts ? -EOPNOTSUPP : 0, sb, + mnt_opts, kern_flags, set_kern_flags); } EXPORT_SYMBOL(security_sb_set_mnt_opts); +/** + * security_sb_clone_mnt_opts() - Duplicate superblock mount options + * @oldsb: source superblock + * @newsb: destination superblock + * @kern_flags: kernel flags (in) + * @set_kern_flags: kernel flags (out) + * + * Copy all security options from a given superblock to another. + * + * Return: Returns 0 on success, error on failure. + */ int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb, - unsigned long kern_flags, - unsigned long *set_kern_flags) + struct super_block *newsb, + unsigned long kern_flags, + unsigned long *set_kern_flags) { return call_int_hook(sb_clone_mnt_opts, 0, oldsb, newsb, - kern_flags, set_kern_flags); + kern_flags, set_kern_flags); } EXPORT_SYMBOL(security_sb_clone_mnt_opts); -int security_move_mount(const struct path *from_path, const struct path *to_path) +/** + * security_move_mount() - Check permissions for moving a mount + * @from_path: source mount point + * @to_path: destination mount point + * + * Check permission before a mount is moved. + * + * Return: Returns 0 if permission is granted. + */ +int security_move_mount(const struct path *from_path, + const struct path *to_path) { return call_int_hook(move_mount, 0, from_path, to_path); } +/** + * security_path_notify() - Check if setting a watch is allowed + * @path: file path + * @mask: event mask + * @obj_type: file path type + * + * Check permissions before setting a watch on events as defined by @mask, on + * an object at @path, whose type is defined by @obj_type. + * + * Return: Returns 0 if permission is granted. + */ int security_path_notify(const struct path *path, u64 mask, - unsigned int obj_type) + unsigned int obj_type) { return call_int_hook(path_notify, 0, path, mask, obj_type); } +/** + * security_inode_alloc() - Allocate an inode LSM blob + * @inode: the inode + * + * Allocate and attach a security structure to @inode->i_security. The + * i_security field is initialized to NULL when the inode structure is + * allocated. + * + * Return: Return 0 if operation was successful. + */ int security_inode_alloc(struct inode *inode) { int rc = lsm_inode_alloc(inode); @@ -1069,6 +1494,12 @@ static void inode_free_by_rcu(struct rcu_head *head) kmem_cache_free(lsm_inode_cache, head); } +/** + * security_inode_free() - Free an inode's LSM blob + * @inode: the inode + * + * Deallocate the inode security structure and set @inode->i_security to NULL. + */ void security_inode_free(struct inode *inode) { integrity_inode_free(inode); @@ -1084,9 +1515,24 @@ void security_inode_free(struct inode *inode) */ if (inode->i_security) call_rcu((struct rcu_head *)inode->i_security, - inode_free_by_rcu); + inode_free_by_rcu); } +/** + * security_dentry_init_security() - Perform dentry initialization + * @dentry: the dentry to initialize + * @mode: mode used to determine resource type + * @name: name of the last path component + * @xattr_name: name of the security/LSM xattr + * @ctx: pointer to the resulting LSM context + * @ctxlen: length of @ctx + * + * Compute a context for a dentry as the inode is not yet available since NFSv4 + * has no label backed by an EA anyway. It is important to note that + * @xattr_name does not need to be free'd by the caller, it is a static string. + * + * Return: Returns 0 on success, negative values on failure. + */ int security_dentry_init_security(struct dentry *dentry, int mode, const struct qstr *name, const char **xattr_name, void **ctx, @@ -1098,7 +1544,8 @@ int security_dentry_init_security(struct dentry *dentry, int mode, /* * Only one module will provide a security context. */ - hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, list) { + hlist_for_each_entry(hp, &security_hook_heads.dentry_init_security, + list) { rc = hp->hook.dentry_init_security(dentry, mode, name, xattr_name, ctx, ctxlen); if (rc != LSM_RET_DEFAULT(dentry_init_security)) @@ -1108,15 +1555,51 @@ int security_dentry_init_security(struct dentry *dentry, int mode, } EXPORT_SYMBOL(security_dentry_init_security); +/** + * security_dentry_create_files_as() - Perform dentry initialization + * @dentry: the dentry to initialize + * @mode: mode used to determine resource type + * @name: name of the last path component + * @old: creds to use for LSM context calculations + * @new: creds to modify + * + * Compute a context for a dentry as the inode is not yet available and set + * that context in passed in creds so that new files are created using that + * context. Context is calculated using the passed in creds and not the creds + * of the caller. + * + * Return: Returns 0 on success, error on failure. + */ int security_dentry_create_files_as(struct dentry *dentry, int mode, struct qstr *name, const struct cred *old, struct cred *new) { return call_int_hook(dentry_create_files_as, 0, dentry, mode, - name, old, new); + name, old, new); } EXPORT_SYMBOL(security_dentry_create_files_as); +/** + * security_inode_init_security() - Initialize an inode's LSM context + * @inode: the inode + * @dir: parent directory + * @qstr: last component of the pathname + * @initxattrs: callback function to write xattrs + * @fs_data: filesystem specific data + * + * Obtain the security attribute name suffix and value to set on a newly + * created inode and set up the incore security field for the new inode. This + * hook is called by the fs code as part of the inode creation transaction and + * provides for atomic labeling of the inode, unlike the post_create/mkdir/... + * hooks called by the VFS. The hook function is expected to allocate the name + * and value via kmalloc, with the caller being responsible for calling kfree + * after using them. If the security module does not use security attributes + * or does not wish to put a security attribute on this particular inode, then + * it should return -EOPNOTSUPP to skip this processing. + * + * Return: Returns 0 on success, -EOPNOTSUPP if no security attribute is + * needed, or -ENOMEM on memory allocation failure. + */ int security_inode_init_security(struct inode *inode, struct inode *dir, const struct qstr *qstr, const initxattrs initxattrs, void *fs_data) @@ -1134,9 +1617,9 @@ int security_inode_init_security(struct inode *inode, struct inode *dir, memset(new_xattrs, 0, sizeof(new_xattrs)); lsm_xattr = new_xattrs; ret = call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, qstr, - &lsm_xattr->name, - &lsm_xattr->value, - &lsm_xattr->value_len); + &lsm_xattr->name, + &lsm_xattr->value, + &lsm_xattr->value_len); if (ret) goto out; @@ -1152,6 +1635,18 @@ out: } EXPORT_SYMBOL(security_inode_init_security); +/** + * security_inode_init_security_anon() - Initialize an anonymous inode + * @inode: the inode + * @name: the anonymous inode class + * @context_inode: an optional related inode + * + * Set up the incore security field for the new anonymous inode and return + * whether the inode creation is permitted by the security module or not. + * + * Return: Returns 0 on success, -EACCES if the security module denies the + * creation of this inode, or another -errno upon other errors. + */ int security_inode_init_security_anon(struct inode *inode, const struct qstr *name, const struct inode *context_inode) @@ -1160,20 +1655,21 @@ int security_inode_init_security_anon(struct inode *inode, context_inode); } -int security_old_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, const char **name, - void **value, size_t *len) -{ - if (unlikely(IS_PRIVATE(inode))) - return -EOPNOTSUPP; - return call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, - qstr, name, value, len); -} -EXPORT_SYMBOL(security_old_inode_init_security); - #ifdef CONFIG_SECURITY_PATH -int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode, - unsigned int dev) +/** + * security_path_mknod() - Check if creating a special file is allowed + * @dir: parent directory + * @dentry: new file + * @mode: new file mode + * @dev: device number + * + * Check permissions when creating a file. Note that this hook is called even + * if mknod operation is being done for a regular file. + * + * Return: Returns 0 if permission is granted. + */ +int security_path_mknod(const struct path *dir, struct dentry *dentry, + umode_t mode, unsigned int dev) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; @@ -1181,7 +1677,18 @@ int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t m } EXPORT_SYMBOL(security_path_mknod); -int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t mode) +/** + * security_path_mkdir() - Check if creating a new directory is allowed + * @dir: parent directory + * @dentry: new directory + * @mode: new directory mode + * + * Check permissions to create a new directory in the existing directory. + * + * Return: Returns 0 if permission is granted. + */ +int security_path_mkdir(const struct path *dir, struct dentry *dentry, + umode_t mode) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) return 0; @@ -1189,6 +1696,15 @@ int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t m } EXPORT_SYMBOL(security_path_mkdir); +/** + * security_path_rmdir() - Check if removing a directory is allowed + * @dir: parent directory + * @dentry: directory to remove + * + * Check the permission to remove a directory. + * + * Return: Returns 0 if permission is granted. + */ int security_path_rmdir(const struct path *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) @@ -1196,6 +1712,15 @@ int security_path_rmdir(const struct path *dir, struct dentry *dentry) return call_int_hook(path_rmdir, 0, dir, dentry); } +/** + * security_path_unlink() - Check if removing a hard link is allowed + * @dir: parent directory + * @dentry: file + * + * Check the permission to remove a hard link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_path_unlink(const struct path *dir, struct dentry *dentry) { if (unlikely(IS_PRIVATE(d_backing_inode(dir->dentry)))) @@ -1204,6 +1729,16 @@ int security_path_unlink(const struct path *dir, struct dentry *dentry) } EXPORT_SYMBOL(security_path_unlink); +/** + * security_path_symlink() - Check if creating a symbolic link is allowed + * @dir: parent directory + * @dentry: symbolic link + * @old_name: file pathname + * + * Check the permission to create a symbolic link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_path_symlink(const struct path *dir, struct dentry *dentry, const char *old_name) { @@ -1212,6 +1747,16 @@ int security_path_symlink(const struct path *dir, struct dentry *dentry, return call_int_hook(path_symlink, 0, dir, dentry, old_name); } +/** + * security_path_link - Check if creating a hard link is allowed + * @old_dentry: existing file + * @new_dir: new parent directory + * @new_dentry: new link + * + * Check permission before creating a new hard link to a file. + * + * Return: Returns 0 if permission is granted. + */ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry) { @@ -1220,19 +1765,42 @@ int security_path_link(struct dentry *old_dentry, const struct path *new_dir, return call_int_hook(path_link, 0, old_dentry, new_dir, new_dentry); } +/** + * security_path_rename() - Check if renaming a file is allowed + * @old_dir: parent directory of the old file + * @old_dentry: the old file + * @new_dir: parent directory of the new file + * @new_dentry: the new file + * @flags: flags + * + * Check for permission to rename a file or directory. + * + * Return: Returns 0 if per |
