Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47c805dc authored by Al Viro's avatar Al Viro
Browse files

switch do_filp_open() to struct open_flags



take calculation of open_flags by open(2) arguments into new helper
in fs/open.c, move filp_open() over there, have it and do_sys_open()
use that helper, switch exec.c callers of do_filp_open() to explicit
(and constant) struct open_flags.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent c3e380b0
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -115,13 +115,16 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
	struct file *file;
	char *tmp = getname(library);
	int error = PTR_ERR(tmp);
	static const struct open_flags uselib_flags = {
		.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
		.acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
		.intent = LOOKUP_OPEN
	};

	if (IS_ERR(tmp))
		goto out;

	file = do_filp_open(AT_FDCWD, tmp,
				O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
				MAY_READ | MAY_EXEC | MAY_OPEN);
	file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
	putname(tmp);
	error = PTR_ERR(file);
	if (IS_ERR(file))
@@ -721,10 +724,13 @@ struct file *open_exec(const char *name)
{
	struct file *file;
	int err;
	static const struct open_flags open_exec_flags = {
		.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
		.acc_mode = MAY_EXEC | MAY_OPEN,
		.intent = LOOKUP_OPEN
	};

	file = do_filp_open(AT_FDCWD, name,
				O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
				MAY_EXEC | MAY_OPEN);
	file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW);
	if (IS_ERR(file))
		goto out;

+8 −0
Original line number Diff line number Diff line
@@ -106,6 +106,14 @@ extern void put_super(struct super_block *sb);
struct nameidata;
extern struct file *nameidata_to_filp(struct nameidata *);
extern void release_open_intent(struct nameidata *);
struct open_flags {
	int open_flag;
	int mode;
	int acc_mode;
	int intent;
};
extern struct file *do_filp_open(int dfd, const char *pathname,
		const struct open_flags *op, int lookup_flags);

/*
 * inode.c
+9 −79
Original line number Diff line number Diff line
@@ -2169,13 +2169,6 @@ static struct file *finish_open(struct nameidata *nd,
	return ERR_PTR(error);
}

struct open_flags {
	int open_flag;
	int mode;
	int acc_mode;
	int intent;
};

/*
 * Handle O_CREAT case for do_filp_open
 */
@@ -2305,74 +2298,28 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
 * open_to_namei_flags() for more details.
 */
struct file *do_filp_open(int dfd, const char *pathname,
		int open_flag, int mode, int acc_mode)
		const struct open_flags *op, int flags)
{
	struct file *filp;
	struct nameidata nd;
	int error;
	struct path path;
	int count = 0;
	int flag = open_to_namei_flags(open_flag);
	int flags = 0;
	struct open_flags op;

	if (!(open_flag & O_CREAT))
		mode = 0;

	/* Must never be set by userspace */
	open_flag &= ~FMODE_NONOTIFY;

	/*
	 * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
	 * check for O_DSYNC if the need any syncing at all we enforce it's
	 * always set instead of having to deal with possibly weird behaviour
	 * for malicious applications setting only __O_SYNC.
	 */
	if (open_flag & __O_SYNC)
		open_flag |= O_DSYNC;

	op.open_flag = open_flag;

	if (!acc_mode)
		acc_mode = MAY_OPEN | ACC_MODE(open_flag);

	/* O_TRUNC implies we need access checks for write permissions */
	if (open_flag & O_TRUNC)
		acc_mode |= MAY_WRITE;

	/* Allow the LSM permission hook to distinguish append 
	   access from general write access. */
	if (open_flag & O_APPEND)
		acc_mode |= MAY_APPEND;

	op.acc_mode = acc_mode;

	op.intent = LOOKUP_OPEN;
	if (open_flag & O_CREAT) {
		op.intent |= LOOKUP_CREATE;
		if (open_flag & O_EXCL)
			op.intent |= LOOKUP_EXCL;
	}

	if (open_flag & O_DIRECTORY)
		flags |= LOOKUP_DIRECTORY;
	if (!(open_flag & O_NOFOLLOW))
		flags |= LOOKUP_FOLLOW;

	filp = get_empty_filp();
	if (!filp)
		return ERR_PTR(-ENFILE);

	filp->f_flags = open_flag;
	filp->f_flags = op->open_flag;
	nd.intent.open.file = filp;
	nd.intent.open.flags = flag;
	nd.intent.open.create_mode = mode;
	nd.intent.open.flags = open_to_namei_flags(op->open_flag);
	nd.intent.open.create_mode = op->mode;

	if (open_flag & O_CREAT)
	if (op->open_flag & O_CREAT)
		goto creat;

	/* !O_CREAT, simple open */
	error = do_path_lookup(dfd, pathname, flags | op.intent, &nd);
	error = do_path_lookup(dfd, pathname, flags | op->intent, &nd);
	if (unlikely(error))
		goto out_filp2;
	error = -ELOOP;
@@ -2386,7 +2333,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
			goto out_path2;
	}
	audit_inode(pathname, nd.path.dentry);
	filp = finish_open(&nd, open_flag, acc_mode);
	filp = finish_open(&nd, op->open_flag, op->acc_mode);
