*/
void final_putname(struct filename *name)
{
- __putname(name->name);
- kfree(name);
+ if (name->separate) {
+ __putname(name->name);
+ kfree(name);
+ } else {
+ __putname(name);
+ }
}
+#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename))
+
static struct filename *
getname_flags(const char __user *filename, int flags, int *empty)
{
struct filename *result, *err;
- char *kname;
int len;
+ long max;
+ char *kname;
result = audit_reusename(filename);
if (result)
return result;
- /* FIXME: create dedicated slabcache? */
- result = kzalloc(sizeof(*result), GFP_KERNEL);
+ result = __getname();
if (unlikely(!result))
return ERR_PTR(-ENOMEM);
- kname = __getname();
- if (unlikely(!kname)) {
- err = ERR_PTR(-ENOMEM);
- goto error_free_name;
- }
-
+ /*
+ * First, try to embed the struct filename inside the names_cache
+ * allocation
+ */
+ kname = (char *)result + sizeof(*result);
result->name = kname;
- result->uptr = filename;
- len = strncpy_from_user(kname, filename, PATH_MAX);
+ result->separate = false;
+ max = EMBEDDED_NAME_MAX;
+
+recopy:
+ len = strncpy_from_user(kname, filename, max);
if (unlikely(len < 0)) {
err = ERR_PTR(len);
goto error;
}
+ /*
+ * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a
+ * separate struct filename so we can dedicate the entire
+ * names_cache allocation for the pathname, and re-do the copy from
+ * userland.
+ */
+ if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) {
+ kname = (char *)result;
+
+ result = kzalloc(sizeof(*result), GFP_KERNEL);
+ if (!result) {
+ err = ERR_PTR(-ENOMEM);
+ result = (struct filename *)kname;
+ goto error;
+ }
+ result->name = kname;
+ result->separate = true;
+ max = PATH_MAX;
+ goto recopy;
+ }
+
/* The empty path is special. */
if (unlikely(!len)) {
if (empty)
}
err = ERR_PTR(-ENAMETOOLONG);
- if (likely(len < PATH_MAX)) {
- audit_getname(result);
- return result;
- }
+ if (unlikely(len >= PATH_MAX))
+ goto error;
+
+ result->uptr = filename;
+ audit_getname(result);
+ return result;
error:
- __putname(kname);
-error_free_name:
- kfree(result);
+ final_putname(result);
return err;
}
flags | LOOKUP_REVAL, nd);
if (likely(!retval))
- audit_inode(name->name, nd->path.dentry,
- flags & LOOKUP_PARENT);
+ audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);
return retval;
}
struct path save_parent = { .dentry = NULL, .mnt = NULL };
bool retried = false;
int error;
- const char *pathname = name->name;
nd->flags &= ~LOOKUP_PARENT;
nd->flags |= op->intent;
error = complete_walk(nd);
if (error)
return error;
- audit_inode(pathname, nd->path.dentry, 0);
+ audit_inode(name, nd->path.dentry, 0);
if (open_flag & O_CREAT) {
error = -EISDIR;
goto out;
error = complete_walk(nd);
if (error)
return error;
- audit_inode(pathname, dir, 0);
+ audit_inode(name, dir, 0);
goto finish_open;
}
if (error)
return error;
- audit_inode(pathname, dir, 0);
+ audit_inode(name, dir, 0);
error = -EISDIR;
/* trailing slashes? */
if (nd->last.name[nd->last.len])
!S_ISREG(file->f_path.dentry->d_inode->i_mode))
will_truncate = false;
- audit_inode(pathname, file->f_path.dentry, 0);
+ audit_inode(name, file->f_path.dentry, 0);
goto opened;
}
* create/update audit record if it already exists.
*/
if (path->dentry->d_inode)
- audit_inode(pathname, path->dentry, 0);
+ audit_inode(name, path->dentry, 0);
/*
* If atomic_open() acquired write access it is dropped now due to
error = -ENOTDIR;
if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)
goto out;
- audit_inode(pathname, nd->path.dentry, 0);
+ audit_inode(name, nd->path.dentry, 0);
finish_open:
if (!S_ISREG(nd->inode->i_mode))
will_truncate = false;