CVE-2016-4913 The get_rock_ridge_filename function in fs/isofs/rock.c in the Linux kernel before 4.5.5 mishandles


SUBMITTED BY: parthenos

DATE: May 27, 2016, 10:44 a.m.

FORMAT: Text only

SIZE: 2.0 kB

HITS: 504017

  1. get_rock_ridge_filename(): handle malformed NM entries
  2. Payloads of NM entries are not supposed to contain NUL. When we run
  3. into such, only the part prior to the first NUL goes into the
  4. concatenation (i.e. the directory entry name being encoded by a bunch
  5. of NM entries). We do stop when the amount collected so far + the
  6. claimed amount in the current NM entry exceed 254. So far, so good,
  7. but what we return as the total length is the sum of *claimed*
  8. sizes, not the actual amount collected. And that can grow pretty
  9. large - not unlimited, since you'd need to put CE entries in
  10. between to be able to get more than the maximum that could be
  11. contained in one isofs directory entry / continuation chunk and
  12. we are stop once we'd encountered 32 CEs, but you can get about 8Kb
  13. easily. And that's what will be passed to readdir callback as the
  14. name length. 8Kb __copy_to_user() from a buffer allocated by
  15. __get_free_page()
  16. Cc: stable@vger.kernel.org # 0.98pl6+ (yes, really)
  17. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  18. Diffstat
  19. -rw-r--r-- fs/isofs/rock.c 13
  20. 1 files changed, 10 insertions, 3 deletions
  21. diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
  22. index 5384ceb..98b3eb7 100644
  23. --- a/fs/isofs/rock.c
  24. +++ b/fs/isofs/rock.c
  25. @@ -203,6 +203,8 @@ int get_rock_ridge_filename(struct iso_directory_record *de,
  26. int retnamlen = 0;
  27. int truncate = 0;
  28. int ret = 0;
  29. + char *p;
  30. + int len;
  31. if (!ISOFS_SB(inode->i_sb)->s_rock)
  32. return 0;
  33. @@ -267,12 +269,17 @@ repeat:
  34. rr->u.NM.flags);
  35. break;
  36. }
  37. - if ((strlen(retname) + rr->len - 5) >= 254) {
  38. + len = rr->len - 5;
  39. + if (retnamlen + len >= 254) {
  40. truncate = 1;
  41. break;
  42. }
  43. - strncat(retname, rr->u.NM.name, rr->len - 5);
  44. - retnamlen += rr->len - 5;
  45. + p = memchr(rr->u.NM.name, '\0', len);
  46. + if (unlikely(p))
  47. + len = p - rr->u.NM.name;
  48. + memcpy(retname + retnamlen, rr->u.NM.name, len);
  49. + retnamlen += len;
  50. + retname[retnamlen] = '\0';
  51. break;
  52. case SIG('R', 'E'):
  53. kfree(rs.buffer);

comments powered by Disqus