Commit 2f7d98f1 authored by Al Viro's avatar Al Viro
Browse files

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: default avatarJan Kara <jack@suse.cz>
Reviewed-by: default avatarChristian Brauner <brauner@kernel.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent ae842501
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -171,7 +171,7 @@ static int init_file(struct file *f, int flags, const struct cred *cred)
	 * the respective member when opening the file.
	 */
	mutex_init(&f->f_pos_lock);
	memset(&f->f_path, 0, sizeof(f->f_path));
	memset(&f->__f_path, 0, sizeof(f->f_path));
	memset(&f->f_ra, 0, sizeof(f->f_ra));

	f->f_flags	= flags;
@@ -319,7 +319,7 @@ struct file *alloc_empty_backing_file(int flags, const struct cred *cred)
static void file_init_path(struct file *file, const struct path *path,
			   const struct file_operations *fop)
{
	file->f_path = *path;
	file->__f_path = *path;
	file->f_inode = path->dentry->d_inode;
	file->f_mapping = path->dentry->d_inode->i_mapping;
	file->f_wb_err = filemap_sample_wb_err(file->f_mapping);
+4 −4
Original line number Diff line number Diff line
@@ -3563,8 +3563,8 @@ static struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry,
	if (nd->flags & LOOKUP_DIRECTORY)
		open_flag |= O_DIRECTORY;

	file->f_path.dentry = DENTRY_NOT_SET;
	file->f_path.mnt = nd->path.mnt;
	file->__f_path.dentry = DENTRY_NOT_SET;
	file->__f_path.mnt = nd->path.mnt;
	error = dir->i_op->atomic_open(dir, dentry, file,
				       open_to_namei_flags(open_flag), mode);
	d_lookup_done(dentry);
@@ -3932,8 +3932,8 @@ int vfs_tmpfile(struct mnt_idmap *idmap,
	child = d_alloc(parentpath->dentry, &slash_name);
	if (unlikely(!child))
		return -ENOMEM;
	file->f_path.mnt = parentpath->mnt;
	file->f_path.dentry = child;
	file->__f_path.mnt = parentpath->mnt;
	file->__f_path.dentry = child;
	mode = vfs_prepare_mode(idmap, dir, mode, mode, mode);
	error = dir->i_op->tmpfile(idmap, dir, file, mode);
	dput(child);
+5 −5
Original line number Diff line number Diff line
@@ -1022,8 +1022,8 @@ static int do_dentry_open(struct file *f,
	put_file_access(f);
cleanup_file:
	path_put(&f->f_path);
	f->f_path.mnt = NULL;
	f->f_path.dentry = NULL;
	f->__f_path.mnt = NULL;
	f->__f_path.dentry = NULL;
	f->f_inode = NULL;
	return error;
}
@@ -1050,7 +1050,7 @@ int finish_open(struct file *file, struct dentry *dentry,
{
	BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */

	file->f_path.dentry = dentry;
	file->__f_path.dentry = dentry;
	return do_dentry_open(file, open);
}
EXPORT_SYMBOL(finish_open);
@@ -1071,7 +1071,7 @@ EXPORT_SYMBOL(finish_open);
 */
int finish_no_open(struct file *file, struct dentry *dentry)
{
	file->f_path.dentry = dentry;
	file->__f_path.dentry = dentry;
	return 0;
}
EXPORT_SYMBOL(finish_no_open);
@@ -1091,7 +1091,7 @@ int vfs_open(const struct path *path, struct file *file)
{
	int ret;

	file->f_path = *path;
	file->__f_path = *path;
	ret = do_dentry_open(file, NULL);
	if (!ret) {
		/*
+6 −1
Original line number Diff line number Diff line
@@ -1082,6 +1082,8 @@ static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index)
 * @f_cred: stashed credentials of creator/opener
 * @f_owner: file owner
 * @f_path: path of the file
 * @__f_path: writable alias for @f_path; *ONLY* for core VFS and only before
 *   the file gets open
 * @f_pos_lock: lock protecting file position
 * @f_pipe: specific to pipes
 * @f_pos: file position
@@ -1107,7 +1109,10 @@ struct file {
	const struct cred		*f_cred;
	struct fown_struct		*f_owner;
	/* --- cacheline 1 boundary (64 bytes) --- */
	struct path			f_path;
	union {
		const struct path	f_path;
		struct path		__f_path;
	};
	union {
		/* regular files (with FMODE_ATOMIC_POS) and directories */
		struct mutex		f_pos_lock;