Commit fd2f7cb5 authored by Al Viro's avatar Al Viro

kill struct filename.separate

just make const char iname[] the last member and compare name->name with
name->iname instead of checking name->separate

We need to make sure that out-of-line name doesn't end up allocated adjacent
to struct filename refering to it; fortunately, it's easy to achieve - just
allocate that struct filename with one byte in ->iname[], so that ->iname[0]
will be inside the same object and thus have an address different from that
of out-of-line name [spotted by Boqun Feng <boqun.feng@gmail.com>]
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 6e8a1f87
...@@ -119,7 +119,7 @@ ...@@ -119,7 +119,7 @@
* PATH_MAX includes the nul terminator --RR. * PATH_MAX includes the nul terminator --RR.
*/ */
#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) #define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
struct filename * struct filename *
getname_flags(const char __user *filename, int flags, int *empty) getname_flags(const char __user *filename, int flags, int *empty)
...@@ -140,9 +140,8 @@ getname_flags(const char __user *filename, int flags, int *empty) ...@@ -140,9 +140,8 @@ getname_flags(const char __user *filename, int flags, int *empty)
* First, try to embed the struct filename inside the names_cache * First, try to embed the struct filename inside the names_cache
* allocation * allocation
*/ */
kname = (char *)result + sizeof(*result); kname = (char *)result->iname;
result->name = kname; result->name = kname;
result->separate = false;
len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
if (unlikely(len < 0)) { if (unlikely(len < 0)) {
...@@ -157,15 +156,20 @@ getname_flags(const char __user *filename, int flags, int *empty) ...@@ -157,15 +156,20 @@ getname_flags(const char __user *filename, int flags, int *empty)
* userland. * userland.
*/ */
if (unlikely(len == EMBEDDED_NAME_MAX)) { if (unlikely(len == EMBEDDED_NAME_MAX)) {
const size_t size = offsetof(struct filename, iname[1]);
kname = (char *)result; kname = (char *)result;
result = kzalloc(sizeof(*result), GFP_KERNEL); /*
* size is chosen that way we to guarantee that
* result->iname[0] is within the same object and that
* kname can't be equal to result->iname, no matter what.
*/
result = kzalloc(size, GFP_KERNEL);
if (unlikely(!result)) { if (unlikely(!result)) {
__putname(kname); __putname(kname);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
result->name = kname; result->name = kname;
result->separate = true;
len = strncpy_from_user(kname, filename, PATH_MAX); len = strncpy_from_user(kname, filename, PATH_MAX);
if (unlikely(len < 0)) { if (unlikely(len < 0)) {
__putname(kname); __putname(kname);
...@@ -213,8 +217,7 @@ getname_kernel(const char * filename) ...@@ -213,8 +217,7 @@ getname_kernel(const char * filename)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (len <= EMBEDDED_NAME_MAX) { if (len <= EMBEDDED_NAME_MAX) {
result->name = (char *)(result) + sizeof(*result); result->name = (char *)result->iname;
result->separate = false;
} else if (len <= PATH_MAX) { } else if (len <= PATH_MAX) {
struct filename *tmp; struct filename *tmp;
...@@ -224,7 +227,6 @@ getname_kernel(const char * filename) ...@@ -224,7 +227,6 @@ getname_kernel(const char * filename)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
tmp->name = (char *)result; tmp->name = (char *)result;
tmp->separate = true;
result = tmp; result = tmp;
} else { } else {
__putname(result); __putname(result);
...@@ -246,7 +248,7 @@ void putname(struct filename *name) ...@@ -246,7 +248,7 @@ void putname(struct filename *name)
if (--name->refcnt > 0) if (--name->refcnt > 0)
return; return;
if (name->separate) { if (name->name != name->iname) {
__putname(name->name); __putname(name->name);
kfree(name); kfree(name);
} else } else
...@@ -1852,6 +1854,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, ...@@ -1852,6 +1854,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
struct nameidata *nd) struct nameidata *nd)
{ {
int retval = 0; int retval = 0;
const char *s = name->name;
nd->last_type = LAST_ROOT; /* if there are only slashes... */ nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
...@@ -1860,7 +1863,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, ...@@ -1860,7 +1863,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
if (flags & LOOKUP_ROOT) { if (flags & LOOKUP_ROOT) {
struct dentry *root = nd->root.dentry; struct dentry *root = nd->root.dentry;
struct inode *inode = root->d_inode; struct inode *inode = root->d_inode;
if (name->name[0]) { if (*s) {
if (!d_can_lookup(root)) if (!d_can_lookup(root))
return -ENOTDIR; return -ENOTDIR;
retval = inode_permission(inode, MAY_EXEC); retval = inode_permission(inode, MAY_EXEC);
...@@ -1882,7 +1885,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, ...@@ -1882,7 +1885,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
nd->root.mnt = NULL; nd->root.mnt = NULL;
nd->m_seq = read_seqbegin(&mount_lock); nd->m_seq = read_seqbegin(&mount_lock);
if (name->name[0] == '/') { if (*s == '/') {
if (flags & LOOKUP_RCU) { if (flags & LOOKUP_RCU) {
rcu_read_lock(); rcu_read_lock();
nd->seq = set_root_rcu(nd); nd->seq = set_root_rcu(nd);
...@@ -1916,7 +1919,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, ...@@ -1916,7 +1919,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
dentry = f.file->f_path.dentry; dentry = f.file->f_path.dentry;
if (name->name[0]) { if (*s) {
if (!d_can_lookup(dentry)) { if (!d_can_lookup(dentry)) {
fdput(f); fdput(f);
return -ENOTDIR; return -ENOTDIR;
...@@ -1946,7 +1949,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags, ...@@ -1946,7 +1949,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
return -ECHILD; return -ECHILD;
done: done:
current->total_link_count = 0; current->total_link_count = 0;
return link_path_walk(name->name, nd); return link_path_walk(s, nd);
} }
static void path_cleanup(struct nameidata *nd) static void path_cleanup(struct nameidata *nd)
......
...@@ -2144,7 +2144,7 @@ struct filename { ...@@ -2144,7 +2144,7 @@ struct filename {
const __user char *uptr; /* original userland pointer */ const __user char *uptr; /* original userland pointer */
struct audit_names *aname; struct audit_names *aname;
int refcnt; int refcnt;
bool separate; /* should "name" be freed? */ const char iname[];
}; };
extern long vfs_truncate(struct path *, loff_t); extern long vfs_truncate(struct path *, loff_t);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment