Skip to content

Commit d3d90cc

Browse files
committed
Merge tag 'pull-revalidate' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs d_revalidate updates from Al Viro: "Provide stable parent and name to ->d_revalidate() instances Most of the filesystem methods where we care about dentry name and parent have their stability guaranteed by the callers; ->d_revalidate() is the major exception. It's easy enough for callers to supply stable values for expected name and expected parent of the dentry being validated. That kills quite a bit of boilerplate in ->d_revalidate() instances, along with a bunch of races where they used to access ->d_name without sufficient precautions" * tag 'pull-revalidate' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: 9p: fix ->rename_sem exclusion orangefs_d_revalidate(): use stable parent inode and name passed by caller ocfs2_dentry_revalidate(): use stable parent inode and name passed by caller nfs: fix ->d_revalidate() UAF on ->d_name accesses nfs{,4}_lookup_validate(): use stable parent inode passed by caller gfs2_drevalidate(): use stable parent inode and name passed by caller fuse_dentry_revalidate(): use stable parent inode and name passed by caller vfat_revalidate{,_ci}(): use stable parent inode passed by caller exfat_d_revalidate(): use stable parent inode passed by caller fscrypt_d_revalidate(): use stable parent inode passed by caller ceph_d_revalidate(): propagate stable name down into request encoding ceph_d_revalidate(): use stable parent inode passed by caller afs_d_revalidate(): use stable name and parent inode passed by caller Pass parent directory inode and expected name to ->d_revalidate() generic_ci_d_compare(): use shortname_storage ext4 fast_commit: make use of name_snapshot primitives dissolve external_name.u into separate members make take_dentry_name_snapshot() lockless dcache: back inline names with a struct-wrapped array of unsigned long make sure that DNAME_INLINE_LEN is a multiple of word size
2 parents ce33580 + 30d61ef commit d3d90cc

File tree

43 files changed

+359
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+359
-307
lines changed

Documentation/filesystems/locking.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ dentry_operations
1717

1818
prototypes::
1919

20-
int (*d_revalidate)(struct dentry *, unsigned int);
20+
int (*d_revalidate)(struct inode *, const struct qstr *,
21+
struct dentry *, unsigned int);
2122
int (*d_weak_revalidate)(struct dentry *, unsigned int);
2223
int (*d_hash)(const struct dentry *, struct qstr *);
2324
int (*d_compare)(const struct dentry *,
@@ -30,6 +31,8 @@ prototypes::
3031
struct vfsmount *(*d_automount)(struct path *path);
3132
int (*d_manage)(const struct path *, bool);
3233
struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
34+
bool (*d_unalias_trylock)(const struct dentry *);
35+
void (*d_unalias_unlock)(const struct dentry *);
3336

3437
locking rules:
3538

@@ -49,6 +52,8 @@ d_dname: no no no no
4952
d_automount: no no yes no
5053
d_manage: no no yes (ref-walk) maybe
5154
d_real no no yes no
55+
d_unalias_trylock yes no no no
56+
d_unalias_unlock yes no no no
5257
================== =========== ======== ============== ========
5358

5459
inode_operations

Documentation/filesystems/porting.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,3 +1141,19 @@ pointer are gone.
11411141

11421142
set_blocksize() takes opened struct file instead of struct block_device now
11431143
and it *must* be opened exclusive.
1144+
1145+
---
1146+
1147+
** mandatory**
1148+
1149+
->d_revalidate() gets two extra arguments - inode of parent directory and
1150+
name our dentry is expected to have. Both are stable (dir is pinned in
1151+
non-RCU case and will stay around during the call in RCU case, and name
1152+
is guaranteed to stay unchanging). Your instance doesn't have to use
1153+
either, but it often helps to avoid a lot of painful boilerplate.
1154+
Note that while name->name is stable and NUL-terminated, it may (and
1155+
often will) have name->name[name->len] equal to '/' rather than '\0' -
1156+
in normal case it points into the pathname being looked up.
1157+
NOTE: if you need something like full path from the root of filesystem,
1158+
you are still on your own - this assists with simple cases, but it's not
1159+
magic.

Documentation/filesystems/vfs.rst

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,7 +1251,8 @@ defined:
12511251
.. code-block:: c
12521252
12531253
struct dentry_operations {
1254-
int (*d_revalidate)(struct dentry *, unsigned int);
1254+
int (*d_revalidate)(struct inode *, const struct qstr *,
1255+
struct dentry *, unsigned int);
12551256
int (*d_weak_revalidate)(struct dentry *, unsigned int);
12561257
int (*d_hash)(const struct dentry *, struct qstr *);
12571258
int (*d_compare)(const struct dentry *,
@@ -1264,6 +1265,8 @@ defined:
12641265
struct vfsmount *(*d_automount)(struct path *);
12651266
int (*d_manage)(const struct path *, bool);
12661267
struct dentry *(*d_real)(struct dentry *, enum d_real_type type);
1268+
bool (*d_unalias_trylock)(const struct dentry *);
1269+
void (*d_unalias_unlock)(const struct dentry *);
12671270
};
12681271
12691272
``d_revalidate``
@@ -1427,6 +1430,25 @@ defined:
14271430

14281431
For non-regular files, the 'dentry' argument is returned.
14291432

1433+
``d_unalias_trylock``
1434+
if present, will be called by d_splice_alias() before moving a
1435+
preexisting attached alias. Returning false prevents __d_move(),
1436+
making d_splice_alias() fail with -ESTALE.
1437+
1438+
Rationale: setting FS_RENAME_DOES_D_MOVE will prevent d_move()
1439+
and d_exchange() calls from the outside of filesystem methods;
1440+
however, it does not guarantee that attached dentries won't
1441+
be renamed or moved by d_splice_alias() finding a preexisting
1442+
alias for a directory inode. Normally we would not care;
1443+
however, something that wants to stabilize the entire path to
1444+
root over a blocking operation might need that. See 9p for one
1445+
(and hopefully only) example.
1446+
1447+
``d_unalias_unlock``
1448+
should be paired with ``d_unalias_trylock``; that one is called after
1449+
__d_move() call in __d_unalias().
1450+
1451+
14301452
Each dentry has a pointer to its parent dentry, as well as a hash list
14311453
of child dentries. Child dentries are basically like files in a
14321454
directory.

fs/9p/v9fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ static inline struct v9fs_session_info *v9fs_inode2v9ses(struct inode *inode)
202202
return inode->i_sb->s_fs_info;
203203
}
204204

205-
static inline struct v9fs_session_info *v9fs_dentry2v9ses(struct dentry *dentry)
205+
static inline struct v9fs_session_info *v9fs_dentry2v9ses(const struct dentry *dentry)
206206
{
207207
return dentry->d_sb->s_fs_info;
208208
}

fs/9p/vfs_dentry.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static void v9fs_dentry_release(struct dentry *dentry)
6161
p9_fid_put(hlist_entry(p, struct p9_fid, dlist));
6262
}
6363

