162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/namei.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Some corrections by tytso. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname 1362306a36Sopenharmony_ci * lookup logic. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci/* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/init.h> 1962306a36Sopenharmony_ci#include <linux/export.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/fs.h> 2362306a36Sopenharmony_ci#include <linux/filelock.h> 2462306a36Sopenharmony_ci#include <linux/namei.h> 2562306a36Sopenharmony_ci#include <linux/pagemap.h> 2662306a36Sopenharmony_ci#include <linux/sched/mm.h> 2762306a36Sopenharmony_ci#include <linux/fsnotify.h> 2862306a36Sopenharmony_ci#include <linux/personality.h> 2962306a36Sopenharmony_ci#include <linux/security.h> 3062306a36Sopenharmony_ci#include <linux/ima.h> 3162306a36Sopenharmony_ci#include <linux/syscalls.h> 3262306a36Sopenharmony_ci#include <linux/mount.h> 3362306a36Sopenharmony_ci#include <linux/audit.h> 3462306a36Sopenharmony_ci#include <linux/capability.h> 3562306a36Sopenharmony_ci#include <linux/file.h> 3662306a36Sopenharmony_ci#include <linux/fcntl.h> 3762306a36Sopenharmony_ci#include <linux/device_cgroup.h> 3862306a36Sopenharmony_ci#include <linux/fs_struct.h> 3962306a36Sopenharmony_ci#include <linux/posix_acl.h> 4062306a36Sopenharmony_ci#include <linux/hash.h> 4162306a36Sopenharmony_ci#include <linux/bitops.h> 4262306a36Sopenharmony_ci#include <linux/init_task.h> 4362306a36Sopenharmony_ci#include <linux/uaccess.h> 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#include "internal.h" 4662306a36Sopenharmony_ci#include "mount.h" 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* [Feb-1997 T. Schoebel-Theuer] 4962306a36Sopenharmony_ci * Fundamental changes in the pathname lookup mechanisms (namei) 5062306a36Sopenharmony_ci * were necessary because of omirr. The reason is that omirr needs 5162306a36Sopenharmony_ci * to know the _real_ pathname, not the user-supplied one, in case 5262306a36Sopenharmony_ci * of symlinks (and also when transname replacements occur). 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * The new code replaces the old recursive symlink resolution with 5562306a36Sopenharmony_ci * an iterative one (in case of non-nested symlink chains). It does 5662306a36Sopenharmony_ci * this with calls to <fs>_follow_link(). 5762306a36Sopenharmony_ci * As a side effect, dir_namei(), _namei() and follow_link() are now 5862306a36Sopenharmony_ci * replaced with a single function lookup_dentry() that can handle all 5962306a36Sopenharmony_ci * the special cases of the former code. 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * With the new dcache, the pathname is stored at each inode, at least as 6262306a36Sopenharmony_ci * long as the refcount of the inode is positive. As a side effect, the 6362306a36Sopenharmony_ci * size of the dcache depends on the inode cache and thus is dynamic. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink 6662306a36Sopenharmony_ci * resolution to correspond with current state of the code. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * Note that the symlink resolution is not *completely* iterative. 6962306a36Sopenharmony_ci * There is still a significant amount of tail- and mid- recursion in 7062306a36Sopenharmony_ci * the algorithm. Also, note that <fs>_readlink() is not used in 7162306a36Sopenharmony_ci * lookup_dentry(): lookup_dentry() on the result of <fs>_readlink() 7262306a36Sopenharmony_ci * may return different results than <fs>_follow_link(). Many virtual 7362306a36Sopenharmony_ci * filesystems (including /proc) exhibit this behavior. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation: 7762306a36Sopenharmony_ci * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL 7862306a36Sopenharmony_ci * and the name already exists in form of a symlink, try to create the new 7962306a36Sopenharmony_ci * name indicated by the symlink. The old code always complained that the 8062306a36Sopenharmony_ci * name already exists, due to not following the symlink even if its target 8162306a36Sopenharmony_ci * is nonexistent. The new semantics affects also mknod() and link() when 8262306a36Sopenharmony_ci * the name is a symlink pointing to a non-existent name. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * I don't know which semantics is the right one, since I have no access 8562306a36Sopenharmony_ci * to standards. But I found by trial that HP-UX 9.0 has the full "new" 8662306a36Sopenharmony_ci * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the 8762306a36Sopenharmony_ci * "old" one. Personally, I think the new semantics is much more logical. 8862306a36Sopenharmony_ci * Note that "ln old new" where "new" is a symlink pointing to a non-existing 8962306a36Sopenharmony_ci * file does succeed in both HP-UX and SunOs, but not in Solaris 9062306a36Sopenharmony_ci * and in the old Linux semantics. 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink 9462306a36Sopenharmony_ci * semantics. See the comments in "open_namei" and "do_link" below. 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * [10-Sep-98 Alan Modra] Another symlink change. 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks: 10062306a36Sopenharmony_ci * inside the path - always follow. 10162306a36Sopenharmony_ci * in the last component in creation/removal/renaming - never follow. 10262306a36Sopenharmony_ci * if LOOKUP_FOLLOW passed - follow. 10362306a36Sopenharmony_ci * if the pathname has trailing slashes - follow. 10462306a36Sopenharmony_ci * otherwise - don't follow. 10562306a36Sopenharmony_ci * (applied in that order). 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT 10862306a36Sopenharmony_ci * restored for 2.4. This is the last surviving part of old 4.2BSD bug. 10962306a36Sopenharmony_ci * During the 2.4 we need to fix the userland stuff depending on it - 11062306a36Sopenharmony_ci * hopefully we will be able to get rid of that wart in 2.5. So far only 11162306a36Sopenharmony_ci * XEmacs seems to be relying on it... 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland) 11562306a36Sopenharmony_ci * implemented. Let's see if raised priority of ->s_vfs_rename_mutex gives 11662306a36Sopenharmony_ci * any extra contention... 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci/* In order to reduce some races, while at the same time doing additional 12062306a36Sopenharmony_ci * checking and hopefully speeding things up, we copy filenames to the 12162306a36Sopenharmony_ci * kernel data space before using them.. 12262306a36Sopenharmony_ci * 12362306a36Sopenharmony_ci * POSIX.1 2.4: an empty pathname is invalid (ENOENT). 12462306a36Sopenharmony_ci * PATH_MAX includes the nul terminator --RR. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname)) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistruct filename * 13062306a36Sopenharmony_cigetname_flags(const char __user *filename, int flags, int *empty) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct filename *result; 13362306a36Sopenharmony_ci char *kname; 13462306a36Sopenharmony_ci int len; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci result = audit_reusename(filename); 13762306a36Sopenharmony_ci if (result) 13862306a36Sopenharmony_ci return result; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci result = __getname(); 14162306a36Sopenharmony_ci if (unlikely(!result)) 14262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * First, try to embed the struct filename inside the names_cache 14662306a36Sopenharmony_ci * allocation 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci kname = (char *)result->iname; 14962306a36Sopenharmony_ci result->name = kname; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); 15262306a36Sopenharmony_ci if (unlikely(len < 0)) { 15362306a36Sopenharmony_ci __putname(result); 15462306a36Sopenharmony_ci return ERR_PTR(len); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* 15862306a36Sopenharmony_ci * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a 15962306a36Sopenharmony_ci * separate struct filename so we can dedicate the entire 16062306a36Sopenharmony_ci * names_cache allocation for the pathname, and re-do the copy from 16162306a36Sopenharmony_ci * userland. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_ci if (unlikely(len == EMBEDDED_NAME_MAX)) { 16462306a36Sopenharmony_ci const size_t size = offsetof(struct filename, iname[1]); 16562306a36Sopenharmony_ci kname = (char *)result; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * size is chosen that way we to guarantee that 16962306a36Sopenharmony_ci * result->iname[0] is within the same object and that 17062306a36Sopenharmony_ci * kname can't be equal to result->iname, no matter what. 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci result = kzalloc(size, GFP_KERNEL); 17362306a36Sopenharmony_ci if (unlikely(!result)) { 17462306a36Sopenharmony_ci __putname(kname); 17562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci result->name = kname; 17862306a36Sopenharmony_ci len = strncpy_from_user(kname, filename, PATH_MAX); 17962306a36Sopenharmony_ci if (unlikely(len < 0)) { 18062306a36Sopenharmony_ci __putname(kname); 18162306a36Sopenharmony_ci kfree(result); 18262306a36Sopenharmony_ci return ERR_PTR(len); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci if (unlikely(len == PATH_MAX)) { 18562306a36Sopenharmony_ci __putname(kname); 18662306a36Sopenharmony_ci kfree(result); 18762306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci atomic_set(&result->refcnt, 1); 19262306a36Sopenharmony_ci /* The empty path is special. */ 19362306a36Sopenharmony_ci if (unlikely(!len)) { 19462306a36Sopenharmony_ci if (empty) 19562306a36Sopenharmony_ci *empty = 1; 19662306a36Sopenharmony_ci if (!(flags & LOOKUP_EMPTY)) { 19762306a36Sopenharmony_ci putname(result); 19862306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci result->uptr = filename; 20362306a36Sopenharmony_ci result->aname = NULL; 20462306a36Sopenharmony_ci audit_getname(result); 20562306a36Sopenharmony_ci return result; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistruct filename * 20962306a36Sopenharmony_cigetname_uflags(const char __user *filename, int uflags) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci int flags = (uflags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return getname_flags(filename, flags, NULL); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistruct filename * 21762306a36Sopenharmony_cigetname(const char __user * filename) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci return getname_flags(filename, 0, NULL); 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistruct filename * 22362306a36Sopenharmony_cigetname_kernel(const char * filename) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct filename *result; 22662306a36Sopenharmony_ci int len = strlen(filename) + 1; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci result = __getname(); 22962306a36Sopenharmony_ci if (unlikely(!result)) 23062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (len <= EMBEDDED_NAME_MAX) { 23362306a36Sopenharmony_ci result->name = (char *)result->iname; 23462306a36Sopenharmony_ci } else if (len <= PATH_MAX) { 23562306a36Sopenharmony_ci const size_t size = offsetof(struct filename, iname[1]); 23662306a36Sopenharmony_ci struct filename *tmp; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci tmp = kmalloc(size, GFP_KERNEL); 23962306a36Sopenharmony_ci if (unlikely(!tmp)) { 24062306a36Sopenharmony_ci __putname(result); 24162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci tmp->name = (char *)result; 24462306a36Sopenharmony_ci result = tmp; 24562306a36Sopenharmony_ci } else { 24662306a36Sopenharmony_ci __putname(result); 24762306a36Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci memcpy((char *)result->name, filename, len); 25062306a36Sopenharmony_ci result->uptr = NULL; 25162306a36Sopenharmony_ci result->aname = NULL; 25262306a36Sopenharmony_ci atomic_set(&result->refcnt, 1); 25362306a36Sopenharmony_ci audit_getname(result); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci return result; 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ciEXPORT_SYMBOL(getname_kernel); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid putname(struct filename *name) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci if (IS_ERR(name)) 26262306a36Sopenharmony_ci return; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (WARN_ON_ONCE(!atomic_read(&name->refcnt))) 26562306a36Sopenharmony_ci return; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (!atomic_dec_and_test(&name->refcnt)) 26862306a36Sopenharmony_ci return; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (name->name != name->iname) { 27162306a36Sopenharmony_ci __putname(name->name); 27262306a36Sopenharmony_ci kfree(name); 27362306a36Sopenharmony_ci } else 27462306a36Sopenharmony_ci __putname(name); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ciEXPORT_SYMBOL(putname); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/** 27962306a36Sopenharmony_ci * check_acl - perform ACL permission checking 28062306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 28162306a36Sopenharmony_ci * @inode: inode to check permissions on 28262306a36Sopenharmony_ci * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) 28362306a36Sopenharmony_ci * 28462306a36Sopenharmony_ci * This function performs the ACL permission checking. Since this function 28562306a36Sopenharmony_ci * retrieve POSIX acls it needs to know whether it is called from a blocking or 28662306a36Sopenharmony_ci * non-blocking context and thus cares about the MAY_NOT_BLOCK bit. 28762306a36Sopenharmony_ci * 28862306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 28962306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 29062306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 29162306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 29262306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 29362306a36Sopenharmony_ci */ 29462306a36Sopenharmony_cistatic int check_acl(struct mnt_idmap *idmap, 29562306a36Sopenharmony_ci struct inode *inode, int mask) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci#ifdef CONFIG_FS_POSIX_ACL 29862306a36Sopenharmony_ci struct posix_acl *acl; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (mask & MAY_NOT_BLOCK) { 30162306a36Sopenharmony_ci acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); 30262306a36Sopenharmony_ci if (!acl) 30362306a36Sopenharmony_ci return -EAGAIN; 30462306a36Sopenharmony_ci /* no ->get_inode_acl() calls in RCU mode... */ 30562306a36Sopenharmony_ci if (is_uncached_acl(acl)) 30662306a36Sopenharmony_ci return -ECHILD; 30762306a36Sopenharmony_ci return posix_acl_permission(idmap, inode, acl, mask); 30862306a36Sopenharmony_ci } 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci acl = get_inode_acl(inode, ACL_TYPE_ACCESS); 31162306a36Sopenharmony_ci if (IS_ERR(acl)) 31262306a36Sopenharmony_ci return PTR_ERR(acl); 31362306a36Sopenharmony_ci if (acl) { 31462306a36Sopenharmony_ci int error = posix_acl_permission(idmap, inode, acl, mask); 31562306a36Sopenharmony_ci posix_acl_release(acl); 31662306a36Sopenharmony_ci return error; 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci#endif 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return -EAGAIN; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci/** 32462306a36Sopenharmony_ci * acl_permission_check - perform basic UNIX permission checking 32562306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 32662306a36Sopenharmony_ci * @inode: inode to check permissions on 32762306a36Sopenharmony_ci * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * This function performs the basic UNIX permission checking. Since this 33062306a36Sopenharmony_ci * function may retrieve POSIX acls it needs to know whether it is called from a 33162306a36Sopenharmony_ci * blocking or non-blocking context and thus cares about the MAY_NOT_BLOCK bit. 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 33462306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 33562306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 33662306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 33762306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_cistatic int acl_permission_check(struct mnt_idmap *idmap, 34062306a36Sopenharmony_ci struct inode *inode, int mask) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci unsigned int mode = inode->i_mode; 34362306a36Sopenharmony_ci vfsuid_t vfsuid; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* Are we the owner? If so, ACL's don't matter */ 34662306a36Sopenharmony_ci vfsuid = i_uid_into_vfsuid(idmap, inode); 34762306a36Sopenharmony_ci if (likely(vfsuid_eq_kuid(vfsuid, current_fsuid()))) { 34862306a36Sopenharmony_ci mask &= 7; 34962306a36Sopenharmony_ci mode >>= 6; 35062306a36Sopenharmony_ci return (mask & ~mode) ? -EACCES : 0; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci /* Do we have ACL's? */ 35462306a36Sopenharmony_ci if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { 35562306a36Sopenharmony_ci int error = check_acl(idmap, inode, mask); 35662306a36Sopenharmony_ci if (error != -EAGAIN) 35762306a36Sopenharmony_ci return error; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* Only RWX matters for group/other mode bits */ 36162306a36Sopenharmony_ci mask &= 7; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * Are the group permissions different from 36562306a36Sopenharmony_ci * the other permissions in the bits we care 36662306a36Sopenharmony_ci * about? Need to check group ownership if so. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci if (mask & (mode ^ (mode >> 3))) { 36962306a36Sopenharmony_ci vfsgid_t vfsgid = i_gid_into_vfsgid(idmap, inode); 37062306a36Sopenharmony_ci if (vfsgid_in_group_p(vfsgid)) 37162306a36Sopenharmony_ci mode >>= 3; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Bits in 'mode' clear that we require? */ 37562306a36Sopenharmony_ci return (mask & ~mode) ? -EACCES : 0; 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci/** 37962306a36Sopenharmony_ci * generic_permission - check for access rights on a Posix-like filesystem 38062306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 38162306a36Sopenharmony_ci * @inode: inode to check access rights for 38262306a36Sopenharmony_ci * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, 38362306a36Sopenharmony_ci * %MAY_NOT_BLOCK ...) 38462306a36Sopenharmony_ci * 38562306a36Sopenharmony_ci * Used to check for read/write/execute permissions on a file. 38662306a36Sopenharmony_ci * We use "fsuid" for this, letting us set arbitrary permissions 38762306a36Sopenharmony_ci * for filesystem access without changing the "normal" uids which 38862306a36Sopenharmony_ci * are used for other things. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk 39162306a36Sopenharmony_ci * request cannot be satisfied (eg. requires blocking or too much complexity). 39262306a36Sopenharmony_ci * It would then be called again in ref-walk mode. 39362306a36Sopenharmony_ci * 39462306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 39562306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 39662306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 39762306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 39862306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ciint generic_permission(struct mnt_idmap *idmap, struct inode *inode, 40162306a36Sopenharmony_ci int mask) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci int ret; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* 40662306a36Sopenharmony_ci * Do the basic permission checks. 40762306a36Sopenharmony_ci */ 40862306a36Sopenharmony_ci ret = acl_permission_check(idmap, inode, mask); 40962306a36Sopenharmony_ci if (ret != -EACCES) 41062306a36Sopenharmony_ci return ret; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 41362306a36Sopenharmony_ci /* DACs are overridable for directories */ 41462306a36Sopenharmony_ci if (!(mask & MAY_WRITE)) 41562306a36Sopenharmony_ci if (capable_wrt_inode_uidgid(idmap, inode, 41662306a36Sopenharmony_ci CAP_DAC_READ_SEARCH)) 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci if (capable_wrt_inode_uidgid(idmap, inode, 41962306a36Sopenharmony_ci CAP_DAC_OVERRIDE)) 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci return -EACCES; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* 42562306a36Sopenharmony_ci * Searching includes executable on directories, else just read. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci mask &= MAY_READ | MAY_WRITE | MAY_EXEC; 42862306a36Sopenharmony_ci if (mask == MAY_READ) 42962306a36Sopenharmony_ci if (capable_wrt_inode_uidgid(idmap, inode, 43062306a36Sopenharmony_ci CAP_DAC_READ_SEARCH)) 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci /* 43362306a36Sopenharmony_ci * Read/write DACs are always overridable. 43462306a36Sopenharmony_ci * Executable DACs are overridable when there is 43562306a36Sopenharmony_ci * at least one exec bit set. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) 43862306a36Sopenharmony_ci if (capable_wrt_inode_uidgid(idmap, inode, 43962306a36Sopenharmony_ci CAP_DAC_OVERRIDE)) 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return -EACCES; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ciEXPORT_SYMBOL(generic_permission); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/** 44762306a36Sopenharmony_ci * do_inode_permission - UNIX permission checking 44862306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 44962306a36Sopenharmony_ci * @inode: inode to check permissions on 45062306a36Sopenharmony_ci * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC ...) 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * We _really_ want to just do "generic_permission()" without 45362306a36Sopenharmony_ci * even looking at the inode->i_op values. So we keep a cache 45462306a36Sopenharmony_ci * flag in inode->i_opflags, that says "this has not special 45562306a36Sopenharmony_ci * permission function, use the fast case". 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_cistatic inline int do_inode_permission(struct mnt_idmap *idmap, 45862306a36Sopenharmony_ci struct inode *inode, int mask) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { 46162306a36Sopenharmony_ci if (likely(inode->i_op->permission)) 46262306a36Sopenharmony_ci return inode->i_op->permission(idmap, inode, mask); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* This gets set once for the inode lifetime */ 46562306a36Sopenharmony_ci spin_lock(&inode->i_lock); 46662306a36Sopenharmony_ci inode->i_opflags |= IOP_FASTPERM; 46762306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci return generic_permission(idmap, inode, mask); 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci/** 47362306a36Sopenharmony_ci * sb_permission - Check superblock-level permissions 47462306a36Sopenharmony_ci * @sb: Superblock of inode to check permission on 47562306a36Sopenharmony_ci * @inode: Inode to check permission on 47662306a36Sopenharmony_ci * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) 47762306a36Sopenharmony_ci * 47862306a36Sopenharmony_ci * Separate out file-system wide checks from inode-specific permission checks. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic int sb_permission(struct super_block *sb, struct inode *inode, int mask) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci if (unlikely(mask & MAY_WRITE)) { 48362306a36Sopenharmony_ci umode_t mode = inode->i_mode; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* Nobody gets write access to a read-only fs. */ 48662306a36Sopenharmony_ci if (sb_rdonly(sb) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) 48762306a36Sopenharmony_ci return -EROFS; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/** 49362306a36Sopenharmony_ci * inode_permission - Check for access rights to a given inode 49462306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 49562306a36Sopenharmony_ci * @inode: Inode to check permission on 49662306a36Sopenharmony_ci * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) 49762306a36Sopenharmony_ci * 49862306a36Sopenharmony_ci * Check for read/write/execute permissions on an inode. We use fs[ug]id for 49962306a36Sopenharmony_ci * this, letting us set arbitrary permissions for filesystem access without 50062306a36Sopenharmony_ci * changing the "normal" UIDs which are used for other things. 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ciint inode_permission(struct mnt_idmap *idmap, 50562306a36Sopenharmony_ci struct inode *inode, int mask) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci int retval; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci retval = sb_permission(inode->i_sb, inode, mask); 51062306a36Sopenharmony_ci if (retval) 51162306a36Sopenharmony_ci return retval; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (unlikely(mask & MAY_WRITE)) { 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * Nobody gets write access to an immutable file. 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_ci if (IS_IMMUTABLE(inode)) 51862306a36Sopenharmony_ci return -EPERM; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* 52162306a36Sopenharmony_ci * Updating mtime will likely cause i_uid and i_gid to be 52262306a36Sopenharmony_ci * written back improperly if their true value is unknown 52362306a36Sopenharmony_ci * to the vfs. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci if (HAS_UNMAPPED_ID(idmap, inode)) 52662306a36Sopenharmony_ci return -EACCES; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci retval = do_inode_permission(idmap, inode, mask); 53062306a36Sopenharmony_ci if (retval) 53162306a36Sopenharmony_ci return retval; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci retval = devcgroup_inode_permission(inode, mask); 53462306a36Sopenharmony_ci if (retval) 53562306a36Sopenharmony_ci return retval; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return security_inode_permission(inode, mask); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ciEXPORT_SYMBOL(inode_permission); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci/** 54262306a36Sopenharmony_ci * path_get - get a reference to a path 54362306a36Sopenharmony_ci * @path: path to get the reference to 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * Given a path increment the reference count to the dentry and the vfsmount. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_civoid path_get(const struct path *path) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci mntget(path->mnt); 55062306a36Sopenharmony_ci dget(path->dentry); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ciEXPORT_SYMBOL(path_get); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci/** 55562306a36Sopenharmony_ci * path_put - put a reference to a path 55662306a36Sopenharmony_ci * @path: path to put the reference to 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * Given a path decrement the reference count to the dentry and the vfsmount. 55962306a36Sopenharmony_ci */ 56062306a36Sopenharmony_civoid path_put(const struct path *path) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci dput(path->dentry); 56362306a36Sopenharmony_ci mntput(path->mnt); 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ciEXPORT_SYMBOL(path_put); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci#define EMBEDDED_LEVELS 2 56862306a36Sopenharmony_cistruct nameidata { 56962306a36Sopenharmony_ci struct path path; 57062306a36Sopenharmony_ci struct qstr last; 57162306a36Sopenharmony_ci struct path root; 57262306a36Sopenharmony_ci struct inode *inode; /* path.dentry.d_inode */ 57362306a36Sopenharmony_ci unsigned int flags, state; 57462306a36Sopenharmony_ci unsigned seq, next_seq, m_seq, r_seq; 57562306a36Sopenharmony_ci int last_type; 57662306a36Sopenharmony_ci unsigned depth; 57762306a36Sopenharmony_ci int total_link_count; 57862306a36Sopenharmony_ci struct saved { 57962306a36Sopenharmony_ci struct path link; 58062306a36Sopenharmony_ci struct delayed_call done; 58162306a36Sopenharmony_ci const char *name; 58262306a36Sopenharmony_ci unsigned seq; 58362306a36Sopenharmony_ci } *stack, internal[EMBEDDED_LEVELS]; 58462306a36Sopenharmony_ci struct filename *name; 58562306a36Sopenharmony_ci struct nameidata *saved; 58662306a36Sopenharmony_ci unsigned root_seq; 58762306a36Sopenharmony_ci int dfd; 58862306a36Sopenharmony_ci vfsuid_t dir_vfsuid; 58962306a36Sopenharmony_ci umode_t dir_mode; 59062306a36Sopenharmony_ci} __randomize_layout; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci#define ND_ROOT_PRESET 1 59362306a36Sopenharmony_ci#define ND_ROOT_GRABBED 2 59462306a36Sopenharmony_ci#define ND_JUMPED 4 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_cistatic void __set_nameidata(struct nameidata *p, int dfd, struct filename *name) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct nameidata *old = current->nameidata; 59962306a36Sopenharmony_ci p->stack = p->internal; 60062306a36Sopenharmony_ci p->depth = 0; 60162306a36Sopenharmony_ci p->dfd = dfd; 60262306a36Sopenharmony_ci p->name = name; 60362306a36Sopenharmony_ci p->path.mnt = NULL; 60462306a36Sopenharmony_ci p->path.dentry = NULL; 60562306a36Sopenharmony_ci p->total_link_count = old ? old->total_link_count : 0; 60662306a36Sopenharmony_ci p->saved = old; 60762306a36Sopenharmony_ci current->nameidata = p; 60862306a36Sopenharmony_ci} 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_cistatic inline void set_nameidata(struct nameidata *p, int dfd, struct filename *name, 61162306a36Sopenharmony_ci const struct path *root) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci __set_nameidata(p, dfd, name); 61462306a36Sopenharmony_ci p->state = 0; 61562306a36Sopenharmony_ci if (unlikely(root)) { 61662306a36Sopenharmony_ci p->state = ND_ROOT_PRESET; 61762306a36Sopenharmony_ci p->root = *root; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic void restore_nameidata(void) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct nameidata *now = current->nameidata, *old = now->saved; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci current->nameidata = old; 62662306a36Sopenharmony_ci if (old) 62762306a36Sopenharmony_ci old->total_link_count = now->total_link_count; 62862306a36Sopenharmony_ci if (now->stack != now->internal) 62962306a36Sopenharmony_ci kfree(now->stack); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic bool nd_alloc_stack(struct nameidata *nd) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct saved *p; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci p= kmalloc_array(MAXSYMLINKS, sizeof(struct saved), 63762306a36Sopenharmony_ci nd->flags & LOOKUP_RCU ? GFP_ATOMIC : GFP_KERNEL); 63862306a36Sopenharmony_ci if (unlikely(!p)) 63962306a36Sopenharmony_ci return false; 64062306a36Sopenharmony_ci memcpy(p, nd->internal, sizeof(nd->internal)); 64162306a36Sopenharmony_ci nd->stack = p; 64262306a36Sopenharmony_ci return true; 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci/** 64662306a36Sopenharmony_ci * path_connected - Verify that a dentry is below mnt.mnt_root 64762306a36Sopenharmony_ci * @mnt: The mountpoint to check. 64862306a36Sopenharmony_ci * @dentry: The dentry to check. 64962306a36Sopenharmony_ci * 65062306a36Sopenharmony_ci * Rename can sometimes move a file or directory outside of a bind 65162306a36Sopenharmony_ci * mount, path_connected allows those cases to be detected. 65262306a36Sopenharmony_ci */ 65362306a36Sopenharmony_cistatic bool path_connected(struct vfsmount *mnt, struct dentry *dentry) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct super_block *sb = mnt->mnt_sb; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Bind mounts can have disconnected paths */ 65862306a36Sopenharmony_ci if (mnt->mnt_root == sb->s_root) 65962306a36Sopenharmony_ci return true; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci return is_subdir(dentry, mnt->mnt_root); 66262306a36Sopenharmony_ci} 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_cistatic void drop_links(struct nameidata *nd) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci int i = nd->depth; 66762306a36Sopenharmony_ci while (i--) { 66862306a36Sopenharmony_ci struct saved *last = nd->stack + i; 66962306a36Sopenharmony_ci do_delayed_call(&last->done); 67062306a36Sopenharmony_ci clear_delayed_call(&last->done); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic void leave_rcu(struct nameidata *nd) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci nd->flags &= ~LOOKUP_RCU; 67762306a36Sopenharmony_ci nd->seq = nd->next_seq = 0; 67862306a36Sopenharmony_ci rcu_read_unlock(); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic void terminate_walk(struct nameidata *nd) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci drop_links(nd); 68462306a36Sopenharmony_ci if (!(nd->flags & LOOKUP_RCU)) { 68562306a36Sopenharmony_ci int i; 68662306a36Sopenharmony_ci path_put(&nd->path); 68762306a36Sopenharmony_ci for (i = 0; i < nd->depth; i++) 68862306a36Sopenharmony_ci path_put(&nd->stack[i].link); 68962306a36Sopenharmony_ci if (nd->state & ND_ROOT_GRABBED) { 69062306a36Sopenharmony_ci path_put(&nd->root); 69162306a36Sopenharmony_ci nd->state &= ~ND_ROOT_GRABBED; 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci } else { 69462306a36Sopenharmony_ci leave_rcu(nd); 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci nd->depth = 0; 69762306a36Sopenharmony_ci nd->path.mnt = NULL; 69862306a36Sopenharmony_ci nd->path.dentry = NULL; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci/* path_put is needed afterwards regardless of success or failure */ 70262306a36Sopenharmony_cistatic bool __legitimize_path(struct path *path, unsigned seq, unsigned mseq) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci int res = __legitimize_mnt(path->mnt, mseq); 70562306a36Sopenharmony_ci if (unlikely(res)) { 70662306a36Sopenharmony_ci if (res > 0) 70762306a36Sopenharmony_ci path->mnt = NULL; 70862306a36Sopenharmony_ci path->dentry = NULL; 70962306a36Sopenharmony_ci return false; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci if (unlikely(!lockref_get_not_dead(&path->dentry->d_lockref))) { 71262306a36Sopenharmony_ci path->dentry = NULL; 71362306a36Sopenharmony_ci return false; 71462306a36Sopenharmony_ci } 71562306a36Sopenharmony_ci return !read_seqcount_retry(&path->dentry->d_seq, seq); 71662306a36Sopenharmony_ci} 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_cistatic inline bool legitimize_path(struct nameidata *nd, 71962306a36Sopenharmony_ci struct path *path, unsigned seq) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci return __legitimize_path(path, seq, nd->m_seq); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic bool legitimize_links(struct nameidata *nd) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci int i; 72762306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_CACHED)) { 72862306a36Sopenharmony_ci drop_links(nd); 72962306a36Sopenharmony_ci nd->depth = 0; 73062306a36Sopenharmony_ci return false; 73162306a36Sopenharmony_ci } 73262306a36Sopenharmony_ci for (i = 0; i < nd->depth; i++) { 73362306a36Sopenharmony_ci struct saved *last = nd->stack + i; 73462306a36Sopenharmony_ci if (unlikely(!legitimize_path(nd, &last->link, last->seq))) { 73562306a36Sopenharmony_ci drop_links(nd); 73662306a36Sopenharmony_ci nd->depth = i + 1; 73762306a36Sopenharmony_ci return false; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci } 74062306a36Sopenharmony_ci return true; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic bool legitimize_root(struct nameidata *nd) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci /* Nothing to do if nd->root is zero or is managed by the VFS user. */ 74662306a36Sopenharmony_ci if (!nd->root.mnt || (nd->state & ND_ROOT_PRESET)) 74762306a36Sopenharmony_ci return true; 74862306a36Sopenharmony_ci nd->state |= ND_ROOT_GRABBED; 74962306a36Sopenharmony_ci return legitimize_path(nd, &nd->root, nd->root_seq); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci/* 75362306a36Sopenharmony_ci * Path walking has 2 modes, rcu-walk and ref-walk (see 75462306a36Sopenharmony_ci * Documentation/filesystems/path-lookup.txt). In situations when we can't 75562306a36Sopenharmony_ci * continue in RCU mode, we attempt to drop out of rcu-walk mode and grab 75662306a36Sopenharmony_ci * normal reference counts on dentries and vfsmounts to transition to ref-walk 75762306a36Sopenharmony_ci * mode. Refcounts are grabbed at the last known good point before rcu-walk 75862306a36Sopenharmony_ci * got stuck, so ref-walk may continue from there. If this is not successful 75962306a36Sopenharmony_ci * (eg. a seqcount has changed), then failure is returned and it's up to caller 76062306a36Sopenharmony_ci * to restart the path walk from the beginning in ref-walk mode. 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/** 76462306a36Sopenharmony_ci * try_to_unlazy - try to switch to ref-walk mode. 76562306a36Sopenharmony_ci * @nd: nameidata pathwalk data 76662306a36Sopenharmony_ci * Returns: true on success, false on failure 76762306a36Sopenharmony_ci * 76862306a36Sopenharmony_ci * try_to_unlazy attempts to legitimize the current nd->path and nd->root 76962306a36Sopenharmony_ci * for ref-walk mode. 77062306a36Sopenharmony_ci * Must be called from rcu-walk context. 77162306a36Sopenharmony_ci * Nothing should touch nameidata between try_to_unlazy() failure and 77262306a36Sopenharmony_ci * terminate_walk(). 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_cistatic bool try_to_unlazy(struct nameidata *nd) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct dentry *parent = nd->path.dentry; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci BUG_ON(!(nd->flags & LOOKUP_RCU)); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (unlikely(!legitimize_links(nd))) 78162306a36Sopenharmony_ci goto out1; 78262306a36Sopenharmony_ci if (unlikely(!legitimize_path(nd, &nd->path, nd->seq))) 78362306a36Sopenharmony_ci goto out; 78462306a36Sopenharmony_ci if (unlikely(!legitimize_root(nd))) 78562306a36Sopenharmony_ci goto out; 78662306a36Sopenharmony_ci leave_rcu(nd); 78762306a36Sopenharmony_ci BUG_ON(nd->inode != parent->d_inode); 78862306a36Sopenharmony_ci return true; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ciout1: 79162306a36Sopenharmony_ci nd->path.mnt = NULL; 79262306a36Sopenharmony_ci nd->path.dentry = NULL; 79362306a36Sopenharmony_ciout: 79462306a36Sopenharmony_ci leave_rcu(nd); 79562306a36Sopenharmony_ci return false; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci/** 79962306a36Sopenharmony_ci * try_to_unlazy_next - try to switch to ref-walk mode. 80062306a36Sopenharmony_ci * @nd: nameidata pathwalk data 80162306a36Sopenharmony_ci * @dentry: next dentry to step into 80262306a36Sopenharmony_ci * Returns: true on success, false on failure 80362306a36Sopenharmony_ci * 80462306a36Sopenharmony_ci * Similar to try_to_unlazy(), but here we have the next dentry already 80562306a36Sopenharmony_ci * picked by rcu-walk and want to legitimize that in addition to the current 80662306a36Sopenharmony_ci * nd->path and nd->root for ref-walk mode. Must be called from rcu-walk context. 80762306a36Sopenharmony_ci * Nothing should touch nameidata between try_to_unlazy_next() failure and 80862306a36Sopenharmony_ci * terminate_walk(). 80962306a36Sopenharmony_ci */ 81062306a36Sopenharmony_cistatic bool try_to_unlazy_next(struct nameidata *nd, struct dentry *dentry) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci int res; 81362306a36Sopenharmony_ci BUG_ON(!(nd->flags & LOOKUP_RCU)); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (unlikely(!legitimize_links(nd))) 81662306a36Sopenharmony_ci goto out2; 81762306a36Sopenharmony_ci res = __legitimize_mnt(nd->path.mnt, nd->m_seq); 81862306a36Sopenharmony_ci if (unlikely(res)) { 81962306a36Sopenharmony_ci if (res > 0) 82062306a36Sopenharmony_ci goto out2; 82162306a36Sopenharmony_ci goto out1; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci if (unlikely(!lockref_get_not_dead(&nd->path.dentry->d_lockref))) 82462306a36Sopenharmony_ci goto out1; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* 82762306a36Sopenharmony_ci * We need to move both the parent and the dentry from the RCU domain 82862306a36Sopenharmony_ci * to be properly refcounted. And the sequence number in the dentry 82962306a36Sopenharmony_ci * validates *both* dentry counters, since we checked the sequence 83062306a36Sopenharmony_ci * number of the parent after we got the child sequence number. So we 83162306a36Sopenharmony_ci * know the parent must still be valid if the child sequence number is 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci if (unlikely(!lockref_get_not_dead(&dentry->d_lockref))) 83462306a36Sopenharmony_ci goto out; 83562306a36Sopenharmony_ci if (read_seqcount_retry(&dentry->d_seq, nd->next_seq)) 83662306a36Sopenharmony_ci goto out_dput; 83762306a36Sopenharmony_ci /* 83862306a36Sopenharmony_ci * Sequence counts matched. Now make sure that the root is 83962306a36Sopenharmony_ci * still valid and get it if required. 84062306a36Sopenharmony_ci */ 84162306a36Sopenharmony_ci if (unlikely(!legitimize_root(nd))) 84262306a36Sopenharmony_ci goto out_dput; 84362306a36Sopenharmony_ci leave_rcu(nd); 84462306a36Sopenharmony_ci return true; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ciout2: 84762306a36Sopenharmony_ci nd->path.mnt = NULL; 84862306a36Sopenharmony_ciout1: 84962306a36Sopenharmony_ci nd->path.dentry = NULL; 85062306a36Sopenharmony_ciout: 85162306a36Sopenharmony_ci leave_rcu(nd); 85262306a36Sopenharmony_ci return false; 85362306a36Sopenharmony_ciout_dput: 85462306a36Sopenharmony_ci leave_rcu(nd); 85562306a36Sopenharmony_ci dput(dentry); 85662306a36Sopenharmony_ci return false; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic inline int d_revalidate(struct dentry *dentry, unsigned int flags) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) 86262306a36Sopenharmony_ci return dentry->d_op->d_revalidate(dentry, flags); 86362306a36Sopenharmony_ci else 86462306a36Sopenharmony_ci return 1; 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci/** 86862306a36Sopenharmony_ci * complete_walk - successful completion of path walk 86962306a36Sopenharmony_ci * @nd: pointer nameidata 87062306a36Sopenharmony_ci * 87162306a36Sopenharmony_ci * If we had been in RCU mode, drop out of it and legitimize nd->path. 87262306a36Sopenharmony_ci * Revalidate the final result, unless we'd already done that during 87362306a36Sopenharmony_ci * the path walk or the filesystem doesn't ask for it. Return 0 on 87462306a36Sopenharmony_ci * success, -error on failure. In case of failure caller does not 87562306a36Sopenharmony_ci * need to drop nd->path. 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_cistatic int complete_walk(struct nameidata *nd) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct dentry *dentry = nd->path.dentry; 88062306a36Sopenharmony_ci int status; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 88362306a36Sopenharmony_ci /* 88462306a36Sopenharmony_ci * We don't want to zero nd->root for scoped-lookups or 88562306a36Sopenharmony_ci * externally-managed nd->root. 88662306a36Sopenharmony_ci */ 88762306a36Sopenharmony_ci if (!(nd->state & ND_ROOT_PRESET)) 88862306a36Sopenharmony_ci if (!(nd->flags & LOOKUP_IS_SCOPED)) 88962306a36Sopenharmony_ci nd->root.mnt = NULL; 89062306a36Sopenharmony_ci nd->flags &= ~LOOKUP_CACHED; 89162306a36Sopenharmony_ci if (!try_to_unlazy(nd)) 89262306a36Sopenharmony_ci return -ECHILD; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { 89662306a36Sopenharmony_ci /* 89762306a36Sopenharmony_ci * While the guarantee of LOOKUP_IS_SCOPED is (roughly) "don't 89862306a36Sopenharmony_ci * ever step outside the root during lookup" and should already 89962306a36Sopenharmony_ci * be guaranteed by the rest of namei, we want to avoid a namei 90062306a36Sopenharmony_ci * BUG resulting in userspace being given a path that was not 90162306a36Sopenharmony_ci * scoped within the root at some point during the lookup. 90262306a36Sopenharmony_ci * 90362306a36Sopenharmony_ci * So, do a final sanity-check to make sure that in the 90462306a36Sopenharmony_ci * worst-case scenario (a complete bypass of LOOKUP_IS_SCOPED) 90562306a36Sopenharmony_ci * we won't silently return an fd completely outside of the 90662306a36Sopenharmony_ci * requested root to userspace. 90762306a36Sopenharmony_ci * 90862306a36Sopenharmony_ci * Userspace could move the path outside the root after this 90962306a36Sopenharmony_ci * check, but as discussed elsewhere this is not a concern (the 91062306a36Sopenharmony_ci * resolved file was inside the root at some point). 91162306a36Sopenharmony_ci */ 91262306a36Sopenharmony_ci if (!path_is_under(&nd->path, &nd->root)) 91362306a36Sopenharmony_ci return -EXDEV; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (likely(!(nd->state & ND_JUMPED))) 91762306a36Sopenharmony_ci return 0; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE))) 92062306a36Sopenharmony_ci return 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci status = dentry->d_op->d_weak_revalidate(dentry, nd->flags); 92362306a36Sopenharmony_ci if (status > 0) 92462306a36Sopenharmony_ci return 0; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (!status) 92762306a36Sopenharmony_ci status = -ESTALE; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return status; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic int set_root(struct nameidata *nd) 93362306a36Sopenharmony_ci{ 93462306a36Sopenharmony_ci struct fs_struct *fs = current->fs; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* 93762306a36Sopenharmony_ci * Jumping to the real root in a scoped-lookup is a BUG in namei, but we 93862306a36Sopenharmony_ci * still have to ensure it doesn't happen because it will cause a breakout 93962306a36Sopenharmony_ci * from the dirfd. 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ci if (WARN_ON(nd->flags & LOOKUP_IS_SCOPED)) 94262306a36Sopenharmony_ci return -ENOTRECOVERABLE; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 94562306a36Sopenharmony_ci unsigned seq; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci do { 94862306a36Sopenharmony_ci seq = read_seqcount_begin(&fs->seq); 94962306a36Sopenharmony_ci nd->root = fs->root; 95062306a36Sopenharmony_ci nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq); 95162306a36Sopenharmony_ci } while (read_seqcount_retry(&fs->seq, seq)); 95262306a36Sopenharmony_ci } else { 95362306a36Sopenharmony_ci get_fs_root(fs, &nd->root); 95462306a36Sopenharmony_ci nd->state |= ND_ROOT_GRABBED; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci return 0; 95762306a36Sopenharmony_ci} 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int nd_jump_root(struct nameidata *nd) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_BENEATH)) 96262306a36Sopenharmony_ci return -EXDEV; 96362306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_XDEV)) { 96462306a36Sopenharmony_ci /* Absolute path arguments to path_init() are allowed. */ 96562306a36Sopenharmony_ci if (nd->path.mnt != NULL && nd->path.mnt != nd->root.mnt) 96662306a36Sopenharmony_ci return -EXDEV; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci if (!nd->root.mnt) { 96962306a36Sopenharmony_ci int error = set_root(nd); 97062306a36Sopenharmony_ci if (error) 97162306a36Sopenharmony_ci return error; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 97462306a36Sopenharmony_ci struct dentry *d; 97562306a36Sopenharmony_ci nd->path = nd->root; 97662306a36Sopenharmony_ci d = nd->path.dentry; 97762306a36Sopenharmony_ci nd->inode = d->d_inode; 97862306a36Sopenharmony_ci nd->seq = nd->root_seq; 97962306a36Sopenharmony_ci if (read_seqcount_retry(&d->d_seq, nd->seq)) 98062306a36Sopenharmony_ci return -ECHILD; 98162306a36Sopenharmony_ci } else { 98262306a36Sopenharmony_ci path_put(&nd->path); 98362306a36Sopenharmony_ci nd->path = nd->root; 98462306a36Sopenharmony_ci path_get(&nd->path); 98562306a36Sopenharmony_ci nd->inode = nd->path.dentry->d_inode; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci nd->state |= ND_JUMPED; 98862306a36Sopenharmony_ci return 0; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/* 99262306a36Sopenharmony_ci * Helper to directly jump to a known parsed path from ->get_link, 99362306a36Sopenharmony_ci * caller must have taken a reference to path beforehand. 99462306a36Sopenharmony_ci */ 99562306a36Sopenharmony_ciint nd_jump_link(const struct path *path) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci int error = -ELOOP; 99862306a36Sopenharmony_ci struct nameidata *nd = current->nameidata; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_MAGICLINKS)) 100162306a36Sopenharmony_ci goto err; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ci error = -EXDEV; 100462306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_XDEV)) { 100562306a36Sopenharmony_ci if (nd->path.mnt != path->mnt) 100662306a36Sopenharmony_ci goto err; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci /* Not currently safe for scoped-lookups. */ 100962306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) 101062306a36Sopenharmony_ci goto err; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci path_put(&nd->path); 101362306a36Sopenharmony_ci nd->path = *path; 101462306a36Sopenharmony_ci nd->inode = nd->path.dentry->d_inode; 101562306a36Sopenharmony_ci nd->state |= ND_JUMPED; 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cierr: 101962306a36Sopenharmony_ci path_put(path); 102062306a36Sopenharmony_ci return error; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic inline void put_link(struct nameidata *nd) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct saved *last = nd->stack + --nd->depth; 102662306a36Sopenharmony_ci do_delayed_call(&last->done); 102762306a36Sopenharmony_ci if (!(nd->flags & LOOKUP_RCU)) 102862306a36Sopenharmony_ci path_put(&last->link); 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic int sysctl_protected_symlinks __read_mostly; 103262306a36Sopenharmony_cistatic int sysctl_protected_hardlinks __read_mostly; 103362306a36Sopenharmony_cistatic int sysctl_protected_fifos __read_mostly; 103462306a36Sopenharmony_cistatic int sysctl_protected_regular __read_mostly; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 103762306a36Sopenharmony_cistatic struct ctl_table namei_sysctls[] = { 103862306a36Sopenharmony_ci { 103962306a36Sopenharmony_ci .procname = "protected_symlinks", 104062306a36Sopenharmony_ci .data = &sysctl_protected_symlinks, 104162306a36Sopenharmony_ci .maxlen = sizeof(int), 104262306a36Sopenharmony_ci .mode = 0644, 104362306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 104462306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 104562306a36Sopenharmony_ci .extra2 = SYSCTL_ONE, 104662306a36Sopenharmony_ci }, 104762306a36Sopenharmony_ci { 104862306a36Sopenharmony_ci .procname = "protected_hardlinks", 104962306a36Sopenharmony_ci .data = &sysctl_protected_hardlinks, 105062306a36Sopenharmony_ci .maxlen = sizeof(int), 105162306a36Sopenharmony_ci .mode = 0644, 105262306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 105362306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 105462306a36Sopenharmony_ci .extra2 = SYSCTL_ONE, 105562306a36Sopenharmony_ci }, 105662306a36Sopenharmony_ci { 105762306a36Sopenharmony_ci .procname = "protected_fifos", 105862306a36Sopenharmony_ci .data = &sysctl_protected_fifos, 105962306a36Sopenharmony_ci .maxlen = sizeof(int), 106062306a36Sopenharmony_ci .mode = 0644, 106162306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 106262306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 106362306a36Sopenharmony_ci .extra2 = SYSCTL_TWO, 106462306a36Sopenharmony_ci }, 106562306a36Sopenharmony_ci { 106662306a36Sopenharmony_ci .procname = "protected_regular", 106762306a36Sopenharmony_ci .data = &sysctl_protected_regular, 106862306a36Sopenharmony_ci .maxlen = sizeof(int), 106962306a36Sopenharmony_ci .mode = 0644, 107062306a36Sopenharmony_ci .proc_handler = proc_dointvec_minmax, 107162306a36Sopenharmony_ci .extra1 = SYSCTL_ZERO, 107262306a36Sopenharmony_ci .extra2 = SYSCTL_TWO, 107362306a36Sopenharmony_ci }, 107462306a36Sopenharmony_ci { } 107562306a36Sopenharmony_ci}; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_cistatic int __init init_fs_namei_sysctls(void) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci register_sysctl_init("fs", namei_sysctls); 108062306a36Sopenharmony_ci return 0; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_cifs_initcall(init_fs_namei_sysctls); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci#endif /* CONFIG_SYSCTL */ 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci/** 108762306a36Sopenharmony_ci * may_follow_link - Check symlink following for unsafe situations 108862306a36Sopenharmony_ci * @nd: nameidata pathwalk data 108962306a36Sopenharmony_ci * @inode: Used for idmapping. 109062306a36Sopenharmony_ci * 109162306a36Sopenharmony_ci * In the case of the sysctl_protected_symlinks sysctl being enabled, 109262306a36Sopenharmony_ci * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is 109362306a36Sopenharmony_ci * in a sticky world-writable directory. This is to protect privileged 109462306a36Sopenharmony_ci * processes from failing races against path names that may change out 109562306a36Sopenharmony_ci * from under them by way of other users creating malicious symlinks. 109662306a36Sopenharmony_ci * It will permit symlinks to be followed only when outside a sticky 109762306a36Sopenharmony_ci * world-writable directory, or when the uid of the symlink and follower 109862306a36Sopenharmony_ci * match, or when the directory owner matches the symlink's owner. 109962306a36Sopenharmony_ci * 110062306a36Sopenharmony_ci * Returns 0 if following the symlink is allowed, -ve on error. 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_cistatic inline int may_follow_link(struct nameidata *nd, const struct inode *inode) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci struct mnt_idmap *idmap; 110562306a36Sopenharmony_ci vfsuid_t vfsuid; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (!sysctl_protected_symlinks) 110862306a36Sopenharmony_ci return 0; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci idmap = mnt_idmap(nd->path.mnt); 111162306a36Sopenharmony_ci vfsuid = i_uid_into_vfsuid(idmap, inode); 111262306a36Sopenharmony_ci /* Allowed if owner and follower match. */ 111362306a36Sopenharmony_ci if (vfsuid_eq_kuid(vfsuid, current_fsuid())) 111462306a36Sopenharmony_ci return 0; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci /* Allowed if parent directory not sticky and world-writable. */ 111762306a36Sopenharmony_ci if ((nd->dir_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH)) 111862306a36Sopenharmony_ci return 0; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci /* Allowed if parent directory and link owner match. */ 112162306a36Sopenharmony_ci if (vfsuid_valid(nd->dir_vfsuid) && vfsuid_eq(nd->dir_vfsuid, vfsuid)) 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) 112562306a36Sopenharmony_ci return -ECHILD; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci audit_inode(nd->name, nd->stack[0].link.dentry, 0); 112862306a36Sopenharmony_ci audit_log_path_denied(AUDIT_ANOM_LINK, "follow_link"); 112962306a36Sopenharmony_ci return -EACCES; 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci/** 113362306a36Sopenharmony_ci * safe_hardlink_source - Check for safe hardlink conditions 113462306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 113562306a36Sopenharmony_ci * @inode: the source inode to hardlink from 113662306a36Sopenharmony_ci * 113762306a36Sopenharmony_ci * Return false if at least one of the following conditions: 113862306a36Sopenharmony_ci * - inode is not a regular file 113962306a36Sopenharmony_ci * - inode is setuid 114062306a36Sopenharmony_ci * - inode is setgid and group-exec 114162306a36Sopenharmony_ci * - access failure for read and write 114262306a36Sopenharmony_ci * 114362306a36Sopenharmony_ci * Otherwise returns true. 114462306a36Sopenharmony_ci */ 114562306a36Sopenharmony_cistatic bool safe_hardlink_source(struct mnt_idmap *idmap, 114662306a36Sopenharmony_ci struct inode *inode) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci umode_t mode = inode->i_mode; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci /* Special files should not get pinned to the filesystem. */ 115162306a36Sopenharmony_ci if (!S_ISREG(mode)) 115262306a36Sopenharmony_ci return false; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* Setuid files should not get pinned to the filesystem. */ 115562306a36Sopenharmony_ci if (mode & S_ISUID) 115662306a36Sopenharmony_ci return false; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* Executable setgid files should not get pinned to the filesystem. */ 115962306a36Sopenharmony_ci if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) 116062306a36Sopenharmony_ci return false; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci /* Hardlinking to unreadable or unwritable sources is dangerous. */ 116362306a36Sopenharmony_ci if (inode_permission(idmap, inode, MAY_READ | MAY_WRITE)) 116462306a36Sopenharmony_ci return false; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return true; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci/** 117062306a36Sopenharmony_ci * may_linkat - Check permissions for creating a hardlink 117162306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 117262306a36Sopenharmony_ci * @link: the source to hardlink from 117362306a36Sopenharmony_ci * 117462306a36Sopenharmony_ci * Block hardlink when all of: 117562306a36Sopenharmony_ci * - sysctl_protected_hardlinks enabled 117662306a36Sopenharmony_ci * - fsuid does not match inode 117762306a36Sopenharmony_ci * - hardlink source is unsafe (see safe_hardlink_source() above) 117862306a36Sopenharmony_ci * - not CAP_FOWNER in a namespace with the inode owner uid mapped 117962306a36Sopenharmony_ci * 118062306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 118162306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 118262306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 118362306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 118462306a36Sopenharmony_ci * raw inode simply pass @nop_mnt_idmap. 118562306a36Sopenharmony_ci * 118662306a36Sopenharmony_ci * Returns 0 if successful, -ve on error. 118762306a36Sopenharmony_ci */ 118862306a36Sopenharmony_ciint may_linkat(struct mnt_idmap *idmap, const struct path *link) 118962306a36Sopenharmony_ci{ 119062306a36Sopenharmony_ci struct inode *inode = link->dentry->d_inode; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* Inode writeback is not safe when the uid or gid are invalid. */ 119362306a36Sopenharmony_ci if (!vfsuid_valid(i_uid_into_vfsuid(idmap, inode)) || 119462306a36Sopenharmony_ci !vfsgid_valid(i_gid_into_vfsgid(idmap, inode))) 119562306a36Sopenharmony_ci return -EOVERFLOW; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (!sysctl_protected_hardlinks) 119862306a36Sopenharmony_ci return 0; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* Source inode owner (or CAP_FOWNER) can hardlink all they like, 120162306a36Sopenharmony_ci * otherwise, it must be a safe source. 120262306a36Sopenharmony_ci */ 120362306a36Sopenharmony_ci if (safe_hardlink_source(idmap, inode) || 120462306a36Sopenharmony_ci inode_owner_or_capable(idmap, inode)) 120562306a36Sopenharmony_ci return 0; 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci audit_log_path_denied(AUDIT_ANOM_LINK, "linkat"); 120862306a36Sopenharmony_ci return -EPERM; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci/** 121262306a36Sopenharmony_ci * may_create_in_sticky - Check whether an O_CREAT open in a sticky directory 121362306a36Sopenharmony_ci * should be allowed, or not, on files that already 121462306a36Sopenharmony_ci * exist. 121562306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 121662306a36Sopenharmony_ci * @nd: nameidata pathwalk data 121762306a36Sopenharmony_ci * @inode: the inode of the file to open 121862306a36Sopenharmony_ci * 121962306a36Sopenharmony_ci * Block an O_CREAT open of a FIFO (or a regular file) when: 122062306a36Sopenharmony_ci * - sysctl_protected_fifos (or sysctl_protected_regular) is enabled 122162306a36Sopenharmony_ci * - the file already exists 122262306a36Sopenharmony_ci * - we are in a sticky directory 122362306a36Sopenharmony_ci * - we don't own the file 122462306a36Sopenharmony_ci * - the owner of the directory doesn't own the file 122562306a36Sopenharmony_ci * - the directory is world writable 122662306a36Sopenharmony_ci * If the sysctl_protected_fifos (or sysctl_protected_regular) is set to 2 122762306a36Sopenharmony_ci * the directory doesn't have to be world writable: being group writable will 122862306a36Sopenharmony_ci * be enough. 122962306a36Sopenharmony_ci * 123062306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 123162306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 123262306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 123362306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 123462306a36Sopenharmony_ci * raw inode simply pass @nop_mnt_idmap. 123562306a36Sopenharmony_ci * 123662306a36Sopenharmony_ci * Returns 0 if the open is allowed, -ve on error. 123762306a36Sopenharmony_ci */ 123862306a36Sopenharmony_cistatic int may_create_in_sticky(struct mnt_idmap *idmap, 123962306a36Sopenharmony_ci struct nameidata *nd, struct inode *const inode) 124062306a36Sopenharmony_ci{ 124162306a36Sopenharmony_ci umode_t dir_mode = nd->dir_mode; 124262306a36Sopenharmony_ci vfsuid_t dir_vfsuid = nd->dir_vfsuid; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci if ((!sysctl_protected_fifos && S_ISFIFO(inode->i_mode)) || 124562306a36Sopenharmony_ci (!sysctl_protected_regular && S_ISREG(inode->i_mode)) || 124662306a36Sopenharmony_ci likely(!(dir_mode & S_ISVTX)) || 124762306a36Sopenharmony_ci vfsuid_eq(i_uid_into_vfsuid(idmap, inode), dir_vfsuid) || 124862306a36Sopenharmony_ci vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode), current_fsuid())) 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci if (likely(dir_mode & 0002) || 125262306a36Sopenharmony_ci (dir_mode & 0020 && 125362306a36Sopenharmony_ci ((sysctl_protected_fifos >= 2 && S_ISFIFO(inode->i_mode)) || 125462306a36Sopenharmony_ci (sysctl_protected_regular >= 2 && S_ISREG(inode->i_mode))))) { 125562306a36Sopenharmony_ci const char *operation = S_ISFIFO(inode->i_mode) ? 125662306a36Sopenharmony_ci "sticky_create_fifo" : 125762306a36Sopenharmony_ci "sticky_create_regular"; 125862306a36Sopenharmony_ci audit_log_path_denied(AUDIT_ANOM_CREAT, operation); 125962306a36Sopenharmony_ci return -EACCES; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci return 0; 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci/* 126562306a36Sopenharmony_ci * follow_up - Find the mountpoint of path's vfsmount 126662306a36Sopenharmony_ci * 126762306a36Sopenharmony_ci * Given a path, find the mountpoint of its source file system. 126862306a36Sopenharmony_ci * Replace @path with the path of the mountpoint in the parent mount. 126962306a36Sopenharmony_ci * Up is towards /. 127062306a36Sopenharmony_ci * 127162306a36Sopenharmony_ci * Return 1 if we went up a level and 0 if we were already at the 127262306a36Sopenharmony_ci * root. 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_ciint follow_up(struct path *path) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci struct mount *mnt = real_mount(path->mnt); 127762306a36Sopenharmony_ci struct mount *parent; 127862306a36Sopenharmony_ci struct dentry *mountpoint; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci read_seqlock_excl(&mount_lock); 128162306a36Sopenharmony_ci parent = mnt->mnt_parent; 128262306a36Sopenharmony_ci if (parent == mnt) { 128362306a36Sopenharmony_ci read_sequnlock_excl(&mount_lock); 128462306a36Sopenharmony_ci return 0; 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci mntget(&parent->mnt); 128762306a36Sopenharmony_ci mountpoint = dget(mnt->mnt_mountpoint); 128862306a36Sopenharmony_ci read_sequnlock_excl(&mount_lock); 128962306a36Sopenharmony_ci dput(path->dentry); 129062306a36Sopenharmony_ci path->dentry = mountpoint; 129162306a36Sopenharmony_ci mntput(path->mnt); 129262306a36Sopenharmony_ci path->mnt = &parent->mnt; 129362306a36Sopenharmony_ci return 1; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ciEXPORT_SYMBOL(follow_up); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic bool choose_mountpoint_rcu(struct mount *m, const struct path *root, 129862306a36Sopenharmony_ci struct path *path, unsigned *seqp) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci while (mnt_has_parent(m)) { 130162306a36Sopenharmony_ci struct dentry *mountpoint = m->mnt_mountpoint; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci m = m->mnt_parent; 130462306a36Sopenharmony_ci if (unlikely(root->dentry == mountpoint && 130562306a36Sopenharmony_ci root->mnt == &m->mnt)) 130662306a36Sopenharmony_ci break; 130762306a36Sopenharmony_ci if (mountpoint != m->mnt.mnt_root) { 130862306a36Sopenharmony_ci path->mnt = &m->mnt; 130962306a36Sopenharmony_ci path->dentry = mountpoint; 131062306a36Sopenharmony_ci *seqp = read_seqcount_begin(&mountpoint->d_seq); 131162306a36Sopenharmony_ci return true; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci return false; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cistatic bool choose_mountpoint(struct mount *m, const struct path *root, 131862306a36Sopenharmony_ci struct path *path) 131962306a36Sopenharmony_ci{ 132062306a36Sopenharmony_ci bool found; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci rcu_read_lock(); 132362306a36Sopenharmony_ci while (1) { 132462306a36Sopenharmony_ci unsigned seq, mseq = read_seqbegin(&mount_lock); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci found = choose_mountpoint_rcu(m, root, path, &seq); 132762306a36Sopenharmony_ci if (unlikely(!found)) { 132862306a36Sopenharmony_ci if (!read_seqretry(&mount_lock, mseq)) 132962306a36Sopenharmony_ci break; 133062306a36Sopenharmony_ci } else { 133162306a36Sopenharmony_ci if (likely(__legitimize_path(path, seq, mseq))) 133262306a36Sopenharmony_ci break; 133362306a36Sopenharmony_ci rcu_read_unlock(); 133462306a36Sopenharmony_ci path_put(path); 133562306a36Sopenharmony_ci rcu_read_lock(); 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci rcu_read_unlock(); 133962306a36Sopenharmony_ci return found; 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci/* 134362306a36Sopenharmony_ci * Perform an automount 134462306a36Sopenharmony_ci * - return -EISDIR to tell follow_managed() to stop and return the path we 134562306a36Sopenharmony_ci * were called with. 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_cistatic int follow_automount(struct path *path, int *count, unsigned lookup_flags) 134862306a36Sopenharmony_ci{ 134962306a36Sopenharmony_ci struct dentry *dentry = path->dentry; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci /* We don't want to mount if someone's just doing a stat - 135262306a36Sopenharmony_ci * unless they're stat'ing a directory and appended a '/' to 135362306a36Sopenharmony_ci * the name. 135462306a36Sopenharmony_ci * 135562306a36Sopenharmony_ci * We do, however, want to mount if someone wants to open or 135662306a36Sopenharmony_ci * create a file of any type under the mountpoint, wants to 135762306a36Sopenharmony_ci * traverse through the mountpoint or wants to open the 135862306a36Sopenharmony_ci * mounted directory. Also, autofs may mark negative dentries 135962306a36Sopenharmony_ci * as being automount points. These will need the attentions 136062306a36Sopenharmony_ci * of the daemon to instantiate them before they can be used. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci if (!(lookup_flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | 136362306a36Sopenharmony_ci LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) && 136462306a36Sopenharmony_ci dentry->d_inode) 136562306a36Sopenharmony_ci return -EISDIR; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (count && (*count)++ >= MAXSYMLINKS) 136862306a36Sopenharmony_ci return -ELOOP; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci return finish_automount(dentry->d_op->d_automount(path), path); 137162306a36Sopenharmony_ci} 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci/* 137462306a36Sopenharmony_ci * mount traversal - out-of-line part. One note on ->d_flags accesses - 137562306a36Sopenharmony_ci * dentries are pinned but not locked here, so negative dentry can go 137662306a36Sopenharmony_ci * positive right under us. Use of smp_load_acquire() provides a barrier 137762306a36Sopenharmony_ci * sufficient for ->d_inode and ->d_flags consistency. 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_cistatic int __traverse_mounts(struct path *path, unsigned flags, bool *jumped, 138062306a36Sopenharmony_ci int *count, unsigned lookup_flags) 138162306a36Sopenharmony_ci{ 138262306a36Sopenharmony_ci struct vfsmount *mnt = path->mnt; 138362306a36Sopenharmony_ci bool need_mntput = false; 138462306a36Sopenharmony_ci int ret = 0; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci while (flags & DCACHE_MANAGED_DENTRY) { 138762306a36Sopenharmony_ci /* Allow the filesystem to manage the transit without i_mutex 138862306a36Sopenharmony_ci * being held. */ 138962306a36Sopenharmony_ci if (flags & DCACHE_MANAGE_TRANSIT) { 139062306a36Sopenharmony_ci ret = path->dentry->d_op->d_manage(path, false); 139162306a36Sopenharmony_ci flags = smp_load_acquire(&path->dentry->d_flags); 139262306a36Sopenharmony_ci if (ret < 0) 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (flags & DCACHE_MOUNTED) { // something's mounted on it.. 139762306a36Sopenharmony_ci struct vfsmount *mounted = lookup_mnt(path); 139862306a36Sopenharmony_ci if (mounted) { // ... in our namespace 139962306a36Sopenharmony_ci dput(path->dentry); 140062306a36Sopenharmony_ci if (need_mntput) 140162306a36Sopenharmony_ci mntput(path->mnt); 140262306a36Sopenharmony_ci path->mnt = mounted; 140362306a36Sopenharmony_ci path->dentry = dget(mounted->mnt_root); 140462306a36Sopenharmony_ci // here we know it's positive 140562306a36Sopenharmony_ci flags = path->dentry->d_flags; 140662306a36Sopenharmony_ci need_mntput = true; 140762306a36Sopenharmony_ci continue; 140862306a36Sopenharmony_ci } 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if (!(flags & DCACHE_NEED_AUTOMOUNT)) 141262306a36Sopenharmony_ci break; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci // uncovered automount point 141562306a36Sopenharmony_ci ret = follow_automount(path, count, lookup_flags); 141662306a36Sopenharmony_ci flags = smp_load_acquire(&path->dentry->d_flags); 141762306a36Sopenharmony_ci if (ret < 0) 141862306a36Sopenharmony_ci break; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (ret == -EISDIR) 142262306a36Sopenharmony_ci ret = 0; 142362306a36Sopenharmony_ci // possible if you race with several mount --move 142462306a36Sopenharmony_ci if (need_mntput && path->mnt == mnt) 142562306a36Sopenharmony_ci mntput(path->mnt); 142662306a36Sopenharmony_ci if (!ret && unlikely(d_flags_negative(flags))) 142762306a36Sopenharmony_ci ret = -ENOENT; 142862306a36Sopenharmony_ci *jumped = need_mntput; 142962306a36Sopenharmony_ci return ret; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cistatic inline int traverse_mounts(struct path *path, bool *jumped, 143362306a36Sopenharmony_ci int *count, unsigned lookup_flags) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci unsigned flags = smp_load_acquire(&path->dentry->d_flags); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* fastpath */ 143862306a36Sopenharmony_ci if (likely(!(flags & DCACHE_MANAGED_DENTRY))) { 143962306a36Sopenharmony_ci *jumped = false; 144062306a36Sopenharmony_ci if (unlikely(d_flags_negative(flags))) 144162306a36Sopenharmony_ci return -ENOENT; 144262306a36Sopenharmony_ci return 0; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci return __traverse_mounts(path, flags, jumped, count, lookup_flags); 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ciint follow_down_one(struct path *path) 144862306a36Sopenharmony_ci{ 144962306a36Sopenharmony_ci struct vfsmount *mounted; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci mounted = lookup_mnt(path); 145262306a36Sopenharmony_ci if (mounted) { 145362306a36Sopenharmony_ci dput(path->dentry); 145462306a36Sopenharmony_ci mntput(path->mnt); 145562306a36Sopenharmony_ci path->mnt = mounted; 145662306a36Sopenharmony_ci path->dentry = dget(mounted->mnt_root); 145762306a36Sopenharmony_ci return 1; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci return 0; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ciEXPORT_SYMBOL(follow_down_one); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci/* 146462306a36Sopenharmony_ci * Follow down to the covering mount currently visible to userspace. At each 146562306a36Sopenharmony_ci * point, the filesystem owning that dentry may be queried as to whether the 146662306a36Sopenharmony_ci * caller is permitted to proceed or not. 146762306a36Sopenharmony_ci */ 146862306a36Sopenharmony_ciint follow_down(struct path *path, unsigned int flags) 146962306a36Sopenharmony_ci{ 147062306a36Sopenharmony_ci struct vfsmount *mnt = path->mnt; 147162306a36Sopenharmony_ci bool jumped; 147262306a36Sopenharmony_ci int ret = traverse_mounts(path, &jumped, NULL, flags); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (path->mnt != mnt) 147562306a36Sopenharmony_ci mntput(mnt); 147662306a36Sopenharmony_ci return ret; 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ciEXPORT_SYMBOL(follow_down); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci/* 148162306a36Sopenharmony_ci * Try to skip to top of mountpoint pile in rcuwalk mode. Fail if 148262306a36Sopenharmony_ci * we meet a managed dentry that would need blocking. 148362306a36Sopenharmony_ci */ 148462306a36Sopenharmony_cistatic bool __follow_mount_rcu(struct nameidata *nd, struct path *path) 148562306a36Sopenharmony_ci{ 148662306a36Sopenharmony_ci struct dentry *dentry = path->dentry; 148762306a36Sopenharmony_ci unsigned int flags = dentry->d_flags; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (likely(!(flags & DCACHE_MANAGED_DENTRY))) 149062306a36Sopenharmony_ci return true; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_XDEV)) 149362306a36Sopenharmony_ci return false; 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci for (;;) { 149662306a36Sopenharmony_ci /* 149762306a36Sopenharmony_ci * Don't forget we might have a non-mountpoint managed dentry 149862306a36Sopenharmony_ci * that wants to block transit. 149962306a36Sopenharmony_ci */ 150062306a36Sopenharmony_ci if (unlikely(flags & DCACHE_MANAGE_TRANSIT)) { 150162306a36Sopenharmony_ci int res = dentry->d_op->d_manage(path, true); 150262306a36Sopenharmony_ci if (res) 150362306a36Sopenharmony_ci return res == -EISDIR; 150462306a36Sopenharmony_ci flags = dentry->d_flags; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci if (flags & DCACHE_MOUNTED) { 150862306a36Sopenharmony_ci struct mount *mounted = __lookup_mnt(path->mnt, dentry); 150962306a36Sopenharmony_ci if (mounted) { 151062306a36Sopenharmony_ci path->mnt = &mounted->mnt; 151162306a36Sopenharmony_ci dentry = path->dentry = mounted->mnt.mnt_root; 151262306a36Sopenharmony_ci nd->state |= ND_JUMPED; 151362306a36Sopenharmony_ci nd->next_seq = read_seqcount_begin(&dentry->d_seq); 151462306a36Sopenharmony_ci flags = dentry->d_flags; 151562306a36Sopenharmony_ci // makes sure that non-RCU pathwalk could reach 151662306a36Sopenharmony_ci // this state. 151762306a36Sopenharmony_ci if (read_seqretry(&mount_lock, nd->m_seq)) 151862306a36Sopenharmony_ci return false; 151962306a36Sopenharmony_ci continue; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci if (read_seqretry(&mount_lock, nd->m_seq)) 152262306a36Sopenharmony_ci return false; 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci return !(flags & DCACHE_NEED_AUTOMOUNT); 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_cistatic inline int handle_mounts(struct nameidata *nd, struct dentry *dentry, 152962306a36Sopenharmony_ci struct path *path) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci bool jumped; 153262306a36Sopenharmony_ci int ret; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci path->mnt = nd->path.mnt; 153562306a36Sopenharmony_ci path->dentry = dentry; 153662306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 153762306a36Sopenharmony_ci unsigned int seq = nd->next_seq; 153862306a36Sopenharmony_ci if (likely(__follow_mount_rcu(nd, path))) 153962306a36Sopenharmony_ci return 0; 154062306a36Sopenharmony_ci // *path and nd->next_seq might've been clobbered 154162306a36Sopenharmony_ci path->mnt = nd->path.mnt; 154262306a36Sopenharmony_ci path->dentry = dentry; 154362306a36Sopenharmony_ci nd->next_seq = seq; 154462306a36Sopenharmony_ci if (!try_to_unlazy_next(nd, dentry)) 154562306a36Sopenharmony_ci return -ECHILD; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci ret = traverse_mounts(path, &jumped, &nd->total_link_count, nd->flags); 154862306a36Sopenharmony_ci if (jumped) { 154962306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_XDEV)) 155062306a36Sopenharmony_ci ret = -EXDEV; 155162306a36Sopenharmony_ci else 155262306a36Sopenharmony_ci nd->state |= ND_JUMPED; 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci if (unlikely(ret)) { 155562306a36Sopenharmony_ci dput(path->dentry); 155662306a36Sopenharmony_ci if (path->mnt != nd->path.mnt) 155762306a36Sopenharmony_ci mntput(path->mnt); 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci return ret; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci/* 156362306a36Sopenharmony_ci * This looks up the name in dcache and possibly revalidates the found dentry. 156462306a36Sopenharmony_ci * NULL is returned if the dentry does not exist in the cache. 156562306a36Sopenharmony_ci */ 156662306a36Sopenharmony_cistatic struct dentry *lookup_dcache(const struct qstr *name, 156762306a36Sopenharmony_ci struct dentry *dir, 156862306a36Sopenharmony_ci unsigned int flags) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci struct dentry *dentry = d_lookup(dir, name); 157162306a36Sopenharmony_ci if (dentry) { 157262306a36Sopenharmony_ci int error = d_revalidate(dentry, flags); 157362306a36Sopenharmony_ci if (unlikely(error <= 0)) { 157462306a36Sopenharmony_ci if (!error) 157562306a36Sopenharmony_ci d_invalidate(dentry); 157662306a36Sopenharmony_ci dput(dentry); 157762306a36Sopenharmony_ci return ERR_PTR(error); 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci return dentry; 158162306a36Sopenharmony_ci} 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci/* 158462306a36Sopenharmony_ci * Parent directory has inode locked exclusive. This is one 158562306a36Sopenharmony_ci * and only case when ->lookup() gets called on non in-lookup 158662306a36Sopenharmony_ci * dentries - as the matter of fact, this only gets called 158762306a36Sopenharmony_ci * when directory is guaranteed to have no in-lookup children 158862306a36Sopenharmony_ci * at all. 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_cistruct dentry *lookup_one_qstr_excl(const struct qstr *name, 159162306a36Sopenharmony_ci struct dentry *base, 159262306a36Sopenharmony_ci unsigned int flags) 159362306a36Sopenharmony_ci{ 159462306a36Sopenharmony_ci struct dentry *dentry = lookup_dcache(name, base, flags); 159562306a36Sopenharmony_ci struct dentry *old; 159662306a36Sopenharmony_ci struct inode *dir = base->d_inode; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci if (dentry) 159962306a36Sopenharmony_ci return dentry; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* Don't create child dentry for a dead directory. */ 160262306a36Sopenharmony_ci if (unlikely(IS_DEADDIR(dir))) 160362306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci dentry = d_alloc(base, name); 160662306a36Sopenharmony_ci if (unlikely(!dentry)) 160762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci old = dir->i_op->lookup(dir, dentry, flags); 161062306a36Sopenharmony_ci if (unlikely(old)) { 161162306a36Sopenharmony_ci dput(dentry); 161262306a36Sopenharmony_ci dentry = old; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci return dentry; 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_one_qstr_excl); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_cistatic struct dentry *lookup_fast(struct nameidata *nd) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci struct dentry *dentry, *parent = nd->path.dentry; 162162306a36Sopenharmony_ci int status = 1; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci /* 162462306a36Sopenharmony_ci * Rename seqlock is not required here because in the off chance 162562306a36Sopenharmony_ci * of a false negative due to a concurrent rename, the caller is 162662306a36Sopenharmony_ci * going to fall back to non-racy lookup. 162762306a36Sopenharmony_ci */ 162862306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 162962306a36Sopenharmony_ci dentry = __d_lookup_rcu(parent, &nd->last, &nd->next_seq); 163062306a36Sopenharmony_ci if (unlikely(!dentry)) { 163162306a36Sopenharmony_ci if (!try_to_unlazy(nd)) 163262306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 163362306a36Sopenharmony_ci return NULL; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci /* 163762306a36Sopenharmony_ci * This sequence count validates that the parent had no 163862306a36Sopenharmony_ci * changes while we did the lookup of the dentry above. 163962306a36Sopenharmony_ci */ 164062306a36Sopenharmony_ci if (read_seqcount_retry(&parent->d_seq, nd->seq)) 164162306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci status = d_revalidate(dentry, nd->flags); 164462306a36Sopenharmony_ci if (likely(status > 0)) 164562306a36Sopenharmony_ci return dentry; 164662306a36Sopenharmony_ci if (!try_to_unlazy_next(nd, dentry)) 164762306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 164862306a36Sopenharmony_ci if (status == -ECHILD) 164962306a36Sopenharmony_ci /* we'd been told to redo it in non-rcu mode */ 165062306a36Sopenharmony_ci status = d_revalidate(dentry, nd->flags); 165162306a36Sopenharmony_ci } else { 165262306a36Sopenharmony_ci dentry = __d_lookup(parent, &nd->last); 165362306a36Sopenharmony_ci if (unlikely(!dentry)) 165462306a36Sopenharmony_ci return NULL; 165562306a36Sopenharmony_ci status = d_revalidate(dentry, nd->flags); 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci if (unlikely(status <= 0)) { 165862306a36Sopenharmony_ci if (!status) 165962306a36Sopenharmony_ci d_invalidate(dentry); 166062306a36Sopenharmony_ci dput(dentry); 166162306a36Sopenharmony_ci return ERR_PTR(status); 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci return dentry; 166462306a36Sopenharmony_ci} 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci/* Fast lookup failed, do it the slow way */ 166762306a36Sopenharmony_cistatic struct dentry *__lookup_slow(const struct qstr *name, 166862306a36Sopenharmony_ci struct dentry *dir, 166962306a36Sopenharmony_ci unsigned int flags) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci struct dentry *dentry, *old; 167262306a36Sopenharmony_ci struct inode *inode = dir->d_inode; 167362306a36Sopenharmony_ci DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci /* Don't go there if it's already dead */ 167662306a36Sopenharmony_ci if (unlikely(IS_DEADDIR(inode))) 167762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 167862306a36Sopenharmony_ciagain: 167962306a36Sopenharmony_ci dentry = d_alloc_parallel(dir, name, &wq); 168062306a36Sopenharmony_ci if (IS_ERR(dentry)) 168162306a36Sopenharmony_ci return dentry; 168262306a36Sopenharmony_ci if (unlikely(!d_in_lookup(dentry))) { 168362306a36Sopenharmony_ci int error = d_revalidate(dentry, flags); 168462306a36Sopenharmony_ci if (unlikely(error <= 0)) { 168562306a36Sopenharmony_ci if (!error) { 168662306a36Sopenharmony_ci d_invalidate(dentry); 168762306a36Sopenharmony_ci dput(dentry); 168862306a36Sopenharmony_ci goto again; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci dput(dentry); 169162306a36Sopenharmony_ci dentry = ERR_PTR(error); 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci } else { 169462306a36Sopenharmony_ci old = inode->i_op->lookup(inode, dentry, flags); 169562306a36Sopenharmony_ci d_lookup_done(dentry); 169662306a36Sopenharmony_ci if (unlikely(old)) { 169762306a36Sopenharmony_ci dput(dentry); 169862306a36Sopenharmony_ci dentry = old; 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci return dentry; 170262306a36Sopenharmony_ci} 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_cistatic struct dentry *lookup_slow(const struct qstr *name, 170562306a36Sopenharmony_ci struct dentry *dir, 170662306a36Sopenharmony_ci unsigned int flags) 170762306a36Sopenharmony_ci{ 170862306a36Sopenharmony_ci struct inode *inode = dir->d_inode; 170962306a36Sopenharmony_ci struct dentry *res; 171062306a36Sopenharmony_ci inode_lock_shared(inode); 171162306a36Sopenharmony_ci res = __lookup_slow(name, dir, flags); 171262306a36Sopenharmony_ci inode_unlock_shared(inode); 171362306a36Sopenharmony_ci return res; 171462306a36Sopenharmony_ci} 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_cistatic inline int may_lookup(struct mnt_idmap *idmap, 171762306a36Sopenharmony_ci struct nameidata *nd) 171862306a36Sopenharmony_ci{ 171962306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 172062306a36Sopenharmony_ci int err = inode_permission(idmap, nd->inode, MAY_EXEC|MAY_NOT_BLOCK); 172162306a36Sopenharmony_ci if (err != -ECHILD || !try_to_unlazy(nd)) 172262306a36Sopenharmony_ci return err; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci return inode_permission(idmap, nd->inode, MAY_EXEC); 172562306a36Sopenharmony_ci} 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_cistatic int reserve_stack(struct nameidata *nd, struct path *link) 172862306a36Sopenharmony_ci{ 172962306a36Sopenharmony_ci if (unlikely(nd->total_link_count++ >= MAXSYMLINKS)) 173062306a36Sopenharmony_ci return -ELOOP; 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci if (likely(nd->depth != EMBEDDED_LEVELS)) 173362306a36Sopenharmony_ci return 0; 173462306a36Sopenharmony_ci if (likely(nd->stack != nd->internal)) 173562306a36Sopenharmony_ci return 0; 173662306a36Sopenharmony_ci if (likely(nd_alloc_stack(nd))) 173762306a36Sopenharmony_ci return 0; 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 174062306a36Sopenharmony_ci // we need to grab link before we do unlazy. And we can't skip 174162306a36Sopenharmony_ci // unlazy even if we fail to grab the link - cleanup needs it 174262306a36Sopenharmony_ci bool grabbed_link = legitimize_path(nd, link, nd->next_seq); 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci if (!try_to_unlazy(nd) || !grabbed_link) 174562306a36Sopenharmony_ci return -ECHILD; 174662306a36Sopenharmony_ci 174762306a36Sopenharmony_ci if (nd_alloc_stack(nd)) 174862306a36Sopenharmony_ci return 0; 174962306a36Sopenharmony_ci } 175062306a36Sopenharmony_ci return -ENOMEM; 175162306a36Sopenharmony_ci} 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_cienum {WALK_TRAILING = 1, WALK_MORE = 2, WALK_NOFOLLOW = 4}; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_cistatic const char *pick_link(struct nameidata *nd, struct path *link, 175662306a36Sopenharmony_ci struct inode *inode, int flags) 175762306a36Sopenharmony_ci{ 175862306a36Sopenharmony_ci struct saved *last; 175962306a36Sopenharmony_ci const char *res; 176062306a36Sopenharmony_ci int error = reserve_stack(nd, link); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci if (unlikely(error)) { 176362306a36Sopenharmony_ci if (!(nd->flags & LOOKUP_RCU)) 176462306a36Sopenharmony_ci path_put(link); 176562306a36Sopenharmony_ci return ERR_PTR(error); 176662306a36Sopenharmony_ci } 176762306a36Sopenharmony_ci last = nd->stack + nd->depth++; 176862306a36Sopenharmony_ci last->link = *link; 176962306a36Sopenharmony_ci clear_delayed_call(&last->done); 177062306a36Sopenharmony_ci last->seq = nd->next_seq; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci if (flags & WALK_TRAILING) { 177362306a36Sopenharmony_ci error = may_follow_link(nd, inode); 177462306a36Sopenharmony_ci if (unlikely(error)) 177562306a36Sopenharmony_ci return ERR_PTR(error); 177662306a36Sopenharmony_ci } 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_SYMLINKS) || 177962306a36Sopenharmony_ci unlikely(link->mnt->mnt_flags & MNT_NOSYMFOLLOW)) 178062306a36Sopenharmony_ci return ERR_PTR(-ELOOP); 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (!(nd->flags & LOOKUP_RCU)) { 178362306a36Sopenharmony_ci touch_atime(&last->link); 178462306a36Sopenharmony_ci cond_resched(); 178562306a36Sopenharmony_ci } else if (atime_needs_update(&last->link, inode)) { 178662306a36Sopenharmony_ci if (!try_to_unlazy(nd)) 178762306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 178862306a36Sopenharmony_ci touch_atime(&last->link); 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci error = security_inode_follow_link(link->dentry, inode, 179262306a36Sopenharmony_ci nd->flags & LOOKUP_RCU); 179362306a36Sopenharmony_ci if (unlikely(error)) 179462306a36Sopenharmony_ci return ERR_PTR(error); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci res = READ_ONCE(inode->i_link); 179762306a36Sopenharmony_ci if (!res) { 179862306a36Sopenharmony_ci const char * (*get)(struct dentry *, struct inode *, 179962306a36Sopenharmony_ci struct delayed_call *); 180062306a36Sopenharmony_ci get = inode->i_op->get_link; 180162306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 180262306a36Sopenharmony_ci res = get(NULL, inode, &last->done); 180362306a36Sopenharmony_ci if (res == ERR_PTR(-ECHILD) && try_to_unlazy(nd)) 180462306a36Sopenharmony_ci res = get(link->dentry, inode, &last->done); 180562306a36Sopenharmony_ci } else { 180662306a36Sopenharmony_ci res = get(link->dentry, inode, &last->done); 180762306a36Sopenharmony_ci } 180862306a36Sopenharmony_ci if (!res) 180962306a36Sopenharmony_ci goto all_done; 181062306a36Sopenharmony_ci if (IS_ERR(res)) 181162306a36Sopenharmony_ci return res; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci if (*res == '/') { 181462306a36Sopenharmony_ci error = nd_jump_root(nd); 181562306a36Sopenharmony_ci if (unlikely(error)) 181662306a36Sopenharmony_ci return ERR_PTR(error); 181762306a36Sopenharmony_ci while (unlikely(*++res == '/')) 181862306a36Sopenharmony_ci ; 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci if (*res) 182162306a36Sopenharmony_ci return res; 182262306a36Sopenharmony_ciall_done: // pure jump 182362306a36Sopenharmony_ci put_link(nd); 182462306a36Sopenharmony_ci return NULL; 182562306a36Sopenharmony_ci} 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci/* 182862306a36Sopenharmony_ci * Do we need to follow links? We _really_ want to be able 182962306a36Sopenharmony_ci * to do this check without having to look at inode->i_op, 183062306a36Sopenharmony_ci * so we keep a cache of "no, this doesn't need follow_link" 183162306a36Sopenharmony_ci * for the common case. 183262306a36Sopenharmony_ci * 183362306a36Sopenharmony_ci * NOTE: dentry must be what nd->next_seq had been sampled from. 183462306a36Sopenharmony_ci */ 183562306a36Sopenharmony_cistatic const char *step_into(struct nameidata *nd, int flags, 183662306a36Sopenharmony_ci struct dentry *dentry) 183762306a36Sopenharmony_ci{ 183862306a36Sopenharmony_ci struct path path; 183962306a36Sopenharmony_ci struct inode *inode; 184062306a36Sopenharmony_ci int err = handle_mounts(nd, dentry, &path); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci if (err < 0) 184362306a36Sopenharmony_ci return ERR_PTR(err); 184462306a36Sopenharmony_ci inode = path.dentry->d_inode; 184562306a36Sopenharmony_ci if (likely(!d_is_symlink(path.dentry)) || 184662306a36Sopenharmony_ci ((flags & WALK_TRAILING) && !(nd->flags & LOOKUP_FOLLOW)) || 184762306a36Sopenharmony_ci (flags & WALK_NOFOLLOW)) { 184862306a36Sopenharmony_ci /* not a symlink or should not follow */ 184962306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 185062306a36Sopenharmony_ci if (read_seqcount_retry(&path.dentry->d_seq, nd->next_seq)) 185162306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 185262306a36Sopenharmony_ci if (unlikely(!inode)) 185362306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 185462306a36Sopenharmony_ci } else { 185562306a36Sopenharmony_ci dput(nd->path.dentry); 185662306a36Sopenharmony_ci if (nd->path.mnt != path.mnt) 185762306a36Sopenharmony_ci mntput(nd->path.mnt); 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci nd->path = path; 186062306a36Sopenharmony_ci nd->inode = inode; 186162306a36Sopenharmony_ci nd->seq = nd->next_seq; 186262306a36Sopenharmony_ci return NULL; 186362306a36Sopenharmony_ci } 186462306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 186562306a36Sopenharmony_ci /* make sure that d_is_symlink above matches inode */ 186662306a36Sopenharmony_ci if (read_seqcount_retry(&path.dentry->d_seq, nd->next_seq)) 186762306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 186862306a36Sopenharmony_ci } else { 186962306a36Sopenharmony_ci if (path.mnt == nd->path.mnt) 187062306a36Sopenharmony_ci mntget(path.mnt); 187162306a36Sopenharmony_ci } 187262306a36Sopenharmony_ci return pick_link(nd, &path, inode, flags); 187362306a36Sopenharmony_ci} 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistatic struct dentry *follow_dotdot_rcu(struct nameidata *nd) 187662306a36Sopenharmony_ci{ 187762306a36Sopenharmony_ci struct dentry *parent, *old; 187862306a36Sopenharmony_ci 187962306a36Sopenharmony_ci if (path_equal(&nd->path, &nd->root)) 188062306a36Sopenharmony_ci goto in_root; 188162306a36Sopenharmony_ci if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) { 188262306a36Sopenharmony_ci struct path path; 188362306a36Sopenharmony_ci unsigned seq; 188462306a36Sopenharmony_ci if (!choose_mountpoint_rcu(real_mount(nd->path.mnt), 188562306a36Sopenharmony_ci &nd->root, &path, &seq)) 188662306a36Sopenharmony_ci goto in_root; 188762306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_XDEV)) 188862306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 188962306a36Sopenharmony_ci nd->path = path; 189062306a36Sopenharmony_ci nd->inode = path.dentry->d_inode; 189162306a36Sopenharmony_ci nd->seq = seq; 189262306a36Sopenharmony_ci // makes sure that non-RCU pathwalk could reach this state 189362306a36Sopenharmony_ci if (read_seqretry(&mount_lock, nd->m_seq)) 189462306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 189562306a36Sopenharmony_ci /* we know that mountpoint was pinned */ 189662306a36Sopenharmony_ci } 189762306a36Sopenharmony_ci old = nd->path.dentry; 189862306a36Sopenharmony_ci parent = old->d_parent; 189962306a36Sopenharmony_ci nd->next_seq = read_seqcount_begin(&parent->d_seq); 190062306a36Sopenharmony_ci // makes sure that non-RCU pathwalk could reach this state 190162306a36Sopenharmony_ci if (read_seqcount_retry(&old->d_seq, nd->seq)) 190262306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 190362306a36Sopenharmony_ci if (unlikely(!path_connected(nd->path.mnt, parent))) 190462306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 190562306a36Sopenharmony_ci return parent; 190662306a36Sopenharmony_ciin_root: 190762306a36Sopenharmony_ci if (read_seqretry(&mount_lock, nd->m_seq)) 190862306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 190962306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_BENEATH)) 191062306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 191162306a36Sopenharmony_ci nd->next_seq = nd->seq; 191262306a36Sopenharmony_ci return nd->path.dentry; 191362306a36Sopenharmony_ci} 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_cistatic struct dentry *follow_dotdot(struct nameidata *nd) 191662306a36Sopenharmony_ci{ 191762306a36Sopenharmony_ci struct dentry *parent; 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if (path_equal(&nd->path, &nd->root)) 192062306a36Sopenharmony_ci goto in_root; 192162306a36Sopenharmony_ci if (unlikely(nd->path.dentry == nd->path.mnt->mnt_root)) { 192262306a36Sopenharmony_ci struct path path; 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci if (!choose_mountpoint(real_mount(nd->path.mnt), 192562306a36Sopenharmony_ci &nd->root, &path)) 192662306a36Sopenharmony_ci goto in_root; 192762306a36Sopenharmony_ci path_put(&nd->path); 192862306a36Sopenharmony_ci nd->path = path; 192962306a36Sopenharmony_ci nd->inode = path.dentry->d_inode; 193062306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_NO_XDEV)) 193162306a36Sopenharmony_ci return ERR_PTR(-EXDEV); 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci /* rare case of legitimate dget_parent()... */ 193462306a36Sopenharmony_ci parent = dget_parent(nd->path.dentry); 193562306a36Sopenharmony_ci if (unlikely(!path_connected(nd->path.mnt, parent))) { 193662306a36Sopenharmony_ci dput(parent); 193762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 193862306a36Sopenharmony_ci } 193962306a36Sopenharmony_ci return parent; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ciin_root: 194262306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_BENEATH)) 194362306a36Sopenharmony_ci return ERR_PTR(-EXDEV); 194462306a36Sopenharmony_ci return dget(nd->path.dentry); 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_cistatic const char *handle_dots(struct nameidata *nd, int type) 194862306a36Sopenharmony_ci{ 194962306a36Sopenharmony_ci if (type == LAST_DOTDOT) { 195062306a36Sopenharmony_ci const char *error = NULL; 195162306a36Sopenharmony_ci struct dentry *parent; 195262306a36Sopenharmony_ci 195362306a36Sopenharmony_ci if (!nd->root.mnt) { 195462306a36Sopenharmony_ci error = ERR_PTR(set_root(nd)); 195562306a36Sopenharmony_ci if (error) 195662306a36Sopenharmony_ci return error; 195762306a36Sopenharmony_ci } 195862306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) 195962306a36Sopenharmony_ci parent = follow_dotdot_rcu(nd); 196062306a36Sopenharmony_ci else 196162306a36Sopenharmony_ci parent = follow_dotdot(nd); 196262306a36Sopenharmony_ci if (IS_ERR(parent)) 196362306a36Sopenharmony_ci return ERR_CAST(parent); 196462306a36Sopenharmony_ci error = step_into(nd, WALK_NOFOLLOW, parent); 196562306a36Sopenharmony_ci if (unlikely(error)) 196662306a36Sopenharmony_ci return error; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci if (unlikely(nd->flags & LOOKUP_IS_SCOPED)) { 196962306a36Sopenharmony_ci /* 197062306a36Sopenharmony_ci * If there was a racing rename or mount along our 197162306a36Sopenharmony_ci * path, then we can't be sure that ".." hasn't jumped 197262306a36Sopenharmony_ci * above nd->root (and so userspace should retry or use 197362306a36Sopenharmony_ci * some fallback). 197462306a36Sopenharmony_ci */ 197562306a36Sopenharmony_ci smp_rmb(); 197662306a36Sopenharmony_ci if (__read_seqcount_retry(&mount_lock.seqcount, nd->m_seq)) 197762306a36Sopenharmony_ci return ERR_PTR(-EAGAIN); 197862306a36Sopenharmony_ci if (__read_seqcount_retry(&rename_lock.seqcount, nd->r_seq)) 197962306a36Sopenharmony_ci return ERR_PTR(-EAGAIN); 198062306a36Sopenharmony_ci } 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci return NULL; 198362306a36Sopenharmony_ci} 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_cistatic const char *walk_component(struct nameidata *nd, int flags) 198662306a36Sopenharmony_ci{ 198762306a36Sopenharmony_ci struct dentry *dentry; 198862306a36Sopenharmony_ci /* 198962306a36Sopenharmony_ci * "." and ".." are special - ".." especially so because it has 199062306a36Sopenharmony_ci * to be able to know about the current root directory and 199162306a36Sopenharmony_ci * parent relationships. 199262306a36Sopenharmony_ci */ 199362306a36Sopenharmony_ci if (unlikely(nd->last_type != LAST_NORM)) { 199462306a36Sopenharmony_ci if (!(flags & WALK_MORE) && nd->depth) 199562306a36Sopenharmony_ci put_link(nd); 199662306a36Sopenharmony_ci return handle_dots(nd, nd->last_type); 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci dentry = lookup_fast(nd); 199962306a36Sopenharmony_ci if (IS_ERR(dentry)) 200062306a36Sopenharmony_ci return ERR_CAST(dentry); 200162306a36Sopenharmony_ci if (unlikely(!dentry)) { 200262306a36Sopenharmony_ci dentry = lookup_slow(&nd->last, nd->path.dentry, nd->flags); 200362306a36Sopenharmony_ci if (IS_ERR(dentry)) 200462306a36Sopenharmony_ci return ERR_CAST(dentry); 200562306a36Sopenharmony_ci } 200662306a36Sopenharmony_ci if (!(flags & WALK_MORE) && nd->depth) 200762306a36Sopenharmony_ci put_link(nd); 200862306a36Sopenharmony_ci return step_into(nd, flags, dentry); 200962306a36Sopenharmony_ci} 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ci/* 201262306a36Sopenharmony_ci * We can do the critical dentry name comparison and hashing 201362306a36Sopenharmony_ci * operations one word at a time, but we are limited to: 201462306a36Sopenharmony_ci * 201562306a36Sopenharmony_ci * - Architectures with fast unaligned word accesses. We could 201662306a36Sopenharmony_ci * do a "get_unaligned()" if this helps and is sufficiently 201762306a36Sopenharmony_ci * fast. 201862306a36Sopenharmony_ci * 201962306a36Sopenharmony_ci * - non-CONFIG_DEBUG_PAGEALLOC configurations (so that we 202062306a36Sopenharmony_ci * do not trap on the (extremely unlikely) case of a page 202162306a36Sopenharmony_ci * crossing operation. 202262306a36Sopenharmony_ci * 202362306a36Sopenharmony_ci * - Furthermore, we need an efficient 64-bit compile for the 202462306a36Sopenharmony_ci * 64-bit case in order to generate the "number of bytes in 202562306a36Sopenharmony_ci * the final mask". Again, that could be replaced with a 202662306a36Sopenharmony_ci * efficient population count instruction or similar. 202762306a36Sopenharmony_ci */ 202862306a36Sopenharmony_ci#ifdef CONFIG_DCACHE_WORD_ACCESS 202962306a36Sopenharmony_ci 203062306a36Sopenharmony_ci#include <asm/word-at-a-time.h> 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci#ifdef HASH_MIX 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci/* Architecture provides HASH_MIX and fold_hash() in <asm/hash.h> */ 203562306a36Sopenharmony_ci 203662306a36Sopenharmony_ci#elif defined(CONFIG_64BIT) 203762306a36Sopenharmony_ci/* 203862306a36Sopenharmony_ci * Register pressure in the mixing function is an issue, particularly 203962306a36Sopenharmony_ci * on 32-bit x86, but almost any function requires one state value and 204062306a36Sopenharmony_ci * one temporary. Instead, use a function designed for two state values 204162306a36Sopenharmony_ci * and no temporaries. 204262306a36Sopenharmony_ci * 204362306a36Sopenharmony_ci * This function cannot create a collision in only two iterations, so 204462306a36Sopenharmony_ci * we have two iterations to achieve avalanche. In those two iterations, 204562306a36Sopenharmony_ci * we have six layers of mixing, which is enough to spread one bit's 204662306a36Sopenharmony_ci * influence out to 2^6 = 64 state bits. 204762306a36Sopenharmony_ci * 204862306a36Sopenharmony_ci * Rotate constants are scored by considering either 64 one-bit input 204962306a36Sopenharmony_ci * deltas or 64*63/2 = 2016 two-bit input deltas, and finding the 205062306a36Sopenharmony_ci * probability of that delta causing a change to each of the 128 output 205162306a36Sopenharmony_ci * bits, using a sample of random initial states. 205262306a36Sopenharmony_ci * 205362306a36Sopenharmony_ci * The Shannon entropy of the computed probabilities is then summed 205462306a36Sopenharmony_ci * to produce a score. Ideally, any input change has a 50% chance of 205562306a36Sopenharmony_ci * toggling any given output bit. 205662306a36Sopenharmony_ci * 205762306a36Sopenharmony_ci * Mixing scores (in bits) for (12,45): 205862306a36Sopenharmony_ci * Input delta: 1-bit 2-bit 205962306a36Sopenharmony_ci * 1 round: 713.3 42542.6 206062306a36Sopenharmony_ci * 2 rounds: 2753.7 140389.8 206162306a36Sopenharmony_ci * 3 rounds: 5954.1 233458.2 206262306a36Sopenharmony_ci * 4 rounds: 7862.6 256672.2 206362306a36Sopenharmony_ci * Perfect: 8192 258048 206462306a36Sopenharmony_ci * (64*128) (64*63/2 * 128) 206562306a36Sopenharmony_ci */ 206662306a36Sopenharmony_ci#define HASH_MIX(x, y, a) \ 206762306a36Sopenharmony_ci ( x ^= (a), \ 206862306a36Sopenharmony_ci y ^= x, x = rol64(x,12),\ 206962306a36Sopenharmony_ci x += y, y = rol64(y,45),\ 207062306a36Sopenharmony_ci y *= 9 ) 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci/* 207362306a36Sopenharmony_ci * Fold two longs into one 32-bit hash value. This must be fast, but 207462306a36Sopenharmony_ci * latency isn't quite as critical, as there is a fair bit of additional 207562306a36Sopenharmony_ci * work done before the hash value is used. 207662306a36Sopenharmony_ci */ 207762306a36Sopenharmony_cistatic inline unsigned int fold_hash(unsigned long x, unsigned long y) 207862306a36Sopenharmony_ci{ 207962306a36Sopenharmony_ci y ^= x * GOLDEN_RATIO_64; 208062306a36Sopenharmony_ci y *= GOLDEN_RATIO_64; 208162306a36Sopenharmony_ci return y >> 32; 208262306a36Sopenharmony_ci} 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci#else /* 32-bit case */ 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci/* 208762306a36Sopenharmony_ci * Mixing scores (in bits) for (7,20): 208862306a36Sopenharmony_ci * Input delta: 1-bit 2-bit 208962306a36Sopenharmony_ci * 1 round: 330.3 9201.6 209062306a36Sopenharmony_ci * 2 rounds: 1246.4 25475.4 209162306a36Sopenharmony_ci * 3 rounds: 1907.1 31295.1 209262306a36Sopenharmony_ci * 4 rounds: 2042.3 31718.6 209362306a36Sopenharmony_ci * Perfect: 2048 31744 209462306a36Sopenharmony_ci * (32*64) (32*31/2 * 64) 209562306a36Sopenharmony_ci */ 209662306a36Sopenharmony_ci#define HASH_MIX(x, y, a) \ 209762306a36Sopenharmony_ci ( x ^= (a), \ 209862306a36Sopenharmony_ci y ^= x, x = rol32(x, 7),\ 209962306a36Sopenharmony_ci x += y, y = rol32(y,20),\ 210062306a36Sopenharmony_ci y *= 9 ) 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_cistatic inline unsigned int fold_hash(unsigned long x, unsigned long y) 210362306a36Sopenharmony_ci{ 210462306a36Sopenharmony_ci /* Use arch-optimized multiply if one exists */ 210562306a36Sopenharmony_ci return __hash_32(y ^ __hash_32(x)); 210662306a36Sopenharmony_ci} 210762306a36Sopenharmony_ci 210862306a36Sopenharmony_ci#endif 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci/* 211162306a36Sopenharmony_ci * Return the hash of a string of known length. This is carfully 211262306a36Sopenharmony_ci * designed to match hash_name(), which is the more critical function. 211362306a36Sopenharmony_ci * In particular, we must end by hashing a final word containing 0..7 211462306a36Sopenharmony_ci * payload bytes, to match the way that hash_name() iterates until it 211562306a36Sopenharmony_ci * finds the delimiter after the name. 211662306a36Sopenharmony_ci */ 211762306a36Sopenharmony_ciunsigned int full_name_hash(const void *salt, const char *name, unsigned int len) 211862306a36Sopenharmony_ci{ 211962306a36Sopenharmony_ci unsigned long a, x = 0, y = (unsigned long)salt; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci for (;;) { 212262306a36Sopenharmony_ci if (!len) 212362306a36Sopenharmony_ci goto done; 212462306a36Sopenharmony_ci a = load_unaligned_zeropad(name); 212562306a36Sopenharmony_ci if (len < sizeof(unsigned long)) 212662306a36Sopenharmony_ci break; 212762306a36Sopenharmony_ci HASH_MIX(x, y, a); 212862306a36Sopenharmony_ci name += sizeof(unsigned long); 212962306a36Sopenharmony_ci len -= sizeof(unsigned long); 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci x ^= a & bytemask_from_count(len); 213262306a36Sopenharmony_cidone: 213362306a36Sopenharmony_ci return fold_hash(x, y); 213462306a36Sopenharmony_ci} 213562306a36Sopenharmony_ciEXPORT_SYMBOL(full_name_hash); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci/* Return the "hash_len" (hash and length) of a null-terminated string */ 213862306a36Sopenharmony_ciu64 hashlen_string(const void *salt, const char *name) 213962306a36Sopenharmony_ci{ 214062306a36Sopenharmony_ci unsigned long a = 0, x = 0, y = (unsigned long)salt; 214162306a36Sopenharmony_ci unsigned long adata, mask, len; 214262306a36Sopenharmony_ci const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci len = 0; 214562306a36Sopenharmony_ci goto inside; 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci do { 214862306a36Sopenharmony_ci HASH_MIX(x, y, a); 214962306a36Sopenharmony_ci len += sizeof(unsigned long); 215062306a36Sopenharmony_ciinside: 215162306a36Sopenharmony_ci a = load_unaligned_zeropad(name+len); 215262306a36Sopenharmony_ci } while (!has_zero(a, &adata, &constants)); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci adata = prep_zero_mask(a, adata, &constants); 215562306a36Sopenharmony_ci mask = create_zero_mask(adata); 215662306a36Sopenharmony_ci x ^= a & zero_bytemask(mask); 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci return hashlen_create(fold_hash(x, y), len + find_zero(mask)); 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ciEXPORT_SYMBOL(hashlen_string); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci/* 216362306a36Sopenharmony_ci * Calculate the length and hash of the path component, and 216462306a36Sopenharmony_ci * return the "hash_len" as the result. 216562306a36Sopenharmony_ci */ 216662306a36Sopenharmony_cistatic inline u64 hash_name(const void *salt, const char *name) 216762306a36Sopenharmony_ci{ 216862306a36Sopenharmony_ci unsigned long a = 0, b, x = 0, y = (unsigned long)salt; 216962306a36Sopenharmony_ci unsigned long adata, bdata, mask, len; 217062306a36Sopenharmony_ci const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci len = 0; 217362306a36Sopenharmony_ci goto inside; 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci do { 217662306a36Sopenharmony_ci HASH_MIX(x, y, a); 217762306a36Sopenharmony_ci len += sizeof(unsigned long); 217862306a36Sopenharmony_ciinside: 217962306a36Sopenharmony_ci a = load_unaligned_zeropad(name+len); 218062306a36Sopenharmony_ci b = a ^ REPEAT_BYTE('/'); 218162306a36Sopenharmony_ci } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants))); 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci adata = prep_zero_mask(a, adata, &constants); 218462306a36Sopenharmony_ci bdata = prep_zero_mask(b, bdata, &constants); 218562306a36Sopenharmony_ci mask = create_zero_mask(adata | bdata); 218662306a36Sopenharmony_ci x ^= a & zero_bytemask(mask); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci return hashlen_create(fold_hash(x, y), len + find_zero(mask)); 218962306a36Sopenharmony_ci} 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci#else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */ 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci/* Return the hash of a string of known length */ 219462306a36Sopenharmony_ciunsigned int full_name_hash(const void *salt, const char *name, unsigned int len) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci unsigned long hash = init_name_hash(salt); 219762306a36Sopenharmony_ci while (len--) 219862306a36Sopenharmony_ci hash = partial_name_hash((unsigned char)*name++, hash); 219962306a36Sopenharmony_ci return end_name_hash(hash); 220062306a36Sopenharmony_ci} 220162306a36Sopenharmony_ciEXPORT_SYMBOL(full_name_hash); 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci/* Return the "hash_len" (hash and length) of a null-terminated string */ 220462306a36Sopenharmony_ciu64 hashlen_string(const void *salt, const char *name) 220562306a36Sopenharmony_ci{ 220662306a36Sopenharmony_ci unsigned long hash = init_name_hash(salt); 220762306a36Sopenharmony_ci unsigned long len = 0, c; 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci c = (unsigned char)*name; 221062306a36Sopenharmony_ci while (c) { 221162306a36Sopenharmony_ci len++; 221262306a36Sopenharmony_ci hash = partial_name_hash(c, hash); 221362306a36Sopenharmony_ci c = (unsigned char)name[len]; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci return hashlen_create(end_name_hash(hash), len); 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_ciEXPORT_SYMBOL(hashlen_string); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci/* 222062306a36Sopenharmony_ci * We know there's a real path component here of at least 222162306a36Sopenharmony_ci * one character. 222262306a36Sopenharmony_ci */ 222362306a36Sopenharmony_cistatic inline u64 hash_name(const void *salt, const char *name) 222462306a36Sopenharmony_ci{ 222562306a36Sopenharmony_ci unsigned long hash = init_name_hash(salt); 222662306a36Sopenharmony_ci unsigned long len = 0, c; 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci c = (unsigned char)*name; 222962306a36Sopenharmony_ci do { 223062306a36Sopenharmony_ci len++; 223162306a36Sopenharmony_ci hash = partial_name_hash(c, hash); 223262306a36Sopenharmony_ci c = (unsigned char)name[len]; 223362306a36Sopenharmony_ci } while (c && c != '/'); 223462306a36Sopenharmony_ci return hashlen_create(end_name_hash(hash), len); 223562306a36Sopenharmony_ci} 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci#endif 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci/* 224062306a36Sopenharmony_ci * Name resolution. 224162306a36Sopenharmony_ci * This is the basic name resolution function, turning a pathname into 224262306a36Sopenharmony_ci * the final dentry. We expect 'base' to be positive and a directory. 224362306a36Sopenharmony_ci * 224462306a36Sopenharmony_ci * Returns 0 and nd will have valid dentry and mnt on success. 224562306a36Sopenharmony_ci * Returns error and drops reference to input namei data on failure. 224662306a36Sopenharmony_ci */ 224762306a36Sopenharmony_cistatic int link_path_walk(const char *name, struct nameidata *nd) 224862306a36Sopenharmony_ci{ 224962306a36Sopenharmony_ci int depth = 0; // depth <= nd->depth 225062306a36Sopenharmony_ci int err; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci nd->last_type = LAST_ROOT; 225362306a36Sopenharmony_ci nd->flags |= LOOKUP_PARENT; 225462306a36Sopenharmony_ci if (IS_ERR(name)) 225562306a36Sopenharmony_ci return PTR_ERR(name); 225662306a36Sopenharmony_ci while (*name=='/') 225762306a36Sopenharmony_ci name++; 225862306a36Sopenharmony_ci if (!*name) { 225962306a36Sopenharmony_ci nd->dir_mode = 0; // short-circuit the 'hardening' idiocy 226062306a36Sopenharmony_ci return 0; 226162306a36Sopenharmony_ci } 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci /* At this point we know we have a real path component. */ 226462306a36Sopenharmony_ci for(;;) { 226562306a36Sopenharmony_ci struct mnt_idmap *idmap; 226662306a36Sopenharmony_ci const char *link; 226762306a36Sopenharmony_ci u64 hash_len; 226862306a36Sopenharmony_ci int type; 226962306a36Sopenharmony_ci 227062306a36Sopenharmony_ci idmap = mnt_idmap(nd->path.mnt); 227162306a36Sopenharmony_ci err = may_lookup(idmap, nd); 227262306a36Sopenharmony_ci if (err) 227362306a36Sopenharmony_ci return err; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci hash_len = hash_name(nd->path.dentry, name); 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci type = LAST_NORM; 227862306a36Sopenharmony_ci if (name[0] == '.') switch (hashlen_len(hash_len)) { 227962306a36Sopenharmony_ci case 2: 228062306a36Sopenharmony_ci if (name[1] == '.') { 228162306a36Sopenharmony_ci type = LAST_DOTDOT; 228262306a36Sopenharmony_ci nd->state |= ND_JUMPED; 228362306a36Sopenharmony_ci } 228462306a36Sopenharmony_ci break; 228562306a36Sopenharmony_ci case 1: 228662306a36Sopenharmony_ci type = LAST_DOT; 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci if (likely(type == LAST_NORM)) { 228962306a36Sopenharmony_ci struct dentry *parent = nd->path.dentry; 229062306a36Sopenharmony_ci nd->state &= ~ND_JUMPED; 229162306a36Sopenharmony_ci if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { 229262306a36Sopenharmony_ci struct qstr this = { { .hash_len = hash_len }, .name = name }; 229362306a36Sopenharmony_ci err = parent->d_op->d_hash(parent, &this); 229462306a36Sopenharmony_ci if (err < 0) 229562306a36Sopenharmony_ci return err; 229662306a36Sopenharmony_ci hash_len = this.hash_len; 229762306a36Sopenharmony_ci name = this.name; 229862306a36Sopenharmony_ci } 229962306a36Sopenharmony_ci } 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci nd->last.hash_len = hash_len; 230262306a36Sopenharmony_ci nd->last.name = name; 230362306a36Sopenharmony_ci nd->last_type = type; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci name += hashlen_len(hash_len); 230662306a36Sopenharmony_ci if (!*name) 230762306a36Sopenharmony_ci goto OK; 230862306a36Sopenharmony_ci /* 230962306a36Sopenharmony_ci * If it wasn't NUL, we know it was '/'. Skip that 231062306a36Sopenharmony_ci * slash, and continue until no more slashes. 231162306a36Sopenharmony_ci */ 231262306a36Sopenharmony_ci do { 231362306a36Sopenharmony_ci name++; 231462306a36Sopenharmony_ci } while (unlikely(*name == '/')); 231562306a36Sopenharmony_ci if (unlikely(!*name)) { 231662306a36Sopenharmony_ciOK: 231762306a36Sopenharmony_ci /* pathname or trailing symlink, done */ 231862306a36Sopenharmony_ci if (!depth) { 231962306a36Sopenharmony_ci nd->dir_vfsuid = i_uid_into_vfsuid(idmap, nd->inode); 232062306a36Sopenharmony_ci nd->dir_mode = nd->inode->i_mode; 232162306a36Sopenharmony_ci nd->flags &= ~LOOKUP_PARENT; 232262306a36Sopenharmony_ci return 0; 232362306a36Sopenharmony_ci } 232462306a36Sopenharmony_ci /* last component of nested symlink */ 232562306a36Sopenharmony_ci name = nd->stack[--depth].name; 232662306a36Sopenharmony_ci link = walk_component(nd, 0); 232762306a36Sopenharmony_ci } else { 232862306a36Sopenharmony_ci /* not the last component */ 232962306a36Sopenharmony_ci link = walk_component(nd, WALK_MORE); 233062306a36Sopenharmony_ci } 233162306a36Sopenharmony_ci if (unlikely(link)) { 233262306a36Sopenharmony_ci if (IS_ERR(link)) 233362306a36Sopenharmony_ci return PTR_ERR(link); 233462306a36Sopenharmony_ci /* a symlink to follow */ 233562306a36Sopenharmony_ci nd->stack[depth++].name = name; 233662306a36Sopenharmony_ci name = link; 233762306a36Sopenharmony_ci continue; 233862306a36Sopenharmony_ci } 233962306a36Sopenharmony_ci if (unlikely(!d_can_lookup(nd->path.dentry))) { 234062306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 234162306a36Sopenharmony_ci if (!try_to_unlazy(nd)) 234262306a36Sopenharmony_ci return -ECHILD; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci return -ENOTDIR; 234562306a36Sopenharmony_ci } 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci} 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci/* must be paired with terminate_walk() */ 235062306a36Sopenharmony_cistatic const char *path_init(struct nameidata *nd, unsigned flags) 235162306a36Sopenharmony_ci{ 235262306a36Sopenharmony_ci int error; 235362306a36Sopenharmony_ci const char *s = nd->name->name; 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci /* LOOKUP_CACHED requires RCU, ask caller to retry */ 235662306a36Sopenharmony_ci if ((flags & (LOOKUP_RCU | LOOKUP_CACHED)) == LOOKUP_CACHED) 235762306a36Sopenharmony_ci return ERR_PTR(-EAGAIN); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci if (!*s) 236062306a36Sopenharmony_ci flags &= ~LOOKUP_RCU; 236162306a36Sopenharmony_ci if (flags & LOOKUP_RCU) 236262306a36Sopenharmony_ci rcu_read_lock(); 236362306a36Sopenharmony_ci else 236462306a36Sopenharmony_ci nd->seq = nd->next_seq = 0; 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci nd->flags = flags; 236762306a36Sopenharmony_ci nd->state |= ND_JUMPED; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci nd->m_seq = __read_seqcount_begin(&mount_lock.seqcount); 237062306a36Sopenharmony_ci nd->r_seq = __read_seqcount_begin(&rename_lock.seqcount); 237162306a36Sopenharmony_ci smp_rmb(); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci if (nd->state & ND_ROOT_PRESET) { 237462306a36Sopenharmony_ci struct dentry *root = nd->root.dentry; 237562306a36Sopenharmony_ci struct inode *inode = root->d_inode; 237662306a36Sopenharmony_ci if (*s && unlikely(!d_can_lookup(root))) 237762306a36Sopenharmony_ci return ERR_PTR(-ENOTDIR); 237862306a36Sopenharmony_ci nd->path = nd->root; 237962306a36Sopenharmony_ci nd->inode = inode; 238062306a36Sopenharmony_ci if (flags & LOOKUP_RCU) { 238162306a36Sopenharmony_ci nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); 238262306a36Sopenharmony_ci nd->root_seq = nd->seq; 238362306a36Sopenharmony_ci } else { 238462306a36Sopenharmony_ci path_get(&nd->path); 238562306a36Sopenharmony_ci } 238662306a36Sopenharmony_ci return s; 238762306a36Sopenharmony_ci } 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci nd->root.mnt = NULL; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci /* Absolute pathname -- fetch the root (LOOKUP_IN_ROOT uses nd->dfd). */ 239262306a36Sopenharmony_ci if (*s == '/' && !(flags & LOOKUP_IN_ROOT)) { 239362306a36Sopenharmony_ci error = nd_jump_root(nd); 239462306a36Sopenharmony_ci if (unlikely(error)) 239562306a36Sopenharmony_ci return ERR_PTR(error); 239662306a36Sopenharmony_ci return s; 239762306a36Sopenharmony_ci } 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci /* Relative pathname -- get the starting-point it is relative to. */ 240062306a36Sopenharmony_ci if (nd->dfd == AT_FDCWD) { 240162306a36Sopenharmony_ci if (flags & LOOKUP_RCU) { 240262306a36Sopenharmony_ci struct fs_struct *fs = current->fs; 240362306a36Sopenharmony_ci unsigned seq; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci do { 240662306a36Sopenharmony_ci seq = read_seqcount_begin(&fs->seq); 240762306a36Sopenharmony_ci nd->path = fs->pwd; 240862306a36Sopenharmony_ci nd->inode = nd->path.dentry->d_inode; 240962306a36Sopenharmony_ci nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); 241062306a36Sopenharmony_ci } while (read_seqcount_retry(&fs->seq, seq)); 241162306a36Sopenharmony_ci } else { 241262306a36Sopenharmony_ci get_fs_pwd(current->fs, &nd->path); 241362306a36Sopenharmony_ci nd->inode = nd->path.dentry->d_inode; 241462306a36Sopenharmony_ci } 241562306a36Sopenharmony_ci } else { 241662306a36Sopenharmony_ci /* Caller must check execute permissions on the starting path component */ 241762306a36Sopenharmony_ci struct fd f = fdget_raw(nd->dfd); 241862306a36Sopenharmony_ci struct dentry *dentry; 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci if (!f.file) 242162306a36Sopenharmony_ci return ERR_PTR(-EBADF); 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci dentry = f.file->f_path.dentry; 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (*s && unlikely(!d_can_lookup(dentry))) { 242662306a36Sopenharmony_ci fdput(f); 242762306a36Sopenharmony_ci return ERR_PTR(-ENOTDIR); 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci nd->path = f.file->f_path; 243162306a36Sopenharmony_ci if (flags & LOOKUP_RCU) { 243262306a36Sopenharmony_ci nd->inode = nd->path.dentry->d_inode; 243362306a36Sopenharmony_ci nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); 243462306a36Sopenharmony_ci } else { 243562306a36Sopenharmony_ci path_get(&nd->path); 243662306a36Sopenharmony_ci nd->inode = nd->path.dentry->d_inode; 243762306a36Sopenharmony_ci } 243862306a36Sopenharmony_ci fdput(f); 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci /* For scoped-lookups we need to set the root to the dirfd as well. */ 244262306a36Sopenharmony_ci if (flags & LOOKUP_IS_SCOPED) { 244362306a36Sopenharmony_ci nd->root = nd->path; 244462306a36Sopenharmony_ci if (flags & LOOKUP_RCU) { 244562306a36Sopenharmony_ci nd->root_seq = nd->seq; 244662306a36Sopenharmony_ci } else { 244762306a36Sopenharmony_ci path_get(&nd->root); 244862306a36Sopenharmony_ci nd->state |= ND_ROOT_GRABBED; 244962306a36Sopenharmony_ci } 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci return s; 245262306a36Sopenharmony_ci} 245362306a36Sopenharmony_ci 245462306a36Sopenharmony_cistatic inline const char *lookup_last(struct nameidata *nd) 245562306a36Sopenharmony_ci{ 245662306a36Sopenharmony_ci if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) 245762306a36Sopenharmony_ci nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci return walk_component(nd, WALK_TRAILING); 246062306a36Sopenharmony_ci} 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_cistatic int handle_lookup_down(struct nameidata *nd) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci if (!(nd->flags & LOOKUP_RCU)) 246562306a36Sopenharmony_ci dget(nd->path.dentry); 246662306a36Sopenharmony_ci nd->next_seq = nd->seq; 246762306a36Sopenharmony_ci return PTR_ERR(step_into(nd, WALK_NOFOLLOW, nd->path.dentry)); 246862306a36Sopenharmony_ci} 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_ci/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ 247162306a36Sopenharmony_cistatic int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path) 247262306a36Sopenharmony_ci{ 247362306a36Sopenharmony_ci const char *s = path_init(nd, flags); 247462306a36Sopenharmony_ci int err; 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci if (unlikely(flags & LOOKUP_DOWN) && !IS_ERR(s)) { 247762306a36Sopenharmony_ci err = handle_lookup_down(nd); 247862306a36Sopenharmony_ci if (unlikely(err < 0)) 247962306a36Sopenharmony_ci s = ERR_PTR(err); 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci while (!(err = link_path_walk(s, nd)) && 248362306a36Sopenharmony_ci (s = lookup_last(nd)) != NULL) 248462306a36Sopenharmony_ci ; 248562306a36Sopenharmony_ci if (!err && unlikely(nd->flags & LOOKUP_MOUNTPOINT)) { 248662306a36Sopenharmony_ci err = handle_lookup_down(nd); 248762306a36Sopenharmony_ci nd->state &= ~ND_JUMPED; // no d_weak_revalidate(), please... 248862306a36Sopenharmony_ci } 248962306a36Sopenharmony_ci if (!err) 249062306a36Sopenharmony_ci err = complete_walk(nd); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci if (!err && nd->flags & LOOKUP_DIRECTORY) 249362306a36Sopenharmony_ci if (!d_can_lookup(nd->path.dentry)) 249462306a36Sopenharmony_ci err = -ENOTDIR; 249562306a36Sopenharmony_ci if (!err) { 249662306a36Sopenharmony_ci *path = nd->path; 249762306a36Sopenharmony_ci nd->path.mnt = NULL; 249862306a36Sopenharmony_ci nd->path.dentry = NULL; 249962306a36Sopenharmony_ci } 250062306a36Sopenharmony_ci terminate_walk(nd); 250162306a36Sopenharmony_ci return err; 250262306a36Sopenharmony_ci} 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ciint filename_lookup(int dfd, struct filename *name, unsigned flags, 250562306a36Sopenharmony_ci struct path *path, struct path *root) 250662306a36Sopenharmony_ci{ 250762306a36Sopenharmony_ci int retval; 250862306a36Sopenharmony_ci struct nameidata nd; 250962306a36Sopenharmony_ci if (IS_ERR(name)) 251062306a36Sopenharmony_ci return PTR_ERR(name); 251162306a36Sopenharmony_ci set_nameidata(&nd, dfd, name, root); 251262306a36Sopenharmony_ci retval = path_lookupat(&nd, flags | LOOKUP_RCU, path); 251362306a36Sopenharmony_ci if (unlikely(retval == -ECHILD)) 251462306a36Sopenharmony_ci retval = path_lookupat(&nd, flags, path); 251562306a36Sopenharmony_ci if (unlikely(retval == -ESTALE)) 251662306a36Sopenharmony_ci retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path); 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci if (likely(!retval)) 251962306a36Sopenharmony_ci audit_inode(name, path->dentry, 252062306a36Sopenharmony_ci flags & LOOKUP_MOUNTPOINT ? AUDIT_INODE_NOEVAL : 0); 252162306a36Sopenharmony_ci restore_nameidata(); 252262306a36Sopenharmony_ci return retval; 252362306a36Sopenharmony_ci} 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ 252662306a36Sopenharmony_cistatic int path_parentat(struct nameidata *nd, unsigned flags, 252762306a36Sopenharmony_ci struct path *parent) 252862306a36Sopenharmony_ci{ 252962306a36Sopenharmony_ci const char *s = path_init(nd, flags); 253062306a36Sopenharmony_ci int err = link_path_walk(s, nd); 253162306a36Sopenharmony_ci if (!err) 253262306a36Sopenharmony_ci err = complete_walk(nd); 253362306a36Sopenharmony_ci if (!err) { 253462306a36Sopenharmony_ci *parent = nd->path; 253562306a36Sopenharmony_ci nd->path.mnt = NULL; 253662306a36Sopenharmony_ci nd->path.dentry = NULL; 253762306a36Sopenharmony_ci } 253862306a36Sopenharmony_ci terminate_walk(nd); 253962306a36Sopenharmony_ci return err; 254062306a36Sopenharmony_ci} 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci/* Note: this does not consume "name" */ 254362306a36Sopenharmony_cistatic int __filename_parentat(int dfd, struct filename *name, 254462306a36Sopenharmony_ci unsigned int flags, struct path *parent, 254562306a36Sopenharmony_ci struct qstr *last, int *type, 254662306a36Sopenharmony_ci const struct path *root) 254762306a36Sopenharmony_ci{ 254862306a36Sopenharmony_ci int retval; 254962306a36Sopenharmony_ci struct nameidata nd; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci if (IS_ERR(name)) 255262306a36Sopenharmony_ci return PTR_ERR(name); 255362306a36Sopenharmony_ci set_nameidata(&nd, dfd, name, root); 255462306a36Sopenharmony_ci retval = path_parentat(&nd, flags | LOOKUP_RCU, parent); 255562306a36Sopenharmony_ci if (unlikely(retval == -ECHILD)) 255662306a36Sopenharmony_ci retval = path_parentat(&nd, flags, parent); 255762306a36Sopenharmony_ci if (unlikely(retval == -ESTALE)) 255862306a36Sopenharmony_ci retval = path_parentat(&nd, flags | LOOKUP_REVAL, parent); 255962306a36Sopenharmony_ci if (likely(!retval)) { 256062306a36Sopenharmony_ci *last = nd.last; 256162306a36Sopenharmony_ci *type = nd.last_type; 256262306a36Sopenharmony_ci audit_inode(name, parent->dentry, AUDIT_INODE_PARENT); 256362306a36Sopenharmony_ci } 256462306a36Sopenharmony_ci restore_nameidata(); 256562306a36Sopenharmony_ci return retval; 256662306a36Sopenharmony_ci} 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_cistatic int filename_parentat(int dfd, struct filename *name, 256962306a36Sopenharmony_ci unsigned int flags, struct path *parent, 257062306a36Sopenharmony_ci struct qstr *last, int *type) 257162306a36Sopenharmony_ci{ 257262306a36Sopenharmony_ci return __filename_parentat(dfd, name, flags, parent, last, type, NULL); 257362306a36Sopenharmony_ci} 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci/* does lookup, returns the object with parent locked */ 257662306a36Sopenharmony_cistatic struct dentry *__kern_path_locked(struct filename *name, struct path *path) 257762306a36Sopenharmony_ci{ 257862306a36Sopenharmony_ci struct dentry *d; 257962306a36Sopenharmony_ci struct qstr last; 258062306a36Sopenharmony_ci int type, error; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci error = filename_parentat(AT_FDCWD, name, 0, path, &last, &type); 258362306a36Sopenharmony_ci if (error) 258462306a36Sopenharmony_ci return ERR_PTR(error); 258562306a36Sopenharmony_ci if (unlikely(type != LAST_NORM)) { 258662306a36Sopenharmony_ci path_put(path); 258762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 258862306a36Sopenharmony_ci } 258962306a36Sopenharmony_ci inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); 259062306a36Sopenharmony_ci d = lookup_one_qstr_excl(&last, path->dentry, 0); 259162306a36Sopenharmony_ci if (IS_ERR(d)) { 259262306a36Sopenharmony_ci inode_unlock(path->dentry->d_inode); 259362306a36Sopenharmony_ci path_put(path); 259462306a36Sopenharmony_ci } 259562306a36Sopenharmony_ci return d; 259662306a36Sopenharmony_ci} 259762306a36Sopenharmony_ci 259862306a36Sopenharmony_cistruct dentry *kern_path_locked(const char *name, struct path *path) 259962306a36Sopenharmony_ci{ 260062306a36Sopenharmony_ci struct filename *filename = getname_kernel(name); 260162306a36Sopenharmony_ci struct dentry *res = __kern_path_locked(filename, path); 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_ci putname(filename); 260462306a36Sopenharmony_ci return res; 260562306a36Sopenharmony_ci} 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ciint kern_path(const char *name, unsigned int flags, struct path *path) 260862306a36Sopenharmony_ci{ 260962306a36Sopenharmony_ci struct filename *filename = getname_kernel(name); 261062306a36Sopenharmony_ci int ret = filename_lookup(AT_FDCWD, filename, flags, path, NULL); 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci putname(filename); 261362306a36Sopenharmony_ci return ret; 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci} 261662306a36Sopenharmony_ciEXPORT_SYMBOL(kern_path); 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_ci/** 261962306a36Sopenharmony_ci * vfs_path_parent_lookup - lookup a parent path relative to a dentry-vfsmount pair 262062306a36Sopenharmony_ci * @filename: filename structure 262162306a36Sopenharmony_ci * @flags: lookup flags 262262306a36Sopenharmony_ci * @parent: pointer to struct path to fill 262362306a36Sopenharmony_ci * @last: last component 262462306a36Sopenharmony_ci * @type: type of the last component 262562306a36Sopenharmony_ci * @root: pointer to struct path of the base directory 262662306a36Sopenharmony_ci */ 262762306a36Sopenharmony_ciint vfs_path_parent_lookup(struct filename *filename, unsigned int flags, 262862306a36Sopenharmony_ci struct path *parent, struct qstr *last, int *type, 262962306a36Sopenharmony_ci const struct path *root) 263062306a36Sopenharmony_ci{ 263162306a36Sopenharmony_ci return __filename_parentat(AT_FDCWD, filename, flags, parent, last, 263262306a36Sopenharmony_ci type, root); 263362306a36Sopenharmony_ci} 263462306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_path_parent_lookup); 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci/** 263762306a36Sopenharmony_ci * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair 263862306a36Sopenharmony_ci * @dentry: pointer to dentry of the base directory 263962306a36Sopenharmony_ci * @mnt: pointer to vfs mount of the base directory 264062306a36Sopenharmony_ci * @name: pointer to file name 264162306a36Sopenharmony_ci * @flags: lookup flags 264262306a36Sopenharmony_ci * @path: pointer to struct path to fill 264362306a36Sopenharmony_ci */ 264462306a36Sopenharmony_ciint vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, 264562306a36Sopenharmony_ci const char *name, unsigned int flags, 264662306a36Sopenharmony_ci struct path *path) 264762306a36Sopenharmony_ci{ 264862306a36Sopenharmony_ci struct filename *filename; 264962306a36Sopenharmony_ci struct path root = {.mnt = mnt, .dentry = dentry}; 265062306a36Sopenharmony_ci int ret; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci filename = getname_kernel(name); 265362306a36Sopenharmony_ci /* the first argument of filename_lookup() is ignored with root */ 265462306a36Sopenharmony_ci ret = filename_lookup(AT_FDCWD, filename, flags, path, &root); 265562306a36Sopenharmony_ci putname(filename); 265662306a36Sopenharmony_ci return ret; 265762306a36Sopenharmony_ci} 265862306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_path_lookup); 265962306a36Sopenharmony_ci 266062306a36Sopenharmony_cistatic int lookup_one_common(struct mnt_idmap *idmap, 266162306a36Sopenharmony_ci const char *name, struct dentry *base, int len, 266262306a36Sopenharmony_ci struct qstr *this) 266362306a36Sopenharmony_ci{ 266462306a36Sopenharmony_ci this->name = name; 266562306a36Sopenharmony_ci this->len = len; 266662306a36Sopenharmony_ci this->hash = full_name_hash(base, name, len); 266762306a36Sopenharmony_ci if (!len) 266862306a36Sopenharmony_ci return -EACCES; 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci if (unlikely(name[0] == '.')) { 267162306a36Sopenharmony_ci if (len < 2 || (len == 2 && name[1] == '.')) 267262306a36Sopenharmony_ci return -EACCES; 267362306a36Sopenharmony_ci } 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci while (len--) { 267662306a36Sopenharmony_ci unsigned int c = *(const unsigned char *)name++; 267762306a36Sopenharmony_ci if (c == '/' || c == '\0') 267862306a36Sopenharmony_ci return -EACCES; 267962306a36Sopenharmony_ci } 268062306a36Sopenharmony_ci /* 268162306a36Sopenharmony_ci * See if the low-level filesystem might want 268262306a36Sopenharmony_ci * to use its own hash.. 268362306a36Sopenharmony_ci */ 268462306a36Sopenharmony_ci if (base->d_flags & DCACHE_OP_HASH) { 268562306a36Sopenharmony_ci int err = base->d_op->d_hash(base, this); 268662306a36Sopenharmony_ci if (err < 0) 268762306a36Sopenharmony_ci return err; 268862306a36Sopenharmony_ci } 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_ci return inode_permission(idmap, base->d_inode, MAY_EXEC); 269162306a36Sopenharmony_ci} 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci/** 269462306a36Sopenharmony_ci * try_lookup_one_len - filesystem helper to lookup single pathname component 269562306a36Sopenharmony_ci * @name: pathname component to lookup 269662306a36Sopenharmony_ci * @base: base directory to lookup from 269762306a36Sopenharmony_ci * @len: maximum length @len should be interpreted to 269862306a36Sopenharmony_ci * 269962306a36Sopenharmony_ci * Look up a dentry by name in the dcache, returning NULL if it does not 270062306a36Sopenharmony_ci * currently exist. The function does not try to create a dentry. 270162306a36Sopenharmony_ci * 270262306a36Sopenharmony_ci * Note that this routine is purely a helper for filesystem usage and should 270362306a36Sopenharmony_ci * not be called by generic code. 270462306a36Sopenharmony_ci * 270562306a36Sopenharmony_ci * The caller must hold base->i_mutex. 270662306a36Sopenharmony_ci */ 270762306a36Sopenharmony_cistruct dentry *try_lookup_one_len(const char *name, struct dentry *base, int len) 270862306a36Sopenharmony_ci{ 270962306a36Sopenharmony_ci struct qstr this; 271062306a36Sopenharmony_ci int err; 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(base->d_inode)); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci err = lookup_one_common(&nop_mnt_idmap, name, base, len, &this); 271562306a36Sopenharmony_ci if (err) 271662306a36Sopenharmony_ci return ERR_PTR(err); 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci return lookup_dcache(&this, base, 0); 271962306a36Sopenharmony_ci} 272062306a36Sopenharmony_ciEXPORT_SYMBOL(try_lookup_one_len); 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci/** 272362306a36Sopenharmony_ci * lookup_one_len - filesystem helper to lookup single pathname component 272462306a36Sopenharmony_ci * @name: pathname component to lookup 272562306a36Sopenharmony_ci * @base: base directory to lookup from 272662306a36Sopenharmony_ci * @len: maximum length @len should be interpreted to 272762306a36Sopenharmony_ci * 272862306a36Sopenharmony_ci * Note that this routine is purely a helper for filesystem usage and should 272962306a36Sopenharmony_ci * not be called by generic code. 273062306a36Sopenharmony_ci * 273162306a36Sopenharmony_ci * The caller must hold base->i_mutex. 273262306a36Sopenharmony_ci */ 273362306a36Sopenharmony_cistruct dentry *lookup_one_len(const char *name, struct dentry *base, int len) 273462306a36Sopenharmony_ci{ 273562306a36Sopenharmony_ci struct dentry *dentry; 273662306a36Sopenharmony_ci struct qstr this; 273762306a36Sopenharmony_ci int err; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(base->d_inode)); 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci err = lookup_one_common(&nop_mnt_idmap, name, base, len, &this); 274262306a36Sopenharmony_ci if (err) 274362306a36Sopenharmony_ci return ERR_PTR(err); 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci dentry = lookup_dcache(&this, base, 0); 274662306a36Sopenharmony_ci return dentry ? dentry : __lookup_slow(&this, base, 0); 274762306a36Sopenharmony_ci} 274862306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_one_len); 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci/** 275162306a36Sopenharmony_ci * lookup_one - filesystem helper to lookup single pathname component 275262306a36Sopenharmony_ci * @idmap: idmap of the mount the lookup is performed from 275362306a36Sopenharmony_ci * @name: pathname component to lookup 275462306a36Sopenharmony_ci * @base: base directory to lookup from 275562306a36Sopenharmony_ci * @len: maximum length @len should be interpreted to 275662306a36Sopenharmony_ci * 275762306a36Sopenharmony_ci * Note that this routine is purely a helper for filesystem usage and should 275862306a36Sopenharmony_ci * not be called by generic code. 275962306a36Sopenharmony_ci * 276062306a36Sopenharmony_ci * The caller must hold base->i_mutex. 276162306a36Sopenharmony_ci */ 276262306a36Sopenharmony_cistruct dentry *lookup_one(struct mnt_idmap *idmap, const char *name, 276362306a36Sopenharmony_ci struct dentry *base, int len) 276462306a36Sopenharmony_ci{ 276562306a36Sopenharmony_ci struct dentry *dentry; 276662306a36Sopenharmony_ci struct qstr this; 276762306a36Sopenharmony_ci int err; 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci WARN_ON_ONCE(!inode_is_locked(base->d_inode)); 277062306a36Sopenharmony_ci 277162306a36Sopenharmony_ci err = lookup_one_common(idmap, name, base, len, &this); 277262306a36Sopenharmony_ci if (err) 277362306a36Sopenharmony_ci return ERR_PTR(err); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci dentry = lookup_dcache(&this, base, 0); 277662306a36Sopenharmony_ci return dentry ? dentry : __lookup_slow(&this, base, 0); 277762306a36Sopenharmony_ci} 277862306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_one); 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci/** 278162306a36Sopenharmony_ci * lookup_one_unlocked - filesystem helper to lookup single pathname component 278262306a36Sopenharmony_ci * @idmap: idmap of the mount the lookup is performed from 278362306a36Sopenharmony_ci * @name: pathname component to lookup 278462306a36Sopenharmony_ci * @base: base directory to lookup from 278562306a36Sopenharmony_ci * @len: maximum length @len should be interpreted to 278662306a36Sopenharmony_ci * 278762306a36Sopenharmony_ci * Note that this routine is purely a helper for filesystem usage and should 278862306a36Sopenharmony_ci * not be called by generic code. 278962306a36Sopenharmony_ci * 279062306a36Sopenharmony_ci * Unlike lookup_one_len, it should be called without the parent 279162306a36Sopenharmony_ci * i_mutex held, and will take the i_mutex itself if necessary. 279262306a36Sopenharmony_ci */ 279362306a36Sopenharmony_cistruct dentry *lookup_one_unlocked(struct mnt_idmap *idmap, 279462306a36Sopenharmony_ci const char *name, struct dentry *base, 279562306a36Sopenharmony_ci int len) 279662306a36Sopenharmony_ci{ 279762306a36Sopenharmony_ci struct qstr this; 279862306a36Sopenharmony_ci int err; 279962306a36Sopenharmony_ci struct dentry *ret; 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci err = lookup_one_common(idmap, name, base, len, &this); 280262306a36Sopenharmony_ci if (err) 280362306a36Sopenharmony_ci return ERR_PTR(err); 280462306a36Sopenharmony_ci 280562306a36Sopenharmony_ci ret = lookup_dcache(&this, base, 0); 280662306a36Sopenharmony_ci if (!ret) 280762306a36Sopenharmony_ci ret = lookup_slow(&this, base, 0); 280862306a36Sopenharmony_ci return ret; 280962306a36Sopenharmony_ci} 281062306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_one_unlocked); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci/** 281362306a36Sopenharmony_ci * lookup_one_positive_unlocked - filesystem helper to lookup single 281462306a36Sopenharmony_ci * pathname component 281562306a36Sopenharmony_ci * @idmap: idmap of the mount the lookup is performed from 281662306a36Sopenharmony_ci * @name: pathname component to lookup 281762306a36Sopenharmony_ci * @base: base directory to lookup from 281862306a36Sopenharmony_ci * @len: maximum length @len should be interpreted to 281962306a36Sopenharmony_ci * 282062306a36Sopenharmony_ci * This helper will yield ERR_PTR(-ENOENT) on negatives. The helper returns 282162306a36Sopenharmony_ci * known positive or ERR_PTR(). This is what most of the users want. 282262306a36Sopenharmony_ci * 282362306a36Sopenharmony_ci * Note that pinned negative with unlocked parent _can_ become positive at any 282462306a36Sopenharmony_ci * time, so callers of lookup_one_unlocked() need to be very careful; pinned 282562306a36Sopenharmony_ci * positives have >d_inode stable, so this one avoids such problems. 282662306a36Sopenharmony_ci * 282762306a36Sopenharmony_ci * Note that this routine is purely a helper for filesystem usage and should 282862306a36Sopenharmony_ci * not be called by generic code. 282962306a36Sopenharmony_ci * 283062306a36Sopenharmony_ci * The helper should be called without i_mutex held. 283162306a36Sopenharmony_ci */ 283262306a36Sopenharmony_cistruct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap, 283362306a36Sopenharmony_ci const char *name, 283462306a36Sopenharmony_ci struct dentry *base, int len) 283562306a36Sopenharmony_ci{ 283662306a36Sopenharmony_ci struct dentry *ret = lookup_one_unlocked(idmap, name, base, len); 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_ci if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) { 283962306a36Sopenharmony_ci dput(ret); 284062306a36Sopenharmony_ci ret = ERR_PTR(-ENOENT); 284162306a36Sopenharmony_ci } 284262306a36Sopenharmony_ci return ret; 284362306a36Sopenharmony_ci} 284462306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_one_positive_unlocked); 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_ci/** 284762306a36Sopenharmony_ci * lookup_one_len_unlocked - filesystem helper to lookup single pathname component 284862306a36Sopenharmony_ci * @name: pathname component to lookup 284962306a36Sopenharmony_ci * @base: base directory to lookup from 285062306a36Sopenharmony_ci * @len: maximum length @len should be interpreted to 285162306a36Sopenharmony_ci * 285262306a36Sopenharmony_ci * Note that this routine is purely a helper for filesystem usage and should 285362306a36Sopenharmony_ci * not be called by generic code. 285462306a36Sopenharmony_ci * 285562306a36Sopenharmony_ci * Unlike lookup_one_len, it should be called without the parent 285662306a36Sopenharmony_ci * i_mutex held, and will take the i_mutex itself if necessary. 285762306a36Sopenharmony_ci */ 285862306a36Sopenharmony_cistruct dentry *lookup_one_len_unlocked(const char *name, 285962306a36Sopenharmony_ci struct dentry *base, int len) 286062306a36Sopenharmony_ci{ 286162306a36Sopenharmony_ci return lookup_one_unlocked(&nop_mnt_idmap, name, base, len); 286262306a36Sopenharmony_ci} 286362306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_one_len_unlocked); 286462306a36Sopenharmony_ci 286562306a36Sopenharmony_ci/* 286662306a36Sopenharmony_ci * Like lookup_one_len_unlocked(), except that it yields ERR_PTR(-ENOENT) 286762306a36Sopenharmony_ci * on negatives. Returns known positive or ERR_PTR(); that's what 286862306a36Sopenharmony_ci * most of the users want. Note that pinned negative with unlocked parent 286962306a36Sopenharmony_ci * _can_ become positive at any time, so callers of lookup_one_len_unlocked() 287062306a36Sopenharmony_ci * need to be very careful; pinned positives have ->d_inode stable, so 287162306a36Sopenharmony_ci * this one avoids such problems. 287262306a36Sopenharmony_ci */ 287362306a36Sopenharmony_cistruct dentry *lookup_positive_unlocked(const char *name, 287462306a36Sopenharmony_ci struct dentry *base, int len) 287562306a36Sopenharmony_ci{ 287662306a36Sopenharmony_ci return lookup_one_positive_unlocked(&nop_mnt_idmap, name, base, len); 287762306a36Sopenharmony_ci} 287862306a36Sopenharmony_ciEXPORT_SYMBOL(lookup_positive_unlocked); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci#ifdef CONFIG_UNIX98_PTYS 288162306a36Sopenharmony_ciint path_pts(struct path *path) 288262306a36Sopenharmony_ci{ 288362306a36Sopenharmony_ci /* Find something mounted on "pts" in the same directory as 288462306a36Sopenharmony_ci * the input path. 288562306a36Sopenharmony_ci */ 288662306a36Sopenharmony_ci struct dentry *parent = dget_parent(path->dentry); 288762306a36Sopenharmony_ci struct dentry *child; 288862306a36Sopenharmony_ci struct qstr this = QSTR_INIT("pts", 3); 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci if (unlikely(!path_connected(path->mnt, parent))) { 289162306a36Sopenharmony_ci dput(parent); 289262306a36Sopenharmony_ci return -ENOENT; 289362306a36Sopenharmony_ci } 289462306a36Sopenharmony_ci dput(path->dentry); 289562306a36Sopenharmony_ci path->dentry = parent; 289662306a36Sopenharmony_ci child = d_hash_and_lookup(parent, &this); 289762306a36Sopenharmony_ci if (IS_ERR_OR_NULL(child)) 289862306a36Sopenharmony_ci return -ENOENT; 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci path->dentry = child; 290162306a36Sopenharmony_ci dput(parent); 290262306a36Sopenharmony_ci follow_down(path, 0); 290362306a36Sopenharmony_ci return 0; 290462306a36Sopenharmony_ci} 290562306a36Sopenharmony_ci#endif 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ciint user_path_at_empty(int dfd, const char __user *name, unsigned flags, 290862306a36Sopenharmony_ci struct path *path, int *empty) 290962306a36Sopenharmony_ci{ 291062306a36Sopenharmony_ci struct filename *filename = getname_flags(name, flags, empty); 291162306a36Sopenharmony_ci int ret = filename_lookup(dfd, filename, flags, path, NULL); 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci putname(filename); 291462306a36Sopenharmony_ci return ret; 291562306a36Sopenharmony_ci} 291662306a36Sopenharmony_ciEXPORT_SYMBOL(user_path_at_empty); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ciint __check_sticky(struct mnt_idmap *idmap, struct inode *dir, 291962306a36Sopenharmony_ci struct inode *inode) 292062306a36Sopenharmony_ci{ 292162306a36Sopenharmony_ci kuid_t fsuid = current_fsuid(); 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_ci if (vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode), fsuid)) 292462306a36Sopenharmony_ci return 0; 292562306a36Sopenharmony_ci if (vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, dir), fsuid)) 292662306a36Sopenharmony_ci return 0; 292762306a36Sopenharmony_ci return !capable_wrt_inode_uidgid(idmap, inode, CAP_FOWNER); 292862306a36Sopenharmony_ci} 292962306a36Sopenharmony_ciEXPORT_SYMBOL(__check_sticky); 293062306a36Sopenharmony_ci 293162306a36Sopenharmony_ci/* 293262306a36Sopenharmony_ci * Check whether we can remove a link victim from directory dir, check 293362306a36Sopenharmony_ci * whether the type of victim is right. 293462306a36Sopenharmony_ci * 1. We can't do it if dir is read-only (done in permission()) 293562306a36Sopenharmony_ci * 2. We should have write and exec permissions on dir 293662306a36Sopenharmony_ci * 3. We can't remove anything from append-only dir 293762306a36Sopenharmony_ci * 4. We can't do anything with immutable dir (done in permission()) 293862306a36Sopenharmony_ci * 5. If the sticky bit on dir is set we should either 293962306a36Sopenharmony_ci * a. be owner of dir, or 294062306a36Sopenharmony_ci * b. be owner of victim, or 294162306a36Sopenharmony_ci * c. have CAP_FOWNER capability 294262306a36Sopenharmony_ci * 6. If the victim is append-only or immutable we can't do antyhing with 294362306a36Sopenharmony_ci * links pointing to it. 294462306a36Sopenharmony_ci * 7. If the victim has an unknown uid or gid we can't change the inode. 294562306a36Sopenharmony_ci * 8. If we were asked to remove a directory and victim isn't one - ENOTDIR. 294662306a36Sopenharmony_ci * 9. If we were asked to remove a non-directory and victim isn't one - EISDIR. 294762306a36Sopenharmony_ci * 10. We can't remove a root or mountpoint. 294862306a36Sopenharmony_ci * 11. We don't allow removal of NFS sillyrenamed files; it's handled by 294962306a36Sopenharmony_ci * nfs_async_unlink(). 295062306a36Sopenharmony_ci */ 295162306a36Sopenharmony_cistatic int may_delete(struct mnt_idmap *idmap, struct inode *dir, 295262306a36Sopenharmony_ci struct dentry *victim, bool isdir) 295362306a36Sopenharmony_ci{ 295462306a36Sopenharmony_ci struct inode *inode = d_backing_inode(victim); 295562306a36Sopenharmony_ci int error; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci if (d_is_negative(victim)) 295862306a36Sopenharmony_ci return -ENOENT; 295962306a36Sopenharmony_ci BUG_ON(!inode); 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci BUG_ON(victim->d_parent->d_inode != dir); 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci /* Inode writeback is not safe when the uid or gid are invalid. */ 296462306a36Sopenharmony_ci if (!vfsuid_valid(i_uid_into_vfsuid(idmap, inode)) || 296562306a36Sopenharmony_ci !vfsgid_valid(i_gid_into_vfsgid(idmap, inode))) 296662306a36Sopenharmony_ci return -EOVERFLOW; 296762306a36Sopenharmony_ci 296862306a36Sopenharmony_ci audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC); 297162306a36Sopenharmony_ci if (error) 297262306a36Sopenharmony_ci return error; 297362306a36Sopenharmony_ci if (IS_APPEND(dir)) 297462306a36Sopenharmony_ci return -EPERM; 297562306a36Sopenharmony_ci 297662306a36Sopenharmony_ci if (check_sticky(idmap, dir, inode) || IS_APPEND(inode) || 297762306a36Sopenharmony_ci IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || 297862306a36Sopenharmony_ci HAS_UNMAPPED_ID(idmap, inode)) 297962306a36Sopenharmony_ci return -EPERM; 298062306a36Sopenharmony_ci if (isdir) { 298162306a36Sopenharmony_ci if (!d_is_dir(victim)) 298262306a36Sopenharmony_ci return -ENOTDIR; 298362306a36Sopenharmony_ci if (IS_ROOT(victim)) 298462306a36Sopenharmony_ci return -EBUSY; 298562306a36Sopenharmony_ci } else if (d_is_dir(victim)) 298662306a36Sopenharmony_ci return -EISDIR; 298762306a36Sopenharmony_ci if (IS_DEADDIR(dir)) 298862306a36Sopenharmony_ci return -ENOENT; 298962306a36Sopenharmony_ci if (victim->d_flags & DCACHE_NFSFS_RENAMED) 299062306a36Sopenharmony_ci return -EBUSY; 299162306a36Sopenharmony_ci return 0; 299262306a36Sopenharmony_ci} 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci/* Check whether we can create an object with dentry child in directory 299562306a36Sopenharmony_ci * dir. 299662306a36Sopenharmony_ci * 1. We can't do it if child already exists (open has special treatment for 299762306a36Sopenharmony_ci * this case, but since we are inlined it's OK) 299862306a36Sopenharmony_ci * 2. We can't do it if dir is read-only (done in permission()) 299962306a36Sopenharmony_ci * 3. We can't do it if the fs can't represent the fsuid or fsgid. 300062306a36Sopenharmony_ci * 4. We should have write and exec permissions on dir 300162306a36Sopenharmony_ci * 5. We can't do it if dir is immutable (done in permission()) 300262306a36Sopenharmony_ci */ 300362306a36Sopenharmony_cistatic inline int may_create(struct mnt_idmap *idmap, 300462306a36Sopenharmony_ci struct inode *dir, struct dentry *child) 300562306a36Sopenharmony_ci{ 300662306a36Sopenharmony_ci audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); 300762306a36Sopenharmony_ci if (child->d_inode) 300862306a36Sopenharmony_ci return -EEXIST; 300962306a36Sopenharmony_ci if (IS_DEADDIR(dir)) 301062306a36Sopenharmony_ci return -ENOENT; 301162306a36Sopenharmony_ci if (!fsuidgid_has_mapping(dir->i_sb, idmap)) 301262306a36Sopenharmony_ci return -EOVERFLOW; 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci return inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC); 301562306a36Sopenharmony_ci} 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_cistatic struct dentry *lock_two_directories(struct dentry *p1, struct dentry *p2) 301862306a36Sopenharmony_ci{ 301962306a36Sopenharmony_ci struct dentry *p; 302062306a36Sopenharmony_ci 302162306a36Sopenharmony_ci p = d_ancestor(p2, p1); 302262306a36Sopenharmony_ci if (p) { 302362306a36Sopenharmony_ci inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); 302462306a36Sopenharmony_ci inode_lock_nested(p1->d_inode, I_MUTEX_PARENT2); 302562306a36Sopenharmony_ci return p; 302662306a36Sopenharmony_ci } 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci p = d_ancestor(p1, p2); 302962306a36Sopenharmony_ci inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); 303062306a36Sopenharmony_ci inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2); 303162306a36Sopenharmony_ci return p; 303262306a36Sopenharmony_ci} 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci/* 303562306a36Sopenharmony_ci * p1 and p2 should be directories on the same fs. 303662306a36Sopenharmony_ci */ 303762306a36Sopenharmony_cistruct dentry *lock_rename(struct dentry *p1, struct dentry *p2) 303862306a36Sopenharmony_ci{ 303962306a36Sopenharmony_ci if (p1 == p2) { 304062306a36Sopenharmony_ci inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); 304162306a36Sopenharmony_ci return NULL; 304262306a36Sopenharmony_ci } 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci mutex_lock(&p1->d_sb->s_vfs_rename_mutex); 304562306a36Sopenharmony_ci return lock_two_directories(p1, p2); 304662306a36Sopenharmony_ci} 304762306a36Sopenharmony_ciEXPORT_SYMBOL(lock_rename); 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci/* 305062306a36Sopenharmony_ci * c1 and p2 should be on the same fs. 305162306a36Sopenharmony_ci */ 305262306a36Sopenharmony_cistruct dentry *lock_rename_child(struct dentry *c1, struct dentry *p2) 305362306a36Sopenharmony_ci{ 305462306a36Sopenharmony_ci if (READ_ONCE(c1->d_parent) == p2) { 305562306a36Sopenharmony_ci /* 305662306a36Sopenharmony_ci * hopefully won't need to touch ->s_vfs_rename_mutex at all. 305762306a36Sopenharmony_ci */ 305862306a36Sopenharmony_ci inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); 305962306a36Sopenharmony_ci /* 306062306a36Sopenharmony_ci * now that p2 is locked, nobody can move in or out of it, 306162306a36Sopenharmony_ci * so the test below is safe. 306262306a36Sopenharmony_ci */ 306362306a36Sopenharmony_ci if (likely(c1->d_parent == p2)) 306462306a36Sopenharmony_ci return NULL; 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci /* 306762306a36Sopenharmony_ci * c1 got moved out of p2 while we'd been taking locks; 306862306a36Sopenharmony_ci * unlock and fall back to slow case. 306962306a36Sopenharmony_ci */ 307062306a36Sopenharmony_ci inode_unlock(p2->d_inode); 307162306a36Sopenharmony_ci } 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci mutex_lock(&c1->d_sb->s_vfs_rename_mutex); 307462306a36Sopenharmony_ci /* 307562306a36Sopenharmony_ci * nobody can move out of any directories on this fs. 307662306a36Sopenharmony_ci */ 307762306a36Sopenharmony_ci if (likely(c1->d_parent != p2)) 307862306a36Sopenharmony_ci return lock_two_directories(c1->d_parent, p2); 307962306a36Sopenharmony_ci 308062306a36Sopenharmony_ci /* 308162306a36Sopenharmony_ci * c1 got moved into p2 while we were taking locks; 308262306a36Sopenharmony_ci * we need p2 locked and ->s_vfs_rename_mutex unlocked, 308362306a36Sopenharmony_ci * for consistency with lock_rename(). 308462306a36Sopenharmony_ci */ 308562306a36Sopenharmony_ci inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); 308662306a36Sopenharmony_ci mutex_unlock(&c1->d_sb->s_vfs_rename_mutex); 308762306a36Sopenharmony_ci return NULL; 308862306a36Sopenharmony_ci} 308962306a36Sopenharmony_ciEXPORT_SYMBOL(lock_rename_child); 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_civoid unlock_rename(struct dentry *p1, struct dentry *p2) 309262306a36Sopenharmony_ci{ 309362306a36Sopenharmony_ci inode_unlock(p1->d_inode); 309462306a36Sopenharmony_ci if (p1 != p2) { 309562306a36Sopenharmony_ci inode_unlock(p2->d_inode); 309662306a36Sopenharmony_ci mutex_unlock(&p1->d_sb->s_vfs_rename_mutex); 309762306a36Sopenharmony_ci } 309862306a36Sopenharmony_ci} 309962306a36Sopenharmony_ciEXPORT_SYMBOL(unlock_rename); 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci/** 310262306a36Sopenharmony_ci * mode_strip_umask - handle vfs umask stripping 310362306a36Sopenharmony_ci * @dir: parent directory of the new inode 310462306a36Sopenharmony_ci * @mode: mode of the new inode to be created in @dir 310562306a36Sopenharmony_ci * 310662306a36Sopenharmony_ci * Umask stripping depends on whether or not the filesystem supports POSIX 310762306a36Sopenharmony_ci * ACLs. If the filesystem doesn't support it umask stripping is done directly 310862306a36Sopenharmony_ci * in here. If the filesystem does support POSIX ACLs umask stripping is 310962306a36Sopenharmony_ci * deferred until the filesystem calls posix_acl_create(). 311062306a36Sopenharmony_ci * 311162306a36Sopenharmony_ci * Returns: mode 311262306a36Sopenharmony_ci */ 311362306a36Sopenharmony_cistatic inline umode_t mode_strip_umask(const struct inode *dir, umode_t mode) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci if (!IS_POSIXACL(dir)) 311662306a36Sopenharmony_ci mode &= ~current_umask(); 311762306a36Sopenharmony_ci return mode; 311862306a36Sopenharmony_ci} 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci/** 312162306a36Sopenharmony_ci * vfs_prepare_mode - prepare the mode to be used for a new inode 312262306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 312362306a36Sopenharmony_ci * @dir: parent directory of the new inode 312462306a36Sopenharmony_ci * @mode: mode of the new inode 312562306a36Sopenharmony_ci * @mask_perms: allowed permission by the vfs 312662306a36Sopenharmony_ci * @type: type of file to be created 312762306a36Sopenharmony_ci * 312862306a36Sopenharmony_ci * This helper consolidates and enforces vfs restrictions on the @mode of a new 312962306a36Sopenharmony_ci * object to be created. 313062306a36Sopenharmony_ci * 313162306a36Sopenharmony_ci * Umask stripping depends on whether the filesystem supports POSIX ACLs (see 313262306a36Sopenharmony_ci * the kernel documentation for mode_strip_umask()). Moving umask stripping 313362306a36Sopenharmony_ci * after setgid stripping allows the same ordering for both non-POSIX ACL and 313462306a36Sopenharmony_ci * POSIX ACL supporting filesystems. 313562306a36Sopenharmony_ci * 313662306a36Sopenharmony_ci * Note that it's currently valid for @type to be 0 if a directory is created. 313762306a36Sopenharmony_ci * Filesystems raise that flag individually and we need to check whether each 313862306a36Sopenharmony_ci * filesystem can deal with receiving S_IFDIR from the vfs before we enforce a 313962306a36Sopenharmony_ci * non-zero type. 314062306a36Sopenharmony_ci * 314162306a36Sopenharmony_ci * Returns: mode to be passed to the filesystem 314262306a36Sopenharmony_ci */ 314362306a36Sopenharmony_cistatic inline umode_t vfs_prepare_mode(struct mnt_idmap *idmap, 314462306a36Sopenharmony_ci const struct inode *dir, umode_t mode, 314562306a36Sopenharmony_ci umode_t mask_perms, umode_t type) 314662306a36Sopenharmony_ci{ 314762306a36Sopenharmony_ci mode = mode_strip_sgid(idmap, dir, mode); 314862306a36Sopenharmony_ci mode = mode_strip_umask(dir, mode); 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci /* 315162306a36Sopenharmony_ci * Apply the vfs mandated allowed permission mask and set the type of 315262306a36Sopenharmony_ci * file to be created before we call into the filesystem. 315362306a36Sopenharmony_ci */ 315462306a36Sopenharmony_ci mode &= (mask_perms & ~S_IFMT); 315562306a36Sopenharmony_ci mode |= (type & S_IFMT); 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci return mode; 315862306a36Sopenharmony_ci} 315962306a36Sopenharmony_ci 316062306a36Sopenharmony_ci/** 316162306a36Sopenharmony_ci * vfs_create - create new file 316262306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 316362306a36Sopenharmony_ci * @dir: inode of @dentry 316462306a36Sopenharmony_ci * @dentry: pointer to dentry of the base directory 316562306a36Sopenharmony_ci * @mode: mode of the new file 316662306a36Sopenharmony_ci * @want_excl: whether the file must not yet exist 316762306a36Sopenharmony_ci * 316862306a36Sopenharmony_ci * Create a new file. 316962306a36Sopenharmony_ci * 317062306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 317162306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 317262306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 317362306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 317462306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 317562306a36Sopenharmony_ci */ 317662306a36Sopenharmony_ciint vfs_create(struct mnt_idmap *idmap, struct inode *dir, 317762306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, bool want_excl) 317862306a36Sopenharmony_ci{ 317962306a36Sopenharmony_ci int error; 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci error = may_create(idmap, dir, dentry); 318262306a36Sopenharmony_ci if (error) 318362306a36Sopenharmony_ci return error; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_ci if (!dir->i_op->create) 318662306a36Sopenharmony_ci return -EACCES; /* shouldn't it be ENOSYS? */ 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci mode = vfs_prepare_mode(idmap, dir, mode, S_IALLUGO, S_IFREG); 318962306a36Sopenharmony_ci error = security_inode_create(dir, dentry, mode); 319062306a36Sopenharmony_ci if (error) 319162306a36Sopenharmony_ci return error; 319262306a36Sopenharmony_ci error = dir->i_op->create(idmap, dir, dentry, mode, want_excl); 319362306a36Sopenharmony_ci if (!error) 319462306a36Sopenharmony_ci fsnotify_create(dir, dentry); 319562306a36Sopenharmony_ci return error; 319662306a36Sopenharmony_ci} 319762306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_create); 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ciint vfs_mkobj(struct dentry *dentry, umode_t mode, 320062306a36Sopenharmony_ci int (*f)(struct dentry *, umode_t, void *), 320162306a36Sopenharmony_ci void *arg) 320262306a36Sopenharmony_ci{ 320362306a36Sopenharmony_ci struct inode *dir = dentry->d_parent->d_inode; 320462306a36Sopenharmony_ci int error = may_create(&nop_mnt_idmap, dir, dentry); 320562306a36Sopenharmony_ci if (error) 320662306a36Sopenharmony_ci return error; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci mode &= S_IALLUGO; 320962306a36Sopenharmony_ci mode |= S_IFREG; 321062306a36Sopenharmony_ci error = security_inode_create(dir, dentry, mode); 321162306a36Sopenharmony_ci if (error) 321262306a36Sopenharmony_ci return error; 321362306a36Sopenharmony_ci error = f(dentry, mode, arg); 321462306a36Sopenharmony_ci if (!error) 321562306a36Sopenharmony_ci fsnotify_create(dir, dentry); 321662306a36Sopenharmony_ci return error; 321762306a36Sopenharmony_ci} 321862306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_mkobj); 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_cibool may_open_dev(const struct path *path) 322162306a36Sopenharmony_ci{ 322262306a36Sopenharmony_ci return !(path->mnt->mnt_flags & MNT_NODEV) && 322362306a36Sopenharmony_ci !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV); 322462306a36Sopenharmony_ci} 322562306a36Sopenharmony_ci 322662306a36Sopenharmony_cistatic int may_open(struct mnt_idmap *idmap, const struct path *path, 322762306a36Sopenharmony_ci int acc_mode, int flag) 322862306a36Sopenharmony_ci{ 322962306a36Sopenharmony_ci struct dentry *dentry = path->dentry; 323062306a36Sopenharmony_ci struct inode *inode = dentry->d_inode; 323162306a36Sopenharmony_ci int error; 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci if (!inode) 323462306a36Sopenharmony_ci return -ENOENT; 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci switch (inode->i_mode & S_IFMT) { 323762306a36Sopenharmony_ci case S_IFLNK: 323862306a36Sopenharmony_ci return -ELOOP; 323962306a36Sopenharmony_ci case S_IFDIR: 324062306a36Sopenharmony_ci if (acc_mode & MAY_WRITE) 324162306a36Sopenharmony_ci return -EISDIR; 324262306a36Sopenharmony_ci if (acc_mode & MAY_EXEC) 324362306a36Sopenharmony_ci return -EACCES; 324462306a36Sopenharmony_ci break; 324562306a36Sopenharmony_ci case S_IFBLK: 324662306a36Sopenharmony_ci case S_IFCHR: 324762306a36Sopenharmony_ci if (!may_open_dev(path)) 324862306a36Sopenharmony_ci return -EACCES; 324962306a36Sopenharmony_ci fallthrough; 325062306a36Sopenharmony_ci case S_IFIFO: 325162306a36Sopenharmony_ci case S_IFSOCK: 325262306a36Sopenharmony_ci if (acc_mode & MAY_EXEC) 325362306a36Sopenharmony_ci return -EACCES; 325462306a36Sopenharmony_ci flag &= ~O_TRUNC; 325562306a36Sopenharmony_ci break; 325662306a36Sopenharmony_ci case S_IFREG: 325762306a36Sopenharmony_ci if ((acc_mode & MAY_EXEC) && path_noexec(path)) 325862306a36Sopenharmony_ci return -EACCES; 325962306a36Sopenharmony_ci break; 326062306a36Sopenharmony_ci } 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci error = inode_permission(idmap, inode, MAY_OPEN | acc_mode); 326362306a36Sopenharmony_ci if (error) 326462306a36Sopenharmony_ci return error; 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci /* 326762306a36Sopenharmony_ci * An append-only file must be opened in append mode for writing. 326862306a36Sopenharmony_ci */ 326962306a36Sopenharmony_ci if (IS_APPEND(inode)) { 327062306a36Sopenharmony_ci if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) 327162306a36Sopenharmony_ci return -EPERM; 327262306a36Sopenharmony_ci if (flag & O_TRUNC) 327362306a36Sopenharmony_ci return -EPERM; 327462306a36Sopenharmony_ci } 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci /* O_NOATIME can only be set by the owner or superuser */ 327762306a36Sopenharmony_ci if (flag & O_NOATIME && !inode_owner_or_capable(idmap, inode)) 327862306a36Sopenharmony_ci return -EPERM; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci return 0; 328162306a36Sopenharmony_ci} 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_cistatic int handle_truncate(struct mnt_idmap *idmap, struct file *filp) 328462306a36Sopenharmony_ci{ 328562306a36Sopenharmony_ci const struct path *path = &filp->f_path; 328662306a36Sopenharmony_ci struct inode *inode = path->dentry->d_inode; 328762306a36Sopenharmony_ci int error = get_write_access(inode); 328862306a36Sopenharmony_ci if (error) 328962306a36Sopenharmony_ci return error; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci error = security_file_truncate(filp); 329262306a36Sopenharmony_ci if (!error) { 329362306a36Sopenharmony_ci error = do_truncate(idmap, path->dentry, 0, 329462306a36Sopenharmony_ci ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, 329562306a36Sopenharmony_ci filp); 329662306a36Sopenharmony_ci } 329762306a36Sopenharmony_ci put_write_access(inode); 329862306a36Sopenharmony_ci return error; 329962306a36Sopenharmony_ci} 330062306a36Sopenharmony_ci 330162306a36Sopenharmony_cistatic inline int open_to_namei_flags(int flag) 330262306a36Sopenharmony_ci{ 330362306a36Sopenharmony_ci if ((flag & O_ACCMODE) == 3) 330462306a36Sopenharmony_ci flag--; 330562306a36Sopenharmony_ci return flag; 330662306a36Sopenharmony_ci} 330762306a36Sopenharmony_ci 330862306a36Sopenharmony_cistatic int may_o_create(struct mnt_idmap *idmap, 330962306a36Sopenharmony_ci const struct path *dir, struct dentry *dentry, 331062306a36Sopenharmony_ci umode_t mode) 331162306a36Sopenharmony_ci{ 331262306a36Sopenharmony_ci int error = security_path_mknod(dir, dentry, mode, 0); 331362306a36Sopenharmony_ci if (error) 331462306a36Sopenharmony_ci return error; 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci if (!fsuidgid_has_mapping(dir->dentry->d_sb, idmap)) 331762306a36Sopenharmony_ci return -EOVERFLOW; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci error = inode_permission(idmap, dir->dentry->d_inode, 332062306a36Sopenharmony_ci MAY_WRITE | MAY_EXEC); 332162306a36Sopenharmony_ci if (error) 332262306a36Sopenharmony_ci return error; 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_ci return security_inode_create(dir->dentry->d_inode, dentry, mode); 332562306a36Sopenharmony_ci} 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_ci/* 332862306a36Sopenharmony_ci * Attempt to atomically look up, create and open a file from a negative 332962306a36Sopenharmony_ci * dentry. 333062306a36Sopenharmony_ci * 333162306a36Sopenharmony_ci * Returns 0 if successful. The file will have been created and attached to 333262306a36Sopenharmony_ci * @file by the filesystem calling finish_open(). 333362306a36Sopenharmony_ci * 333462306a36Sopenharmony_ci * If the file was looked up only or didn't need creating, FMODE_OPENED won't 333562306a36Sopenharmony_ci * be set. The caller will need to perform the open themselves. @path will 333662306a36Sopenharmony_ci * have been updated to point to the new dentry. This may be negative. 333762306a36Sopenharmony_ci * 333862306a36Sopenharmony_ci * Returns an error code otherwise. 333962306a36Sopenharmony_ci */ 334062306a36Sopenharmony_cistatic struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry, 334162306a36Sopenharmony_ci struct file *file, 334262306a36Sopenharmony_ci int open_flag, umode_t mode) 334362306a36Sopenharmony_ci{ 334462306a36Sopenharmony_ci struct dentry *const DENTRY_NOT_SET = (void *) -1UL; 334562306a36Sopenharmony_ci struct inode *dir = nd->path.dentry->d_inode; 334662306a36Sopenharmony_ci int error; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci if (nd->flags & LOOKUP_DIRECTORY) 334962306a36Sopenharmony_ci open_flag |= O_DIRECTORY; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci file->f_path.dentry = DENTRY_NOT_SET; 335262306a36Sopenharmony_ci file->f_path.mnt = nd->path.mnt; 335362306a36Sopenharmony_ci error = dir->i_op->atomic_open(dir, dentry, file, 335462306a36Sopenharmony_ci open_to_namei_flags(open_flag), mode); 335562306a36Sopenharmony_ci d_lookup_done(dentry); 335662306a36Sopenharmony_ci if (!error) { 335762306a36Sopenharmony_ci if (file->f_mode & FMODE_OPENED) { 335862306a36Sopenharmony_ci if (unlikely(dentry != file->f_path.dentry)) { 335962306a36Sopenharmony_ci dput(dentry); 336062306a36Sopenharmony_ci dentry = dget(file->f_path.dentry); 336162306a36Sopenharmony_ci } 336262306a36Sopenharmony_ci } else if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { 336362306a36Sopenharmony_ci error = -EIO; 336462306a36Sopenharmony_ci } else { 336562306a36Sopenharmony_ci if (file->f_path.dentry) { 336662306a36Sopenharmony_ci dput(dentry); 336762306a36Sopenharmony_ci dentry = file->f_path.dentry; 336862306a36Sopenharmony_ci } 336962306a36Sopenharmony_ci if (unlikely(d_is_negative(dentry))) 337062306a36Sopenharmony_ci error = -ENOENT; 337162306a36Sopenharmony_ci } 337262306a36Sopenharmony_ci } 337362306a36Sopenharmony_ci if (error) { 337462306a36Sopenharmony_ci dput(dentry); 337562306a36Sopenharmony_ci dentry = ERR_PTR(error); 337662306a36Sopenharmony_ci } 337762306a36Sopenharmony_ci return dentry; 337862306a36Sopenharmony_ci} 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci/* 338162306a36Sopenharmony_ci * Look up and maybe create and open the last component. 338262306a36Sopenharmony_ci * 338362306a36Sopenharmony_ci * Must be called with parent locked (exclusive in O_CREAT case). 338462306a36Sopenharmony_ci * 338562306a36Sopenharmony_ci * Returns 0 on success, that is, if 338662306a36Sopenharmony_ci * the file was successfully atomically created (if necessary) and opened, or 338762306a36Sopenharmony_ci * the file was not completely opened at this time, though lookups and 338862306a36Sopenharmony_ci * creations were performed. 338962306a36Sopenharmony_ci * These case are distinguished by presence of FMODE_OPENED on file->f_mode. 339062306a36Sopenharmony_ci * In the latter case dentry returned in @path might be negative if O_CREAT 339162306a36Sopenharmony_ci * hadn't been specified. 339262306a36Sopenharmony_ci * 339362306a36Sopenharmony_ci * An error code is returned on failure. 339462306a36Sopenharmony_ci */ 339562306a36Sopenharmony_cistatic struct dentry *lookup_open(struct nameidata *nd, struct file *file, 339662306a36Sopenharmony_ci const struct open_flags *op, 339762306a36Sopenharmony_ci bool got_write) 339862306a36Sopenharmony_ci{ 339962306a36Sopenharmony_ci struct mnt_idmap *idmap; 340062306a36Sopenharmony_ci struct dentry *dir = nd->path.dentry; 340162306a36Sopenharmony_ci struct inode *dir_inode = dir->d_inode; 340262306a36Sopenharmony_ci int open_flag = op->open_flag; 340362306a36Sopenharmony_ci struct dentry *dentry; 340462306a36Sopenharmony_ci int error, create_error = 0; 340562306a36Sopenharmony_ci umode_t mode = op->mode; 340662306a36Sopenharmony_ci DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); 340762306a36Sopenharmony_ci 340862306a36Sopenharmony_ci if (unlikely(IS_DEADDIR(dir_inode))) 340962306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci file->f_mode &= ~FMODE_CREATED; 341262306a36Sopenharmony_ci dentry = d_lookup(dir, &nd->last); 341362306a36Sopenharmony_ci for (;;) { 341462306a36Sopenharmony_ci if (!dentry) { 341562306a36Sopenharmony_ci dentry = d_alloc_parallel(dir, &nd->last, &wq); 341662306a36Sopenharmony_ci if (IS_ERR(dentry)) 341762306a36Sopenharmony_ci return dentry; 341862306a36Sopenharmony_ci } 341962306a36Sopenharmony_ci if (d_in_lookup(dentry)) 342062306a36Sopenharmony_ci break; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_ci error = d_revalidate(dentry, nd->flags); 342362306a36Sopenharmony_ci if (likely(error > 0)) 342462306a36Sopenharmony_ci break; 342562306a36Sopenharmony_ci if (error) 342662306a36Sopenharmony_ci goto out_dput; 342762306a36Sopenharmony_ci d_invalidate(dentry); 342862306a36Sopenharmony_ci dput(dentry); 342962306a36Sopenharmony_ci dentry = NULL; 343062306a36Sopenharmony_ci } 343162306a36Sopenharmony_ci if (dentry->d_inode) { 343262306a36Sopenharmony_ci /* Cached positive dentry: will open in f_op->open */ 343362306a36Sopenharmony_ci return dentry; 343462306a36Sopenharmony_ci } 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci /* 343762306a36Sopenharmony_ci * Checking write permission is tricky, bacuse we don't know if we are 343862306a36Sopenharmony_ci * going to actually need it: O_CREAT opens should work as long as the 343962306a36Sopenharmony_ci * file exists. But checking existence breaks atomicity. The trick is 344062306a36Sopenharmony_ci * to check access and if not granted clear O_CREAT from the flags. 344162306a36Sopenharmony_ci * 344262306a36Sopenharmony_ci * Another problem is returing the "right" error value (e.g. for an 344362306a36Sopenharmony_ci * O_EXCL open we want to return EEXIST not EROFS). 344462306a36Sopenharmony_ci */ 344562306a36Sopenharmony_ci if (unlikely(!got_write)) 344662306a36Sopenharmony_ci open_flag &= ~O_TRUNC; 344762306a36Sopenharmony_ci idmap = mnt_idmap(nd->path.mnt); 344862306a36Sopenharmony_ci if (open_flag & O_CREAT) { 344962306a36Sopenharmony_ci if (open_flag & O_EXCL) 345062306a36Sopenharmony_ci open_flag &= ~O_TRUNC; 345162306a36Sopenharmony_ci mode = vfs_prepare_mode(idmap, dir->d_inode, mode, mode, mode); 345262306a36Sopenharmony_ci if (likely(got_write)) 345362306a36Sopenharmony_ci create_error = may_o_create(idmap, &nd->path, 345462306a36Sopenharmony_ci dentry, mode); 345562306a36Sopenharmony_ci else 345662306a36Sopenharmony_ci create_error = -EROFS; 345762306a36Sopenharmony_ci } 345862306a36Sopenharmony_ci if (create_error) 345962306a36Sopenharmony_ci open_flag &= ~O_CREAT; 346062306a36Sopenharmony_ci if (dir_inode->i_op->atomic_open) { 346162306a36Sopenharmony_ci dentry = atomic_open(nd, dentry, file, open_flag, mode); 346262306a36Sopenharmony_ci if (unlikely(create_error) && dentry == ERR_PTR(-ENOENT)) 346362306a36Sopenharmony_ci dentry = ERR_PTR(create_error); 346462306a36Sopenharmony_ci return dentry; 346562306a36Sopenharmony_ci } 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_ci if (d_in_lookup(dentry)) { 346862306a36Sopenharmony_ci struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry, 346962306a36Sopenharmony_ci nd->flags); 347062306a36Sopenharmony_ci d_lookup_done(dentry); 347162306a36Sopenharmony_ci if (unlikely(res)) { 347262306a36Sopenharmony_ci if (IS_ERR(res)) { 347362306a36Sopenharmony_ci error = PTR_ERR(res); 347462306a36Sopenharmony_ci goto out_dput; 347562306a36Sopenharmony_ci } 347662306a36Sopenharmony_ci dput(dentry); 347762306a36Sopenharmony_ci dentry = res; 347862306a36Sopenharmony_ci } 347962306a36Sopenharmony_ci } 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci /* Negative dentry, just create the file */ 348262306a36Sopenharmony_ci if (!dentry->d_inode && (open_flag & O_CREAT)) { 348362306a36Sopenharmony_ci file->f_mode |= FMODE_CREATED; 348462306a36Sopenharmony_ci audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); 348562306a36Sopenharmony_ci if (!dir_inode->i_op->create) { 348662306a36Sopenharmony_ci error = -EACCES; 348762306a36Sopenharmony_ci goto out_dput; 348862306a36Sopenharmony_ci } 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci error = dir_inode->i_op->create(idmap, dir_inode, dentry, 349162306a36Sopenharmony_ci mode, open_flag & O_EXCL); 349262306a36Sopenharmony_ci if (error) 349362306a36Sopenharmony_ci goto out_dput; 349462306a36Sopenharmony_ci } 349562306a36Sopenharmony_ci if (unlikely(create_error) && !dentry->d_inode) { 349662306a36Sopenharmony_ci error = create_error; 349762306a36Sopenharmony_ci goto out_dput; 349862306a36Sopenharmony_ci } 349962306a36Sopenharmony_ci return dentry; 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ciout_dput: 350262306a36Sopenharmony_ci dput(dentry); 350362306a36Sopenharmony_ci return ERR_PTR(error); 350462306a36Sopenharmony_ci} 350562306a36Sopenharmony_ci 350662306a36Sopenharmony_cistatic const char *open_last_lookups(struct nameidata *nd, 350762306a36Sopenharmony_ci struct file *file, const struct open_flags *op) 350862306a36Sopenharmony_ci{ 350962306a36Sopenharmony_ci struct dentry *dir = nd->path.dentry; 351062306a36Sopenharmony_ci int open_flag = op->open_flag; 351162306a36Sopenharmony_ci bool got_write = false; 351262306a36Sopenharmony_ci struct dentry *dentry; 351362306a36Sopenharmony_ci const char *res; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci nd->flags |= op->intent; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci if (nd->last_type != LAST_NORM) { 351862306a36Sopenharmony_ci if (nd->depth) 351962306a36Sopenharmony_ci put_link(nd); 352062306a36Sopenharmony_ci return handle_dots(nd, nd->last_type); 352162306a36Sopenharmony_ci } 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci if (!(open_flag & O_CREAT)) { 352462306a36Sopenharmony_ci if (nd->last.name[nd->last.len]) 352562306a36Sopenharmony_ci nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; 352662306a36Sopenharmony_ci /* we _can_ be in RCU mode here */ 352762306a36Sopenharmony_ci dentry = lookup_fast(nd); 352862306a36Sopenharmony_ci if (IS_ERR(dentry)) 352962306a36Sopenharmony_ci return ERR_CAST(dentry); 353062306a36Sopenharmony_ci if (likely(dentry)) 353162306a36Sopenharmony_ci goto finish_lookup; 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci BUG_ON(nd->flags & LOOKUP_RCU); 353462306a36Sopenharmony_ci } else { 353562306a36Sopenharmony_ci /* create side of things */ 353662306a36Sopenharmony_ci if (nd->flags & LOOKUP_RCU) { 353762306a36Sopenharmony_ci if (!try_to_unlazy(nd)) 353862306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 353962306a36Sopenharmony_ci } 354062306a36Sopenharmony_ci audit_inode(nd->name, dir, AUDIT_INODE_PARENT); 354162306a36Sopenharmony_ci /* trailing slashes? */ 354262306a36Sopenharmony_ci if (unlikely(nd->last.name[nd->last.len])) 354362306a36Sopenharmony_ci return ERR_PTR(-EISDIR); 354462306a36Sopenharmony_ci } 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { 354762306a36Sopenharmony_ci got_write = !mnt_want_write(nd->path.mnt); 354862306a36Sopenharmony_ci /* 354962306a36Sopenharmony_ci * do _not_ fail yet - we might not need that or fail with 355062306a36Sopenharmony_ci * a different error; let lookup_open() decide; we'll be 355162306a36Sopenharmony_ci * dropping this one anyway. 355262306a36Sopenharmony_ci */ 355362306a36Sopenharmony_ci } 355462306a36Sopenharmony_ci if (open_flag & O_CREAT) 355562306a36Sopenharmony_ci inode_lock(dir->d_inode); 355662306a36Sopenharmony_ci else 355762306a36Sopenharmony_ci inode_lock_shared(dir->d_inode); 355862306a36Sopenharmony_ci dentry = lookup_open(nd, file, op, got_write); 355962306a36Sopenharmony_ci if (!IS_ERR(dentry) && (file->f_mode & FMODE_CREATED)) 356062306a36Sopenharmony_ci fsnotify_create(dir->d_inode, dentry); 356162306a36Sopenharmony_ci if (open_flag & O_CREAT) 356262306a36Sopenharmony_ci inode_unlock(dir->d_inode); 356362306a36Sopenharmony_ci else 356462306a36Sopenharmony_ci inode_unlock_shared(dir->d_inode); 356562306a36Sopenharmony_ci 356662306a36Sopenharmony_ci if (got_write) 356762306a36Sopenharmony_ci mnt_drop_write(nd->path.mnt); 356862306a36Sopenharmony_ci 356962306a36Sopenharmony_ci if (IS_ERR(dentry)) 357062306a36Sopenharmony_ci return ERR_CAST(dentry); 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_ci if (file->f_mode & (FMODE_OPENED | FMODE_CREATED)) { 357362306a36Sopenharmony_ci dput(nd->path.dentry); 357462306a36Sopenharmony_ci nd->path.dentry = dentry; 357562306a36Sopenharmony_ci return NULL; 357662306a36Sopenharmony_ci } 357762306a36Sopenharmony_ci 357862306a36Sopenharmony_cifinish_lookup: 357962306a36Sopenharmony_ci if (nd->depth) 358062306a36Sopenharmony_ci put_link(nd); 358162306a36Sopenharmony_ci res = step_into(nd, WALK_TRAILING, dentry); 358262306a36Sopenharmony_ci if (unlikely(res)) 358362306a36Sopenharmony_ci nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); 358462306a36Sopenharmony_ci return res; 358562306a36Sopenharmony_ci} 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci/* 358862306a36Sopenharmony_ci * Handle the last step of open() 358962306a36Sopenharmony_ci */ 359062306a36Sopenharmony_cistatic int do_open(struct nameidata *nd, 359162306a36Sopenharmony_ci struct file *file, const struct open_flags *op) 359262306a36Sopenharmony_ci{ 359362306a36Sopenharmony_ci struct mnt_idmap *idmap; 359462306a36Sopenharmony_ci int open_flag = op->open_flag; 359562306a36Sopenharmony_ci bool do_truncate; 359662306a36Sopenharmony_ci int acc_mode; 359762306a36Sopenharmony_ci int error; 359862306a36Sopenharmony_ci 359962306a36Sopenharmony_ci if (!(file->f_mode & (FMODE_OPENED | FMODE_CREATED))) { 360062306a36Sopenharmony_ci error = complete_walk(nd); 360162306a36Sopenharmony_ci if (error) 360262306a36Sopenharmony_ci return error; 360362306a36Sopenharmony_ci } 360462306a36Sopenharmony_ci if (!(file->f_mode & FMODE_CREATED)) 360562306a36Sopenharmony_ci audit_inode(nd->name, nd->path.dentry, 0); 360662306a36Sopenharmony_ci idmap = mnt_idmap(nd->path.mnt); 360762306a36Sopenharmony_ci if (open_flag & O_CREAT) { 360862306a36Sopenharmony_ci if ((open_flag & O_EXCL) && !(file->f_mode & FMODE_CREATED)) 360962306a36Sopenharmony_ci return -EEXIST; 361062306a36Sopenharmony_ci if (d_is_dir(nd->path.dentry)) 361162306a36Sopenharmony_ci return -EISDIR; 361262306a36Sopenharmony_ci error = may_create_in_sticky(idmap, nd, 361362306a36Sopenharmony_ci d_backing_inode(nd->path.dentry)); 361462306a36Sopenharmony_ci if (unlikely(error)) 361562306a36Sopenharmony_ci return error; 361662306a36Sopenharmony_ci } 361762306a36Sopenharmony_ci if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) 361862306a36Sopenharmony_ci return -ENOTDIR; 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci do_truncate = false; 362162306a36Sopenharmony_ci acc_mode = op->acc_mode; 362262306a36Sopenharmony_ci if (file->f_mode & FMODE_CREATED) { 362362306a36Sopenharmony_ci /* Don't check for write permission, don't truncate */ 362462306a36Sopenharmony_ci open_flag &= ~O_TRUNC; 362562306a36Sopenharmony_ci acc_mode = 0; 362662306a36Sopenharmony_ci } else if (d_is_reg(nd->path.dentry) && open_flag & O_TRUNC) { 362762306a36Sopenharmony_ci error = mnt_want_write(nd->path.mnt); 362862306a36Sopenharmony_ci if (error) 362962306a36Sopenharmony_ci return error; 363062306a36Sopenharmony_ci do_truncate = true; 363162306a36Sopenharmony_ci } 363262306a36Sopenharmony_ci error = may_open(idmap, &nd->path, acc_mode, open_flag); 363362306a36Sopenharmony_ci if (!error && !(file->f_mode & FMODE_OPENED)) 363462306a36Sopenharmony_ci error = vfs_open(&nd->path, file); 363562306a36Sopenharmony_ci if (!error) 363662306a36Sopenharmony_ci error = ima_file_check(file, op->acc_mode); 363762306a36Sopenharmony_ci if (!error && do_truncate) 363862306a36Sopenharmony_ci error = handle_truncate(idmap, file); 363962306a36Sopenharmony_ci if (unlikely(error > 0)) { 364062306a36Sopenharmony_ci WARN_ON(1); 364162306a36Sopenharmony_ci error = -EINVAL; 364262306a36Sopenharmony_ci } 364362306a36Sopenharmony_ci if (do_truncate) 364462306a36Sopenharmony_ci mnt_drop_write(nd->path.mnt); 364562306a36Sopenharmony_ci return error; 364662306a36Sopenharmony_ci} 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci/** 364962306a36Sopenharmony_ci * vfs_tmpfile - create tmpfile 365062306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 365162306a36Sopenharmony_ci * @parentpath: pointer to the path of the base directory 365262306a36Sopenharmony_ci * @file: file descriptor of the new tmpfile 365362306a36Sopenharmony_ci * @mode: mode of the new tmpfile 365462306a36Sopenharmony_ci * 365562306a36Sopenharmony_ci * Create a temporary file. 365662306a36Sopenharmony_ci * 365762306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 365862306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 365962306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 366062306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 366162306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 366262306a36Sopenharmony_ci */ 366362306a36Sopenharmony_cistatic int vfs_tmpfile(struct mnt_idmap *idmap, 366462306a36Sopenharmony_ci const struct path *parentpath, 366562306a36Sopenharmony_ci struct file *file, umode_t mode) 366662306a36Sopenharmony_ci{ 366762306a36Sopenharmony_ci struct dentry *child; 366862306a36Sopenharmony_ci struct inode *dir = d_inode(parentpath->dentry); 366962306a36Sopenharmony_ci struct inode *inode; 367062306a36Sopenharmony_ci int error; 367162306a36Sopenharmony_ci int open_flag = file->f_flags; 367262306a36Sopenharmony_ci 367362306a36Sopenharmony_ci /* we want directory to be writable */ 367462306a36Sopenharmony_ci error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC); 367562306a36Sopenharmony_ci if (error) 367662306a36Sopenharmony_ci return error; 367762306a36Sopenharmony_ci if (!dir->i_op->tmpfile) 367862306a36Sopenharmony_ci return -EOPNOTSUPP; 367962306a36Sopenharmony_ci child = d_alloc(parentpath->dentry, &slash_name); 368062306a36Sopenharmony_ci if (unlikely(!child)) 368162306a36Sopenharmony_ci return -ENOMEM; 368262306a36Sopenharmony_ci file->f_path.mnt = parentpath->mnt; 368362306a36Sopenharmony_ci file->f_path.dentry = child; 368462306a36Sopenharmony_ci mode = vfs_prepare_mode(idmap, dir, mode, mode, mode); 368562306a36Sopenharmony_ci error = dir->i_op->tmpfile(idmap, dir, file, mode); 368662306a36Sopenharmony_ci dput(child); 368762306a36Sopenharmony_ci if (error) 368862306a36Sopenharmony_ci return error; 368962306a36Sopenharmony_ci /* Don't check for other permissions, the inode was just created */ 369062306a36Sopenharmony_ci error = may_open(idmap, &file->f_path, 0, file->f_flags); 369162306a36Sopenharmony_ci if (error) 369262306a36Sopenharmony_ci return error; 369362306a36Sopenharmony_ci inode = file_inode(file); 369462306a36Sopenharmony_ci if (!(open_flag & O_EXCL)) { 369562306a36Sopenharmony_ci spin_lock(&inode->i_lock); 369662306a36Sopenharmony_ci inode->i_state |= I_LINKABLE; 369762306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 369862306a36Sopenharmony_ci } 369962306a36Sopenharmony_ci ima_post_create_tmpfile(idmap, inode); 370062306a36Sopenharmony_ci return 0; 370162306a36Sopenharmony_ci} 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci/** 370462306a36Sopenharmony_ci * kernel_tmpfile_open - open a tmpfile for kernel internal use 370562306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 370662306a36Sopenharmony_ci * @parentpath: path of the base directory 370762306a36Sopenharmony_ci * @mode: mode of the new tmpfile 370862306a36Sopenharmony_ci * @open_flag: flags 370962306a36Sopenharmony_ci * @cred: credentials for open 371062306a36Sopenharmony_ci * 371162306a36Sopenharmony_ci * Create and open a temporary file. The file is not accounted in nr_files, 371262306a36Sopenharmony_ci * hence this is only for kernel internal use, and must not be installed into 371362306a36Sopenharmony_ci * file tables or such. 371462306a36Sopenharmony_ci */ 371562306a36Sopenharmony_cistruct file *kernel_tmpfile_open(struct mnt_idmap *idmap, 371662306a36Sopenharmony_ci const struct path *parentpath, 371762306a36Sopenharmony_ci umode_t mode, int open_flag, 371862306a36Sopenharmony_ci const struct cred *cred) 371962306a36Sopenharmony_ci{ 372062306a36Sopenharmony_ci struct file *file; 372162306a36Sopenharmony_ci int error; 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci file = alloc_empty_file_noaccount(open_flag, cred); 372462306a36Sopenharmony_ci if (IS_ERR(file)) 372562306a36Sopenharmony_ci return file; 372662306a36Sopenharmony_ci 372762306a36Sopenharmony_ci error = vfs_tmpfile(idmap, parentpath, file, mode); 372862306a36Sopenharmony_ci if (error) { 372962306a36Sopenharmony_ci fput(file); 373062306a36Sopenharmony_ci file = ERR_PTR(error); 373162306a36Sopenharmony_ci } 373262306a36Sopenharmony_ci return file; 373362306a36Sopenharmony_ci} 373462306a36Sopenharmony_ciEXPORT_SYMBOL(kernel_tmpfile_open); 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_cistatic int do_tmpfile(struct nameidata *nd, unsigned flags, 373762306a36Sopenharmony_ci const struct open_flags *op, 373862306a36Sopenharmony_ci struct file *file) 373962306a36Sopenharmony_ci{ 374062306a36Sopenharmony_ci struct path path; 374162306a36Sopenharmony_ci int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path); 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci if (unlikely(error)) 374462306a36Sopenharmony_ci return error; 374562306a36Sopenharmony_ci error = mnt_want_write(path.mnt); 374662306a36Sopenharmony_ci if (unlikely(error)) 374762306a36Sopenharmony_ci goto out; 374862306a36Sopenharmony_ci error = vfs_tmpfile(mnt_idmap(path.mnt), &path, file, op->mode); 374962306a36Sopenharmony_ci if (error) 375062306a36Sopenharmony_ci goto out2; 375162306a36Sopenharmony_ci audit_inode(nd->name, file->f_path.dentry, 0); 375262306a36Sopenharmony_ciout2: 375362306a36Sopenharmony_ci mnt_drop_write(path.mnt); 375462306a36Sopenharmony_ciout: 375562306a36Sopenharmony_ci path_put(&path); 375662306a36Sopenharmony_ci return error; 375762306a36Sopenharmony_ci} 375862306a36Sopenharmony_ci 375962306a36Sopenharmony_cistatic int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) 376062306a36Sopenharmony_ci{ 376162306a36Sopenharmony_ci struct path path; 376262306a36Sopenharmony_ci int error = path_lookupat(nd, flags, &path); 376362306a36Sopenharmony_ci if (!error) { 376462306a36Sopenharmony_ci audit_inode(nd->name, path.dentry, 0); 376562306a36Sopenharmony_ci error = vfs_open(&path, file); 376662306a36Sopenharmony_ci path_put(&path); 376762306a36Sopenharmony_ci } 376862306a36Sopenharmony_ci return error; 376962306a36Sopenharmony_ci} 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_cistatic struct file *path_openat(struct nameidata *nd, 377262306a36Sopenharmony_ci const struct open_flags *op, unsigned flags) 377362306a36Sopenharmony_ci{ 377462306a36Sopenharmony_ci struct file *file; 377562306a36Sopenharmony_ci int error; 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci file = alloc_empty_file(op->open_flag, current_cred()); 377862306a36Sopenharmony_ci if (IS_ERR(file)) 377962306a36Sopenharmony_ci return file; 378062306a36Sopenharmony_ci 378162306a36Sopenharmony_ci if (unlikely(file->f_flags & __O_TMPFILE)) { 378262306a36Sopenharmony_ci error = do_tmpfile(nd, flags, op, file); 378362306a36Sopenharmony_ci } else if (unlikely(file->f_flags & O_PATH)) { 378462306a36Sopenharmony_ci error = do_o_path(nd, flags, file); 378562306a36Sopenharmony_ci } else { 378662306a36Sopenharmony_ci const char *s = path_init(nd, flags); 378762306a36Sopenharmony_ci while (!(error = link_path_walk(s, nd)) && 378862306a36Sopenharmony_ci (s = open_last_lookups(nd, file, op)) != NULL) 378962306a36Sopenharmony_ci ; 379062306a36Sopenharmony_ci if (!error) 379162306a36Sopenharmony_ci error = do_open(nd, file, op); 379262306a36Sopenharmony_ci terminate_walk(nd); 379362306a36Sopenharmony_ci } 379462306a36Sopenharmony_ci if (likely(!error)) { 379562306a36Sopenharmony_ci if (likely(file->f_mode & FMODE_OPENED)) 379662306a36Sopenharmony_ci return file; 379762306a36Sopenharmony_ci WARN_ON(1); 379862306a36Sopenharmony_ci error = -EINVAL; 379962306a36Sopenharmony_ci } 380062306a36Sopenharmony_ci fput(file); 380162306a36Sopenharmony_ci if (error == -EOPENSTALE) { 380262306a36Sopenharmony_ci if (flags & LOOKUP_RCU) 380362306a36Sopenharmony_ci error = -ECHILD; 380462306a36Sopenharmony_ci else 380562306a36Sopenharmony_ci error = -ESTALE; 380662306a36Sopenharmony_ci } 380762306a36Sopenharmony_ci return ERR_PTR(error); 380862306a36Sopenharmony_ci} 380962306a36Sopenharmony_ci 381062306a36Sopenharmony_cistruct file *do_filp_open(int dfd, struct filename *pathname, 381162306a36Sopenharmony_ci const struct open_flags *op) 381262306a36Sopenharmony_ci{ 381362306a36Sopenharmony_ci struct nameidata nd; 381462306a36Sopenharmony_ci int flags = op->lookup_flags; 381562306a36Sopenharmony_ci struct file *filp; 381662306a36Sopenharmony_ci 381762306a36Sopenharmony_ci set_nameidata(&nd, dfd, pathname, NULL); 381862306a36Sopenharmony_ci filp = path_openat(&nd, op, flags | LOOKUP_RCU); 381962306a36Sopenharmony_ci if (unlikely(filp == ERR_PTR(-ECHILD))) 382062306a36Sopenharmony_ci filp = path_openat(&nd, op, flags); 382162306a36Sopenharmony_ci if (unlikely(filp == ERR_PTR(-ESTALE))) 382262306a36Sopenharmony_ci filp = path_openat(&nd, op, flags | LOOKUP_REVAL); 382362306a36Sopenharmony_ci restore_nameidata(); 382462306a36Sopenharmony_ci return filp; 382562306a36Sopenharmony_ci} 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_cistruct file *do_file_open_root(const struct path *root, 382862306a36Sopenharmony_ci const char *name, const struct open_flags *op) 382962306a36Sopenharmony_ci{ 383062306a36Sopenharmony_ci struct nameidata nd; 383162306a36Sopenharmony_ci struct file *file; 383262306a36Sopenharmony_ci struct filename *filename; 383362306a36Sopenharmony_ci int flags = op->lookup_flags; 383462306a36Sopenharmony_ci 383562306a36Sopenharmony_ci if (d_is_symlink(root->dentry) && op->intent & LOOKUP_OPEN) 383662306a36Sopenharmony_ci return ERR_PTR(-ELOOP); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci filename = getname_kernel(name); 383962306a36Sopenharmony_ci if (IS_ERR(filename)) 384062306a36Sopenharmony_ci return ERR_CAST(filename); 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci set_nameidata(&nd, -1, filename, root); 384362306a36Sopenharmony_ci file = path_openat(&nd, op, flags | LOOKUP_RCU); 384462306a36Sopenharmony_ci if (unlikely(file == ERR_PTR(-ECHILD))) 384562306a36Sopenharmony_ci file = path_openat(&nd, op, flags); 384662306a36Sopenharmony_ci if (unlikely(file == ERR_PTR(-ESTALE))) 384762306a36Sopenharmony_ci file = path_openat(&nd, op, flags | LOOKUP_REVAL); 384862306a36Sopenharmony_ci restore_nameidata(); 384962306a36Sopenharmony_ci putname(filename); 385062306a36Sopenharmony_ci return file; 385162306a36Sopenharmony_ci} 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_cistatic struct dentry *filename_create(int dfd, struct filename *name, 385462306a36Sopenharmony_ci struct path *path, unsigned int lookup_flags) 385562306a36Sopenharmony_ci{ 385662306a36Sopenharmony_ci struct dentry *dentry = ERR_PTR(-EEXIST); 385762306a36Sopenharmony_ci struct qstr last; 385862306a36Sopenharmony_ci bool want_dir = lookup_flags & LOOKUP_DIRECTORY; 385962306a36Sopenharmony_ci unsigned int reval_flag = lookup_flags & LOOKUP_REVAL; 386062306a36Sopenharmony_ci unsigned int create_flags = LOOKUP_CREATE | LOOKUP_EXCL; 386162306a36Sopenharmony_ci int type; 386262306a36Sopenharmony_ci int err2; 386362306a36Sopenharmony_ci int error; 386462306a36Sopenharmony_ci 386562306a36Sopenharmony_ci error = filename_parentat(dfd, name, reval_flag, path, &last, &type); 386662306a36Sopenharmony_ci if (error) 386762306a36Sopenharmony_ci return ERR_PTR(error); 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci /* 387062306a36Sopenharmony_ci * Yucky last component or no last component at all? 387162306a36Sopenharmony_ci * (foo/., foo/.., /////) 387262306a36Sopenharmony_ci */ 387362306a36Sopenharmony_ci if (unlikely(type != LAST_NORM)) 387462306a36Sopenharmony_ci goto out; 387562306a36Sopenharmony_ci 387662306a36Sopenharmony_ci /* don't fail immediately if it's r/o, at least try to report other errors */ 387762306a36Sopenharmony_ci err2 = mnt_want_write(path->mnt); 387862306a36Sopenharmony_ci /* 387962306a36Sopenharmony_ci * Do the final lookup. Suppress 'create' if there is a trailing 388062306a36Sopenharmony_ci * '/', and a directory wasn't requested. 388162306a36Sopenharmony_ci */ 388262306a36Sopenharmony_ci if (last.name[last.len] && !want_dir) 388362306a36Sopenharmony_ci create_flags = 0; 388462306a36Sopenharmony_ci inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); 388562306a36Sopenharmony_ci dentry = lookup_one_qstr_excl(&last, path->dentry, 388662306a36Sopenharmony_ci reval_flag | create_flags); 388762306a36Sopenharmony_ci if (IS_ERR(dentry)) 388862306a36Sopenharmony_ci goto unlock; 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_ci error = -EEXIST; 389162306a36Sopenharmony_ci if (d_is_positive(dentry)) 389262306a36Sopenharmony_ci goto fail; 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_ci /* 389562306a36Sopenharmony_ci * Special case - lookup gave negative, but... we had foo/bar/ 389662306a36Sopenharmony_ci * From the vfs_mknod() POV we just have a negative dentry - 389762306a36Sopenharmony_ci * all is fine. Let's be bastards - you had / on the end, you've 389862306a36Sopenharmony_ci * been asking for (non-existent) directory. -ENOENT for you. 389962306a36Sopenharmony_ci */ 390062306a36Sopenharmony_ci if (unlikely(!create_flags)) { 390162306a36Sopenharmony_ci error = -ENOENT; 390262306a36Sopenharmony_ci goto fail; 390362306a36Sopenharmony_ci } 390462306a36Sopenharmony_ci if (unlikely(err2)) { 390562306a36Sopenharmony_ci error = err2; 390662306a36Sopenharmony_ci goto fail; 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci return dentry; 390962306a36Sopenharmony_cifail: 391062306a36Sopenharmony_ci dput(dentry); 391162306a36Sopenharmony_ci dentry = ERR_PTR(error); 391262306a36Sopenharmony_ciunlock: 391362306a36Sopenharmony_ci inode_unlock(path->dentry->d_inode); 391462306a36Sopenharmony_ci if (!err2) 391562306a36Sopenharmony_ci mnt_drop_write(path->mnt); 391662306a36Sopenharmony_ciout: 391762306a36Sopenharmony_ci path_put(path); 391862306a36Sopenharmony_ci return dentry; 391962306a36Sopenharmony_ci} 392062306a36Sopenharmony_ci 392162306a36Sopenharmony_cistruct dentry *kern_path_create(int dfd, const char *pathname, 392262306a36Sopenharmony_ci struct path *path, unsigned int lookup_flags) 392362306a36Sopenharmony_ci{ 392462306a36Sopenharmony_ci struct filename *filename = getname_kernel(pathname); 392562306a36Sopenharmony_ci struct dentry *res = filename_create(dfd, filename, path, lookup_flags); 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_ci putname(filename); 392862306a36Sopenharmony_ci return res; 392962306a36Sopenharmony_ci} 393062306a36Sopenharmony_ciEXPORT_SYMBOL(kern_path_create); 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_civoid done_path_create(struct path *path, struct dentry *dentry) 393362306a36Sopenharmony_ci{ 393462306a36Sopenharmony_ci dput(dentry); 393562306a36Sopenharmony_ci inode_unlock(path->dentry->d_inode); 393662306a36Sopenharmony_ci mnt_drop_write(path->mnt); 393762306a36Sopenharmony_ci path_put(path); 393862306a36Sopenharmony_ci} 393962306a36Sopenharmony_ciEXPORT_SYMBOL(done_path_create); 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ciinline struct dentry *user_path_create(int dfd, const char __user *pathname, 394262306a36Sopenharmony_ci struct path *path, unsigned int lookup_flags) 394362306a36Sopenharmony_ci{ 394462306a36Sopenharmony_ci struct filename *filename = getname(pathname); 394562306a36Sopenharmony_ci struct dentry *res = filename_create(dfd, filename, path, lookup_flags); 394662306a36Sopenharmony_ci 394762306a36Sopenharmony_ci putname(filename); 394862306a36Sopenharmony_ci return res; 394962306a36Sopenharmony_ci} 395062306a36Sopenharmony_ciEXPORT_SYMBOL(user_path_create); 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci/** 395362306a36Sopenharmony_ci * vfs_mknod - create device node or file 395462306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 395562306a36Sopenharmony_ci * @dir: inode of @dentry 395662306a36Sopenharmony_ci * @dentry: pointer to dentry of the base directory 395762306a36Sopenharmony_ci * @mode: mode of the new device node or file 395862306a36Sopenharmony_ci * @dev: device number of device to create 395962306a36Sopenharmony_ci * 396062306a36Sopenharmony_ci * Create a device node or file. 396162306a36Sopenharmony_ci * 396262306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 396362306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 396462306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 396562306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 396662306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 396762306a36Sopenharmony_ci */ 396862306a36Sopenharmony_ciint vfs_mknod(struct mnt_idmap *idmap, struct inode *dir, 396962306a36Sopenharmony_ci struct dentry *dentry, umode_t mode, dev_t dev) 397062306a36Sopenharmony_ci{ 397162306a36Sopenharmony_ci bool is_whiteout = S_ISCHR(mode) && dev == WHITEOUT_DEV; 397262306a36Sopenharmony_ci int error = may_create(idmap, dir, dentry); 397362306a36Sopenharmony_ci 397462306a36Sopenharmony_ci if (error) 397562306a36Sopenharmony_ci return error; 397662306a36Sopenharmony_ci 397762306a36Sopenharmony_ci if ((S_ISCHR(mode) || S_ISBLK(mode)) && !is_whiteout && 397862306a36Sopenharmony_ci !capable(CAP_MKNOD)) 397962306a36Sopenharmony_ci return -EPERM; 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci if (!dir->i_op->mknod) 398262306a36Sopenharmony_ci return -EPERM; 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci mode = vfs_prepare_mode(idmap, dir, mode, mode, mode); 398562306a36Sopenharmony_ci error = devcgroup_inode_mknod(mode, dev); 398662306a36Sopenharmony_ci if (error) 398762306a36Sopenharmony_ci return error; 398862306a36Sopenharmony_ci 398962306a36Sopenharmony_ci error = security_inode_mknod(dir, dentry, mode, dev); 399062306a36Sopenharmony_ci if (error) 399162306a36Sopenharmony_ci return error; 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci error = dir->i_op->mknod(idmap, dir, dentry, mode, dev); 399462306a36Sopenharmony_ci if (!error) 399562306a36Sopenharmony_ci fsnotify_create(dir, dentry); 399662306a36Sopenharmony_ci return error; 399762306a36Sopenharmony_ci} 399862306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_mknod); 399962306a36Sopenharmony_ci 400062306a36Sopenharmony_cistatic int may_mknod(umode_t mode) 400162306a36Sopenharmony_ci{ 400262306a36Sopenharmony_ci switch (mode & S_IFMT) { 400362306a36Sopenharmony_ci case S_IFREG: 400462306a36Sopenharmony_ci case S_IFCHR: 400562306a36Sopenharmony_ci case S_IFBLK: 400662306a36Sopenharmony_ci case S_IFIFO: 400762306a36Sopenharmony_ci case S_IFSOCK: 400862306a36Sopenharmony_ci case 0: /* zero mode translates to S_IFREG */ 400962306a36Sopenharmony_ci return 0; 401062306a36Sopenharmony_ci case S_IFDIR: 401162306a36Sopenharmony_ci return -EPERM; 401262306a36Sopenharmony_ci default: 401362306a36Sopenharmony_ci return -EINVAL; 401462306a36Sopenharmony_ci } 401562306a36Sopenharmony_ci} 401662306a36Sopenharmony_ci 401762306a36Sopenharmony_cistatic int do_mknodat(int dfd, struct filename *name, umode_t mode, 401862306a36Sopenharmony_ci unsigned int dev) 401962306a36Sopenharmony_ci{ 402062306a36Sopenharmony_ci struct mnt_idmap *idmap; 402162306a36Sopenharmony_ci struct dentry *dentry; 402262306a36Sopenharmony_ci struct path path; 402362306a36Sopenharmony_ci int error; 402462306a36Sopenharmony_ci unsigned int lookup_flags = 0; 402562306a36Sopenharmony_ci 402662306a36Sopenharmony_ci error = may_mknod(mode); 402762306a36Sopenharmony_ci if (error) 402862306a36Sopenharmony_ci goto out1; 402962306a36Sopenharmony_ciretry: 403062306a36Sopenharmony_ci dentry = filename_create(dfd, name, &path, lookup_flags); 403162306a36Sopenharmony_ci error = PTR_ERR(dentry); 403262306a36Sopenharmony_ci if (IS_ERR(dentry)) 403362306a36Sopenharmony_ci goto out1; 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci error = security_path_mknod(&path, dentry, 403662306a36Sopenharmony_ci mode_strip_umask(path.dentry->d_inode, mode), dev); 403762306a36Sopenharmony_ci if (error) 403862306a36Sopenharmony_ci goto out2; 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_ci idmap = mnt_idmap(path.mnt); 404162306a36Sopenharmony_ci switch (mode & S_IFMT) { 404262306a36Sopenharmony_ci case 0: case S_IFREG: 404362306a36Sopenharmony_ci error = vfs_create(idmap, path.dentry->d_inode, 404462306a36Sopenharmony_ci dentry, mode, true); 404562306a36Sopenharmony_ci if (!error) 404662306a36Sopenharmony_ci ima_post_path_mknod(idmap, dentry); 404762306a36Sopenharmony_ci break; 404862306a36Sopenharmony_ci case S_IFCHR: case S_IFBLK: 404962306a36Sopenharmony_ci error = vfs_mknod(idmap, path.dentry->d_inode, 405062306a36Sopenharmony_ci dentry, mode, new_decode_dev(dev)); 405162306a36Sopenharmony_ci break; 405262306a36Sopenharmony_ci case S_IFIFO: case S_IFSOCK: 405362306a36Sopenharmony_ci error = vfs_mknod(idmap, path.dentry->d_inode, 405462306a36Sopenharmony_ci dentry, mode, 0); 405562306a36Sopenharmony_ci break; 405662306a36Sopenharmony_ci } 405762306a36Sopenharmony_ciout2: 405862306a36Sopenharmony_ci done_path_create(&path, dentry); 405962306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 406062306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 406162306a36Sopenharmony_ci goto retry; 406262306a36Sopenharmony_ci } 406362306a36Sopenharmony_ciout1: 406462306a36Sopenharmony_ci putname(name); 406562306a36Sopenharmony_ci return error; 406662306a36Sopenharmony_ci} 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ciSYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, 406962306a36Sopenharmony_ci unsigned int, dev) 407062306a36Sopenharmony_ci{ 407162306a36Sopenharmony_ci return do_mknodat(dfd, getname(filename), mode, dev); 407262306a36Sopenharmony_ci} 407362306a36Sopenharmony_ci 407462306a36Sopenharmony_ciSYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev) 407562306a36Sopenharmony_ci{ 407662306a36Sopenharmony_ci return do_mknodat(AT_FDCWD, getname(filename), mode, dev); 407762306a36Sopenharmony_ci} 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci/** 408062306a36Sopenharmony_ci * vfs_mkdir - create directory 408162306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 408262306a36Sopenharmony_ci * @dir: inode of @dentry 408362306a36Sopenharmony_ci * @dentry: pointer to dentry of the base directory 408462306a36Sopenharmony_ci * @mode: mode of the new directory 408562306a36Sopenharmony_ci * 408662306a36Sopenharmony_ci * Create a directory. 408762306a36Sopenharmony_ci * 408862306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 408962306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 409062306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 409162306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 409262306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 409362306a36Sopenharmony_ci */ 409462306a36Sopenharmony_ciint vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, 409562306a36Sopenharmony_ci struct dentry *dentry, umode_t mode) 409662306a36Sopenharmony_ci{ 409762306a36Sopenharmony_ci int error; 409862306a36Sopenharmony_ci unsigned max_links = dir->i_sb->s_max_links; 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci error = may_create(idmap, dir, dentry); 410162306a36Sopenharmony_ci if (error) 410262306a36Sopenharmony_ci return error; 410362306a36Sopenharmony_ci 410462306a36Sopenharmony_ci if (!dir->i_op->mkdir) 410562306a36Sopenharmony_ci return -EPERM; 410662306a36Sopenharmony_ci 410762306a36Sopenharmony_ci mode = vfs_prepare_mode(idmap, dir, mode, S_IRWXUGO | S_ISVTX, 0); 410862306a36Sopenharmony_ci error = security_inode_mkdir(dir, dentry, mode); 410962306a36Sopenharmony_ci if (error) 411062306a36Sopenharmony_ci return error; 411162306a36Sopenharmony_ci 411262306a36Sopenharmony_ci if (max_links && dir->i_nlink >= max_links) 411362306a36Sopenharmony_ci return -EMLINK; 411462306a36Sopenharmony_ci 411562306a36Sopenharmony_ci error = dir->i_op->mkdir(idmap, dir, dentry, mode); 411662306a36Sopenharmony_ci if (!error) 411762306a36Sopenharmony_ci fsnotify_mkdir(dir, dentry); 411862306a36Sopenharmony_ci return error; 411962306a36Sopenharmony_ci} 412062306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_mkdir); 412162306a36Sopenharmony_ci 412262306a36Sopenharmony_ciint do_mkdirat(int dfd, struct filename *name, umode_t mode) 412362306a36Sopenharmony_ci{ 412462306a36Sopenharmony_ci struct dentry *dentry; 412562306a36Sopenharmony_ci struct path path; 412662306a36Sopenharmony_ci int error; 412762306a36Sopenharmony_ci unsigned int lookup_flags = LOOKUP_DIRECTORY; 412862306a36Sopenharmony_ci 412962306a36Sopenharmony_ciretry: 413062306a36Sopenharmony_ci dentry = filename_create(dfd, name, &path, lookup_flags); 413162306a36Sopenharmony_ci error = PTR_ERR(dentry); 413262306a36Sopenharmony_ci if (IS_ERR(dentry)) 413362306a36Sopenharmony_ci goto out_putname; 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci error = security_path_mkdir(&path, dentry, 413662306a36Sopenharmony_ci mode_strip_umask(path.dentry->d_inode, mode)); 413762306a36Sopenharmony_ci if (!error) { 413862306a36Sopenharmony_ci error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, 413962306a36Sopenharmony_ci dentry, mode); 414062306a36Sopenharmony_ci } 414162306a36Sopenharmony_ci done_path_create(&path, dentry); 414262306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 414362306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 414462306a36Sopenharmony_ci goto retry; 414562306a36Sopenharmony_ci } 414662306a36Sopenharmony_ciout_putname: 414762306a36Sopenharmony_ci putname(name); 414862306a36Sopenharmony_ci return error; 414962306a36Sopenharmony_ci} 415062306a36Sopenharmony_ci 415162306a36Sopenharmony_ciSYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) 415262306a36Sopenharmony_ci{ 415362306a36Sopenharmony_ci return do_mkdirat(dfd, getname(pathname), mode); 415462306a36Sopenharmony_ci} 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ciSYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) 415762306a36Sopenharmony_ci{ 415862306a36Sopenharmony_ci return do_mkdirat(AT_FDCWD, getname(pathname), mode); 415962306a36Sopenharmony_ci} 416062306a36Sopenharmony_ci 416162306a36Sopenharmony_ci/** 416262306a36Sopenharmony_ci * vfs_rmdir - remove directory 416362306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 416462306a36Sopenharmony_ci * @dir: inode of @dentry 416562306a36Sopenharmony_ci * @dentry: pointer to dentry of the base directory 416662306a36Sopenharmony_ci * 416762306a36Sopenharmony_ci * Remove a directory. 416862306a36Sopenharmony_ci * 416962306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 417062306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 417162306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 417262306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 417362306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 417462306a36Sopenharmony_ci */ 417562306a36Sopenharmony_ciint vfs_rmdir(struct mnt_idmap *idmap, struct inode *dir, 417662306a36Sopenharmony_ci struct dentry *dentry) 417762306a36Sopenharmony_ci{ 417862306a36Sopenharmony_ci int error = may_delete(idmap, dir, dentry, 1); 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci if (error) 418162306a36Sopenharmony_ci return error; 418262306a36Sopenharmony_ci 418362306a36Sopenharmony_ci if (!dir->i_op->rmdir) 418462306a36Sopenharmony_ci return -EPERM; 418562306a36Sopenharmony_ci 418662306a36Sopenharmony_ci dget(dentry); 418762306a36Sopenharmony_ci inode_lock(dentry->d_inode); 418862306a36Sopenharmony_ci 418962306a36Sopenharmony_ci error = -EBUSY; 419062306a36Sopenharmony_ci if (is_local_mountpoint(dentry) || 419162306a36Sopenharmony_ci (dentry->d_inode->i_flags & S_KERNEL_FILE)) 419262306a36Sopenharmony_ci goto out; 419362306a36Sopenharmony_ci 419462306a36Sopenharmony_ci error = security_inode_rmdir(dir, dentry); 419562306a36Sopenharmony_ci if (error) 419662306a36Sopenharmony_ci goto out; 419762306a36Sopenharmony_ci 419862306a36Sopenharmony_ci error = dir->i_op->rmdir(dir, dentry); 419962306a36Sopenharmony_ci if (error) 420062306a36Sopenharmony_ci goto out; 420162306a36Sopenharmony_ci 420262306a36Sopenharmony_ci shrink_dcache_parent(dentry); 420362306a36Sopenharmony_ci dentry->d_inode->i_flags |= S_DEAD; 420462306a36Sopenharmony_ci dont_mount(dentry); 420562306a36Sopenharmony_ci detach_mounts(dentry); 420662306a36Sopenharmony_ci 420762306a36Sopenharmony_ciout: 420862306a36Sopenharmony_ci inode_unlock(dentry->d_inode); 420962306a36Sopenharmony_ci dput(dentry); 421062306a36Sopenharmony_ci if (!error) 421162306a36Sopenharmony_ci d_delete_notify(dir, dentry); 421262306a36Sopenharmony_ci return error; 421362306a36Sopenharmony_ci} 421462306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_rmdir); 421562306a36Sopenharmony_ci 421662306a36Sopenharmony_ciint do_rmdir(int dfd, struct filename *name) 421762306a36Sopenharmony_ci{ 421862306a36Sopenharmony_ci int error; 421962306a36Sopenharmony_ci struct dentry *dentry; 422062306a36Sopenharmony_ci struct path path; 422162306a36Sopenharmony_ci struct qstr last; 422262306a36Sopenharmony_ci int type; 422362306a36Sopenharmony_ci unsigned int lookup_flags = 0; 422462306a36Sopenharmony_ciretry: 422562306a36Sopenharmony_ci error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); 422662306a36Sopenharmony_ci if (error) 422762306a36Sopenharmony_ci goto exit1; 422862306a36Sopenharmony_ci 422962306a36Sopenharmony_ci switch (type) { 423062306a36Sopenharmony_ci case LAST_DOTDOT: 423162306a36Sopenharmony_ci error = -ENOTEMPTY; 423262306a36Sopenharmony_ci goto exit2; 423362306a36Sopenharmony_ci case LAST_DOT: 423462306a36Sopenharmony_ci error = -EINVAL; 423562306a36Sopenharmony_ci goto exit2; 423662306a36Sopenharmony_ci case LAST_ROOT: 423762306a36Sopenharmony_ci error = -EBUSY; 423862306a36Sopenharmony_ci goto exit2; 423962306a36Sopenharmony_ci } 424062306a36Sopenharmony_ci 424162306a36Sopenharmony_ci error = mnt_want_write(path.mnt); 424262306a36Sopenharmony_ci if (error) 424362306a36Sopenharmony_ci goto exit2; 424462306a36Sopenharmony_ci 424562306a36Sopenharmony_ci inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); 424662306a36Sopenharmony_ci dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags); 424762306a36Sopenharmony_ci error = PTR_ERR(dentry); 424862306a36Sopenharmony_ci if (IS_ERR(dentry)) 424962306a36Sopenharmony_ci goto exit3; 425062306a36Sopenharmony_ci if (!dentry->d_inode) { 425162306a36Sopenharmony_ci error = -ENOENT; 425262306a36Sopenharmony_ci goto exit4; 425362306a36Sopenharmony_ci } 425462306a36Sopenharmony_ci error = security_path_rmdir(&path, dentry); 425562306a36Sopenharmony_ci if (error) 425662306a36Sopenharmony_ci goto exit4; 425762306a36Sopenharmony_ci error = vfs_rmdir(mnt_idmap(path.mnt), path.dentry->d_inode, dentry); 425862306a36Sopenharmony_ciexit4: 425962306a36Sopenharmony_ci dput(dentry); 426062306a36Sopenharmony_ciexit3: 426162306a36Sopenharmony_ci inode_unlock(path.dentry->d_inode); 426262306a36Sopenharmony_ci mnt_drop_write(path.mnt); 426362306a36Sopenharmony_ciexit2: 426462306a36Sopenharmony_ci path_put(&path); 426562306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 426662306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 426762306a36Sopenharmony_ci goto retry; 426862306a36Sopenharmony_ci } 426962306a36Sopenharmony_ciexit1: 427062306a36Sopenharmony_ci putname(name); 427162306a36Sopenharmony_ci return error; 427262306a36Sopenharmony_ci} 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ciSYSCALL_DEFINE1(rmdir, const char __user *, pathname) 427562306a36Sopenharmony_ci{ 427662306a36Sopenharmony_ci return do_rmdir(AT_FDCWD, getname(pathname)); 427762306a36Sopenharmony_ci} 427862306a36Sopenharmony_ci 427962306a36Sopenharmony_ci/** 428062306a36Sopenharmony_ci * vfs_unlink - unlink a filesystem object 428162306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 428262306a36Sopenharmony_ci * @dir: parent directory 428362306a36Sopenharmony_ci * @dentry: victim 428462306a36Sopenharmony_ci * @delegated_inode: returns victim inode, if the inode is delegated. 428562306a36Sopenharmony_ci * 428662306a36Sopenharmony_ci * The caller must hold dir->i_mutex. 428762306a36Sopenharmony_ci * 428862306a36Sopenharmony_ci * If vfs_unlink discovers a delegation, it will return -EWOULDBLOCK and 428962306a36Sopenharmony_ci * return a reference to the inode in delegated_inode. The caller 429062306a36Sopenharmony_ci * should then break the delegation on that inode and retry. Because 429162306a36Sopenharmony_ci * breaking a delegation may take a long time, the caller should drop 429262306a36Sopenharmony_ci * dir->i_mutex before doing so. 429362306a36Sopenharmony_ci * 429462306a36Sopenharmony_ci * Alternatively, a caller may pass NULL for delegated_inode. This may 429562306a36Sopenharmony_ci * be appropriate for callers that expect the underlying filesystem not 429662306a36Sopenharmony_ci * to be NFS exported. 429762306a36Sopenharmony_ci * 429862306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 429962306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 430062306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 430162306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 430262306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 430362306a36Sopenharmony_ci */ 430462306a36Sopenharmony_ciint vfs_unlink(struct mnt_idmap *idmap, struct inode *dir, 430562306a36Sopenharmony_ci struct dentry *dentry, struct inode **delegated_inode) 430662306a36Sopenharmony_ci{ 430762306a36Sopenharmony_ci struct inode *target = dentry->d_inode; 430862306a36Sopenharmony_ci int error = may_delete(idmap, dir, dentry, 0); 430962306a36Sopenharmony_ci 431062306a36Sopenharmony_ci if (error) 431162306a36Sopenharmony_ci return error; 431262306a36Sopenharmony_ci 431362306a36Sopenharmony_ci if (!dir->i_op->unlink) 431462306a36Sopenharmony_ci return -EPERM; 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_ci inode_lock(target); 431762306a36Sopenharmony_ci if (IS_SWAPFILE(target)) 431862306a36Sopenharmony_ci error = -EPERM; 431962306a36Sopenharmony_ci else if (is_local_mountpoint(dentry)) 432062306a36Sopenharmony_ci error = -EBUSY; 432162306a36Sopenharmony_ci else { 432262306a36Sopenharmony_ci error = security_inode_unlink(dir, dentry); 432362306a36Sopenharmony_ci if (!error) { 432462306a36Sopenharmony_ci error = try_break_deleg(target, delegated_inode); 432562306a36Sopenharmony_ci if (error) 432662306a36Sopenharmony_ci goto out; 432762306a36Sopenharmony_ci error = dir->i_op->unlink(dir, dentry); 432862306a36Sopenharmony_ci if (!error) { 432962306a36Sopenharmony_ci dont_mount(dentry); 433062306a36Sopenharmony_ci detach_mounts(dentry); 433162306a36Sopenharmony_ci } 433262306a36Sopenharmony_ci } 433362306a36Sopenharmony_ci } 433462306a36Sopenharmony_ciout: 433562306a36Sopenharmony_ci inode_unlock(target); 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_ci /* We don't d_delete() NFS sillyrenamed files--they still exist. */ 433862306a36Sopenharmony_ci if (!error && dentry->d_flags & DCACHE_NFSFS_RENAMED) { 433962306a36Sopenharmony_ci fsnotify_unlink(dir, dentry); 434062306a36Sopenharmony_ci } else if (!error) { 434162306a36Sopenharmony_ci fsnotify_link_count(target); 434262306a36Sopenharmony_ci d_delete_notify(dir, dentry); 434362306a36Sopenharmony_ci } 434462306a36Sopenharmony_ci 434562306a36Sopenharmony_ci return error; 434662306a36Sopenharmony_ci} 434762306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_unlink); 434862306a36Sopenharmony_ci 434962306a36Sopenharmony_ci/* 435062306a36Sopenharmony_ci * Make sure that the actual truncation of the file will occur outside its 435162306a36Sopenharmony_ci * directory's i_mutex. Truncate can take a long time if there is a lot of 435262306a36Sopenharmony_ci * writeout happening, and we don't want to prevent access to the directory 435362306a36Sopenharmony_ci * while waiting on the I/O. 435462306a36Sopenharmony_ci */ 435562306a36Sopenharmony_ciint do_unlinkat(int dfd, struct filename *name) 435662306a36Sopenharmony_ci{ 435762306a36Sopenharmony_ci int error; 435862306a36Sopenharmony_ci struct dentry *dentry; 435962306a36Sopenharmony_ci struct path path; 436062306a36Sopenharmony_ci struct qstr last; 436162306a36Sopenharmony_ci int type; 436262306a36Sopenharmony_ci struct inode *inode = NULL; 436362306a36Sopenharmony_ci struct inode *delegated_inode = NULL; 436462306a36Sopenharmony_ci unsigned int lookup_flags = 0; 436562306a36Sopenharmony_ciretry: 436662306a36Sopenharmony_ci error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type); 436762306a36Sopenharmony_ci if (error) 436862306a36Sopenharmony_ci goto exit1; 436962306a36Sopenharmony_ci 437062306a36Sopenharmony_ci error = -EISDIR; 437162306a36Sopenharmony_ci if (type != LAST_NORM) 437262306a36Sopenharmony_ci goto exit2; 437362306a36Sopenharmony_ci 437462306a36Sopenharmony_ci error = mnt_want_write(path.mnt); 437562306a36Sopenharmony_ci if (error) 437662306a36Sopenharmony_ci goto exit2; 437762306a36Sopenharmony_ciretry_deleg: 437862306a36Sopenharmony_ci inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); 437962306a36Sopenharmony_ci dentry = lookup_one_qstr_excl(&last, path.dentry, lookup_flags); 438062306a36Sopenharmony_ci error = PTR_ERR(dentry); 438162306a36Sopenharmony_ci if (!IS_ERR(dentry)) { 438262306a36Sopenharmony_ci 438362306a36Sopenharmony_ci /* Why not before? Because we want correct error value */ 438462306a36Sopenharmony_ci if (last.name[last.len]) 438562306a36Sopenharmony_ci goto slashes; 438662306a36Sopenharmony_ci inode = dentry->d_inode; 438762306a36Sopenharmony_ci if (d_is_negative(dentry)) 438862306a36Sopenharmony_ci goto slashes; 438962306a36Sopenharmony_ci ihold(inode); 439062306a36Sopenharmony_ci error = security_path_unlink(&path, dentry); 439162306a36Sopenharmony_ci if (error) 439262306a36Sopenharmony_ci goto exit3; 439362306a36Sopenharmony_ci error = vfs_unlink(mnt_idmap(path.mnt), path.dentry->d_inode, 439462306a36Sopenharmony_ci dentry, &delegated_inode); 439562306a36Sopenharmony_ciexit3: 439662306a36Sopenharmony_ci dput(dentry); 439762306a36Sopenharmony_ci } 439862306a36Sopenharmony_ci inode_unlock(path.dentry->d_inode); 439962306a36Sopenharmony_ci if (inode) 440062306a36Sopenharmony_ci iput(inode); /* truncate the inode here */ 440162306a36Sopenharmony_ci inode = NULL; 440262306a36Sopenharmony_ci if (delegated_inode) { 440362306a36Sopenharmony_ci error = break_deleg_wait(&delegated_inode); 440462306a36Sopenharmony_ci if (!error) 440562306a36Sopenharmony_ci goto retry_deleg; 440662306a36Sopenharmony_ci } 440762306a36Sopenharmony_ci mnt_drop_write(path.mnt); 440862306a36Sopenharmony_ciexit2: 440962306a36Sopenharmony_ci path_put(&path); 441062306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 441162306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 441262306a36Sopenharmony_ci inode = NULL; 441362306a36Sopenharmony_ci goto retry; 441462306a36Sopenharmony_ci } 441562306a36Sopenharmony_ciexit1: 441662306a36Sopenharmony_ci putname(name); 441762306a36Sopenharmony_ci return error; 441862306a36Sopenharmony_ci 441962306a36Sopenharmony_cislashes: 442062306a36Sopenharmony_ci if (d_is_negative(dentry)) 442162306a36Sopenharmony_ci error = -ENOENT; 442262306a36Sopenharmony_ci else if (d_is_dir(dentry)) 442362306a36Sopenharmony_ci error = -EISDIR; 442462306a36Sopenharmony_ci else 442562306a36Sopenharmony_ci error = -ENOTDIR; 442662306a36Sopenharmony_ci goto exit3; 442762306a36Sopenharmony_ci} 442862306a36Sopenharmony_ci 442962306a36Sopenharmony_ciSYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag) 443062306a36Sopenharmony_ci{ 443162306a36Sopenharmony_ci if ((flag & ~AT_REMOVEDIR) != 0) 443262306a36Sopenharmony_ci return -EINVAL; 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_ci if (flag & AT_REMOVEDIR) 443562306a36Sopenharmony_ci return do_rmdir(dfd, getname(pathname)); 443662306a36Sopenharmony_ci return do_unlinkat(dfd, getname(pathname)); 443762306a36Sopenharmony_ci} 443862306a36Sopenharmony_ci 443962306a36Sopenharmony_ciSYSCALL_DEFINE1(unlink, const char __user *, pathname) 444062306a36Sopenharmony_ci{ 444162306a36Sopenharmony_ci return do_unlinkat(AT_FDCWD, getname(pathname)); 444262306a36Sopenharmony_ci} 444362306a36Sopenharmony_ci 444462306a36Sopenharmony_ci/** 444562306a36Sopenharmony_ci * vfs_symlink - create symlink 444662306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 444762306a36Sopenharmony_ci * @dir: inode of @dentry 444862306a36Sopenharmony_ci * @dentry: pointer to dentry of the base directory 444962306a36Sopenharmony_ci * @oldname: name of the file to link to 445062306a36Sopenharmony_ci * 445162306a36Sopenharmony_ci * Create a symlink. 445262306a36Sopenharmony_ci * 445362306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 445462306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 445562306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 445662306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 445762306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 445862306a36Sopenharmony_ci */ 445962306a36Sopenharmony_ciint vfs_symlink(struct mnt_idmap *idmap, struct inode *dir, 446062306a36Sopenharmony_ci struct dentry *dentry, const char *oldname) 446162306a36Sopenharmony_ci{ 446262306a36Sopenharmony_ci int error; 446362306a36Sopenharmony_ci 446462306a36Sopenharmony_ci error = may_create(idmap, dir, dentry); 446562306a36Sopenharmony_ci if (error) 446662306a36Sopenharmony_ci return error; 446762306a36Sopenharmony_ci 446862306a36Sopenharmony_ci if (!dir->i_op->symlink) 446962306a36Sopenharmony_ci return -EPERM; 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci error = security_inode_symlink(dir, dentry, oldname); 447262306a36Sopenharmony_ci if (error) 447362306a36Sopenharmony_ci return error; 447462306a36Sopenharmony_ci 447562306a36Sopenharmony_ci error = dir->i_op->symlink(idmap, dir, dentry, oldname); 447662306a36Sopenharmony_ci if (!error) 447762306a36Sopenharmony_ci fsnotify_create(dir, dentry); 447862306a36Sopenharmony_ci return error; 447962306a36Sopenharmony_ci} 448062306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_symlink); 448162306a36Sopenharmony_ci 448262306a36Sopenharmony_ciint do_symlinkat(struct filename *from, int newdfd, struct filename *to) 448362306a36Sopenharmony_ci{ 448462306a36Sopenharmony_ci int error; 448562306a36Sopenharmony_ci struct dentry *dentry; 448662306a36Sopenharmony_ci struct path path; 448762306a36Sopenharmony_ci unsigned int lookup_flags = 0; 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci if (IS_ERR(from)) { 449062306a36Sopenharmony_ci error = PTR_ERR(from); 449162306a36Sopenharmony_ci goto out_putnames; 449262306a36Sopenharmony_ci } 449362306a36Sopenharmony_ciretry: 449462306a36Sopenharmony_ci dentry = filename_create(newdfd, to, &path, lookup_flags); 449562306a36Sopenharmony_ci error = PTR_ERR(dentry); 449662306a36Sopenharmony_ci if (IS_ERR(dentry)) 449762306a36Sopenharmony_ci goto out_putnames; 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci error = security_path_symlink(&path, dentry, from->name); 450062306a36Sopenharmony_ci if (!error) 450162306a36Sopenharmony_ci error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode, 450262306a36Sopenharmony_ci dentry, from->name); 450362306a36Sopenharmony_ci done_path_create(&path, dentry); 450462306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) { 450562306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 450662306a36Sopenharmony_ci goto retry; 450762306a36Sopenharmony_ci } 450862306a36Sopenharmony_ciout_putnames: 450962306a36Sopenharmony_ci putname(to); 451062306a36Sopenharmony_ci putname(from); 451162306a36Sopenharmony_ci return error; 451262306a36Sopenharmony_ci} 451362306a36Sopenharmony_ci 451462306a36Sopenharmony_ciSYSCALL_DEFINE3(symlinkat, const char __user *, oldname, 451562306a36Sopenharmony_ci int, newdfd, const char __user *, newname) 451662306a36Sopenharmony_ci{ 451762306a36Sopenharmony_ci return do_symlinkat(getname(oldname), newdfd, getname(newname)); 451862306a36Sopenharmony_ci} 451962306a36Sopenharmony_ci 452062306a36Sopenharmony_ciSYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname) 452162306a36Sopenharmony_ci{ 452262306a36Sopenharmony_ci return do_symlinkat(getname(oldname), AT_FDCWD, getname(newname)); 452362306a36Sopenharmony_ci} 452462306a36Sopenharmony_ci 452562306a36Sopenharmony_ci/** 452662306a36Sopenharmony_ci * vfs_link - create a new link 452762306a36Sopenharmony_ci * @old_dentry: object to be linked 452862306a36Sopenharmony_ci * @idmap: idmap of the mount 452962306a36Sopenharmony_ci * @dir: new parent 453062306a36Sopenharmony_ci * @new_dentry: where to create the new link 453162306a36Sopenharmony_ci * @delegated_inode: returns inode needing a delegation break 453262306a36Sopenharmony_ci * 453362306a36Sopenharmony_ci * The caller must hold dir->i_mutex 453462306a36Sopenharmony_ci * 453562306a36Sopenharmony_ci * If vfs_link discovers a delegation on the to-be-linked file in need 453662306a36Sopenharmony_ci * of breaking, it will return -EWOULDBLOCK and return a reference to the 453762306a36Sopenharmony_ci * inode in delegated_inode. The caller should then break the delegation 453862306a36Sopenharmony_ci * and retry. Because breaking a delegation may take a long time, the 453962306a36Sopenharmony_ci * caller should drop the i_mutex before doing so. 454062306a36Sopenharmony_ci * 454162306a36Sopenharmony_ci * Alternatively, a caller may pass NULL for delegated_inode. This may 454262306a36Sopenharmony_ci * be appropriate for callers that expect the underlying filesystem not 454362306a36Sopenharmony_ci * to be NFS exported. 454462306a36Sopenharmony_ci * 454562306a36Sopenharmony_ci * If the inode has been found through an idmapped mount the idmap of 454662306a36Sopenharmony_ci * the vfsmount must be passed through @idmap. This function will then take 454762306a36Sopenharmony_ci * care to map the inode according to @idmap before checking permissions. 454862306a36Sopenharmony_ci * On non-idmapped mounts or if permission checking is to be performed on the 454962306a36Sopenharmony_ci * raw inode simply passs @nop_mnt_idmap. 455062306a36Sopenharmony_ci */ 455162306a36Sopenharmony_ciint vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap, 455262306a36Sopenharmony_ci struct inode *dir, struct dentry *new_dentry, 455362306a36Sopenharmony_ci struct inode **delegated_inode) 455462306a36Sopenharmony_ci{ 455562306a36Sopenharmony_ci struct inode *inode = old_dentry->d_inode; 455662306a36Sopenharmony_ci unsigned max_links = dir->i_sb->s_max_links; 455762306a36Sopenharmony_ci int error; 455862306a36Sopenharmony_ci 455962306a36Sopenharmony_ci if (!inode) 456062306a36Sopenharmony_ci return -ENOENT; 456162306a36Sopenharmony_ci 456262306a36Sopenharmony_ci error = may_create(idmap, dir, new_dentry); 456362306a36Sopenharmony_ci if (error) 456462306a36Sopenharmony_ci return error; 456562306a36Sopenharmony_ci 456662306a36Sopenharmony_ci if (dir->i_sb != inode->i_sb) 456762306a36Sopenharmony_ci return -EXDEV; 456862306a36Sopenharmony_ci 456962306a36Sopenharmony_ci /* 457062306a36Sopenharmony_ci * A link to an append-only or immutable file cannot be created. 457162306a36Sopenharmony_ci */ 457262306a36Sopenharmony_ci if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) 457362306a36Sopenharmony_ci return -EPERM; 457462306a36Sopenharmony_ci /* 457562306a36Sopenharmony_ci * Updating the link count will likely cause i_uid and i_gid to 457662306a36Sopenharmony_ci * be writen back improperly if their true value is unknown to 457762306a36Sopenharmony_ci * the vfs. 457862306a36Sopenharmony_ci */ 457962306a36Sopenharmony_ci if (HAS_UNMAPPED_ID(idmap, inode)) 458062306a36Sopenharmony_ci return -EPERM; 458162306a36Sopenharmony_ci if (!dir->i_op->link) 458262306a36Sopenharmony_ci return -EPERM; 458362306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode)) 458462306a36Sopenharmony_ci return -EPERM; 458562306a36Sopenharmony_ci 458662306a36Sopenharmony_ci error = security_inode_link(old_dentry, dir, new_dentry); 458762306a36Sopenharmony_ci if (error) 458862306a36Sopenharmony_ci return error; 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci inode_lock(inode); 459162306a36Sopenharmony_ci /* Make sure we don't allow creating hardlink to an unlinked file */ 459262306a36Sopenharmony_ci if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE)) 459362306a36Sopenharmony_ci error = -ENOENT; 459462306a36Sopenharmony_ci else if (max_links && inode->i_nlink >= max_links) 459562306a36Sopenharmony_ci error = -EMLINK; 459662306a36Sopenharmony_ci else { 459762306a36Sopenharmony_ci error = try_break_deleg(inode, delegated_inode); 459862306a36Sopenharmony_ci if (!error) 459962306a36Sopenharmony_ci error = dir->i_op->link(old_dentry, dir, new_dentry); 460062306a36Sopenharmony_ci } 460162306a36Sopenharmony_ci 460262306a36Sopenharmony_ci if (!error && (inode->i_state & I_LINKABLE)) { 460362306a36Sopenharmony_ci spin_lock(&inode->i_lock); 460462306a36Sopenharmony_ci inode->i_state &= ~I_LINKABLE; 460562306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 460662306a36Sopenharmony_ci } 460762306a36Sopenharmony_ci inode_unlock(inode); 460862306a36Sopenharmony_ci if (!error) 460962306a36Sopenharmony_ci fsnotify_link(dir, inode, new_dentry); 461062306a36Sopenharmony_ci return error; 461162306a36Sopenharmony_ci} 461262306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_link); 461362306a36Sopenharmony_ci 461462306a36Sopenharmony_ci/* 461562306a36Sopenharmony_ci * Hardlinks are often used in delicate situations. We avoid 461662306a36Sopenharmony_ci * security-related surprises by not following symlinks on the 461762306a36Sopenharmony_ci * newname. --KAB 461862306a36Sopenharmony_ci * 461962306a36Sopenharmony_ci * We don't follow them on the oldname either to be compatible 462062306a36Sopenharmony_ci * with linux 2.0, and to avoid hard-linking to directories 462162306a36Sopenharmony_ci * and other special files. --ADM 462262306a36Sopenharmony_ci */ 462362306a36Sopenharmony_ciint do_linkat(int olddfd, struct filename *old, int newdfd, 462462306a36Sopenharmony_ci struct filename *new, int flags) 462562306a36Sopenharmony_ci{ 462662306a36Sopenharmony_ci struct mnt_idmap *idmap; 462762306a36Sopenharmony_ci struct dentry *new_dentry; 462862306a36Sopenharmony_ci struct path old_path, new_path; 462962306a36Sopenharmony_ci struct inode *delegated_inode = NULL; 463062306a36Sopenharmony_ci int how = 0; 463162306a36Sopenharmony_ci int error; 463262306a36Sopenharmony_ci 463362306a36Sopenharmony_ci if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) { 463462306a36Sopenharmony_ci error = -EINVAL; 463562306a36Sopenharmony_ci goto out_putnames; 463662306a36Sopenharmony_ci } 463762306a36Sopenharmony_ci /* 463862306a36Sopenharmony_ci * To use null names we require CAP_DAC_READ_SEARCH 463962306a36Sopenharmony_ci * This ensures that not everyone will be able to create 464062306a36Sopenharmony_ci * handlink using the passed filedescriptor. 464162306a36Sopenharmony_ci */ 464262306a36Sopenharmony_ci if (flags & AT_EMPTY_PATH && !capable(CAP_DAC_READ_SEARCH)) { 464362306a36Sopenharmony_ci error = -ENOENT; 464462306a36Sopenharmony_ci goto out_putnames; 464562306a36Sopenharmony_ci } 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci if (flags & AT_SYMLINK_FOLLOW) 464862306a36Sopenharmony_ci how |= LOOKUP_FOLLOW; 464962306a36Sopenharmony_ciretry: 465062306a36Sopenharmony_ci error = filename_lookup(olddfd, old, how, &old_path, NULL); 465162306a36Sopenharmony_ci if (error) 465262306a36Sopenharmony_ci goto out_putnames; 465362306a36Sopenharmony_ci 465462306a36Sopenharmony_ci new_dentry = filename_create(newdfd, new, &new_path, 465562306a36Sopenharmony_ci (how & LOOKUP_REVAL)); 465662306a36Sopenharmony_ci error = PTR_ERR(new_dentry); 465762306a36Sopenharmony_ci if (IS_ERR(new_dentry)) 465862306a36Sopenharmony_ci goto out_putpath; 465962306a36Sopenharmony_ci 466062306a36Sopenharmony_ci error = -EXDEV; 466162306a36Sopenharmony_ci if (old_path.mnt != new_path.mnt) 466262306a36Sopenharmony_ci goto out_dput; 466362306a36Sopenharmony_ci idmap = mnt_idmap(new_path.mnt); 466462306a36Sopenharmony_ci error = may_linkat(idmap, &old_path); 466562306a36Sopenharmony_ci if (unlikely(error)) 466662306a36Sopenharmony_ci goto out_dput; 466762306a36Sopenharmony_ci error = security_path_link(old_path.dentry, &new_path, new_dentry); 466862306a36Sopenharmony_ci if (error) 466962306a36Sopenharmony_ci goto out_dput; 467062306a36Sopenharmony_ci error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode, 467162306a36Sopenharmony_ci new_dentry, &delegated_inode); 467262306a36Sopenharmony_ciout_dput: 467362306a36Sopenharmony_ci done_path_create(&new_path, new_dentry); 467462306a36Sopenharmony_ci if (delegated_inode) { 467562306a36Sopenharmony_ci error = break_deleg_wait(&delegated_inode); 467662306a36Sopenharmony_ci if (!error) { 467762306a36Sopenharmony_ci path_put(&old_path); 467862306a36Sopenharmony_ci goto retry; 467962306a36Sopenharmony_ci } 468062306a36Sopenharmony_ci } 468162306a36Sopenharmony_ci if (retry_estale(error, how)) { 468262306a36Sopenharmony_ci path_put(&old_path); 468362306a36Sopenharmony_ci how |= LOOKUP_REVAL; 468462306a36Sopenharmony_ci goto retry; 468562306a36Sopenharmony_ci } 468662306a36Sopenharmony_ciout_putpath: 468762306a36Sopenharmony_ci path_put(&old_path); 468862306a36Sopenharmony_ciout_putnames: 468962306a36Sopenharmony_ci putname(old); 469062306a36Sopenharmony_ci putname(new); 469162306a36Sopenharmony_ci 469262306a36Sopenharmony_ci return error; 469362306a36Sopenharmony_ci} 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ciSYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, 469662306a36Sopenharmony_ci int, newdfd, const char __user *, newname, int, flags) 469762306a36Sopenharmony_ci{ 469862306a36Sopenharmony_ci return do_linkat(olddfd, getname_uflags(oldname, flags), 469962306a36Sopenharmony_ci newdfd, getname(newname), flags); 470062306a36Sopenharmony_ci} 470162306a36Sopenharmony_ci 470262306a36Sopenharmony_ciSYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname) 470362306a36Sopenharmony_ci{ 470462306a36Sopenharmony_ci return do_linkat(AT_FDCWD, getname(oldname), AT_FDCWD, getname(newname), 0); 470562306a36Sopenharmony_ci} 470662306a36Sopenharmony_ci 470762306a36Sopenharmony_ci/** 470862306a36Sopenharmony_ci * vfs_rename - rename a filesystem object 470962306a36Sopenharmony_ci * @rd: pointer to &struct renamedata info 471062306a36Sopenharmony_ci * 471162306a36Sopenharmony_ci * The caller must hold multiple mutexes--see lock_rename()). 471262306a36Sopenharmony_ci * 471362306a36Sopenharmony_ci * If vfs_rename discovers a delegation in need of breaking at either 471462306a36Sopenharmony_ci * the source or destination, it will return -EWOULDBLOCK and return a 471562306a36Sopenharmony_ci * reference to the inode in delegated_inode. The caller should then 471662306a36Sopenharmony_ci * break the delegation and retry. Because breaking a delegation may 471762306a36Sopenharmony_ci * take a long time, the caller should drop all locks before doing 471862306a36Sopenharmony_ci * so. 471962306a36Sopenharmony_ci * 472062306a36Sopenharmony_ci * Alternatively, a caller may pass NULL for delegated_inode. This may 472162306a36Sopenharmony_ci * be appropriate for callers that expect the underlying filesystem not 472262306a36Sopenharmony_ci * to be NFS exported. 472362306a36Sopenharmony_ci * 472462306a36Sopenharmony_ci * The worst of all namespace operations - renaming directory. "Perverted" 472562306a36Sopenharmony_ci * doesn't even start to describe it. Somebody in UCB had a heck of a trip... 472662306a36Sopenharmony_ci * Problems: 472762306a36Sopenharmony_ci * 472862306a36Sopenharmony_ci * a) we can get into loop creation. 472962306a36Sopenharmony_ci * b) race potential - two innocent renames can create a loop together. 473062306a36Sopenharmony_ci * That's where 4.4BSD screws up. Current fix: serialization on 473162306a36Sopenharmony_ci * sb->s_vfs_rename_mutex. We might be more accurate, but that's another 473262306a36Sopenharmony_ci * story. 473362306a36Sopenharmony_ci * c) we may have to lock up to _four_ objects - parents and victim (if it exists), 473462306a36Sopenharmony_ci * and source (if it's a non-directory or a subdirectory that moves to 473562306a36Sopenharmony_ci * different parent). 473662306a36Sopenharmony_ci * And that - after we got ->i_mutex on parents (until then we don't know 473762306a36Sopenharmony_ci * whether the target exists). Solution: try to be smart with locking 473862306a36Sopenharmony_ci * order for inodes. We rely on the fact that tree topology may change 473962306a36Sopenharmony_ci * only under ->s_vfs_rename_mutex _and_ that parent of the object we 474062306a36Sopenharmony_ci * move will be locked. Thus we can rank directories by the tree 474162306a36Sopenharmony_ci * (ancestors first) and rank all non-directories after them. 474262306a36Sopenharmony_ci * That works since everybody except rename does "lock parent, lookup, 474362306a36Sopenharmony_ci * lock child" and rename is under ->s_vfs_rename_mutex. 474462306a36Sopenharmony_ci * HOWEVER, it relies on the assumption that any object with ->lookup() 474562306a36Sopenharmony_ci * has no more than 1 dentry. If "hybrid" objects will ever appear, 474662306a36Sopenharmony_ci * we'd better make sure that there's no link(2) for them. 474762306a36Sopenharmony_ci * d) conversion from fhandle to dentry may come in the wrong moment - when 474862306a36Sopenharmony_ci * we are removing the target. Solution: we will have to grab ->i_mutex 474962306a36Sopenharmony_ci * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on 475062306a36Sopenharmony_ci * ->i_mutex on parents, which works but leads to some truly excessive 475162306a36Sopenharmony_ci * locking]. 475262306a36Sopenharmony_ci */ 475362306a36Sopenharmony_ciint vfs_rename(struct renamedata *rd) 475462306a36Sopenharmony_ci{ 475562306a36Sopenharmony_ci int error; 475662306a36Sopenharmony_ci struct inode *old_dir = rd->old_dir, *new_dir = rd->new_dir; 475762306a36Sopenharmony_ci struct dentry *old_dentry = rd->old_dentry; 475862306a36Sopenharmony_ci struct dentry *new_dentry = rd->new_dentry; 475962306a36Sopenharmony_ci struct inode **delegated_inode = rd->delegated_inode; 476062306a36Sopenharmony_ci unsigned int flags = rd->flags; 476162306a36Sopenharmony_ci bool is_dir = d_is_dir(old_dentry); 476262306a36Sopenharmony_ci struct inode *source = old_dentry->d_inode; 476362306a36Sopenharmony_ci struct inode *target = new_dentry->d_inode; 476462306a36Sopenharmony_ci bool new_is_dir = false; 476562306a36Sopenharmony_ci unsigned max_links = new_dir->i_sb->s_max_links; 476662306a36Sopenharmony_ci struct name_snapshot old_name; 476762306a36Sopenharmony_ci bool lock_old_subdir, lock_new_subdir; 476862306a36Sopenharmony_ci 476962306a36Sopenharmony_ci if (source == target) 477062306a36Sopenharmony_ci return 0; 477162306a36Sopenharmony_ci 477262306a36Sopenharmony_ci error = may_delete(rd->old_mnt_idmap, old_dir, old_dentry, is_dir); 477362306a36Sopenharmony_ci if (error) 477462306a36Sopenharmony_ci return error; 477562306a36Sopenharmony_ci 477662306a36Sopenharmony_ci if (!target) { 477762306a36Sopenharmony_ci error = may_create(rd->new_mnt_idmap, new_dir, new_dentry); 477862306a36Sopenharmony_ci } else { 477962306a36Sopenharmony_ci new_is_dir = d_is_dir(new_dentry); 478062306a36Sopenharmony_ci 478162306a36Sopenharmony_ci if (!(flags & RENAME_EXCHANGE)) 478262306a36Sopenharmony_ci error = may_delete(rd->new_mnt_idmap, new_dir, 478362306a36Sopenharmony_ci new_dentry, is_dir); 478462306a36Sopenharmony_ci else 478562306a36Sopenharmony_ci error = may_delete(rd->new_mnt_idmap, new_dir, 478662306a36Sopenharmony_ci new_dentry, new_is_dir); 478762306a36Sopenharmony_ci } 478862306a36Sopenharmony_ci if (error) 478962306a36Sopenharmony_ci return error; 479062306a36Sopenharmony_ci 479162306a36Sopenharmony_ci if (!old_dir->i_op->rename) 479262306a36Sopenharmony_ci return -EPERM; 479362306a36Sopenharmony_ci 479462306a36Sopenharmony_ci /* 479562306a36Sopenharmony_ci * If we are going to change the parent - check write permissions, 479662306a36Sopenharmony_ci * we'll need to flip '..'. 479762306a36Sopenharmony_ci */ 479862306a36Sopenharmony_ci if (new_dir != old_dir) { 479962306a36Sopenharmony_ci if (is_dir) { 480062306a36Sopenharmony_ci error = inode_permission(rd->old_mnt_idmap, source, 480162306a36Sopenharmony_ci MAY_WRITE); 480262306a36Sopenharmony_ci if (error) 480362306a36Sopenharmony_ci return error; 480462306a36Sopenharmony_ci } 480562306a36Sopenharmony_ci if ((flags & RENAME_EXCHANGE) && new_is_dir) { 480662306a36Sopenharmony_ci error = inode_permission(rd->new_mnt_idmap, target, 480762306a36Sopenharmony_ci MAY_WRITE); 480862306a36Sopenharmony_ci if (error) 480962306a36Sopenharmony_ci return error; 481062306a36Sopenharmony_ci } 481162306a36Sopenharmony_ci } 481262306a36Sopenharmony_ci 481362306a36Sopenharmony_ci error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry, 481462306a36Sopenharmony_ci flags); 481562306a36Sopenharmony_ci if (error) 481662306a36Sopenharmony_ci return error; 481762306a36Sopenharmony_ci 481862306a36Sopenharmony_ci take_dentry_name_snapshot(&old_name, old_dentry); 481962306a36Sopenharmony_ci dget(new_dentry); 482062306a36Sopenharmony_ci /* 482162306a36Sopenharmony_ci * Lock children. 482262306a36Sopenharmony_ci * The source subdirectory needs to be locked on cross-directory 482362306a36Sopenharmony_ci * rename or cross-directory exchange since its parent changes. 482462306a36Sopenharmony_ci * The target subdirectory needs to be locked on cross-directory 482562306a36Sopenharmony_ci * exchange due to parent change and on any rename due to becoming 482662306a36Sopenharmony_ci * a victim. 482762306a36Sopenharmony_ci * Non-directories need locking in all cases (for NFS reasons); 482862306a36Sopenharmony_ci * they get locked after any subdirectories (in inode address order). 482962306a36Sopenharmony_ci * 483062306a36Sopenharmony_ci * NOTE: WE ONLY LOCK UNRELATED DIRECTORIES IN CROSS-DIRECTORY CASE. 483162306a36Sopenharmony_ci * NEVER, EVER DO THAT WITHOUT ->s_vfs_rename_mutex. 483262306a36Sopenharmony_ci */ 483362306a36Sopenharmony_ci lock_old_subdir = new_dir != old_dir; 483462306a36Sopenharmony_ci lock_new_subdir = new_dir != old_dir || !(flags & RENAME_EXCHANGE); 483562306a36Sopenharmony_ci if (is_dir) { 483662306a36Sopenharmony_ci if (lock_old_subdir) 483762306a36Sopenharmony_ci inode_lock_nested(source, I_MUTEX_CHILD); 483862306a36Sopenharmony_ci if (target && (!new_is_dir || lock_new_subdir)) 483962306a36Sopenharmony_ci inode_lock(target); 484062306a36Sopenharmony_ci } else if (new_is_dir) { 484162306a36Sopenharmony_ci if (lock_new_subdir) 484262306a36Sopenharmony_ci inode_lock_nested(target, I_MUTEX_CHILD); 484362306a36Sopenharmony_ci inode_lock(source); 484462306a36Sopenharmony_ci } else { 484562306a36Sopenharmony_ci lock_two_nondirectories(source, target); 484662306a36Sopenharmony_ci } 484762306a36Sopenharmony_ci 484862306a36Sopenharmony_ci error = -EPERM; 484962306a36Sopenharmony_ci if (IS_SWAPFILE(source) || (target && IS_SWAPFILE(target))) 485062306a36Sopenharmony_ci goto out; 485162306a36Sopenharmony_ci 485262306a36Sopenharmony_ci error = -EBUSY; 485362306a36Sopenharmony_ci if (is_local_mountpoint(old_dentry) || is_local_mountpoint(new_dentry)) 485462306a36Sopenharmony_ci goto out; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci if (max_links && new_dir != old_dir) { 485762306a36Sopenharmony_ci error = -EMLINK; 485862306a36Sopenharmony_ci if (is_dir && !new_is_dir && new_dir->i_nlink >= max_links) 485962306a36Sopenharmony_ci goto out; 486062306a36Sopenharmony_ci if ((flags & RENAME_EXCHANGE) && !is_dir && new_is_dir && 486162306a36Sopenharmony_ci old_dir->i_nlink >= max_links) 486262306a36Sopenharmony_ci goto out; 486362306a36Sopenharmony_ci } 486462306a36Sopenharmony_ci if (!is_dir) { 486562306a36Sopenharmony_ci error = try_break_deleg(source, delegated_inode); 486662306a36Sopenharmony_ci if (error) 486762306a36Sopenharmony_ci goto out; 486862306a36Sopenharmony_ci } 486962306a36Sopenharmony_ci if (target && !new_is_dir) { 487062306a36Sopenharmony_ci error = try_break_deleg(target, delegated_inode); 487162306a36Sopenharmony_ci if (error) 487262306a36Sopenharmony_ci goto out; 487362306a36Sopenharmony_ci } 487462306a36Sopenharmony_ci error = old_dir->i_op->rename(rd->new_mnt_idmap, old_dir, old_dentry, 487562306a36Sopenharmony_ci new_dir, new_dentry, flags); 487662306a36Sopenharmony_ci if (error) 487762306a36Sopenharmony_ci goto out; 487862306a36Sopenharmony_ci 487962306a36Sopenharmony_ci if (!(flags & RENAME_EXCHANGE) && target) { 488062306a36Sopenharmony_ci if (is_dir) { 488162306a36Sopenharmony_ci shrink_dcache_parent(new_dentry); 488262306a36Sopenharmony_ci target->i_flags |= S_DEAD; 488362306a36Sopenharmony_ci } 488462306a36Sopenharmony_ci dont_mount(new_dentry); 488562306a36Sopenharmony_ci detach_mounts(new_dentry); 488662306a36Sopenharmony_ci } 488762306a36Sopenharmony_ci if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) { 488862306a36Sopenharmony_ci if (!(flags & RENAME_EXCHANGE)) 488962306a36Sopenharmony_ci d_move(old_dentry, new_dentry); 489062306a36Sopenharmony_ci else 489162306a36Sopenharmony_ci d_exchange(old_dentry, new_dentry); 489262306a36Sopenharmony_ci } 489362306a36Sopenharmony_ciout: 489462306a36Sopenharmony_ci if (!is_dir || lock_old_subdir) 489562306a36Sopenharmony_ci inode_unlock(source); 489662306a36Sopenharmony_ci if (target && (!new_is_dir || lock_new_subdir)) 489762306a36Sopenharmony_ci inode_unlock(target); 489862306a36Sopenharmony_ci dput(new_dentry); 489962306a36Sopenharmony_ci if (!error) { 490062306a36Sopenharmony_ci fsnotify_move(old_dir, new_dir, &old_name.name, is_dir, 490162306a36Sopenharmony_ci !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry); 490262306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) { 490362306a36Sopenharmony_ci fsnotify_move(new_dir, old_dir, &old_dentry->d_name, 490462306a36Sopenharmony_ci new_is_dir, NULL, new_dentry); 490562306a36Sopenharmony_ci } 490662306a36Sopenharmony_ci } 490762306a36Sopenharmony_ci release_dentry_name_snapshot(&old_name); 490862306a36Sopenharmony_ci 490962306a36Sopenharmony_ci return error; 491062306a36Sopenharmony_ci} 491162306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_rename); 491262306a36Sopenharmony_ci 491362306a36Sopenharmony_ciint do_renameat2(int olddfd, struct filename *from, int newdfd, 491462306a36Sopenharmony_ci struct filename *to, unsigned int flags) 491562306a36Sopenharmony_ci{ 491662306a36Sopenharmony_ci struct renamedata rd; 491762306a36Sopenharmony_ci struct dentry *old_dentry, *new_dentry; 491862306a36Sopenharmony_ci struct dentry *trap; 491962306a36Sopenharmony_ci struct path old_path, new_path; 492062306a36Sopenharmony_ci struct qstr old_last, new_last; 492162306a36Sopenharmony_ci int old_type, new_type; 492262306a36Sopenharmony_ci struct inode *delegated_inode = NULL; 492362306a36Sopenharmony_ci unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET; 492462306a36Sopenharmony_ci bool should_retry = false; 492562306a36Sopenharmony_ci int error = -EINVAL; 492662306a36Sopenharmony_ci 492762306a36Sopenharmony_ci if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) 492862306a36Sopenharmony_ci goto put_names; 492962306a36Sopenharmony_ci 493062306a36Sopenharmony_ci if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) && 493162306a36Sopenharmony_ci (flags & RENAME_EXCHANGE)) 493262306a36Sopenharmony_ci goto put_names; 493362306a36Sopenharmony_ci 493462306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) 493562306a36Sopenharmony_ci target_flags = 0; 493662306a36Sopenharmony_ci 493762306a36Sopenharmony_ciretry: 493862306a36Sopenharmony_ci error = filename_parentat(olddfd, from, lookup_flags, &old_path, 493962306a36Sopenharmony_ci &old_last, &old_type); 494062306a36Sopenharmony_ci if (error) 494162306a36Sopenharmony_ci goto put_names; 494262306a36Sopenharmony_ci 494362306a36Sopenharmony_ci error = filename_parentat(newdfd, to, lookup_flags, &new_path, &new_last, 494462306a36Sopenharmony_ci &new_type); 494562306a36Sopenharmony_ci if (error) 494662306a36Sopenharmony_ci goto exit1; 494762306a36Sopenharmony_ci 494862306a36Sopenharmony_ci error = -EXDEV; 494962306a36Sopenharmony_ci if (old_path.mnt != new_path.mnt) 495062306a36Sopenharmony_ci goto exit2; 495162306a36Sopenharmony_ci 495262306a36Sopenharmony_ci error = -EBUSY; 495362306a36Sopenharmony_ci if (old_type != LAST_NORM) 495462306a36Sopenharmony_ci goto exit2; 495562306a36Sopenharmony_ci 495662306a36Sopenharmony_ci if (flags & RENAME_NOREPLACE) 495762306a36Sopenharmony_ci error = -EEXIST; 495862306a36Sopenharmony_ci if (new_type != LAST_NORM) 495962306a36Sopenharmony_ci goto exit2; 496062306a36Sopenharmony_ci 496162306a36Sopenharmony_ci error = mnt_want_write(old_path.mnt); 496262306a36Sopenharmony_ci if (error) 496362306a36Sopenharmony_ci goto exit2; 496462306a36Sopenharmony_ci 496562306a36Sopenharmony_ciretry_deleg: 496662306a36Sopenharmony_ci trap = lock_rename(new_path.dentry, old_path.dentry); 496762306a36Sopenharmony_ci 496862306a36Sopenharmony_ci old_dentry = lookup_one_qstr_excl(&old_last, old_path.dentry, 496962306a36Sopenharmony_ci lookup_flags); 497062306a36Sopenharmony_ci error = PTR_ERR(old_dentry); 497162306a36Sopenharmony_ci if (IS_ERR(old_dentry)) 497262306a36Sopenharmony_ci goto exit3; 497362306a36Sopenharmony_ci /* source must exist */ 497462306a36Sopenharmony_ci error = -ENOENT; 497562306a36Sopenharmony_ci if (d_is_negative(old_dentry)) 497662306a36Sopenharmony_ci goto exit4; 497762306a36Sopenharmony_ci new_dentry = lookup_one_qstr_excl(&new_last, new_path.dentry, 497862306a36Sopenharmony_ci lookup_flags | target_flags); 497962306a36Sopenharmony_ci error = PTR_ERR(new_dentry); 498062306a36Sopenharmony_ci if (IS_ERR(new_dentry)) 498162306a36Sopenharmony_ci goto exit4; 498262306a36Sopenharmony_ci error = -EEXIST; 498362306a36Sopenharmony_ci if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) 498462306a36Sopenharmony_ci goto exit5; 498562306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) { 498662306a36Sopenharmony_ci error = -ENOENT; 498762306a36Sopenharmony_ci if (d_is_negative(new_dentry)) 498862306a36Sopenharmony_ci goto exit5; 498962306a36Sopenharmony_ci 499062306a36Sopenharmony_ci if (!d_is_dir(new_dentry)) { 499162306a36Sopenharmony_ci error = -ENOTDIR; 499262306a36Sopenharmony_ci if (new_last.name[new_last.len]) 499362306a36Sopenharmony_ci goto exit5; 499462306a36Sopenharmony_ci } 499562306a36Sopenharmony_ci } 499662306a36Sopenharmony_ci /* unless the source is a directory trailing slashes give -ENOTDIR */ 499762306a36Sopenharmony_ci if (!d_is_dir(old_dentry)) { 499862306a36Sopenharmony_ci error = -ENOTDIR; 499962306a36Sopenharmony_ci if (old_last.name[old_last.len]) 500062306a36Sopenharmony_ci goto exit5; 500162306a36Sopenharmony_ci if (!(flags & RENAME_EXCHANGE) && new_last.name[new_last.len]) 500262306a36Sopenharmony_ci goto exit5; 500362306a36Sopenharmony_ci } 500462306a36Sopenharmony_ci /* source should not be ancestor of target */ 500562306a36Sopenharmony_ci error = -EINVAL; 500662306a36Sopenharmony_ci if (old_dentry == trap) 500762306a36Sopenharmony_ci goto exit5; 500862306a36Sopenharmony_ci /* target should not be an ancestor of source */ 500962306a36Sopenharmony_ci if (!(flags & RENAME_EXCHANGE)) 501062306a36Sopenharmony_ci error = -ENOTEMPTY; 501162306a36Sopenharmony_ci if (new_dentry == trap) 501262306a36Sopenharmony_ci goto exit5; 501362306a36Sopenharmony_ci 501462306a36Sopenharmony_ci error = security_path_rename(&old_path, old_dentry, 501562306a36Sopenharmony_ci &new_path, new_dentry, flags); 501662306a36Sopenharmony_ci if (error) 501762306a36Sopenharmony_ci goto exit5; 501862306a36Sopenharmony_ci 501962306a36Sopenharmony_ci rd.old_dir = old_path.dentry->d_inode; 502062306a36Sopenharmony_ci rd.old_dentry = old_dentry; 502162306a36Sopenharmony_ci rd.old_mnt_idmap = mnt_idmap(old_path.mnt); 502262306a36Sopenharmony_ci rd.new_dir = new_path.dentry->d_inode; 502362306a36Sopenharmony_ci rd.new_dentry = new_dentry; 502462306a36Sopenharmony_ci rd.new_mnt_idmap = mnt_idmap(new_path.mnt); 502562306a36Sopenharmony_ci rd.delegated_inode = &delegated_inode; 502662306a36Sopenharmony_ci rd.flags = flags; 502762306a36Sopenharmony_ci error = vfs_rename(&rd); 502862306a36Sopenharmony_ciexit5: 502962306a36Sopenharmony_ci dput(new_dentry); 503062306a36Sopenharmony_ciexit4: 503162306a36Sopenharmony_ci dput(old_dentry); 503262306a36Sopenharmony_ciexit3: 503362306a36Sopenharmony_ci unlock_rename(new_path.dentry, old_path.dentry); 503462306a36Sopenharmony_ci if (delegated_inode) { 503562306a36Sopenharmony_ci error = break_deleg_wait(&delegated_inode); 503662306a36Sopenharmony_ci if (!error) 503762306a36Sopenharmony_ci goto retry_deleg; 503862306a36Sopenharmony_ci } 503962306a36Sopenharmony_ci mnt_drop_write(old_path.mnt); 504062306a36Sopenharmony_ciexit2: 504162306a36Sopenharmony_ci if (retry_estale(error, lookup_flags)) 504262306a36Sopenharmony_ci should_retry = true; 504362306a36Sopenharmony_ci path_put(&new_path); 504462306a36Sopenharmony_ciexit1: 504562306a36Sopenharmony_ci path_put(&old_path); 504662306a36Sopenharmony_ci if (should_retry) { 504762306a36Sopenharmony_ci should_retry = false; 504862306a36Sopenharmony_ci lookup_flags |= LOOKUP_REVAL; 504962306a36Sopenharmony_ci goto retry; 505062306a36Sopenharmony_ci } 505162306a36Sopenharmony_ciput_names: 505262306a36Sopenharmony_ci putname(from); 505362306a36Sopenharmony_ci putname(to); 505462306a36Sopenharmony_ci return error; 505562306a36Sopenharmony_ci} 505662306a36Sopenharmony_ci 505762306a36Sopenharmony_ciSYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, 505862306a36Sopenharmony_ci int, newdfd, const char __user *, newname, unsigned int, flags) 505962306a36Sopenharmony_ci{ 506062306a36Sopenharmony_ci return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname), 506162306a36Sopenharmony_ci flags); 506262306a36Sopenharmony_ci} 506362306a36Sopenharmony_ci 506462306a36Sopenharmony_ciSYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, 506562306a36Sopenharmony_ci int, newdfd, const char __user *, newname) 506662306a36Sopenharmony_ci{ 506762306a36Sopenharmony_ci return do_renameat2(olddfd, getname(oldname), newdfd, getname(newname), 506862306a36Sopenharmony_ci 0); 506962306a36Sopenharmony_ci} 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ciSYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname) 507262306a36Sopenharmony_ci{ 507362306a36Sopenharmony_ci return do_renameat2(AT_FDCWD, getname(oldname), AT_FDCWD, 507462306a36Sopenharmony_ci getname(newname), 0); 507562306a36Sopenharmony_ci} 507662306a36Sopenharmony_ci 507762306a36Sopenharmony_ciint readlink_copy(char __user *buffer, int buflen, const char *link) 507862306a36Sopenharmony_ci{ 507962306a36Sopenharmony_ci int len = PTR_ERR(link); 508062306a36Sopenharmony_ci if (IS_ERR(link)) 508162306a36Sopenharmony_ci goto out; 508262306a36Sopenharmony_ci 508362306a36Sopenharmony_ci len = strlen(link); 508462306a36Sopenharmony_ci if (len > (unsigned) buflen) 508562306a36Sopenharmony_ci len = buflen; 508662306a36Sopenharmony_ci if (copy_to_user(buffer, link, len)) 508762306a36Sopenharmony_ci len = -EFAULT; 508862306a36Sopenharmony_ciout: 508962306a36Sopenharmony_ci return len; 509062306a36Sopenharmony_ci} 509162306a36Sopenharmony_ci 509262306a36Sopenharmony_ci/** 509362306a36Sopenharmony_ci * vfs_readlink - copy symlink body into userspace buffer 509462306a36Sopenharmony_ci * @dentry: dentry on which to get symbolic link 509562306a36Sopenharmony_ci * @buffer: user memory pointer 509662306a36Sopenharmony_ci * @buflen: size of buffer 509762306a36Sopenharmony_ci * 509862306a36Sopenharmony_ci * Does not touch atime. That's up to the caller if necessary 509962306a36Sopenharmony_ci * 510062306a36Sopenharmony_ci * Does not call security hook. 510162306a36Sopenharmony_ci */ 510262306a36Sopenharmony_ciint vfs_readlink(struct dentry *dentry, char __user *buffer, int buflen) 510362306a36Sopenharmony_ci{ 510462306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 510562306a36Sopenharmony_ci DEFINE_DELAYED_CALL(done); 510662306a36Sopenharmony_ci const char *link; 510762306a36Sopenharmony_ci int res; 510862306a36Sopenharmony_ci 510962306a36Sopenharmony_ci if (unlikely(!(inode->i_opflags & IOP_DEFAULT_READLINK))) { 511062306a36Sopenharmony_ci if (unlikely(inode->i_op->readlink)) 511162306a36Sopenharmony_ci return inode->i_op->readlink(dentry, buffer, buflen); 511262306a36Sopenharmony_ci 511362306a36Sopenharmony_ci if (!d_is_symlink(dentry)) 511462306a36Sopenharmony_ci return -EINVAL; 511562306a36Sopenharmony_ci 511662306a36Sopenharmony_ci spin_lock(&inode->i_lock); 511762306a36Sopenharmony_ci inode->i_opflags |= IOP_DEFAULT_READLINK; 511862306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 511962306a36Sopenharmony_ci } 512062306a36Sopenharmony_ci 512162306a36Sopenharmony_ci link = READ_ONCE(inode->i_link); 512262306a36Sopenharmony_ci if (!link) { 512362306a36Sopenharmony_ci link = inode->i_op->get_link(dentry, inode, &done); 512462306a36Sopenharmony_ci if (IS_ERR(link)) 512562306a36Sopenharmony_ci return PTR_ERR(link); 512662306a36Sopenharmony_ci } 512762306a36Sopenharmony_ci res = readlink_copy(buffer, buflen, link); 512862306a36Sopenharmony_ci do_delayed_call(&done); 512962306a36Sopenharmony_ci return res; 513062306a36Sopenharmony_ci} 513162306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_readlink); 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci/** 513462306a36Sopenharmony_ci * vfs_get_link - get symlink body 513562306a36Sopenharmony_ci * @dentry: dentry on which to get symbolic link 513662306a36Sopenharmony_ci * @done: caller needs to free returned data with this 513762306a36Sopenharmony_ci * 513862306a36Sopenharmony_ci * Calls security hook and i_op->get_link() on the supplied inode. 513962306a36Sopenharmony_ci * 514062306a36Sopenharmony_ci * It does not touch atime. That's up to the caller if necessary. 514162306a36Sopenharmony_ci * 514262306a36Sopenharmony_ci * Does not work on "special" symlinks like /proc/$$/fd/N 514362306a36Sopenharmony_ci */ 514462306a36Sopenharmony_ciconst char *vfs_get_link(struct dentry *dentry, struct delayed_call *done) 514562306a36Sopenharmony_ci{ 514662306a36Sopenharmony_ci const char *res = ERR_PTR(-EINVAL); 514762306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 514862306a36Sopenharmony_ci 514962306a36Sopenharmony_ci if (d_is_symlink(dentry)) { 515062306a36Sopenharmony_ci res = ERR_PTR(security_inode_readlink(dentry)); 515162306a36Sopenharmony_ci if (!res) 515262306a36Sopenharmony_ci res = inode->i_op->get_link(dentry, inode, done); 515362306a36Sopenharmony_ci } 515462306a36Sopenharmony_ci return res; 515562306a36Sopenharmony_ci} 515662306a36Sopenharmony_ciEXPORT_SYMBOL(vfs_get_link); 515762306a36Sopenharmony_ci 515862306a36Sopenharmony_ci/* get the link contents into pagecache */ 515962306a36Sopenharmony_ciconst char *page_get_link(struct dentry *dentry, struct inode *inode, 516062306a36Sopenharmony_ci struct delayed_call *callback) 516162306a36Sopenharmony_ci{ 516262306a36Sopenharmony_ci char *kaddr; 516362306a36Sopenharmony_ci struct page *page; 516462306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci if (!dentry) { 516762306a36Sopenharmony_ci page = find_get_page(mapping, 0); 516862306a36Sopenharmony_ci if (!page) 516962306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 517062306a36Sopenharmony_ci if (!PageUptodate(page)) { 517162306a36Sopenharmony_ci put_page(page); 517262306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 517362306a36Sopenharmony_ci } 517462306a36Sopenharmony_ci } else { 517562306a36Sopenharmony_ci page = read_mapping_page(mapping, 0, NULL); 517662306a36Sopenharmony_ci if (IS_ERR(page)) 517762306a36Sopenharmony_ci return (char*)page; 517862306a36Sopenharmony_ci } 517962306a36Sopenharmony_ci set_delayed_call(callback, page_put_link, page); 518062306a36Sopenharmony_ci BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); 518162306a36Sopenharmony_ci kaddr = page_address(page); 518262306a36Sopenharmony_ci nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1); 518362306a36Sopenharmony_ci return kaddr; 518462306a36Sopenharmony_ci} 518562306a36Sopenharmony_ci 518662306a36Sopenharmony_ciEXPORT_SYMBOL(page_get_link); 518762306a36Sopenharmony_ci 518862306a36Sopenharmony_civoid page_put_link(void *arg) 518962306a36Sopenharmony_ci{ 519062306a36Sopenharmony_ci put_page(arg); 519162306a36Sopenharmony_ci} 519262306a36Sopenharmony_ciEXPORT_SYMBOL(page_put_link); 519362306a36Sopenharmony_ci 519462306a36Sopenharmony_ciint page_readlink(struct dentry *dentry, char __user *buffer, int buflen) 519562306a36Sopenharmony_ci{ 519662306a36Sopenharmony_ci DEFINE_DELAYED_CALL(done); 519762306a36Sopenharmony_ci int res = readlink_copy(buffer, buflen, 519862306a36Sopenharmony_ci page_get_link(dentry, d_inode(dentry), 519962306a36Sopenharmony_ci &done)); 520062306a36Sopenharmony_ci do_delayed_call(&done); 520162306a36Sopenharmony_ci return res; 520262306a36Sopenharmony_ci} 520362306a36Sopenharmony_ciEXPORT_SYMBOL(page_readlink); 520462306a36Sopenharmony_ci 520562306a36Sopenharmony_ciint page_symlink(struct inode *inode, const char *symname, int len) 520662306a36Sopenharmony_ci{ 520762306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 520862306a36Sopenharmony_ci const struct address_space_operations *aops = mapping->a_ops; 520962306a36Sopenharmony_ci bool nofs = !mapping_gfp_constraint(mapping, __GFP_FS); 521062306a36Sopenharmony_ci struct page *page; 521162306a36Sopenharmony_ci void *fsdata = NULL; 521262306a36Sopenharmony_ci int err; 521362306a36Sopenharmony_ci unsigned int flags; 521462306a36Sopenharmony_ci 521562306a36Sopenharmony_ciretry: 521662306a36Sopenharmony_ci if (nofs) 521762306a36Sopenharmony_ci flags = memalloc_nofs_save(); 521862306a36Sopenharmony_ci err = aops->write_begin(NULL, mapping, 0, len-1, &page, &fsdata); 521962306a36Sopenharmony_ci if (nofs) 522062306a36Sopenharmony_ci memalloc_nofs_restore(flags); 522162306a36Sopenharmony_ci if (err) 522262306a36Sopenharmony_ci goto fail; 522362306a36Sopenharmony_ci 522462306a36Sopenharmony_ci memcpy(page_address(page), symname, len-1); 522562306a36Sopenharmony_ci 522662306a36Sopenharmony_ci err = aops->write_end(NULL, mapping, 0, len-1, len-1, 522762306a36Sopenharmony_ci page, fsdata); 522862306a36Sopenharmony_ci if (err < 0) 522962306a36Sopenharmony_ci goto fail; 523062306a36Sopenharmony_ci if (err < len-1) 523162306a36Sopenharmony_ci goto retry; 523262306a36Sopenharmony_ci 523362306a36Sopenharmony_ci mark_inode_dirty(inode); 523462306a36Sopenharmony_ci return 0; 523562306a36Sopenharmony_cifail: 523662306a36Sopenharmony_ci return err; 523762306a36Sopenharmony_ci} 523862306a36Sopenharmony_ciEXPORT_SYMBOL(page_symlink); 523962306a36Sopenharmony_ci 524062306a36Sopenharmony_ciconst struct inode_operations page_symlink_inode_operations = { 524162306a36Sopenharmony_ci .get_link = page_get_link, 524262306a36Sopenharmony_ci}; 524362306a36Sopenharmony_ciEXPORT_SYMBOL(page_symlink_inode_operations); 5244