Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

struct filename: saner handling of long names

Always allocate struct filename from names_cachep, long name or short;
short names would be embedded into struct filename. Longer ones do
not cannibalize the original struct filename - put them into kmalloc'ed
buffers (PATH_MAX-sized for import from userland, strlen() + 1 - for
ones originating kernel-side, where we know the length beforehand).

Cutoff length for short names is chosen so that struct filename would be
192 bytes long - that's both a multiple of 64 and large enough to cover
the majority of real-world uses.

Simplifies logics in getname()/putname() and friends.

[fixed an embarrassing braino in EMBEDDED_NAME_MAX, first reported by
Dan Carpenter]

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 8c888b31 c3a3577c

+41 -56
+33 -54
fs/namei.c
··· 123 123 * PATH_MAX includes the nul terminator --RR. 124 124 */ 125 125 126 - #define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname)) 127 - 128 126 /* SLAB cache for struct filename instances */ 129 127 static struct kmem_cache *names_cachep __ro_after_init; 130 128 131 129 void __init filename_init(void) 132 130 { 133 - names_cachep = kmem_cache_create_usercopy("names_cache", PATH_MAX, 0, 134 - SLAB_HWCACHE_ALIGN|SLAB_PANIC, 0, PATH_MAX, NULL); 131 + names_cachep = kmem_cache_create_usercopy("names_cache", sizeof(struct filename), 0, 132 + SLAB_HWCACHE_ALIGN|SLAB_PANIC, offsetof(struct filename, iname), 133 + EMBEDDED_NAME_MAX, NULL); 135 134 } 136 135 137 136 static inline struct filename *alloc_filename(void) ··· 149 150 atomic_set(&name->refcnt, 1); 150 151 } 151 152 152 - static struct filename *getname_long(struct filename *old, 153 - const char __user *filename) 153 + static int getname_long(struct filename *name, const char __user *filename) 154 154 { 155 155 int len; 156 - /* 157 - * size is chosen that way we to guarantee that 158 - * p->iname[0] is within the same object and that 159 - * p->name can't be equal to p->iname, no matter what. 160 - */ 161 - const size_t size = offsetof(struct filename, iname[1]); 162 - struct filename *p __free(kfree) = kzalloc(size, GFP_KERNEL); 156 + char *p __free(kfree) = kmalloc(PATH_MAX, GFP_KERNEL); 163 157 if (unlikely(!p)) 164 - return ERR_PTR(-ENOMEM); 158 + return -ENOMEM; 165 159 166 - memmove(old, &old->iname, EMBEDDED_NAME_MAX); 167 - p->name = (char *)old; 168 - len = strncpy_from_user((char *)old + EMBEDDED_NAME_MAX, 160 + memcpy(p, &name->iname, EMBEDDED_NAME_MAX); 161 + len = strncpy_from_user(p + EMBEDDED_NAME_MAX, 169 162 filename + EMBEDDED_NAME_MAX, 170 163 PATH_MAX - EMBEDDED_NAME_MAX); 171 164 if (unlikely(len < 0)) 172 - return ERR_PTR(len); 165 + return len; 173 166 if (unlikely(len == PATH_MAX - EMBEDDED_NAME_MAX)) 174 - return ERR_PTR(-ENAMETOOLONG); 175 - return no_free_ptr(p); 167 + return -ENAMETOOLONG; 168 + name->name = no_free_ptr(p); 169 + return 0; 176 170 } 177 171 178 172 struct filename * ··· 191 199 * Handle both empty path and copy failure in one go. 192 200 */ 193 201 if (unlikely(len <= 0)) { 194 - if (unlikely(len < 0)) { 195 - free_filename(result); 196 - return ERR_PTR(len); 197 - } 198 - 199 202 /* The empty path is special. */ 200 - if (!(flags & LOOKUP_EMPTY)) { 201 - free_filename(result); 202 - return ERR_PTR(-ENOENT); 203 - } 203 + if (!len && !(flags & LOOKUP_EMPTY)) 204 + len = -ENOENT; 204 205 } 205 206 206 207 /* ··· 202 217 * names_cache allocation for the pathname, and re-do the copy from 203 218 * userland. 204 219 */ 205 - if (unlikely(len == EMBEDDED_NAME_MAX)) { 206 - struct filename *p = getname_long(result, filename); 207 - if (IS_ERR(p)) { 208 - free_filename(result); 209 - return p; 210 - } 211 - result = p; 220 + if (unlikely(len == EMBEDDED_NAME_MAX)) 221 + len = getname_long(result, filename); 222 + if (unlikely(len < 0)) { 223 + free_filename(result); 224 + return ERR_PTR(len); 212 225 } 226 + 213 227 initname(result); 214 228 audit_getname(result); 215 229 return result; ··· 244 260 { 245 261 struct filename *result; 246 262 int len = strlen(filename) + 1; 263 + char *p; 264 + 265 + if (unlikely(len > PATH_MAX)) 266 + return ERR_PTR(-ENAMETOOLONG); 247 267 248 268 result = alloc_filename(); 249 269 if (unlikely(!result)) 250 270 return ERR_PTR(-ENOMEM); 251 271 252 272 if (len <= EMBEDDED_NAME_MAX) { 253 - result->name = (char *)result->iname; 254 - } else if (len <= PATH_MAX) { 255 - const size_t size = offsetof(struct filename, iname[1]); 256 - struct filename *tmp; 257 - 258 - tmp = kmalloc(size, GFP_KERNEL); 259 - if (unlikely(!tmp)) { 273 + p = (char *)result->iname; 274 + memcpy(p, filename, len); 275 + } else { 276 + p = kmemdup(filename, len, GFP_KERNEL); 277 + if (unlikely(!p)) { 260 278 free_filename(result); 261 279 return ERR_PTR(-ENOMEM); 262 280 } 263 - tmp->name = (char *)result; 264 - result = tmp; 265 - } else { 266 - free_filename(result); 267 - return ERR_PTR(-ENAMETOOLONG); 268 281 } 269 - memcpy((char *)result->name, filename, len); 282 + result->name = p; 270 283 initname(result); 271 284 audit_getname(result); 272 285 return result; ··· 286 305 return; 287 306 } 288 307 289 - if (unlikely(name->name != name->iname)) { 290 - free_filename((struct filename *)name->name); 291 - kfree(name); 292 - } else 293 - free_filename(name); 308 + if (unlikely(name->name != name->iname)) 309 + kfree(name->name); 310 + free_filename(name); 294 311 } 295 312 EXPORT_SYMBOL(putname); 296 313
+8 -2
include/linux/fs.h
··· 2409 2409 2410 2410 /* fs/open.c */ 2411 2411 struct audit_names; 2412 - struct filename { 2412 + 2413 + struct __filename_head { 2413 2414 const char *name; /* pointer to actual string */ 2414 2415 atomic_t refcnt; 2415 2416 struct audit_names *aname; 2416 - const char iname[]; 2417 + }; 2418 + #define EMBEDDED_NAME_MAX (192 - sizeof(struct __filename_head)) 2419 + struct filename { 2420 + struct __filename_head; 2421 + const char iname[EMBEDDED_NAME_MAX]; 2417 2422 }; 2418 2423 static_assert(offsetof(struct filename, iname) % sizeof(long) == 0); 2424 + static_assert(sizeof(struct filename) % 64 == 0); 2419 2425 2420 2426 static inline struct mnt_idmap *file_mnt_idmap(const struct file *file) 2421 2427 {