Skip to content

Commit 8a924db

Browse files
stefanbergerbrauner
authored andcommitted
fs: Pass AT_GETATTR_NOSEC flag to getattr interface function
When vfs_getattr_nosec() calls a filesystem's getattr interface function then the 'nosec' should propagate into this function so that vfs_getattr_nosec() can again be called from the filesystem's gettattr rather than vfs_getattr(). The latter would add unnecessary security checks that the initial vfs_getattr_nosec() call wanted to avoid. Therefore, introduce the getattr flag GETATTR_NOSEC and allow to pass with the new getattr_flags parameter to the getattr interface function. In overlayfs and ecryptfs use this flag to determine which one of the two functions to call. In a recent code change introduced to IMA vfs_getattr_nosec() ended up calling vfs_getattr() in overlayfs, which in turn called security_inode_getattr() on an exiting process that did not have current->fs set anymore, which then caused a kernel NULL pointer dereference. With this change the call to security_inode_getattr() can be avoided, thus avoiding the NULL pointer dereference. Reported-by: <[email protected]> Fixes: db1d1e8 ("IMA: use vfs_getattr_nosec to get the i_version") Cc: Alexander Viro <[email protected]> Cc: <[email protected]> Cc: Miklos Szeredi <[email protected]> Cc: Amir Goldstein <[email protected]> Cc: Tyler Hicks <[email protected]> Cc: Mimi Zohar <[email protected]> Suggested-by: Christian Brauner <[email protected]> Co-developed-by: Amir Goldstein <[email protected]> Signed-off-by: Stefan Berger <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Amir Goldstein <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent b85ea95 commit 8a924db

File tree

5 files changed

+31
-8
lines changed

5 files changed

+31
-8
lines changed

fs/ecryptfs/inode.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,14 @@ static int ecryptfs_getattr_link(struct mnt_idmap *idmap,
998998
return rc;
999999
}
10001000

1001+
static int ecryptfs_do_getattr(const struct path *path, struct kstat *stat,
1002+
u32 request_mask, unsigned int flags)
1003+
{
1004+
if (flags & AT_GETATTR_NOSEC)
1005+
return vfs_getattr_nosec(path, stat, request_mask, flags);
1006+
return vfs_getattr(path, stat, request_mask, flags);
1007+
}
1008+
10011009
static int ecryptfs_getattr(struct mnt_idmap *idmap,
10021010
const struct path *path, struct kstat *stat,
10031011
u32 request_mask, unsigned int flags)
@@ -1006,8 +1014,8 @@ static int ecryptfs_getattr(struct mnt_idmap *idmap,
10061014
struct kstat lower_stat;
10071015
int rc;
10081016

1009-
rc = vfs_getattr(ecryptfs_dentry_to_lower_path(dentry), &lower_stat,
1010-
request_mask, flags);
1017+
rc = ecryptfs_do_getattr(ecryptfs_dentry_to_lower_path(dentry),
1018+
&lower_stat, request_mask, flags);
10111019
if (!rc) {
10121020
fsstack_copy_attr_all(d_inode(dentry),
10131021
ecryptfs_inode_to_lower(d_inode(dentry)));

fs/overlayfs/inode.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
171171

172172
type = ovl_path_real(dentry, &realpath);
173173
old_cred = ovl_override_creds(dentry->d_sb);
174-
err = vfs_getattr(&realpath, stat, request_mask, flags);
174+
err = ovl_do_getattr(&realpath, stat, request_mask, flags);
175175
if (err)
176176
goto out;
177177

@@ -196,8 +196,8 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
196196
(!is_dir ? STATX_NLINK : 0);
197197

198198
ovl_path_lower(dentry, &realpath);
199-
err = vfs_getattr(&realpath, &lowerstat,
200-
lowermask, flags);
199+
err = ovl_do_getattr(&realpath, &lowerstat, lowermask,
200+
flags);
201201
if (err)
202202
goto out;
203203

@@ -249,8 +249,8 @@ int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
249249

250250
ovl_path_lowerdata(dentry, &realpath);
251251
if (realpath.dentry) {
252-
err = vfs_getattr(&realpath, &lowerdatastat,
253-
lowermask, flags);
252+
err = ovl_do_getattr(&realpath, &lowerdatastat,
253+
lowermask, flags);
254254
if (err)
255255
goto out;
256256
} else {

fs/overlayfs/overlayfs.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,14 @@ static inline bool ovl_open_flags_need_copy_up(int flags)
408408
return ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC));
409409
}
410410

411+
static inline int ovl_do_getattr(const struct path *path, struct kstat *stat,
412+
u32 request_mask, unsigned int flags)
413+
{
414+
if (flags & AT_GETATTR_NOSEC)
415+
return vfs_getattr_nosec(path, stat, request_mask, flags);
416+
return vfs_getattr(path, stat, request_mask, flags);
417+
}
418+
411419
/* util.c */
412420
int ovl_get_write_access(struct dentry *dentry);
413421
void ovl_put_write_access(struct dentry *dentry);

fs/stat.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ int vfs_getattr_nosec(const struct path *path, struct kstat *stat,
133133
idmap = mnt_idmap(path->mnt);
134134
if (inode->i_op->getattr)
135135
return inode->i_op->getattr(idmap, path, stat,
136-
request_mask, query_flags);
136+
request_mask,
137+
query_flags | AT_GETATTR_NOSEC);
137138

138139
generic_fillattr(idmap, request_mask, inode, stat);
139140
return 0;
@@ -166,6 +167,9 @@ int vfs_getattr(const struct path *path, struct kstat *stat,
166167
{
167168
int retval;
168169

170+
if (WARN_ON_ONCE(query_flags & AT_GETATTR_NOSEC))
171+
return -EPERM;
172+
169173
retval = security_inode_getattr(path);
170174
if (retval)
171175
return retval;

include/uapi/linux/fcntl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,8 @@
116116
#define AT_HANDLE_FID AT_REMOVEDIR /* file handle is needed to
117117
compare object identity and may not
118118
be usable to open_by_handle_at(2) */
119+
#if defined(__KERNEL__)
120+
#define AT_GETATTR_NOSEC 0x80000000
121+
#endif
119122

120123
#endif /* _UAPI_LINUX_FCNTL_H */

0 commit comments

Comments
 (0)