|
@@ -28,6 +28,7 @@
|
|
|
#include <linux/syscalls.h>
|
|
|
#include <linux/mount.h>
|
|
|
#include <linux/audit.h>
|
|
|
+#include <linux/file.h>
|
|
|
#include <asm/namei.h>
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
@@ -317,6 +318,18 @@ void path_release_on_umount(struct nameidata *nd)
|
|
|
mntput_no_expire(nd->mnt);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * release_open_intent - free up open intent resources
|
|
|
+ * @nd: pointer to nameidata
|
|
|
+ */
|
|
|
+void release_open_intent(struct nameidata *nd)
|
|
|
+{
|
|
|
+ if (nd->intent.open.file->f_dentry == NULL)
|
|
|
+ put_filp(nd->intent.open.file);
|
|
|
+ else
|
|
|
+ fput(nd->intent.open.file);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Internal lookup() using the new generic dcache.
|
|
|
* SMP-safe
|
|
@@ -1052,6 +1065,70 @@ out:
|
|
|
return retval;
|
|
|
}
|
|
|
|
|
|
+static int __path_lookup_intent_open(const char *name, unsigned int lookup_flags,
|
|
|
+ struct nameidata *nd, int open_flags, int create_mode)
|
|
|
+{
|
|
|
+ struct file *filp = get_empty_filp();
|
|
|
+ int err;
|
|
|
+
|
|
|
+ if (filp == NULL)
|
|
|
+ return -ENFILE;
|
|
|
+ nd->intent.open.file = filp;
|
|
|
+ nd->intent.open.flags = open_flags;
|
|
|
+ nd->intent.open.create_mode = create_mode;
|
|
|
+ err = path_lookup(name, lookup_flags|LOOKUP_OPEN, nd);
|
|
|
+ if (IS_ERR(nd->intent.open.file)) {
|
|
|
+ if (err == 0) {
|
|
|
+ err = PTR_ERR(nd->intent.open.file);
|
|
|
+ path_release(nd);
|
|
|
+ }
|
|
|
+ } else if (err != 0)
|
|
|
+ release_open_intent(nd);
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * path_lookup_open - lookup a file path with open intent
|
|
|
+ * @name: pointer to file name
|
|
|
+ * @lookup_flags: lookup intent flags
|
|
|
+ * @nd: pointer to nameidata
|
|
|
+ * @open_flags: open intent flags
|
|
|
+ */
|
|
|
+int path_lookup_open(const char *name, unsigned int lookup_flags,
|
|
|
+ struct nameidata *nd, int open_flags)
|
|
|
+{
|
|
|
+ return __path_lookup_intent_open(name, lookup_flags, nd,
|
|
|
+ open_flags, 0);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * path_lookup_create - lookup a file path with open + create intent
|
|
|
+ * @name: pointer to file name
|
|
|
+ * @lookup_flags: lookup intent flags
|
|
|
+ * @nd: pointer to nameidata
|
|
|
+ * @open_flags: open intent flags
|
|
|
+ * @create_mode: create intent flags
|
|
|
+ */
|
|
|
+int path_lookup_create(const char *name, unsigned int lookup_flags,
|
|
|
+ struct nameidata *nd, int open_flags, int create_mode)
|
|
|
+{
|
|
|
+ return __path_lookup_intent_open(name, lookup_flags|LOOKUP_CREATE, nd,
|
|
|
+ open_flags, create_mode);
|
|
|
+}
|
|
|
+
|
|
|
+int __user_path_lookup_open(const char __user *name, unsigned int lookup_flags,
|
|
|
+ struct nameidata *nd, int open_flags)
|
|
|
+{
|
|
|
+ char *tmp = getname(name);
|
|
|
+ int err = PTR_ERR(tmp);
|
|
|
+
|
|
|
+ if (!IS_ERR(tmp)) {
|
|
|
+ err = __path_lookup_intent_open(tmp, lookup_flags, nd, open_flags, 0);
|
|
|
+ putname(tmp);
|
|
|
+ }
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Restricted form of lookup. Doesn't follow links, single-component only,
|
|
|
* needs parent already locked. Doesn't follow mounts.
|
|
@@ -1416,27 +1493,27 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
|
|
|
*/
|
|
|
int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
|
|
|
{
|
|
|
- int acc_mode, error = 0;
|
|
|
+ int acc_mode, error;
|
|
|
struct path path;
|
|
|
struct dentry *dir;
|
|
|
int count = 0;
|
|
|
|
|
|
acc_mode = ACC_MODE(flag);
|
|
|
|
|
|
+ /* O_TRUNC implies we need access checks for write permissions */
|
|
|
+ if (flag & O_TRUNC)
|
|
|
+ acc_mode |= MAY_WRITE;
|
|
|
+
|
|
|
/* Allow the LSM permission hook to distinguish append
|
|
|
access from general write access. */
|
|
|
if (flag & O_APPEND)
|
|
|
acc_mode |= MAY_APPEND;
|
|
|
|
|
|
- /* Fill in the open() intent data */
|
|
|
- nd->intent.open.flags = flag;
|
|
|
- nd->intent.open.create_mode = mode;
|
|
|
-
|
|
|
/*
|
|
|
* The simplest case - just a plain lookup.
|
|
|
*/
|
|
|
if (!(flag & O_CREAT)) {
|
|
|
- error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd);
|
|
|
+ error = path_lookup_open(pathname, lookup_flags(flag), nd, flag);
|
|
|
if (error)
|
|
|
return error;
|
|
|
goto ok;
|
|
@@ -1445,7 +1522,7 @@ int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
|
|
|
/*
|
|
|
* Create - we need to know the parent.
|
|
|
*/
|
|
|
- error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);
|
|
|
+ error = path_lookup_create(pathname, LOOKUP_PARENT, nd, flag, mode);
|
|
|
if (error)
|
|
|
return error;
|
|
|
|
|
@@ -1520,6 +1597,8 @@ ok:
|
|
|
exit_dput:
|
|
|
dput_path(&path, nd);
|
|
|
exit:
|
|
|
+ if (!IS_ERR(nd->intent.open.file))
|
|
|
+ release_open_intent(nd);
|
|
|
path_release(nd);
|
|
|
return error;
|
|
|
|