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.

d_path: make 'prepend()' fill up the buffer exactly on overflow

Instead of just marking the buffer as having overflowed, fill it up as
much as we can. That will allow the overflow case to then return
whatever truncated result if it wants to.

Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+63 -30
+63 -30
fs/d_path.c
··· 22 22 return ERR_PTR(-ENAMETOOLONG); 23 23 } 24 24 25 - static void prepend(struct prepend_buffer *p, const char *str, int namelen) 25 + static bool prepend_char(struct prepend_buffer *p, unsigned char c) 26 26 { 27 - p->len -= namelen; 28 - if (likely(p->len >= 0)) { 29 - p->buf -= namelen; 30 - memcpy(p->buf, str, namelen); 27 + if (likely(p->len > 0)) { 28 + p->len--; 29 + *--p->buf = c; 30 + return true; 31 31 } 32 + p->len = -1; 33 + return false; 34 + } 35 + 36 + /* 37 + * The source of the prepend data can be an optimistoc load 38 + * of a dentry name and length. And because we don't hold any 39 + * locks, the length and the pointer to the name may not be 40 + * in sync if a concurrent rename happens, and the kernel 41 + * copy might fault as a result. 42 + * 43 + * The end result will correct itself when we check the 44 + * rename sequence count, but we need to be able to handle 45 + * the fault gracefully. 46 + */ 47 + static bool prepend_copy(void *dst, const void *src, int len) 48 + { 49 + if (unlikely(copy_from_kernel_nofault(dst, src, len))) { 50 + memset(dst, 'x', len); 51 + return false; 52 + } 53 + return true; 54 + } 55 + 56 + static bool prepend(struct prepend_buffer *p, const char *str, int namelen) 57 + { 58 + // Already overflowed? 59 + if (p->len < 0) 60 + return false; 61 + 62 + // Will overflow? 63 + if (p->len < namelen) { 64 + // Fill as much as possible from the end of the name 65 + str += namelen - p->len; 66 + p->buf -= p->len; 67 + prepend_copy(p->buf, str, p->len); 68 + p->len = -1; 69 + return false; 70 + } 71 + 72 + // Fits fully 73 + p->len -= namelen; 74 + p->buf -= namelen; 75 + return prepend_copy(p->buf, str, namelen); 32 76 } 33 77 34 78 /** ··· 84 40 * With RCU path tracing, it may race with d_move(). Use READ_ONCE() to 85 41 * make sure that either the old or the new name pointer and length are 86 42 * fetched. However, there may be mismatch between length and pointer. 87 - * The length cannot be trusted, we need to copy it byte-by-byte until 88 - * the length is reached or a null byte is found. It also prepends "/" at 43 + * But since the length cannot be trusted, we need to copy the name very 44 + * carefully when doing the prepend_copy(). It also prepends "/" at 89 45 * the beginning of the name. The sequence number check at the caller will 90 46 * retry it again when a d_move() does happen. So any garbage in the buffer 91 47 * due to mismatched pointer and length will be discarded. 92 48 * 93 - * Load acquire is needed to make sure that we see that terminating NUL. 49 + * Load acquire is needed to make sure that we see the new name data even 50 + * if we might get the length wrong. 94 51 */ 95 52 static bool prepend_name(struct prepend_buffer *p, const struct qstr *name) 96 53 { 97 54 const char *dname = smp_load_acquire(&name->name); /* ^^^ */ 98 55 u32 dlen = READ_ONCE(name->len); 99 - char *s; 100 56 101 - p->len -= dlen + 1; 102 - if (unlikely(p->len < 0)) 103 - return false; 104 - s = p->buf -= dlen + 1; 105 - *s++ = '/'; 106 - while (dlen--) { 107 - char c = *dname++; 108 - if (!c) 109 - break; 110 - *s++ = c; 111 - } 112 - return true; 57 + return prepend(p, dname, dlen) && prepend_char(p, '/'); 113 58 } 114 59 115 60 static int __prepend_path(const struct dentry *dentry, const struct mount *mnt, ··· 191 158 b = *p; 192 159 193 160 if (b.len == p->len) 194 - prepend(&b, "/", 1); 161 + prepend_char(&b, '/'); 195 162 196 163 *p = b; 197 164 return error; ··· 219 186 { 220 187 DECLARE_BUFFER(b, buf, buflen); 221 188 222 - prepend(&b, "", 1); 189 + prepend_char(&b, 0); 223 190 if (unlikely(prepend_path(path, root, &b) > 0)) 224 191 return NULL; 225 192 return extract_string(&b); ··· 231 198 struct path root = {}; 232 199 DECLARE_BUFFER(b, buf, buflen); 233 200 234 - prepend(&b, "", 1); 201 + prepend_char(&b, 0); 235 202 if (unlikely(prepend_path(path, &root, &b) > 1)) 236 203 return ERR_PTR(-EINVAL); 237 204 return extract_string(&b); ··· 288 255 if (unlikely(d_unlinked(path->dentry))) 289 256 prepend(&b, " (deleted)", 11); 290 257 else 291 - prepend(&b, "", 1); 258 + prepend_char(&b, 0); 292 259 prepend_path(path, &root, &b); 293 260 rcu_read_unlock(); 294 261 ··· 323 290 /* these dentries are never renamed, so d_lock is not needed */ 324 291 prepend(&b, " (deleted)", 11); 325 292 prepend(&b, dentry->d_name.name, dentry->d_name.len); 326 - prepend(&b, "/", 1); 293 + prepend_char(&b, '/'); 327 294 return extract_string(&b); 328 295 } 329 296 ··· 357 324 } 358 325 done_seqretry(&rename_lock, seq); 359 326 if (b.len == p->len) 360 - prepend(&b, "/", 1); 327 + prepend_char(&b, '/'); 361 328 return extract_string(&b); 362 329 } 363 330 ··· 365 332 { 366 333 DECLARE_BUFFER(b, buf, buflen); 367 334 368 - prepend(&b, "", 1); 335 + prepend_char(&b, 0); 369 336 return __dentry_path(dentry, &b); 370 337 } 371 338 EXPORT_SYMBOL(dentry_path_raw); ··· 377 344 if (unlikely(d_unlinked(dentry))) 378 345 prepend(&b, "//deleted", 10); 379 346 else 380 - prepend(&b, "", 1); 347 + prepend_char(&b, 0); 381 348 return __dentry_path(dentry, &b); 382 349 } 383 350 ··· 430 397 unsigned len; 431 398 DECLARE_BUFFER(b, page, PATH_MAX); 432 399 433 - prepend(&b, "", 1); 400 + prepend_char(&b, 0); 434 401 if (unlikely(prepend_path(&pwd, &root, &b) > 0)) 435 402 prepend(&b, "(unreachable)", 13); 436 403 rcu_read_unlock();