mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-08-31 06:09:56 +00:00
Use try_lookup_noperm() instead of d_hash_and_lookup() outside of VFS
try_lookup_noperm() and d_hash_and_lookup() are nearly identical. The former does some validation of the name where the latter doesn't. Outside of the VFS that validation is likely valuable, and having only one exported function for this task is certainly a good idea. So make d_hash_and_lookup() local to VFS files and change all other callers to try_lookup_noperm(). Note that the arguments are swapped. Signed-off-by: NeilBrown <neilb@suse.de> Link: https://lore.kernel.org/r/20250319031545.2999807-6-neil@brown.name Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
fa6fe07d15
commit
06c567403a
@ -1232,3 +1232,14 @@ 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
|
ONLY be used internally by a filesystem on itself when it knows that
|
||||||
permissions are irrelevant or in a context where permission checks have
|
permissions are irrelevant or in a context where permission checks have
|
||||||
already been performed such as after vfs_path_parent_lookup()
|
already been performed such as after vfs_path_parent_lookup()
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
** mandatory**
|
||||||
|
|
||||||
|
d_hash_and_lookup() is no longer exported or available outside the VFS.
|
||||||
|
Use try_lookup_noperm() instead. This adds name validation and takes
|
||||||
|
arguments in the opposite order but is otherwise identical.
|
||||||
|
|
||||||
|
Using try_lookup_noperm() will require linux/namei.h to be included.
|
||||||
|
|
||||||
|
@ -2412,7 +2412,6 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name)
|
|||||||
}
|
}
|
||||||
return d_lookup(dir, name);
|
return d_lookup(dir, name);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_hash_and_lookup);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a file is deleted, we have two options:
|
* When a file is deleted, we have two options:
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/statfs.h>
|
#include <linux/statfs.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/printk.h>
|
#include <linux/printk.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@ -204,7 +205,6 @@ bool efivarfs_variable_is_present(efi_char16_t *variable_name,
|
|||||||
char *name = efivar_get_utf8name(variable_name, vendor);
|
char *name = efivar_get_utf8name(variable_name, vendor);
|
||||||
struct super_block *sb = data;
|
struct super_block *sb = data;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct qstr qstr;
|
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
/*
|
/*
|
||||||
@ -217,9 +217,7 @@ bool efivarfs_variable_is_present(efi_char16_t *variable_name,
|
|||||||
*/
|
*/
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
qstr.name = name;
|
dentry = try_lookup_noperm(&QSTR(name), sb->s_root);
|
||||||
qstr.len = strlen(name);
|
|
||||||
dentry = d_hash_and_lookup(sb->s_root, &qstr);
|
|
||||||
kfree(name);
|
kfree(name);
|
||||||
if (!IS_ERR_OR_NULL(dentry))
|
if (!IS_ERR_OR_NULL(dentry))
|
||||||
dput(dentry);
|
dput(dentry);
|
||||||
@ -404,8 +402,8 @@ static bool efivarfs_actor(struct dir_context *ctx, const char *name, int len,
|
|||||||
{
|
{
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
struct efivarfs_ctx *ectx = container_of(ctx, struct efivarfs_ctx, ctx);
|
struct efivarfs_ctx *ectx = container_of(ctx, struct efivarfs_ctx, ctx);
|
||||||
struct qstr qstr = { .name = name, .len = len };
|
struct dentry *dentry = try_lookup_noperm(&QSTR_LEN(name, len),
|
||||||
struct dentry *dentry = d_hash_and_lookup(ectx->sb->s_root, &qstr);
|
ectx->sb->s_root);
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct efivar_entry *entry;
|
struct efivar_entry *entry;
|
||||||
int err;
|
int err;
|
||||||
@ -441,7 +439,6 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
|
|||||||
char *name;
|
char *name;
|
||||||
struct super_block *sb = data;
|
struct super_block *sb = data;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
struct qstr qstr;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID))
|
if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID))
|
||||||
@ -451,9 +448,7 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
|
|||||||
if (!name)
|
if (!name)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
qstr.name = name;
|
dentry = try_lookup_noperm(&QSTR(name), sb->s_root);
|
||||||
qstr.len = strlen(name);
|
|
||||||
dentry = d_hash_and_lookup(sb->s_root, &qstr);
|
|
||||||
if (IS_ERR(dentry)) {
|
if (IS_ERR(dentry)) {
|
||||||
err = PTR_ERR(dentry);
|
err = PTR_ERR(dentry);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -66,6 +66,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
|
|||||||
int vfs_tmpfile(struct mnt_idmap *idmap,
|
int vfs_tmpfile(struct mnt_idmap *idmap,
|
||||||
const struct path *parentpath,
|
const struct path *parentpath,
|
||||||
struct file *file, umode_t mode);
|
struct file *file, umode_t mode);
|
||||||
|
struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* namespace.c
|
* namespace.c
|
||||||
|
@ -2121,7 +2121,7 @@ bool proc_fill_cache(struct file *file, struct dir_context *ctx,
|
|||||||
unsigned type = DT_UNKNOWN;
|
unsigned type = DT_UNKNOWN;
|
||||||
ino_t ino = 1;
|
ino_t ino = 1;
|
||||||
|
|
||||||
child = d_hash_and_lookup(dir, &qname);
|
child = try_lookup_noperm(&qname, dir);
|
||||||
if (!child) {
|
if (!child) {
|
||||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
||||||
child = d_alloc_parallel(dir, &qname, &wq);
|
child = d_alloc_parallel(dir, &qname, &wq);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/stat.h>
|
#include <linux/stat.h>
|
||||||
@ -78,7 +79,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
|
|||||||
|
|
||||||
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
|
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
|
||||||
|
|
||||||
dentry = d_hash_and_lookup(parent, name);
|
dentry = try_lookup_noperm(name, parent);
|
||||||
if (!dentry) {
|
if (!dentry) {
|
||||||
/*
|
/*
|
||||||
* If we know that the inode will need to be revalidated
|
* If we know that the inode will need to be revalidated
|
||||||
|
@ -444,7 +444,7 @@ xrep_adoption_check_dcache(
|
|||||||
if (!d_orphanage)
|
if (!d_orphanage)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
d_child = d_hash_and_lookup(d_orphanage, &qname);
|
d_child = try_lookup_noperm(&qname, d_orphanage);
|
||||||
if (d_child) {
|
if (d_child) {
|
||||||
trace_xrep_adoption_check_child(sc->mp, d_child);
|
trace_xrep_adoption_check_child(sc->mp, d_child);
|
||||||
|
|
||||||
@ -481,7 +481,7 @@ xrep_adoption_zap_dcache(
|
|||||||
if (!d_orphanage)
|
if (!d_orphanage)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
d_child = d_hash_and_lookup(d_orphanage, &qname);
|
d_child = try_lookup_noperm(&qname, d_orphanage);
|
||||||
while (d_child != NULL) {
|
while (d_child != NULL) {
|
||||||
trace_xrep_adoption_invalidate_child(sc->mp, d_child);
|
trace_xrep_adoption_invalidate_child(sc->mp, d_child);
|
||||||
|
|
||||||
|
@ -288,7 +288,6 @@ extern void d_exchange(struct dentry *, struct dentry *);
|
|||||||
extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
|
extern struct dentry *d_ancestor(struct dentry *, struct dentry *);
|
||||||
|
|
||||||
extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
|
extern struct dentry *d_lookup(const struct dentry *, const struct qstr *);
|
||||||
extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *);
|
|
||||||
|
|
||||||
static inline unsigned d_count(const struct dentry *dentry)
|
static inline unsigned d_count(const struct dentry *dentry)
|
||||||
{
|
{
|
||||||
|
@ -631,7 +631,7 @@ static struct dentry *__rpc_lookup_create_exclusive(struct dentry *parent,
|
|||||||
const char *name)
|
const char *name)
|
||||||
{
|
{
|
||||||
struct qstr q = QSTR(name);
|
struct qstr q = QSTR(name);
|
||||||
struct dentry *dentry = d_hash_and_lookup(parent, &q);
|
struct dentry *dentry = try_lookup_noperm(&q, parent);
|
||||||
if (!dentry) {
|
if (!dentry) {
|
||||||
dentry = d_alloc(parent, &q);
|
dentry = d_alloc(parent, &q);
|
||||||
if (!dentry)
|
if (!dentry)
|
||||||
@ -658,7 +658,7 @@ static void __rpc_depopulate(struct dentry *parent,
|
|||||||
for (i = start; i < eof; i++) {
|
for (i = start; i < eof; i++) {
|
||||||
name.name = files[i].name;
|
name.name = files[i].name;
|
||||||
name.len = strlen(files[i].name);
|
name.len = strlen(files[i].name);
|
||||||
dentry = d_hash_and_lookup(parent, &name);
|
dentry = try_lookup_noperm(&name, parent);
|
||||||
|
|
||||||
if (dentry == NULL)
|
if (dentry == NULL)
|
||||||
continue;
|
continue;
|
||||||
@ -1190,7 +1190,7 @@ static const struct rpc_filelist files[] = {
|
|||||||
struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
|
struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
|
||||||
const unsigned char *dir_name)
|
const unsigned char *dir_name)
|
||||||
{
|
{
|
||||||
return d_hash_and_lookup(sb->s_root, &QSTR(dir_name));
|
return try_lookup_noperm(&QSTR(dir_name), sb->s_root);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
|
EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
|
||||||
|
|
||||||
@ -1301,7 +1301,7 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
|
|||||||
struct dentry *pipe_dentry = NULL;
|
struct dentry *pipe_dentry = NULL;
|
||||||
|
|
||||||
/* We should never get this far if "gssd" doesn't exist */
|
/* We should never get this far if "gssd" doesn't exist */
|
||||||
gssd_dentry = d_hash_and_lookup(root, &QSTR(files[RPCAUTH_gssd].name));
|
gssd_dentry = try_lookup_noperm(&QSTR(files[RPCAUTH_gssd].name), root);
|
||||||
if (!gssd_dentry)
|
if (!gssd_dentry)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
@ -1311,8 +1311,8 @@ rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
clnt_dentry = d_hash_and_lookup(gssd_dentry,
|
clnt_dentry = try_lookup_noperm(&QSTR(gssd_dummy_clnt_dir[0].name),
|
||||||
&QSTR(gssd_dummy_clnt_dir[0].name));
|
gssd_dentry);
|
||||||
if (!clnt_dentry) {
|
if (!clnt_dentry) {
|
||||||
__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
|
__rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
|
||||||
pipe_dentry = ERR_PTR(-ENOENT);
|
pipe_dentry = ERR_PTR(-ENOENT);
|
||||||
|
@ -2158,8 +2158,8 @@ static int __init init_sel_fs(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
selinux_null.dentry = d_hash_and_lookup(selinux_null.mnt->mnt_root,
|
selinux_null.dentry = try_lookup_noperm(&null_name,
|
||||||
&null_name);
|
selinux_null.mnt->mnt_root);
|
||||||
if (IS_ERR(selinux_null.dentry)) {
|
if (IS_ERR(selinux_null.dentry)) {
|
||||||
pr_err("selinuxfs: could not lookup null!\n");
|
pr_err("selinuxfs: could not lookup null!\n");
|
||||||
err = PTR_ERR(selinux_null.dentry);
|
err = PTR_ERR(selinux_null.dentry);
|
||||||
|
Loading…
Reference in New Issue
Block a user