aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2015-02-22 20:07:13 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2015-04-11 22:21:24 -0400
commitfd2f7cb5bcac58b63717cd45366bff9a6ab961c6 (patch)
tree4271223c22f541510331e806ac178df920d3b69c
parent6e8a1f8741d6f1179cb3b03991caeac9e4bfd9e2 (diff)
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: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--fs/namei.c29
-rw-r--r--include/linux/fs.h2
2 files changed, 17 insertions, 14 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 2c4b68c12550..6218e62a0534 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -119,7 +119,7 @@
119 * PATH_MAX includes the nul terminator --RR. 119 * PATH_MAX includes the nul terminator --RR.
120 */ 120 */
121 121
122#define EMBEDDED_NAME_MAX (PATH_MAX - sizeof(struct filename)) 122#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname))
123 123
124struct filename * 124struct filename *
125getname_flags(const char __user *filename, int flags, int *empty) 125getname_flags(const char __user *filename, int flags, int *empty)
@@ -140,9 +140,8 @@ getname_flags(const char __user *filename, int flags, int *empty)
140 * First, try to embed the struct filename inside the names_cache 140 * First, try to embed the struct filename inside the names_cache
141 * allocation 141 * allocation
142 */ 142 */
143 kname = (char *)result + sizeof(*result); 143 kname = (char *)result->iname;
144 result->name = kname; 144 result->name = kname;
145 result->separate = false;
146 145
147 len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); 146 len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX);
148 if (unlikely(len < 0)) { 147 if (unlikely(len < 0)) {
@@ -157,15 +156,20 @@ getname_flags(const char __user *filename, int flags, int *empty)
157 * userland. 156 * userland.
158 */ 157 */
159 if (unlikely(len == EMBEDDED_NAME_MAX)) { 158 if (unlikely(len == EMBEDDED_NAME_MAX)) {
159 const size_t size = offsetof(struct filename, iname[1]);
160 kname = (char *)result; 160 kname = (char *)result;
161 161
162 result = kzalloc(sizeof(*result), GFP_KERNEL); 162 /*
163 * size is chosen that way we to guarantee that
164 * result->iname[0] is within the same object and that
165 * kname can't be equal to result->iname, no matter what.
166 */
167 result = kzalloc(size, GFP_KERNEL);
163 if (unlikely(!result)) { 168 if (unlikely(!result)) {
164 __putname(kname); 169 __putname(kname);
165 return ERR_PTR(-ENOMEM); 170 return ERR_PTR(-ENOMEM);
166 } 171 }
167 result->name = kname; 172 result->name = kname;
168 result->separate = true;
169 len = strncpy_from_user(kname, filename, PATH_MAX); 173 len = strncpy_from_user(kname, filename, PATH_MAX);
170 if (unlikely(len < 0)) { 174 if (unlikely(len < 0)) {
171 __putname(kname); 175 __putname(kname);
@@ -213,8 +217,7 @@ getname_kernel(const char * filename)
213 return ERR_PTR(-ENOMEM); 217 return ERR_PTR(-ENOMEM);
214 218
215 if (len <= EMBEDDED_NAME_MAX) { 219 if (len <= EMBEDDED_NAME_MAX) {
216 result->name = (char *)(result) + sizeof(*result); 220 result->name = (char *)result->iname;
217 result->separate = false;
218 } else if (len <= PATH_MAX) { 221 } else if (len <= PATH_MAX) {
219 struct filename *tmp; 222 struct filename *tmp;
220 223
@@ -224,7 +227,6 @@ getname_kernel(const char * filename)
224 return ERR_PTR(-ENOMEM); 227 return ERR_PTR(-ENOMEM);
225 } 228 }
226 tmp->name = (char *)result; 229 tmp->name = (char *)result;
227 tmp->separate = true;
228 result = tmp; 230 result = tmp;
229 } else { 231 } else {
230 __putname(result); 232 __putname(result);
@@ -246,7 +248,7 @@ void putname(struct filename *name)
246 if (--name->refcnt > 0) 248 if (--name->refcnt > 0)
247 return; 249 return;
248 250
249 if (name->separate) { 251 if (name->name != name->iname) {
250 __putname(name->name); 252 __putname(name->name);
251 kfree(name); 253 kfree(name);
252 } else 254 } else
@@ -1852,6 +1854,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
1852 struct nameidata *nd) 1854 struct nameidata *nd)
1853{ 1855{
1854 int retval = 0; 1856 int retval = 0;
1857 const char *s = name->name;
1855 1858
1856 nd->last_type = LAST_ROOT; /* if there are only slashes... */ 1859 nd->last_type = LAST_ROOT; /* if there are only slashes... */
1857 nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; 1860 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 if (flags & LOOKUP_ROOT) { 1863 if (flags & LOOKUP_ROOT) {
1861 struct dentry *root = nd->root.dentry; 1864 struct dentry *root = nd->root.dentry;
1862 struct inode *inode = root->d_inode; 1865 struct inode *inode = root->d_inode;
1863 if (name->name[0]) { 1866 if (*s) {
1864 if (!d_can_lookup(root)) 1867 if (!d_can_lookup(root))
1865 return -ENOTDIR; 1868 return -ENOTDIR;
1866 retval = inode_permission(inode, MAY_EXEC); 1869 retval = inode_permission(inode, MAY_EXEC);
@@ -1882,7 +1885,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
1882 nd->root.mnt = NULL; 1885 nd->root.mnt = NULL;
1883 1886
1884 nd->m_seq = read_seqbegin(&mount_lock); 1887 nd->m_seq = read_seqbegin(&mount_lock);
1885 if (name->name[0] == '/') { 1888 if (*s == '/') {
1886 if (flags & LOOKUP_RCU) { 1889 if (flags & LOOKUP_RCU) {
1887 rcu_read_lock(); 1890 rcu_read_lock();
1888 nd->seq = set_root_rcu(nd); 1891 nd->seq = set_root_rcu(nd);
@@ -1916,7 +1919,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
1916 1919
1917 dentry = f.file->f_path.dentry; 1920 dentry = f.file->f_path.dentry;
1918 1921
1919 if (name->name[0]) { 1922 if (*s) {
1920 if (!d_can_lookup(dentry)) { 1923 if (!d_can_lookup(dentry)) {
1921 fdput(f); 1924 fdput(f);
1922 return -ENOTDIR; 1925 return -ENOTDIR;
@@ -1946,7 +1949,7 @@ static int path_init(int dfd, const struct filename *name, unsigned int flags,
1946 return -ECHILD; 1949 return -ECHILD;
1947done: 1950done:
1948 current->total_link_count = 0; 1951 current->total_link_count = 0;
1949 return link_path_walk(name->name, nd); 1952 return link_path_walk(s, nd);
1950} 1953}
1951 1954
1952static void path_cleanup(struct nameidata *nd) 1955static void path_cleanup(struct nameidata *nd)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b4d71b5e1ff2..d70e333988f1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2144,7 +2144,7 @@ struct filename {
2144 const __user char *uptr; /* original userland pointer */ 2144 const __user char *uptr; /* original userland pointer */
2145 struct audit_names *aname; 2145 struct audit_names *aname;
2146 int refcnt; 2146 int refcnt;
2147 bool separate; /* should "name" be freed? */ 2147 const char iname[];
2148}; 2148};
2149 2149
2150extern long vfs_truncate(struct path *, loff_t); 2150extern long vfs_truncate(struct path *, loff_t);