out2:
	release_open_intent(&nd);
	return filp;
@@ -2416,7 +2363,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
	/*
	 * We have the parent and last component.
	 */
	filp = do_last(&nd, &path, &op, pathname);
	filp = do_last(&nd, &path, op, pathname);
	while (unlikely(!filp)) { /* trailing symlink */
		struct path link = path;
		struct inode *linki = link.dentry->d_inode;
@@ -2443,7 +2390,7 @@ struct file *do_filp_open(int dfd, const char *pathname,
		if (unlikely(error))
			filp = ERR_PTR(error);
		else
			filp = do_last(&nd, &path, &op, pathname);
			filp = do_last(&nd, &path, op, pathname);
		if (!IS_ERR(cookie) && linki->i_op->put_link)
			linki->i_op->put_link(link.dentry, &nd, cookie);
		path_put(&link);
@@ -2465,23 +2412,6 @@ struct file *do_filp_open(int dfd, const char *pathname,
	goto out;
}

/**
 * filp_open - open file and return file pointer
 *
 * @filename:	path to open
 * @flags:	open flags as per the open(2) second argument
 * @mode:	mode for the new file if O_CREAT is set, else ignored
 *
 * This is the helper to open a file from kernelspace if you really
 * have to.  But in generally you should not do this, so please move
 * along, nothing to see here..
 */
struct file *filp_open(const char *filename, int flags, int mode)
{
	return do_filp_open(AT_FDCWD, filename, flags, mode, 0);
}
EXPORT_SYMBOL(filp_open);

/**
 * lookup_create - lookup a dentry, creating it if it doesn't exist
 * @nd: nameidata info
+72 −1
Original line number Diff line number Diff line
@@ -890,15 +890,86 @@ void fd_install(unsigned int fd, struct file *file)

EXPORT_SYMBOL(fd_install);

static inline int build_open_flags(int flags, int mode, struct open_flags *op)
{
	int lookup_flags = 0;
	int acc_mode;

	if (!(flags & O_CREAT))
		mode = 0;
	op->mode = mode;

	/* Must never be set by userspace */
	flags &= ~FMODE_NONOTIFY;

	/*
	 * O_SYNC is implemented as __O_SYNC|O_DSYNC.  As many places only
	 * check for O_DSYNC if the need any syncing at all we enforce it's
	 * always set instead of having to deal with possibly weird behaviour
	 * for malicious applications setting only __O_SYNC.
	 */
	if (flags & __O_SYNC)
		flags |= O_DSYNC;

	op->open_flag = flags;

	acc_mode = MAY_OPEN | ACC_MODE(flags);

	/* O_TRUNC implies we need access checks for write permissions */
	if (flags & O_TRUNC)
		acc_mode |= MAY_WRITE;

	/* Allow the LSM permission hook to distinguish append
	   access from general write access. */
	if (flags & O_APPEND)
		acc_mode |= MAY_APPEND;

	op->acc_mode = acc_mode;

	op->intent = LOOKUP_OPEN;
	if (flags & O_CREAT) {
		op->intent |= LOOKUP_CREATE;
		if (flags & O_EXCL)
			op->intent |= LOOKUP_EXCL;
	}

	if (flags & O_DIRECTORY)
		lookup_flags |= LOOKUP_DIRECTORY;
	if (!(flags & O_NOFOLLOW))
		lookup_flags |= LOOKUP_FOLLOW;
	return lookup_flags;
}

/**
 * filp_open - open file and return file pointer
 *
 * @filename:	path to open
 * @flags:	open flags as per the open(2) second argument
 * @mode:	mode for the new file if O_CREAT is set, else ignored
 *
 * This is the helper to open a file from kernelspace if you really
 * have to.  But in generally you should not do this, so please move
 * along, nothing to see here..
 */
struct file *filp_open(const char *filename, int flags, int mode)
{
	struct open_flags op;
	int lookup = build_open_flags(flags, mode, &op);
	return do_filp_open(AT_FDCWD, filename, &op, lookup);
}
EXPORT_SYMBOL(filp_open);

long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
	struct open_flags op;
	int lookup = build_open_flags(flags, mode, &op);
	char *tmp = getname(filename);
	int fd = PTR_ERR(tmp);

	if (!IS_ERR(tmp)) {
		fd = get_unused_fd_flags(flags);
		if (fd >= 0) {
			struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);
			struct file *f = do_filp_open(dfd, tmp, &op, lookup);
			if (IS_ERR(f)) {
				put_unused_fd(fd);
				fd = PTR_ERR(f);
+0 −2
Original line number Diff line number Diff line
@@ -2205,8 +2205,6 @@ extern struct file *create_read_pipe(struct file *f, int flags);
extern struct file *create_write_pipe(int flags);
extern void free_write_pipe(struct file *);

extern struct file *do_filp_open(int dfd, const char *pathname,
		int open_flag, int mode, int acc_mode);
extern int may_open(struct path *, int, int);

extern int kernel_read(struct file *, loff_t, char *, unsigned long);