Skip to content

Commit 225034c

Browse files
ddissbrauner
authored andcommitted
initramfs: fix hardlink hash leak without TRAILER
Covered in Documentation/driver-api/early-userspace/buffer-format.rst , initramfs archives can carry an optional "TRAILER!!!" entry which serves as a boundary for collecting and associating hardlinks with matching inode and major / minor device numbers. Although optional, if hardlinks are found in an archive without a subsequent "TRAILER!!!" entry then the hardlink state hash table is leaked, e.g. unfixed kernel, with initramfs_test.c hunk applied only: unreferenced object 0xffff9405408cc000 (size 8192): comm "kunit_try_catch", pid 53, jiffies 4294892519 hex dump (first 32 bytes): 01 00 00 00 01 00 00 00 00 00 00 00 ff 81 00 00 ................ 00 00 00 00 00 00 00 00 69 6e 69 74 72 61 6d 66 ........initramf backtrace (crc a9fb0ee0): [<0000000066739faa>] __kmalloc_cache_noprof+0x11d/0x250 [<00000000fc755219>] maybe_link.part.5+0xbc/0x120 [<000000000526a128>] do_name+0xce/0x2f0 [<00000000145c1048>] write_buffer+0x22/0x40 [<000000003f0b4f32>] unpack_to_rootfs+0xf9/0x2a0 [<00000000d6f7e5af>] initramfs_test_hardlink+0xe3/0x3f0 [<0000000014fde8d6>] kunit_try_run_case+0x5f/0x130 [<00000000dc9dafc5>] kunit_generic_run_threadfn_adapter+0x18/0x30 [<000000001076c239>] kthread+0xc8/0x100 [<00000000d939f1c1>] ret_from_fork+0x2b/0x40 [<00000000f848ad1a>] ret_from_fork_asm+0x1a/0x30 Fix this by calling free_hash() after initramfs buffer processing in unpack_to_rootfs(). An extra hardlink_seen global is added as an optimization to avoid walking the 32 entry hash array unnecessarily. The expectation is that a "TRAILER!!!" entry will normally be present, and initramfs hardlinks are uncommon. There is one user facing side-effect of this fix: hardlinks can currently be associated across built-in and external initramfs archives, *if* the built-in initramfs archive lacks a "TRAILER!!!" terminator. I'd consider this cross-archive association broken, but perhaps it's used. Signed-off-by: David Disseldorp <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
1 parent 43094e1 commit 225034c

File tree

1 file changed

+6
-1
lines changed

1 file changed

+6
-1
lines changed

init/initramfs.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static __initdata struct hash {
7676
struct hash *next;
7777
char name[N_ALIGN(PATH_MAX)];
7878
} *head[32];
79+
static __initdata bool hardlink_seen;
7980

8081
static inline int hash(int major, int minor, int ino)
8182
{
@@ -109,19 +110,21 @@ static char __init *find_link(int major, int minor, int ino,
109110
strcpy(q->name, name);
110111
q->next = NULL;
111112
*p = q;
113+
hardlink_seen = true;
112114
return NULL;
113115
}
114116

115117
static void __init free_hash(void)
116118
{
117119
struct hash **p, *q;
118-
for (p = head; p < head + 32; p++) {
120+
for (p = head; hardlink_seen && p < head + 32; p++) {
119121
while (*p) {
120122
q = *p;
121123
*p = q->next;
122124
kfree(q);
123125
}
124126
}
127+
hardlink_seen = false;
125128
}
126129

127130
#ifdef CONFIG_INITRAMFS_PRESERVE_MTIME
@@ -564,6 +567,8 @@ char * __init unpack_to_rootfs(char *buf, unsigned long len)
564567
len -= my_inptr;
565568
}
566569
dir_utime();
570+
/* free any hardlink state collected without optional TRAILER!!! */
571+
free_hash();
567572
kfree(bufs);
568573
return message;
569574
}

0 commit comments

Comments
 (0)