64-
static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
64+
static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
6565
{
6666
struct p9_fid *fid;
6767
struct inode *inode;
@@ -99,14 +99,36 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
9999
return 1;
100100
}
101101

102+
static int v9fs_lookup_revalidate(struct inode *dir, const struct qstr *name,
103+
struct dentry *dentry, unsigned int flags)
104+
{
105+
return __v9fs_lookup_revalidate(dentry, flags);
106+
}
107+
108+
static bool v9fs_dentry_unalias_trylock(const struct dentry *dentry)
109+
{
110+
struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
111+
return down_write_trylock(&v9ses->rename_sem);
112+
}
113+
114+
static void v9fs_dentry_unalias_unlock(const struct dentry *dentry)
115+
{
116+
struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
117+
up_write(&v9ses->rename_sem);
118+
}
119+
102120
const struct dentry_operations v9fs_cached_dentry_operations = {
103121
.d_revalidate = v9fs_lookup_revalidate,
104-
.d_weak_revalidate = v9fs_lookup_revalidate,
122+
.d_weak_revalidate = __v9fs_lookup_revalidate,
105123
.d_delete = v9fs_cached_dentry_delete,
106124
.d_release = v9fs_dentry_release,
125+
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
126+
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
107127
};
108128

109129
const struct dentry_operations v9fs_dentry_operations = {
110130
.d_delete = always_delete_dentry,
111131
.d_release = v9fs_dentry_release,
132+
.d_unalias_trylock = v9fs_dentry_unalias_trylock,
133+
.d_unalias_unlock = v9fs_dentry_unalias_unlock,
112134
};

fs/afs/dir.c

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
2323
unsigned int flags);
2424
static int afs_dir_open(struct inode *inode, struct file *file);
2525
static int afs_readdir(struct file *file, struct dir_context *ctx);
26-
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
26+
static int afs_d_revalidate(struct inode *dir, const struct qstr *name,
27+
struct dentry *dentry, unsigned int flags);
2728
static int afs_d_delete(const struct dentry *dentry);
2829
static void afs_d_iput(struct dentry *dentry, struct inode *inode);
2930
static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
@@ -597,19 +598,19 @@ static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name,
597598
* Do a lookup of a single name in a directory
598599
* - just returns the FID the dentry name maps to if found
599600
*/
600-
static int afs_do_lookup_one(struct inode *dir, struct dentry *dentry,
601+
static int afs_do_lookup_one(struct inode *dir, const struct qstr *name,
601602
struct afs_fid *fid,
602603
afs_dataversion_t *_dir_version)
603604
{
604605
struct afs_super_info *as = dir->i_sb->s_fs_info;
605606
struct afs_lookup_one_cookie cookie = {
606607
.ctx.actor = afs_lookup_one_filldir,
607-
.name = dentry->d_name,
608+
.name = *name,
608609
.fid.vid = as->volume->vid
609610
};
610611
int ret;
611612

612-
_enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
613+
_enter("{%lu},{%.*s},", dir->i_ino, name->len, name->name);
613614

614615
/* search the directory */
615616
ret = afs_dir_iterate(dir, &cookie.ctx, NULL, _dir_version);
@@ -1023,21 +1024,12 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
10231024
/*
10241025
* Check the validity of a dentry under RCU conditions.
10251026
*/
1026-
static int afs_d_revalidate_rcu(struct dentry *dentry)
1027+
static int afs_d_revalidate_rcu(struct afs_vnode *dvnode, struct dentry *dentry)
10271028
{
1028-
struct afs_vnode *dvnode;
1029-
struct dentry *parent;
1030-
struct inode *dir;
10311029
long dir_version, de_version;
10321030

10331031
_enter("%p", dentry);
10341032

1035-
/* Check the parent directory is still valid first. */
1036-
parent = READ_ONCE(dentry->d_parent);
1037-
dir = d_inode_rcu(parent);
1038-
if (!dir)
1039-
return -ECHILD;
1040-
dvnode = AFS_FS_I(dir);
10411033
if (test_bit(AFS_VNODE_DELETED, &dvnode->flags))
10421034
return -ECHILD;
10431035

@@ -1065,19 +1057,19 @@ static int afs_d_revalidate_rcu(struct dentry *dentry)
10651057
* - NOTE! the hit can be a negative hit too, so we can't assume we have an
10661058
* inode
10671059
*/
1068-
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1060+
static int afs_d_revalidate(struct inode *parent_dir, const struct qstr *name,
1061+
struct dentry *dentry, unsigned int flags)
10691062
{
1070-
struct afs_vnode *vnode, *dir;
1063+
struct afs_vnode *vnode, *dir = AFS_FS_I(parent_dir);
10711064
struct afs_fid fid;
1072-
struct dentry *parent;
10731065
struct inode *inode;
10741066
struct key *key;
10751067
afs_dataversion_t dir_version, invalid_before;
10761068
long de_version;
10771069
int ret;
10781070

10791071
if (flags & LOOKUP_RCU)
1080-
return afs_d_revalidate_rcu(dentry);
1072+
return afs_d_revalidate_rcu(dir, dentry);
10811073

10821074
if (d_really_is_positive(dentry)) {
10831075
vnode = AFS_FS_I(d_inode(dentry));
@@ -1092,14 +1084,9 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
10921084
if (IS_ERR(key))
10931085
key = NULL;
10941086

1095-
/* Hold the parent dentry so we can peer at it */
1096-
parent = dget_parent(dentry);
1097-
dir = AFS_FS_I(d_inode(parent));
1098-
10991087
/* validate the parent directory */
11001088
ret = afs_validate(dir, key);
11011089
if (ret == -ERESTARTSYS) {
1102-
dput(parent);
11031090
key_put(key);
11041091
return ret;
11051092
}
@@ -1127,7 +1114,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
11271114
afs_stat_v(dir, n_reval);
11281115

11291116
/* search the directory for this vnode */
1130-
ret = afs_do_lookup_one(&dir->netfs.inode, dentry, &fid, &dir_version);
1117+
ret = afs_do_lookup_one(&dir->netfs.inode, name, &fid, &dir_version);
11311118
switch (ret) {
11321119
case 0:
11331120
/* the filename maps to something */
@@ -1171,22 +1158,19 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
11711158
goto out_valid;
11721159

11731160
default:
1174-
_debug("failed to iterate dir %pd: %d",
1175-
parent, ret);
1161+
_debug("failed to iterate parent %pd2: %d", dentry, ret);
11761162
goto not_found;
11771163
}
11781164

11791165
out_valid:
11801166
dentry->d_fsdata = (void *)(unsigned long)dir_version;
11811167
out_valid_noupdate:
1182-
dput(parent);
11831168
key_put(key);
11841169
_leave(" = 1 [valid]");
11851170
return 1;
11861171

11871172
not_found:
11881173
_debug("dropping dentry %pd2", dentry);
1189-
dput(parent);
11901174
key_put(key);
11911175

11921176
_leave(" = 0 [bad]");

fs/ceph/dir.c

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,29 +1940,19 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry,
19401940
/*
19411941
* Check if cached dentry can be trusted.
19421942
*/
1943-
static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
1943+
static int ceph_d_revalidate(struct inode *dir, const struct qstr *name,
1944+
struct dentry *dentry, unsigned int flags)
19441945
{
19451946
struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(dentry->d_sb)->mdsc;
19461947
struct ceph_client *cl = mdsc->fsc->client;
19471948
int valid = 0;
1948-
struct dentry *parent;
1949-
struct inode *dir, *inode;
1949+
struct inode *inode;
19501950

1951-
valid = fscrypt_d_revalidate(dentry, flags);
1951+
valid = fscrypt_d_revalidate(dir, name, dentry, flags);
19521952
if (valid <= 0)
19531953
return valid;
19541954

1955-
if (flags & LOOKUP_RCU) {
1956-
parent = READ_ONCE(dentry->d_parent);
1957-
dir = d_inode_rcu(parent);
1958-
if (!dir)
1959-
return -ECHILD;
1960-
inode = d_inode_rcu(dentry);
1961-
} else {
1962-
parent = dget_parent(dentry);
1963-
dir = d_inode(parent);
1964-
inode = d_inode(dentry);
1965-
}
1955+
inode = d_inode_rcu(dentry);
19661956

19671957
doutc(cl, "%p '%pd' inode %p offset 0x%llx nokey %d\n",
19681958
dentry, dentry, inode, ceph_dentry(dentry)->offset,
@@ -2008,6 +1998,8 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
20081998
req->r_parent = dir;
20091999
ihold(dir);
20102000

2001+
req->r_dname = name;
2002+
20112003
mask = CEPH_STAT_CAP_INODE | CEPH_CAP_AUTH_SHARED;
20122004
if (ceph_security_xattr_wanted(dir))
20132005
mask |= CEPH_CAP_XATTR_SHARED;
@@ -2038,9 +2030,6 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
20382030
doutc(cl, "%p '%pd' %s\n", dentry, dentry, valid ? "valid" : "invalid");
20392031
if (!valid)
20402032
ceph_dir_clear_complete(dir);
2041-
2042-
if (!(flags & LOOKUP_RCU))
2043-
dput(parent);
20442033
return valid;
20452034
}
20462035

fs/ceph/mds_client.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2621,6 +2621,7 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
26212621
{
26222622
struct inode *dir = req->r_parent;
26232623
struct dentry *dentry = req->r_dentry;
2624+
const struct qstr *name = req->r_dname;
26242625
u8 *cryptbuf = NULL;
26252626
u32 len = 0;
26262627
int ret = 0;
@@ -2641,8 +2642,10 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
26412642
if (!fscrypt_has_encryption_key(dir))
26422643
goto success;
26432644

2644-
if (!fscrypt_fname_encrypted_size(dir, dentry->d_name.len, NAME_MAX,
2645-
&len)) {
2645+
if (!name)
2646+
name = &dentry->d_name;
2647+
2648+
if (!fscrypt_fname_encrypted_size(dir, name->len, NAME_MAX, &len)) {
26462649
WARN_ON_ONCE(1);
26472650
return ERR_PTR(-ENAMETOOLONG);
26482651
}
@@ -2657,7 +2660,7 @@ static u8 *get_fscrypt_altname(const struct ceph_mds_request *req, u32 *plen)
26572660
if (!cryptbuf)
26582661
return ERR_PTR(-ENOMEM);
26592662

2660-
ret = fscrypt_fname_encrypt(dir, &dentry->d_name, cryptbuf, len);
2663+
ret = fscrypt_fname_encrypt(dir, name, cryptbuf, len);
26612664
if (ret) {
26622665
kfree(cryptbuf);
26632666
return ERR_PTR(ret);

fs/ceph/mds_client.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,8 @@ struct ceph_mds_request {
299299
struct inode *r_target_inode; /* resulting inode */
300300
struct inode *r_new_inode; /* new inode (for creates) */
301301

302+
const struct qstr *r_dname; /* stable name (for ->d_revalidate) */
303+
302304
#define CEPH_MDS_R_DIRECT_IS_HASH (1) /* r_direct_hash is valid */
303305
#define CEPH_MDS_R_ABORTED (2) /* call was aborted */
304306
#define CEPH_MDS_R_GOT_UNSAFE (3) /* got an unsafe reply */

fs/coda/dir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
445445
}
446446

447447
/* called when a cache lookup succeeds */
448-
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
448+
static int coda_dentry_revalidate(struct inode *dir, const struct qstr *name,
449+
struct dentry *de, unsigned int flags)
449450
{
450451
struct inode *inode;
451452
struct coda_inode_info *cii;

0 commit comments

Comments
 (0)