VFS: rename lookup_one_len family to lookup_noperm and remove permission check
The lookup_one_len family of functions is (now) only used internally by a filesystem on itself either - in a context where permission checking is irrelevant such as by a virtual filesystem populating itself, or xfs accessing its ORPHANAGE or dquota accessing the quota file; or - in a context where a permission check (MAY_EXEC on the parent) has just been performed such as a network filesystem finding in "silly-rename" file in the same directory. This is also the context after the _parentat() functions where currently lookup_one_qstr_excl() is used. So the permission check is pointless. The name "one_len" is unhelpful in understanding the purpose of these functions and should be changed. Most of the callers pass the len as "strlen()" so using a qstr and QSTR() can simplify the code. This patch renames these functions (include lookup_positive_unlocked() which is part of the family despite the name) to have a name based on "lookup_noperm". They are changed to receive a 'struct qstr' instead of separate name and len. In a few cases the use of QSTR() results in a new call to strlen(). try_lookup_noperm() takes a pointer to a qstr instead of the whole qstr. This is consistent with d_hash_and_lookup() (which is nearly identical) and useful for lookup_noperm_unlocked(). The new lookup_noperm_common() doesn't take a qstr yet. That will be tidied up in a subsequent patch. Signed-off-by: NeilBrown <neil@brown.name> Link: https://lore.kernel.org/r/20250319031545.2999807-5-neil@brown.name Signed-off-by: Christian Brauner <brauner@kernel.org>pull/1250/head
parent
2011067c64
commit
fa6fe07d15
|
|
@ -1212,3 +1212,23 @@ lookup_one(), lookup_one_unlocked(), lookup_one_positive_unlocked() now
|
||||||
take a qstr instead of a name and len. These, not the "one_len"
|
take a qstr instead of a name and len. These, not the "one_len"
|
||||||
versions, should be used whenever accessing a filesystem from outside
|
versions, should be used whenever accessing a filesystem from outside
|
||||||
that filesysmtem, through a mount point - which will have a mnt_idmap.
|
that filesysmtem, through a mount point - which will have a mnt_idmap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
** mandatory**
|
||||||
|
|
||||||
|
Functions try_lookup_one_len(), lookup_one_len(),
|
||||||
|
lookup_one_len_unlocked() and lookup_positive_unlocked() have been
|
||||||
|
renamed to try_lookup_noperm(), lookup_noperm(),
|
||||||
|
lookup_noperm_unlocked(), lookup_noperm_positive_unlocked(). They now
|
||||||
|
take a qstr instead of separate name and length. QSTR() can be used
|
||||||
|
when strlen() is needed for the length.
|
||||||
|
|
||||||
|
For try_lookup_noperm() a reference to the qstr is passed in case the
|
||||||
|
hash might subsequently be needed.
|
||||||
|
|
||||||
|
These function no longer do any permission checking - they previously
|
||||||
|
checked that the caller has 'X' permission on the parent. They must
|
||||||
|
ONLY be used internally by a filesystem on itself when it knows that
|
||||||
|
permissions are irrelevant or in a context where permission checks have
|
||||||
|
already been performed such as after vfs_path_parent_lookup()
|
||||||
|
|
|
||||||
|
|
@ -342,7 +342,7 @@ static struct dentry *hypfs_create_file(struct dentry *parent, const char *name,
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
|
||||||
inode_lock(d_inode(parent));
|
inode_lock(d_inode(parent));
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
dentry = ERR_PTR(-ENOMEM);
|
dentry = ERR_PTR(-ENOMEM);
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ static int binderfs_binder_device_create(struct inode *ref_inode,
|
||||||
inode_lock(d_inode(root));
|
inode_lock(d_inode(root));
|
||||||
|
|
||||||
/* look it up */
|
/* look it up */
|
||||||
dentry = lookup_one_len(name, root, name_len);
|
dentry = lookup_noperm(&QSTR(name), root);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
inode_unlock(d_inode(root));
|
inode_unlock(d_inode(root));
|
||||||
ret = PTR_ERR(dentry);
|
ret = PTR_ERR(dentry);
|
||||||
|
|
@ -487,7 +487,7 @@ static struct dentry *binderfs_create_dentry(struct dentry *parent,
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
return dentry;
|
return dentry;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ static int create_file(const char *name, umode_t mode,
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
inode_lock(d_inode(parent));
|
inode_lock(d_inode(parent));
|
||||||
*dentry = lookup_one_len(name, parent, strlen(name));
|
*dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (!IS_ERR(*dentry))
|
if (!IS_ERR(*dentry))
|
||||||
error = qibfs_mknod(d_inode(parent), *dentry,
|
error = qibfs_mknod(d_inode(parent), *dentry,
|
||||||
mode, fops, data);
|
mode, fops, data);
|
||||||
|
|
@ -433,7 +433,7 @@ static int remove_device_files(struct super_block *sb,
|
||||||
char unit[10];
|
char unit[10];
|
||||||
|
|
||||||
snprintf(unit, sizeof(unit), "%u", dd->unit);
|
snprintf(unit, sizeof(unit), "%u", dd->unit);
|
||||||
dir = lookup_one_len_unlocked(unit, sb->s_root, strlen(unit));
|
dir = lookup_noperm_unlocked(&QSTR(unit), sb->s_root);
|
||||||
|
|
||||||
if (IS_ERR(dir)) {
|
if (IS_ERR(dir)) {
|
||||||
pr_err("Lookup of %s failed\n", unit);
|
pr_err("Lookup of %s failed\n", unit);
|
||||||
|
|
|
||||||
|
|
@ -943,7 +943,7 @@ static struct dentry *afs_lookup_atsys(struct inode *dir, struct dentry *dentry)
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(p, name);
|
strcpy(p, name);
|
||||||
ret = lookup_one_len(buf, dentry->d_parent, len);
|
ret = lookup_noperm(&QSTR(buf), dentry->d_parent);
|
||||||
if (IS_ERR(ret) || d_is_positive(ret))
|
if (IS_ERR(ret) || d_is_positive(ret))
|
||||||
goto out_s;
|
goto out_s;
|
||||||
dput(ret);
|
dput(ret);
|
||||||
|
|
|
||||||
|
|
@ -113,16 +113,14 @@ int afs_sillyrename(struct afs_vnode *dvnode, struct afs_vnode *vnode,
|
||||||
|
|
||||||
sdentry = NULL;
|
sdentry = NULL;
|
||||||
do {
|
do {
|
||||||
int slen;
|
|
||||||
|
|
||||||
dput(sdentry);
|
dput(sdentry);
|
||||||
sillycounter++;
|
sillycounter++;
|
||||||
|
|
||||||
/* Create a silly name. Note that the ".__afs" prefix is
|
/* Create a silly name. Note that the ".__afs" prefix is
|
||||||
* understood by the salvager and must not be changed.
|
* understood by the salvager and must not be changed.
|
||||||
*/
|
*/
|
||||||
slen = scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
|
scnprintf(silly, sizeof(silly), ".__afs%04X", sillycounter);
|
||||||
sdentry = lookup_one_len(silly, dentry->d_parent, slen);
|
sdentry = lookup_noperm(&QSTR(silly), dentry->d_parent);
|
||||||
|
|
||||||
/* N.B. Better to return EBUSY here ... it could be dangerous
|
/* N.B. Better to return EBUSY here ... it could be dangerous
|
||||||
* to delete the file while it's in use.
|
* to delete the file while it's in use.
|
||||||
|
|
|
||||||
|
|
@ -459,7 +459,8 @@ static int autofs_dev_ioctl_timeout(struct file *fp,
|
||||||
"the parent autofs mount timeout which could "
|
"the parent autofs mount timeout which could "
|
||||||
"prevent shutdown\n");
|
"prevent shutdown\n");
|
||||||
|
|
||||||
dentry = try_lookup_one_len(param->path, base, path_len);
|
dentry = try_lookup_noperm(&QSTR_LEN(param->path, path_len),
|
||||||
|
base);
|
||||||
if (IS_ERR_OR_NULL(dentry))
|
if (IS_ERR_OR_NULL(dentry))
|
||||||
return dentry ? PTR_ERR(dentry) : -ENOENT;
|
return dentry ? PTR_ERR(dentry) : -ENOENT;
|
||||||
ino = autofs_dentry_ino(dentry);
|
ino = autofs_dentry_ino(dentry);
|
||||||
|
|
|
||||||
|
|
@ -842,7 +842,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
inode_lock(d_inode(root));
|
inode_lock(d_inode(root));
|
||||||
dentry = lookup_one_len(e->name, root, strlen(e->name));
|
dentry = lookup_noperm(&QSTR(e->name), root);
|
||||||
err = PTR_ERR(dentry);
|
err = PTR_ERR(dentry);
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -346,7 +346,7 @@ struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
|
||||||
if (!parent)
|
if (!parent)
|
||||||
parent = debugfs_mount->mnt_root;
|
parent = debugfs_mount->mnt_root;
|
||||||
|
|
||||||
dentry = lookup_positive_unlocked(name, parent, strlen(name));
|
dentry = lookup_noperm_positive_unlocked(&QSTR(name), parent);
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
return NULL;
|
return NULL;
|
||||||
return dentry;
|
return dentry;
|
||||||
|
|
@ -388,7 +388,7 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
|
||||||
if (unlikely(IS_DEADDIR(d_inode(parent))))
|
if (unlikely(IS_DEADDIR(d_inode(parent))))
|
||||||
dentry = ERR_PTR(-ENOENT);
|
dentry = ERR_PTR(-ENOENT);
|
||||||
else
|
else
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
|
if (!IS_ERR(dentry) && d_really_is_positive(dentry)) {
|
||||||
if (d_is_dir(dentry))
|
if (d_is_dir(dentry))
|
||||||
pr_err("Directory '%s' with parent '%s' already present!\n",
|
pr_err("Directory '%s' with parent '%s' already present!\n",
|
||||||
|
|
@ -872,7 +872,7 @@ int __printf(2, 3) debugfs_change_name(struct dentry *dentry, const char *fmt, .
|
||||||
}
|
}
|
||||||
if (strcmp(old_name.name.name, new_name) == 0)
|
if (strcmp(old_name.name.name, new_name) == 0)
|
||||||
goto out;
|
goto out;
|
||||||
target = lookup_one_len(new_name, parent, strlen(new_name));
|
target = lookup_noperm(&QSTR(new_name), parent);
|
||||||
if (IS_ERR(target)) {
|
if (IS_ERR(target)) {
|
||||||
error = PTR_ERR(target);
|
error = PTR_ERR(target);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -394,8 +394,8 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
|
||||||
char *encrypted_and_encoded_name = NULL;
|
char *encrypted_and_encoded_name = NULL;
|
||||||
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
|
struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
|
||||||
struct dentry *lower_dir_dentry, *lower_dentry;
|
struct dentry *lower_dir_dentry, *lower_dentry;
|
||||||
const char *name = ecryptfs_dentry->d_name.name;
|
struct qstr qname = QSTR_INIT(ecryptfs_dentry->d_name.name,
|
||||||
size_t len = ecryptfs_dentry->d_name.len;
|
ecryptfs_dentry->d_name.len);
|
||||||
struct dentry *res;
|
struct dentry *res;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
|
@ -404,23 +404,25 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
|
||||||
mount_crypt_stat = &ecryptfs_superblock_to_private(
|
mount_crypt_stat = &ecryptfs_superblock_to_private(
|
||||||
ecryptfs_dentry->d_sb)->mount_crypt_stat;
|
ecryptfs_dentry->d_sb)->mount_crypt_stat;
|
||||||
if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
|
if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {
|
||||||
|
size_t len = qname.len;
|
||||||
rc = ecryptfs_encrypt_and_encode_filename(
|
rc = ecryptfs_encrypt_and_encode_filename(
|
||||||
&encrypted_and_encoded_name, &len,
|
&encrypted_and_encoded_name, &len,
|
||||||
mount_crypt_stat, name, len);
|
mount_crypt_stat, qname.name, len);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "%s: Error attempting to encrypt and encode "
|
printk(KERN_ERR "%s: Error attempting to encrypt and encode "
|
||||||
"filename; rc = [%d]\n", __func__, rc);
|
"filename; rc = [%d]\n", __func__, rc);
|
||||||
return ERR_PTR(rc);
|
return ERR_PTR(rc);
|
||||||
}
|
}
|
||||||
name = encrypted_and_encoded_name;
|
qname.name = encrypted_and_encoded_name;
|
||||||
|
qname.len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
lower_dentry = lookup_one_len_unlocked(name, lower_dir_dentry, len);
|
lower_dentry = lookup_noperm_unlocked(&qname, lower_dir_dentry);
|
||||||
if (IS_ERR(lower_dentry)) {
|
if (IS_ERR(lower_dentry)) {
|
||||||
ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned "
|
ecryptfs_printk(KERN_DEBUG, "%s: lookup_noperm() returned "
|
||||||
"[%ld] on lower_dentry = [%s]\n", __func__,
|
"[%ld] on lower_dentry = [%s]\n", __func__,
|
||||||
PTR_ERR(lower_dentry),
|
PTR_ERR(lower_dentry),
|
||||||
name);
|
qname.name);
|
||||||
res = ERR_CAST(lower_dentry);
|
res = ERR_CAST(lower_dentry);
|
||||||
} else {
|
} else {
|
||||||
res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry);
|
res = ecryptfs_lookup_interpose(ecryptfs_dentry, lower_dentry);
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
}
|
}
|
||||||
dtmp = lookup_positive_unlocked(name, dentry, strlen(name));
|
dtmp = lookup_noperm_positive_unlocked(&QSTR(name), dentry);
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
kfree(name);
|
kfree(name);
|
||||||
if (IS_ERR(dtmp))
|
if (IS_ERR(dtmp))
|
||||||
|
|
|
||||||
87
fs/namei.c
87
fs/namei.c
|
|
@ -2834,9 +2834,9 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vfs_path_lookup);
|
EXPORT_SYMBOL(vfs_path_lookup);
|
||||||
|
|
||||||
static int lookup_one_common(struct mnt_idmap *idmap,
|
static int lookup_noperm_common(const char *name, struct dentry *base,
|
||||||
const char *name, struct dentry *base, int len,
|
int len,
|
||||||
struct qstr *this)
|
struct qstr *this)
|
||||||
{
|
{
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->len = len;
|
this->len = len;
|
||||||
|
|
@ -2861,50 +2861,58 @@ static int lookup_one_common(struct mnt_idmap *idmap,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int lookup_one_common(struct mnt_idmap *idmap,
|
||||||
|
const char *name, struct dentry *base, int len,
|
||||||
|
struct qstr *this) {
|
||||||
|
int err;
|
||||||
|
err = lookup_noperm_common(name, base, len, this);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
return inode_permission(idmap, base->d_inode, MAY_EXEC);
|
return inode_permission(idmap, base->d_inode, MAY_EXEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* try_lookup_one_len - filesystem helper to lookup single pathname component
|
* try_lookup_noperm - filesystem helper to lookup single pathname component
|
||||||
* @name: pathname component to lookup
|
* @name: qstr storing pathname component to lookup
|
||||||
* @base: base directory to lookup from
|
* @base: base directory to lookup from
|
||||||
* @len: maximum length @len should be interpreted to
|
|
||||||
*
|
*
|
||||||
* Look up a dentry by name in the dcache, returning NULL if it does not
|
* Look up a dentry by name in the dcache, returning NULL if it does not
|
||||||
* currently exist. The function does not try to create a dentry.
|
* currently exist. The function does not try to create a dentry.
|
||||||
*
|
*
|
||||||
* Note that this routine is purely a helper for filesystem usage and should
|
* Note that this routine is purely a helper for filesystem usage and should
|
||||||
* not be called by generic code.
|
* not be called by generic code. It does no permission checking.
|
||||||
*
|
*
|
||||||
* No locks need be held - only a counted reference to @base is needed.
|
* No locks need be held - only a counted reference to @base is needed.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct dentry *try_lookup_one_len(const char *name, struct dentry *base, int len)
|
struct dentry *try_lookup_noperm(struct qstr *name, struct dentry *base)
|
||||||
{
|
{
|
||||||
struct qstr this;
|
struct qstr this;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = lookup_one_common(&nop_mnt_idmap, name, base, len, &this);
|
err = lookup_noperm_common(name->name, base, name->len, &this);
|
||||||
if (err)
|
if (err)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
return lookup_dcache(&this, base, 0);
|
name->hash = this.hash;
|
||||||
|
return lookup_dcache(name, base, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(try_lookup_one_len);
|
EXPORT_SYMBOL(try_lookup_noperm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lookup_one_len - filesystem helper to lookup single pathname component
|
* lookup_noperm - filesystem helper to lookup single pathname component
|
||||||
* @name: pathname component to lookup
|
* @name: qstr storing pathname component to lookup
|
||||||
* @base: base directory to lookup from
|
* @base: base directory to lookup from
|
||||||
* @len: maximum length @len should be interpreted to
|
|
||||||
*
|
*
|
||||||
* Note that this routine is purely a helper for filesystem usage and should
|
* Note that this routine is purely a helper for filesystem usage and should
|
||||||
* not be called by generic code.
|
* not be called by generic code. It does no permission checking.
|
||||||
*
|
*
|
||||||
* The caller must hold base->i_mutex.
|
* The caller must hold base->i_mutex.
|
||||||
*/
|
*/
|
||||||
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
struct dentry *lookup_noperm(struct qstr *name, struct dentry *base)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct qstr this;
|
struct qstr this;
|
||||||
|
|
@ -2912,14 +2920,14 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
||||||
|
|
||||||
WARN_ON_ONCE(!inode_is_locked(base->d_inode));
|
WARN_ON_ONCE(!inode_is_locked(base->d_inode));
|
||||||
|
|
||||||
err = lookup_one_common(&nop_mnt_idmap, name, base, len, &this);
|
err = lookup_noperm_common(name->name, base, name->len, &this);
|
||||||
if (err)
|
if (err)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
dentry = lookup_dcache(&this, base, 0);
|
dentry = lookup_dcache(&this, base, 0);
|
||||||
return dentry ? dentry : __lookup_slow(&this, base, 0);
|
return dentry ? dentry : __lookup_slow(&this, base, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(lookup_one_len);
|
EXPORT_SYMBOL(lookup_noperm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lookup_one - lookup single pathname component
|
* lookup_one - lookup single pathname component
|
||||||
|
|
@ -2957,7 +2965,7 @@ EXPORT_SYMBOL(lookup_one);
|
||||||
*
|
*
|
||||||
* This can be used for in-kernel filesystem clients such as file servers.
|
* This can be used for in-kernel filesystem clients such as file servers.
|
||||||
*
|
*
|
||||||
* Unlike lookup_one_len, it should be called without the parent
|
* Unlike lookup_one, it should be called without the parent
|
||||||
* i_rwsem held, and will take the i_rwsem itself if necessary.
|
* i_rwsem held, and will take the i_rwsem itself if necessary.
|
||||||
*/
|
*/
|
||||||
struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap,
|
struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap,
|
||||||
|
|
@ -3010,39 +3018,48 @@ struct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap,
|
||||||
EXPORT_SYMBOL(lookup_one_positive_unlocked);
|
EXPORT_SYMBOL(lookup_one_positive_unlocked);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* lookup_one_len_unlocked - filesystem helper to lookup single pathname component
|
* lookup_noperm_unlocked - filesystem helper to lookup single pathname component
|
||||||
* @name: pathname component to lookup
|
* @name: pathname component to lookup
|
||||||
* @base: base directory to lookup from
|
* @base: base directory to lookup from
|
||||||
* @len: maximum length @len should be interpreted to
|
|
||||||
*
|
*
|
||||||
* Note that this routine is purely a helper for filesystem usage and should
|
* Note that this routine is purely a helper for filesystem usage and should
|
||||||
* not be called by generic code.
|
* not be called by generic code. It does no permission checking.
|
||||||
*
|
*
|
||||||
* Unlike lookup_one_len, it should be called without the parent
|
* Unlike lookup_noperm, it should be called without the parent
|
||||||
* i_mutex held, and will take the i_mutex itself if necessary.
|
* i_rwsem held, and will take the i_rwsem itself if necessary.
|
||||||
*/
|
*/
|
||||||
struct dentry *lookup_one_len_unlocked(const char *name,
|
struct dentry *lookup_noperm_unlocked(struct qstr *name, struct dentry *base)
|
||||||
struct dentry *base, int len)
|
|
||||||
{
|
{
|
||||||
return lookup_one_unlocked(&nop_mnt_idmap, &QSTR_LEN(name, len), base);
|
struct dentry *ret;
|
||||||
|
|
||||||
|
ret = try_lookup_noperm(name, base);
|
||||||
|
if (!ret)
|
||||||
|
ret = lookup_slow(name, base, 0);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(lookup_one_len_unlocked);
|
EXPORT_SYMBOL(lookup_noperm_unlocked);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Like lookup_one_len_unlocked(), except that it yields ERR_PTR(-ENOENT)
|
* Like lookup_noperm_unlocked(), except that it yields ERR_PTR(-ENOENT)
|
||||||
* on negatives. Returns known positive or ERR_PTR(); that's what
|
* on negatives. Returns known positive or ERR_PTR(); that's what
|
||||||
* most of the users want. Note that pinned negative with unlocked parent
|
* most of the users want. Note that pinned negative with unlocked parent
|
||||||
* _can_ become positive at any time, so callers of lookup_one_len_unlocked()
|
* _can_ become positive at any time, so callers of lookup_noperm_unlocked()
|
||||||
* need to be very careful; pinned positives have ->d_inode stable, so
|
* need to be very careful; pinned positives have ->d_inode stable, so
|
||||||
* this one avoids such problems.
|
* this one avoids such problems.
|
||||||
*/
|
*/
|
||||||
struct dentry *lookup_positive_unlocked(const char *name,
|
struct dentry *lookup_noperm_positive_unlocked(struct qstr *name,
|
||||||
struct dentry *base, int len)
|
struct dentry *base)
|
||||||
{
|
{
|
||||||
return lookup_one_positive_unlocked(&nop_mnt_idmap,
|
struct dentry *ret;
|
||||||
&QSTR_LEN(name, len), base);
|
|
||||||
|
ret = lookup_noperm_unlocked(name, base);
|
||||||
|
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
|
||||||
|
dput(ret);
|
||||||
|
ret = ERR_PTR(-ENOENT);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(lookup_positive_unlocked);
|
EXPORT_SYMBOL(lookup_noperm_positive_unlocked);
|
||||||
|
|
||||||
#ifdef CONFIG_UNIX98_PTYS
|
#ifdef CONFIG_UNIX98_PTYS
|
||||||
int path_pts(struct path *path)
|
int path_pts(struct path *path)
|
||||||
|
|
|
||||||
|
|
@ -464,18 +464,17 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
|
||||||
|
|
||||||
sdentry = NULL;
|
sdentry = NULL;
|
||||||
do {
|
do {
|
||||||
int slen;
|
|
||||||
dput(sdentry);
|
dput(sdentry);
|
||||||
sillycounter++;
|
sillycounter++;
|
||||||
slen = scnprintf(silly, sizeof(silly),
|
scnprintf(silly, sizeof(silly),
|
||||||
SILLYNAME_PREFIX "%0*llx%0*x",
|
SILLYNAME_PREFIX "%0*llx%0*x",
|
||||||
SILLYNAME_FILEID_LEN, fileid,
|
SILLYNAME_FILEID_LEN, fileid,
|
||||||
SILLYNAME_COUNTER_LEN, sillycounter);
|
SILLYNAME_COUNTER_LEN, sillycounter);
|
||||||
|
|
||||||
dfprintk(VFS, "NFS: trying to rename %pd to %s\n",
|
dfprintk(VFS, "NFS: trying to rename %pd to %s\n",
|
||||||
dentry, silly);
|
dentry, silly);
|
||||||
|
|
||||||
sdentry = lookup_one_len(silly, dentry->d_parent, slen);
|
sdentry = lookup_noperm(&QSTR(silly), dentry->d_parent);
|
||||||
/*
|
/*
|
||||||
* N.B. Better to return EBUSY here ... it could be
|
* N.B. Better to return EBUSY here ... it could be
|
||||||
* dangerous to delete the file while it's in use.
|
* dangerous to delete the file while it's in use.
|
||||||
|
|
|
||||||
|
|
@ -385,11 +385,9 @@ static struct dentry *ovl_lookup_real_one(struct dentry *connected,
|
||||||
*/
|
*/
|
||||||
take_dentry_name_snapshot(&name, real);
|
take_dentry_name_snapshot(&name, real);
|
||||||
/*
|
/*
|
||||||
* No idmap handling here: it's an internal lookup. Could skip
|
* No idmap handling here: it's an internal lookup.
|
||||||
* permission checking altogether, but for now just use non-idmap
|
|
||||||
* transformed ids.
|
|
||||||
*/
|
*/
|
||||||
this = lookup_one_len(name.name.name, connected, name.name.len);
|
this = lookup_noperm(&name.name, connected);
|
||||||
release_dentry_name_snapshot(&name);
|
release_dentry_name_snapshot(&name);
|
||||||
err = PTR_ERR(this);
|
err = PTR_ERR(this);
|
||||||
if (IS_ERR(this)) {
|
if (IS_ERR(this)) {
|
||||||
|
|
|
||||||
|
|
@ -757,7 +757,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh)
|
||||||
if (err)
|
if (err)
|
||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
|
|
||||||
index = lookup_positive_unlocked(name.name, ofs->workdir, name.len);
|
index = lookup_noperm_positive_unlocked(&name, ofs->workdir);
|
||||||
kfree(name.name);
|
kfree(name.name);
|
||||||
if (IS_ERR(index)) {
|
if (IS_ERR(index)) {
|
||||||
if (PTR_ERR(index) == -ENOENT)
|
if (PTR_ERR(index) == -ENOENT)
|
||||||
|
|
|
||||||
|
|
@ -2560,7 +2560,7 @@ int dquot_quota_on_mount(struct super_block *sb, char *qf_name,
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
dentry = lookup_positive_unlocked(qf_name, sb->s_root, strlen(qf_name));
|
dentry = lookup_noperm_positive_unlocked(&QSTR(qf_name), sb->s_root);
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
return PTR_ERR(dentry);
|
return PTR_ERR(dentry);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,8 @@ path_to_dentry(struct cifs_sb_info *cifs_sb, const char *path)
|
||||||
while (*s && *s != sep)
|
while (*s && *s != sep)
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
child = lookup_positive_unlocked(p, dentry, s - p);
|
child = lookup_noperm_positive_unlocked(&QSTR_LEN(p, s - p),
|
||||||
|
dentry);
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
dentry = child;
|
dentry = child;
|
||||||
} while (!IS_ERR(dentry));
|
} while (!IS_ERR(dentry));
|
||||||
|
|
@ -207,7 +208,7 @@ replay_again:
|
||||||
spin_unlock(&cfids->cfid_list_lock);
|
spin_unlock(&cfids->cfid_list_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip any prefix paths in @path as lookup_positive_unlocked() ends up
|
* Skip any prefix paths in @path as lookup_noperm_positive_unlocked() ends up
|
||||||
* calling ->lookup() which already adds those through
|
* calling ->lookup() which already adds those through
|
||||||
* build_path_from_dentry(). Also, do it earlier as we might reconnect
|
* build_path_from_dentry(). Also, do it earlier as we might reconnect
|
||||||
* below when trying to send compounded request and then potentially
|
* below when trying to send compounded request and then potentially
|
||||||
|
|
|
||||||
|
|
@ -929,7 +929,8 @@ cifs_get_root(struct smb3_fs_context *ctx, struct super_block *sb)
|
||||||
while (*s && *s != sep)
|
while (*s && *s != sep)
|
||||||
s++;
|
s++;
|
||||||
|
|
||||||
child = lookup_positive_unlocked(p, dentry, s - p);
|
child = lookup_noperm_positive_unlocked(&QSTR_LEN(p, s - p),
|
||||||
|
dentry);
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
dentry = child;
|
dentry = child;
|
||||||
} while (!IS_ERR(dentry));
|
} while (!IS_ERR(dentry));
|
||||||
|
|
|
||||||
|
|
@ -555,7 +555,7 @@ struct dentry *tracefs_start_creating(const char *name, struct dentry *parent)
|
||||||
if (unlikely(IS_DEADDIR(d_inode(parent))))
|
if (unlikely(IS_DEADDIR(d_inode(parent))))
|
||||||
dentry = ERR_PTR(-ENOENT);
|
dentry = ERR_PTR(-ENOENT);
|
||||||
else
|
else
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (!IS_ERR(dentry) && d_inode(dentry)) {
|
if (!IS_ERR(dentry) && d_inode(dentry)) {
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
dentry = ERR_PTR(-EEXIST);
|
dentry = ERR_PTR(-EEXIST);
|
||||||
|
|
|
||||||
|
|
@ -153,8 +153,7 @@ xrep_orphanage_create(
|
||||||
|
|
||||||
/* Try to find the orphanage directory. */
|
/* Try to find the orphanage directory. */
|
||||||
inode_lock_nested(root_inode, I_MUTEX_PARENT);
|
inode_lock_nested(root_inode, I_MUTEX_PARENT);
|
||||||
orphanage_dentry = lookup_one_len(ORPHANAGE, root_dentry,
|
orphanage_dentry = lookup_noperm(&QSTR(ORPHANAGE), root_dentry);
|
||||||
strlen(ORPHANAGE));
|
|
||||||
if (IS_ERR(orphanage_dentry)) {
|
if (IS_ERR(orphanage_dentry)) {
|
||||||
error = PTR_ERR(orphanage_dentry);
|
error = PTR_ERR(orphanage_dentry);
|
||||||
goto out_unlock_root;
|
goto out_unlock_root;
|
||||||
|
|
|
||||||
|
|
@ -69,10 +69,10 @@ int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
|
||||||
int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
|
int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *,
|
||||||
unsigned int, struct path *);
|
unsigned int, struct path *);
|
||||||
|
|
||||||
extern struct dentry *try_lookup_one_len(const char *, struct dentry *, int);
|
extern struct dentry *try_lookup_noperm(struct qstr *, struct dentry *);
|
||||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
extern struct dentry *lookup_noperm(struct qstr *, struct dentry *);
|
||||||
extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
|
extern struct dentry *lookup_noperm_unlocked(struct qstr *, struct dentry *);
|
||||||
extern struct dentry *lookup_positive_unlocked(const char *, struct dentry *, int);
|
extern struct dentry *lookup_noperm_positive_unlocked(struct qstr *, struct dentry *);
|
||||||
struct dentry *lookup_one(struct mnt_idmap *, struct qstr *, struct dentry *);
|
struct dentry *lookup_one(struct mnt_idmap *, struct qstr *, struct dentry *);
|
||||||
struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap,
|
struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap,
|
||||||
struct qstr *name, struct dentry *base);
|
struct qstr *name, struct dentry *base);
|
||||||
|
|
|
||||||
|
|
@ -913,7 +913,7 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
|
||||||
|
|
||||||
ro = mnt_want_write(mnt); /* we'll drop it in any case */
|
ro = mnt_want_write(mnt); /* we'll drop it in any case */
|
||||||
inode_lock(d_inode(root));
|
inode_lock(d_inode(root));
|
||||||
path.dentry = lookup_one_len(name->name, root, strlen(name->name));
|
path.dentry = lookup_noperm(&QSTR(name->name), root);
|
||||||
if (IS_ERR(path.dentry)) {
|
if (IS_ERR(path.dentry)) {
|
||||||
error = PTR_ERR(path.dentry);
|
error = PTR_ERR(path.dentry);
|
||||||
goto out_putfd;
|
goto out_putfd;
|
||||||
|
|
@ -969,8 +969,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
|
||||||
if (err)
|
if (err)
|
||||||
goto out_name;
|
goto out_name;
|
||||||
inode_lock_nested(d_inode(mnt->mnt_root), I_MUTEX_PARENT);
|
inode_lock_nested(d_inode(mnt->mnt_root), I_MUTEX_PARENT);
|
||||||
dentry = lookup_one_len(name->name, mnt->mnt_root,
|
dentry = lookup_noperm(&QSTR(name->name), mnt->mnt_root);
|
||||||
strlen(name->name));
|
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
err = PTR_ERR(dentry);
|
err = PTR_ERR(dentry);
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
|
||||||
|
|
@ -421,7 +421,7 @@ static int bpf_iter_link_pin_kernel(struct dentry *parent,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
inode_lock(parent->d_inode);
|
inode_lock(parent->d_inode);
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
inode_unlock(parent->d_inode);
|
inode_unlock(parent->d_inode);
|
||||||
return PTR_ERR(dentry);
|
return PTR_ERR(dentry);
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ static struct dentry *aafs_create(const char *name, umode_t mode,
|
||||||
dir = d_inode(parent);
|
dir = d_inode(parent);
|
||||||
|
|
||||||
inode_lock(dir);
|
inode_lock(dir);
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
error = PTR_ERR(dentry);
|
error = PTR_ERR(dentry);
|
||||||
goto fail_lock;
|
goto fail_lock;
|
||||||
|
|
@ -2551,7 +2551,7 @@ static int aa_mk_null_file(struct dentry *parent)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
inode_lock(d_inode(parent));
|
inode_lock(d_inode(parent));
|
||||||
dentry = lookup_one_len(NULL_FILE_NAME, parent, strlen(NULL_FILE_NAME));
|
dentry = lookup_noperm(&QSTR(NULL_FILE_NAME), parent);
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
error = PTR_ERR(dentry);
|
error = PTR_ERR(dentry);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,7 @@ static struct dentry *securityfs_create_dentry(const char *name, umode_t mode,
|
||||||
dir = d_inode(parent);
|
dir = d_inode(parent);
|
||||||
|
|
||||||
inode_lock(dir);
|
inode_lock(dir);
|
||||||
dentry = lookup_one_len(name, parent, strlen(name));
|
dentry = lookup_noperm(&QSTR(name), parent);
|
||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue