| Avoid leaking kernel stack when creating directory names. |
| Backported from FreeBSD base r347475 (MFC r347066). |
| |
| diff -ru --exclude-from freebsd-src-diff-exclude-names /var/archive3/public/freebsd-releng-10.4-src/sys/ufs/ufs/dir.h freebsd-10.4/sys/ufs/ufs/dir.h |
| --- /var/archive3/public/freebsd-releng-10.4-src/sys/ufs/ufs/dir.h 2017-09-29 08:20:02.000000000 +0800 |
| +++ freebsd-10.4/sys/ufs/ufs/dir.h 2019-11-07 11:46:43.667252000 +0800 |
| @@ -109,9 +109,9 @@ |
| * |
| * |
| */ |
| -#define DIRECTSIZ(namlen) \ |
| - (((uintptr_t)&((struct direct *)0)->d_name + \ |
| - ((namlen)+1)*sizeof(((struct direct *)0)->d_name[0]) + 3) & ~3) |
| +#define UFS_DIR_ROUNDUP 4 /* Directory name roundup size */ |
| +#define DIRECTSIZ(namlen) \ |
| + (roundup2(offsetof(struct direct, d_name) + (namlen) + 1, UFS_DIR_ROUNDUP)) |
| #if (BYTE_ORDER == LITTLE_ENDIAN) |
| #define DIRSIZ(oldfmt, dp) \ |
| ((oldfmt) ? DIRECTSIZ((dp)->d_type) : DIRECTSIZ((dp)->d_namlen)) |
| diff -ru --exclude-from freebsd-src-diff-exclude-names /var/archive3/public/freebsd-releng-10.4-src/sys/ufs/ufs/ufs_lookup.c freebsd-10.4/sys/ufs/ufs/ufs_lookup.c |
| --- /var/archive3/public/freebsd-releng-10.4-src/sys/ufs/ufs/ufs_lookup.c 2017-09-29 08:20:02.000000000 +0800 |
| +++ freebsd-10.4/sys/ufs/ufs/ufs_lookup.c 2019-11-07 11:49:15.177407000 +0800 |
| @@ -823,14 +823,21 @@ |
| struct componentname *cnp; |
| struct direct *newdirp; |
| { |
| + u_int namelen; |
| |
| -#ifdef INVARIANTS |
| - if ((cnp->cn_flags & SAVENAME) == 0) |
| - panic("ufs_makedirentry: missing name"); |
| -#endif |
| + namelen = (unsigned)cnp->cn_namelen; |
| + KASSERT((cnp->cn_flags & SAVENAME) != 0, |
| + ("ufs_makedirentry: missing name")); |
| + KASSERT(namelen <= MAXNAMLEN, |
| + ("ufs_makedirentry: name too long")); |
| newdirp->d_ino = ip->i_number; |
| - newdirp->d_namlen = cnp->cn_namelen; |
| - bcopy(cnp->cn_nameptr, newdirp->d_name, (unsigned)cnp->cn_namelen + 1); |
| + newdirp->d_namlen = namelen; |
| + |
| + /* Zero out after-name padding */ |
| + *(u_int32_t *)(&newdirp->d_name[namelen & ~(UFS_DIR_ROUNDUP - 1)]) = 0; |
| + |
| + bcopy(cnp->cn_nameptr, newdirp->d_name, namelen); |
| + |
| if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) |
| newdirp->d_type = IFTODT(ip->i_mode); |
| else { |
| @@ -1208,16 +1215,21 @@ |
| if (ip && rep->d_ino != ip->i_number) |
| panic("ufs_dirremove: ip %ju does not match dirent ino %ju\n", |
| (uintmax_t)ip->i_number, (uintmax_t)rep->d_ino); |
| - if (dp->i_count == 0) { |
| - /* |
| - * First entry in block: set d_ino to zero. |
| - */ |
| - ep->d_ino = 0; |
| - } else { |
| + /* |
| + * Zero out the file directory entry metadata to reduce disk |
| + * scavenging disclosure. |
| + */ |
| + bzero(&rep->d_name[0], rep->d_namlen); |
| + rep->d_namlen = 0; |
| + rep->d_type = 0; |
| + rep->d_ino = 0; |
| + |
| + if (dp->i_count != 0) { |
| /* |
| * Collapse new free space into previous entry. |
| */ |
| ep->d_reclen += rep->d_reclen; |
| + rep->d_reclen = 0; |
| } |
| #ifdef UFS_DIRHASH |
| if (dp->i_dirhash != NULL) |