// SPDX-License-Identifier: GPL-2.0/* * linux/fs/namei.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * Some corrections by tytso. */ /* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname * lookup logic. *//* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture. */ #include <linux/init.h>#include <linux/export.h>#include <linux/slab.h>#include <linux/wordpart.h>#include <linux/fs.h>#include <linux/filelock.h>#include <linux/namei.h>#include <linux/pagemap.h>#include <linux/sched/mm.h>#include <linux/fsnotify.h>#include <linux/personality.h>#include <linux/security.h>#include <linux/syscalls.h>#include <linux/mount.h>#include <linux/audit.h>#include <linux/capability.h>#include <linux/file.h>#include <linux/fcntl.h>#include <linux/device_cgroup.h>#include <linux/fs_struct.h>#include <linux/posix_acl.h>#include <linux/hash.h>#include <linux/bitops.h>#include <linux/init_task.h>#include <linux/uaccess.h> #include <asm/runtime-const.h> #include "internal.h"#include "mount.h" /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) * were necessary because of omirr. The reason is that omirr needs * to know the _real_ pathname, not the user-supplied one, in case * of symlinks (and also when transname replacements occur). * * The new code replaces the old recursive symlink resolution with * an iterative one (in case of non-nested symlink chains). It does * this with calls to <fs>_follow_link(). * As a side effect, dir_namei(), _namei() and follow_link() are now * replaced with a single function lookup_dentry() that can handle all * the special cases of the former code. * * With the new dcache, the pathname is stored at each inode, at least as * long as the refcount of the inode is positive. As a side effect, the * size of the dcache depends on the inode cache and thus is dynamic. * * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink * resolution to correspond with current state of the code. * * Note that the symlink resolution is not *completely* iterative. * There is still a significant amount of tail- and mid- recursion in * the algorithm. Also, note that <fs>_readlink() is not used in * lookup_dentry(): lookup_dentry() on the result of <fs>_readlink() * may return different results than <fs>_follow_link(). Many virtual * filesystems (including /proc) exhibit this behavior. */ /* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation: * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL * and the name already exists in form of a symlink, try to create the new * name indicated by the symlink. The old code always complained that the * name already exists, due to not following the symlink even if its target * is nonexistent. The new semantics affects also mknod() and link() when * the name is a symlink pointing to a non-existent name. * * I don't know which semantics is the right one, since I have no access * to standards. But I found by trial that HP-UX 9.0 has the full "new" * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the * "old" one. Personally, I think the new semantics is much more logical. * Note that "ln old new" where "new" is a symlink pointing to a non-existing * file does succeed in both HP-UX and SunOs, but not in Solaris * and in the old Linux semantics. */ /* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink * semantics. See the comments in "open_namei" and "do_link" below. * * [10-Sep-98 Alan Modra] Another symlink change. */ /* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks: * inside the path - always follow. * in the last component in creation/removal/renaming - never follow. * if LOOKUP_FOLLOW passed - follow. * if the pathname has trailing slashes - follow. * otherwise - don't follow. * (applied in that order). * * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT * restored for 2.4. This is the last surviving part of old 4.2BSD bug. * During the 2.4 we need to fix the userland stuff depending on it - * hopefully we will be able to get rid of that wart in 2.5. So far only * XEmacs seems to be relying on it... *//* * [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland) * implemented. Let's see if raised priority of ->s_vfs_rename_mutex gives * any extra contention... */ /* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. * * POSIX.1 2.4: an empty pathname is invalid (ENOENT). * PATH_MAX includes the nul terminator --RR. */ /* SLAB cache for struct filename instances */static struct kmem_cache *__names_cache __ro_after_init;#define names_cache runtime_const_ptr(__names_cache) /* * Type of the last component on LOOKUP_PARENT */enum last_type {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; void __init filename_init(void){ __names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname), EMBEDDED_NAME_MAX, NULL); runtime_const_init(ptr, __names_cache);} static inline struct filename *alloc_filename(void){ return kmem_cache_alloc(names_cache, GFP_KERNEL);} static inline void free_filename(struct filename *p){ kmem_cache_free(names_cache, p);} static inline void initname(struct filename *name){ name->aname = NULL; name->refcnt = 1;} static int getname_long(struct filename *name, const char __user *filename){ int len; char *p __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL); if (unlikely(!p)) return -ENOMEM; memcpy(p, &name->iname, EMBEDDED_NAME_MAX); len = strncpy_from_user(p + EMBEDDED_NAME_MAX, filename + EMBEDDED_NAME_MAX, PATH_MAX - EMBEDDED_NAME_MAX); if (unlikely(len < 0)) return len; if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX)) return -ENAMETOOLONG; name->name = no_free_ptr(p); return 0;} static struct filename *do_getname(const char __user *filename, int flags, bool incomplete){ struct filename *result; char *kname; int len; result = alloc_filename(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); /* * First, try to embed the struct filename inside the names_cache * allocation */ kname = (char *)result->iname; result->name = kname; len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); /* * Handle both empty path and copy failure in one go. */ if (unlikely(len <= 0)) { /* The empty path is special. */ if (!len && !(flags & LOOKUP_EMPTY)) len = -ENOENT; } /* * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a * separate struct filename so we can dedicate the entire * names_cache allocation for the pathname, and re-do the copy from * userland. */ if (unlikely(len == EMBEDDED_NAME_MAX)) len = getname_long(result, filename); if (unlikely(len < 0)) { free_filename(result); return ERR_PTR(len); } initname(result); if (likely(!incomplete)) audit_getname(result); return result;} struct filename *getname_flags(const char __user *filename, int flags){ return do_getname(filename, flags, false);} struct filename *getname_uflags(const char __user *filename, int uflags){ int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; return getname_flags(filename, flags);} struct filename *__getname_maybe_null(const char __user *pathname){ char c; /* try to save on allocations; loss on um, though */ if (get_user(c, pathname)) return ERR_PTR(-EFAULT); if (!c) return NULL; CLASS(filename_flags, name)(pathname, LOOKUP_EMPTY); /* empty pathname translates to NULL */ if (!IS_ERR(name) && !(name->name[0])) return NULL; return no_free_ptr(name);} static struct filename *do_getname_kernel(const char *filename, bool incomplete){ struct filename *result; int len = strlen(filename) + 1; char *p; if (unlikely(len > PATH_MAX)) return ERR_PTR(-ENAMETOOLONG); result = alloc_filename(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); if (len <= EMBEDDED_NAME_MAX) { p = (char *)result->iname; memcpy(p, filename, len); } else { p = kmemdup(filename, len, GFP_KERNEL); if (unlikely(!p)) { free_filename(result); return ERR_PTR(-ENOMEM); } } result->name = p; initname(result); if (likely(!incomplete)) audit_getname(result); return result;} struct filename *getname_kernel(const char *filename){ return do_getname_kernel(filename, false);}EXPORT_SYMBOL(getname_kernel); void putname(struct filename *name){ int refcnt; if (IS_ERR_OR_NULL(name)) return; refcnt = name->refcnt; if (unlikely(refcnt != 1)) { if (WARN_ON_ONCE(!refcnt)) return; name->refcnt--; return; } if (unlikely(name->name != name->iname)) kfree(name->name); free_filename(name);}EXPORT_SYMBOL(putname); static inline int __delayed_getname(struct delayed_filename *v, const char __user *string, int flags){ v->__incomplete_filename = do_getname(string, flags, true); return PTR_ERR_OR_ZERO(v->__incomplete_filename);} int delayed_getname(struct delayed_filename *v, const char __user *string){ return __delayed_getname(v, string, 0);} int delayed_getname_uflags(struct delayed_filename *v, const char __user *string, int uflags){ int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; return __delayed_getname(v, string, flags);} int putname_to_delayed(struct delayed_filename *v, struct filename *name){ if (likely(name->refcnt == 1)) { v->__incomplete_filename = name; return 0; } name->refcnt--; v->__incomplete_filename = do_getname_kernel(name->name, true); return PTR_ERR_OR_ZERO(v->__incomplete_filename);} void dismiss_delayed_filename(struct delayed_filename *v){ putname(no_free_ptr(v->__incomplete_filename));} struct filename *complete_getname(struct delayed_filename *v){ struct filename *res = no_free_ptr(v->__incomplete_filename); if (!IS_ERR(res)) audit_getname(res); return res;} /** * check_acl - perform ACL permission checking * @idmap: idmap of the mount the inode was found from * @inode: inode to check permissions on * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) * * This function performs the ACL permission checking. Since this function * retrieve POSIX acls it needs to know whether it is called from a blocking or * non-blocking context and thus cares about the MAY_NOT_BLOCK bit. * * If the inode has been found through an idmapped mount the idmap of * the vfsmount must be passed through @idmap. This function will then take * care to map the inode according to @idmap before checking permissions. * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */static int check_acl(struct mnt_idmap *idmap, struct inode *inode, int mask){#ifdef CONFIG_FS_POSIX_ACL struct posix_acl *acl; if (mask & MAY_NOT_BLOCK) { acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); if (!acl) return -EAGAIN; /* no ->get_inode_acl() calls in RCU mode... */ if (is_uncached_acl(acl)) return -ECHILD; return posix_acl_permission(idmap, inode, acl, mask); } acl = get_inode_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { int error = posix_acl_permission(idmap, inode, acl, mask); posix_acl_release(acl); return error; }#endif return -EAGAIN;} /* * Very quick optimistic "we know we have no ACL's" check. * * Note that this is purely for ACL_TYPE_ACCESS, and purely * for the "we have cached that there are no ACLs" case. * * If this returns true, we know there are no ACLs. But if * it returns false, we might still not have ACLs (it could * be the is_uncached_acl() case). */static inline bool no_acl_inode(struct inode *inode){#ifdef CONFIG_FS_POSIX_ACL return likely(!READ_ONCE(inode->i_acl));#else return true;#endif} /** * acl_permission_check - perform basic UNIX permission checking * @idmap: idmap of the mount the inode was found from * @inode: inode to check permissions on * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) * * This function performs the basic UNIX permission checking. Since this * function may retrieve POSIX acls it needs to know whether it is called from a * blocking or non-blocking context and thus cares about the MAY_NOT_BLOCK bit. * * If the inode has been found through an idmapped mount the idmap of * the vfsmount must be passed through @idmap. This function will then take * care to map the inode according to @idmap before checking permissions. * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */static int acl_permission_check(struct mnt_idmap *idmap, struct inode *inode, int mask){ unsigned int mode = inode->i_mode; vfsuid_t vfsuid; /* * Common cheap case: everybody has the requested * rights, and there are no ACLs to check. No need * to do any owner/group checks in that case. * * - 'mask&7' is the requested permission bit set * - multiplying by 0111 spreads them out to all of ugo * - '& ~mode' looks for missing inode permission bits * - the '!' is for "no missing permissions" * * After that, we just need to check that there are no * ACL's on the inode - do the 'IS_POSIXACL()' check last * because it will dereference the ->i_sb pointer and we * want to avoid that if at all possible. */ if (!((mask & 7) * 0111 & ~mode)) { if (no_acl_inode(inode)) return 0; if (!IS_POSIXACL(inode)) return 0; } /* Are we the owner? If so, ACL's don't matter */ vfsuid = i_uid_into_vfsuid(idmap, inode); if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) { mask &= 7; mode >>= 6; return (mask & ~mode) ? -EACCES : 0; } /* Do we have ACL's? */ if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { int error = check_acl(idmap, inode, mask); if (error != -EAGAIN) return error; } /* Only RWX matters for group/other mode bits */ mask &= 7; /* * Are the group permissions different from * the other permissions in the bits we care * about? Need to check group ownership if so. */ if (mask & (mode ^ (mode >> 3))) { vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); if (vfsgid_in_group_p(vfsgid)) mode >>= 3; } /* Bits in 'mode' clear that we require? */ return (mask & ~mode) ? -EACCES : 0;} /** * generic_permission - check for access rights on a Posix-like filesystemLines 1–500 of 6581. Load more
// SPDX-License-Identifier: GPL-2.0 /* * linux/fs/namei.c * * Copyright (C) 1991, 1992 Linus Torvalds */ /* * Some corrections by tytso. */ /* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname * lookup logic. */ /* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture. */ #include <linux/init.h> #include <linux/export.h> #include <linux/slab.h> #include <linux/wordpart.h> #include <linux/fs.h> #include <linux/filelock.h> #include <linux/namei.h> #include <linux/pagemap.h> #include <linux/sched/mm.h> #include <linux/fsnotify.h> #include <linux/personality.h> #include <linux/security.h> #include <linux/syscalls.h> #include <linux/mount.h> #include <linux/audit.h> #include <linux/capability.h> #include <linux/file.h> #include <linux/fcntl.h> #include <linux/device_cgroup.h> #include <linux/fs_struct.h> #include <linux/posix_acl.h> #include <linux/hash.h> #include <linux/bitops.h> #include <linux/init_task.h> #include <linux/uaccess.h> #include <asm/runtime-const.h> #include "internal.h" #include "mount.h" /* [Feb-1997 T. Schoebel-Theuer] * Fundamental changes in the pathname lookup mechanisms (namei) * were necessary because of omirr. The reason is that omirr needs * to know the _real_ pathname, not the user-supplied one, in case * of symlinks (and also when transname replacements occur). * * The new code replaces the old recursive symlink resolution with * an iterative one (in case of non-nested symlink chains). It does * this with calls to <fs>_follow_link(). * As a side effect, dir_namei(), _namei() and follow_link() are now * replaced with a single function lookup_dentry() that can handle all * the special cases of the former code. * * With the new dcache, the pathname is stored at each inode, at least as * long as the refcount of the inode is positive. As a side effect, the * size of the dcache depends on the inode cache and thus is dynamic. * * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink * resolution to correspond with current state of the code. * * Note that the symlink resolution is not *completely* iterative. * There is still a significant amount of tail- and mid- recursion in * the algorithm. Also, note that <fs>_readlink() is not used in * lookup_dentry(): lookup_dentry() on the result of <fs>_readlink() * may return different results than <fs>_follow_link(). Many virtual * filesystems (including /proc) exhibit this behavior. */ /* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation: * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL * and the name already exists in form of a symlink, try to create the new * name indicated by the symlink. The old code always complained that the * name already exists, due to not following the symlink even if its target * is nonexistent. The new semantics affects also mknod() and link() when * the name is a symlink pointing to a non-existent name. * * I don't know which semantics is the right one, since I have no access * to standards. But I found by trial that HP-UX 9.0 has the full "new" * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the * "old" one. Personally, I think the new semantics is much more logical. * Note that "ln old new" where "new" is a symlink pointing to a non-existing * file does succeed in both HP-UX and SunOs, but not in Solaris * and in the old Linux semantics. */ /* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink * semantics. See the comments in "open_namei" and "do_link" below. * * [10-Sep-98 Alan Modra] Another symlink change. */ /* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks: * inside the path - always follow. * in the last component in creation/removal/renaming - never follow. * if LOOKUP_FOLLOW passed - follow. * if the pathname has trailing slashes - follow. * otherwise - don't follow. * (applied in that order). * * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT * restored for 2.4. This is the last surviving part of old 4.2BSD bug. * During the 2.4 we need to fix the userland stuff depending on it - * hopefully we will be able to get rid of that wart in 2.5. So far only * XEmacs seems to be relying on it... */ /* * [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland) * implemented. Let's see if raised priority of ->s_vfs_rename_mutex gives * any extra contention... */ /* In order to reduce some races, while at the same time doing additional * checking and hopefully speeding things up, we copy filenames to the * kernel data space before using them.. * * POSIX.1 2.4: an empty pathname is invalid (ENOENT). * PATH_MAX includes the nul terminator --RR. */ /* SLAB cache for struct filename instances */ static struct kmem_cache *__names_cache __ro_after_init; #define names_cache runtime_const_ptr(__names_cache) /* * Type of the last component on LOOKUP_PARENT */ enum last_type {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT}; void __init filename_init(void) { __names_cache = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname), EMBEDDED_NAME_MAX, NULL); runtime_const_init(ptr, __names_cache); } static inline struct filename *alloc_filename(void) { return kmem_cache_alloc(names_cache, GFP_KERNEL); } static inline void free_filename(struct filename *p) { kmem_cache_free(names_cache, p); } static inline void initname(struct filename *name) { name->aname = NULL; name->refcnt = 1; } static int getname_long(struct filename *name, const char __user *filename) { int len; char *p __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL); if (unlikely(!p)) return -ENOMEM; memcpy(p, &name->iname, EMBEDDED_NAME_MAX); len = strncpy_from_user(p + EMBEDDED_NAME_MAX, filename + EMBEDDED_NAME_MAX, PATH_MAX - EMBEDDED_NAME_MAX); if (unlikely(len < 0)) return len; if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX)) return -ENAMETOOLONG; name->name = no_free_ptr(p); return 0; } static struct filename * do_getname(const char __user *filename, int flags, bool incomplete) { struct filename *result; char *kname; int len; result = alloc_filename(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); /* * First, try to embed the struct filename inside the names_cache * allocation */ kname = (char *)result->iname; result->name = kname; len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); /* * Handle both empty path and copy failure in one go. */ if (unlikely(len <= 0)) { /* The empty path is special. */ if (!len && !(flags & LOOKUP_EMPTY)) len = -ENOENT; } /* * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a * separate struct filename so we can dedicate the entire * names_cache allocation for the pathname, and re-do the copy from * userland. */ if (unlikely(len == EMBEDDED_NAME_MAX)) len = getname_long(result, filename); if (unlikely(len < 0)) { free_filename(result); return ERR_PTR(len); } initname(result); if (likely(!incomplete)) audit_getname(result); return result; } struct filename * getname_flags(const char __user *filename, int flags) { return do_getname(filename, flags, false); } struct filename *getname_uflags(const char __user *filename, int uflags) { int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; return getname_flags(filename, flags); } struct filename *__getname_maybe_null(const char __user *pathname) { char c; /* try to save on allocations; loss on um, though */ if (get_user(c, pathname)) return ERR_PTR(-EFAULT); if (!c) return NULL; CLASS(filename_flags, name)(pathname, LOOKUP_EMPTY); /* empty pathname translates to NULL */ if (!IS_ERR(name) && !(name->name[0])) return NULL; return no_free_ptr(name); } static struct filename *do_getname_kernel(const char *filename, bool incomplete) { struct filename *result; int len = strlen(filename) + 1; char *p; if (unlikely(len > PATH_MAX)) return ERR_PTR(-ENAMETOOLONG); result = alloc_filename(); if (unlikely(!result)) return ERR_PTR(-ENOMEM); if (len <= EMBEDDED_NAME_MAX) { p = (char *)result->iname; memcpy(p, filename, len); } else { p = kmemdup(filename, len, GFP_KERNEL); if (unlikely(!p)) { free_filename(result); return ERR_PTR(-ENOMEM); } } result->name = p; initname(result); if (likely(!incomplete)) audit_getname(result); return result; } struct filename *getname_kernel(const char *filename) { return do_getname_kernel(filename, false); } EXPORT_SYMBOL(getname_kernel); void putname(struct filename *name) { int refcnt; if (IS_ERR_OR_NULL(name)) return; refcnt = name->refcnt; if (unlikely(refcnt != 1)) { if (WARN_ON_ONCE(!refcnt)) return; name->refcnt--; return; } if (unlikely(name->name != name->iname)) kfree(name->name); free_filename(name); } EXPORT_SYMBOL(putname); static inline int __delayed_getname(struct delayed_filename *v, const char __user *string, int flags) { v->__incomplete_filename = do_getname(string, flags, true); return PTR_ERR_OR_ZERO(v->__incomplete_filename); } int delayed_getname(struct delayed_filename *v, const char __user *string) { return __delayed_getname(v, string, 0); } int delayed_getname_uflags(struct delayed_filename *v, const char __user *string, int uflags) { int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; return __delayed_getname(v, string, flags); } int putname_to_delayed(struct delayed_filename *v, struct filename *name) { if (likely(name->refcnt == 1)) { v->__incomplete_filename = name; return 0; } name->refcnt--; v->__incomplete_filename = do_getname_kernel(name->name, true); return PTR_ERR_OR_ZERO(v->__incomplete_filename); } void dismiss_delayed_filename(struct delayed_filename *v) { putname(no_free_ptr(v->__incomplete_filename)); } struct filename *complete_getname(struct delayed_filename *v) { struct filename *res = no_free_ptr(v->__incomplete_filename); if (!IS_ERR(res)) audit_getname(res); return res; } /** * check_acl - perform ACL permission checking * @idmap: idmap of the mount the inode was found from * @inode: inode to check permissions on * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) * * This function performs the ACL permission checking. Since this function * retrieve POSIX acls it needs to know whether it is called from a blocking or * non-blocking context and thus cares about the MAY_NOT_BLOCK bit. * * If the inode has been found through an idmapped mount the idmap of * the vfsmount must be passed through @idmap. This function will then take * care to map the inode according to @idmap before checking permissions. * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ static int check_acl(struct mnt_idmap *idmap, struct inode *inode, int mask) { #ifdef CONFIG_FS_POSIX_ACL struct posix_acl *acl; if (mask & MAY_NOT_BLOCK) { acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); if (!acl) return -EAGAIN; /* no ->get_inode_acl() calls in RCU mode... */ if (is_uncached_acl(acl)) return -ECHILD; return posix_acl_permission(idmap, inode, acl, mask); } acl = get_inode_acl(inode, ACL_TYPE_ACCESS); if (IS_ERR(acl)) return PTR_ERR(acl); if (acl) { int error = posix_acl_permission(idmap, inode, acl, mask); posix_acl_release(acl); return error; } #endif return -EAGAIN; } /* * Very quick optimistic "we know we have no ACL's" check. * * Note that this is purely for ACL_TYPE_ACCESS, and purely * for the "we have cached that there are no ACLs" case. * * If this returns true, we know there are no ACLs. But if * it returns false, we might still not have ACLs (it could * be the is_uncached_acl() case). */ static inline bool no_acl_inode(struct inode *inode) { #ifdef CONFIG_FS_POSIX_ACL return likely(!READ_ONCE(inode->i_acl)); #else return true; #endif } /** * acl_permission_check - perform basic UNIX permission checking * @idmap: idmap of the mount the inode was found from * @inode: inode to check permissions on * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) * * This function performs the basic UNIX permission checking. Since this * function may retrieve POSIX acls it needs to know whether it is called from a * blocking or non-blocking context and thus cares about the MAY_NOT_BLOCK bit. * * If the inode has been found through an idmapped mount the idmap of * the vfsmount must be passed through @idmap. This function will then take * care to map the inode according to @idmap before checking permissions. * On non-idmapped mounts or if permission checking is to be performed on the * raw inode simply pass @nop_mnt_idmap. */ static int acl_permission_check(struct mnt_idmap *idmap, struct inode *inode, int mask) { unsigned int mode = inode->i_mode; vfsuid_t vfsuid; /* * Common cheap case: everybody has the requested * rights, and there are no ACLs to check. No need * to do any owner/group checks in that case. * * - 'mask&7' is the requested permission bit set * - multiplying by 0111 spreads them out to all of ugo * - '& ~mode' looks for missing inode permission bits * - the '!' is for "no missing permissions" * * After that, we just need to check that there are no * ACL's on the inode - do the 'IS_POSIXACL()' check last * because it will dereference the ->i_sb pointer and we * want to avoid that if at all possible. */ if (!((mask & 7) * 0111 & ~mode)) { if (no_acl_inode(inode)) return 0; if (!IS_POSIXACL(inode)) return 0; } /* Are we the owner? If so, ACL's don't matter */ vfsuid = i_uid_into_vfsuid(idmap, inode); if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) { mask &= 7; mode >>= 6; return (mask & ~mode) ? -EACCES : 0; } /* Do we have ACL's? */ if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { int error = check_acl(idmap, inode, mask); if (error != -EAGAIN) return error; } /* Only RWX matters for group/other mode bits */ mask &= 7; /* * Are the group permissions different from * the other permissions in the bits we care * about? Need to check group ownership if so. */ if (mask & (mode ^ (mode >> 3))) { vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); if (vfsgid_in_group_p(vfsgid)) mode >>= 3; } /* Bits in 'mode' clear that we require? */ return (mask & ~mode) ? -EACCES : 0; } /** * generic_permission - check for access rights on a Posix-like filesystem