blob: 8868b4244bf13594e16bc64353491a516da4c3a2 [file] [log] [blame] [raw]
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)