Skip to content

Commit 2f7d98f

Browse files
author
Al Viro
committed
Have cc(1) catch attempts to modify ->f_path
There are very few places that have cause to do that - all in core VFS now, and all done to files that are not yet opened (or visible to anybody else, for that matter). Let's turn f_path into a union of struct path __f_path and const struct path f_path. It's C, not C++ - 6.5.2.3[4] in C99 and later explicitly allows that kind of type-punning. That way any attempts to bypass these checks will be either very easy to catch, or (if the bastards get sufficiently creative to make it hard to spot with grep alone) very clearly malicious - and still catchable with a bit of instrumentation for sparse. Reviewed-by: Jan Kara <[email protected]> Reviewed-by: Christian Brauner <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent ae84250 commit 2f7d98f

File tree

4 files changed

+17
-12
lines changed

4 files changed

+17
-12
lines changed

fs/file_table.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ static int init_file(struct file *f, int flags, const struct cred *cred)
171171
* the respective member when opening the file.
172172
*/
173173
mutex_init(&f->f_pos_lock);
174-
memset(&f->f_path, 0, sizeof(f->f_path));
174+
memset(&f->__f_path, 0, sizeof(f->f_path));
175175
memset(&f->f_ra, 0, sizeof(f->f_ra));
176176

177177
f->f_flags = flags;
@@ -319,7 +319,7 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
319319
static void file_init_path(struct file *file, const struct path *path,
320320
const struct file_operations *fop)
321321
{
322-
file->f_path = *path;
322+
file->__f_path = *path;
323323
file->f_inode = path->dentry->d_inode;
324324
file->f_mapping = path->dentry->d_inode->i_mapping;
325325
file->f_wb_err = filemap_sample_wb_err(file->f_mapping);

fs/namei.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3563,8 +3563,8 @@ static struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry,
35633563
if (nd->flags & LOOKUP_DIRECTORY)
35643564
open_flag |= O_DIRECTORY;
35653565

3566-
file->f_path.dentry = DENTRY_NOT_SET;
3567-
file->f_path.mnt = nd->path.mnt;
3566+
file->__f_path.dentry = DENTRY_NOT_SET;
3567+
file->__f_path.mnt = nd->path.mnt;
35683568
error = dir->i_op->atomic_open(dir, dentry, file,
35693569
open_to_namei_flags(open_flag), mode);
35703570
d_lookup_done(dentry);
@@ -3932,8 +3932,8 @@ int vfs_tmpfile(struct mnt_idmap *idmap,
39323932
child = d_alloc(parentpath->dentry, &slash_name);
39333933
if (unlikely(!child))
39343934
return -ENOMEM;
3935-
file->f_path.mnt = parentpath->mnt;
3936-
file->f_path.dentry = child;
3935+
file->__f_path.mnt = parentpath->mnt;
3936+
file->__f_path.dentry = child;
39373937
mode = vfs_prepare_mode(idmap, dir, mode, mode, mode);
39383938
error = dir->i_op->tmpfile(idmap, dir, file, mode);
39393939
dput(child);

fs/open.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,8 +1022,8 @@ static int do_dentry_open(struct file *f,
10221022
put_file_access(f);
10231023
cleanup_file:
10241024
path_put(&f->f_path);
1025-
f->f_path.mnt = NULL;
1026-
f->f_path.dentry = NULL;
1025+
f->__f_path.mnt = NULL;
1026+
f->__f_path.dentry = NULL;
10271027
f->f_inode = NULL;
10281028
return error;
10291029
}
@@ -1050,7 +1050,7 @@ int finish_open(struct file *file, struct dentry *dentry,
10501050
{
10511051
BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */
10521052

1053-
file->f_path.dentry = dentry;
1053+
file->__f_path.dentry = dentry;
10541054
return do_dentry_open(file, open);
10551055
}
10561056
EXPORT_SYMBOL(finish_open);
@@ -1071,7 +1071,7 @@ EXPORT_SYMBOL(finish_open);
10711071
*/
10721072
int finish_no_open(struct file *file, struct dentry *dentry)
10731073
{
1074-
file->f_path.dentry = dentry;
1074+
file->__f_path.dentry = dentry;
10751075
return 0;
10761076
}
10771077
EXPORT_SYMBOL(finish_no_open);
@@ -1091,7 +1091,7 @@ int vfs_open(const struct path *path, struct file *file)
10911091
{
10921092
int ret;
10931093

1094-
file->f_path = *path;
1094+
file->__f_path = *path;
10951095
ret = do_dentry_open(file, NULL);
10961096
if (!ret) {
10971097
/*

include/linux/fs.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,8 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index)
10821082
* @f_cred: stashed credentials of creator/opener
10831083
* @f_owner: file owner
10841084
* @f_path: path of the file
1085+
* @__f_path: writable alias for @f_path; *ONLY* for core VFS and only before
1086+
* the file gets open
10851087
* @f_pos_lock: lock protecting file position
10861088
* @f_pipe: specific to pipes
10871089
* @f_pos: file position
@@ -1107,7 +1109,10 @@ struct file {
11071109
const struct cred *f_cred;
11081110
struct fown_struct *f_owner;
11091111
/* --- cacheline 1 boundary (64 bytes) --- */
1110-
struct path f_path;
1112+
union {
1113+
const struct path f_path;
1114+
struct path __f_path;
1115+
};
11111116
union {
11121117
/* regular files (with FMODE_ATOMIC_POS) and directories */
11131118
struct mutex f_pos_lock;

0 commit comments

Comments
 (0)