Skip to content

Commit f43461a

Browse files
jjm2473lcp
andauthored
loader/linux: Ensure the newc pathname is NULL-terminated (#3082)
Per "man 5 cpio", the namesize in the cpio header includes the trailing NUL byte of the pathname and the pathname is followed by NUL bytes, but the current implementation ignores the trailing NUL byte when making the newc header. Although make_header() tries to pad the pathname string, the padding won't happen when strlen(name) + sizeof(struct newc_head) is a multiple of 4, and the non-NULL-terminated pathname may lead to unexpected results. Assume that a file is created with 'echo -n aaaa > /boot/test12' and loaded by grub2: linux /boot/vmlinuz initrd newc:test12:/boot/test12 /boot/initrd The initrd command eventually invoked grub_initrd_load() and sent 't''e''s''t''1''2' to make_header() to generate the header: 00000070 30 37 30 37 30 31 33 30 31 43 41 30 44 45 30 30 |070701301CA0DE00| 00000080 30 30 38 31 41 34 30 30 30 30 30 33 45 38 30 30 |0081A4000003E800| 00000090 30 30 30 30 36 34 30 30 30 30 30 30 30 31 36 33 |0000640000000163| 000000a0 37 36 45 34 35 32 30 30 30 30 30 30 30 34 30 30 |76E4520000000400| 000000b0 30 30 30 30 30 38 30 30 30 30 30 30 31 33 30 30 |0000080000001300| 000000c0 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000| 000000d0 30 30 30 30 30 36 30 30 30 30 30 30 30 30 74 65 |00000600000000te| ^namesize 000000e0 73 74 31 32 61 61 61 61 30 37 30 37 30 31 30 30 |st12aaaa07070100| ^^ end of the pathname Since strlen("test12") + sizeof(struct newc_head) is 116 = 29 * 4, make_header() didn't pad the pathname, and the file content followed "test12" immediately. This violates the cpio format and may trigger such error during linux boot: Initramfs unpacking failed: ZSTD-compressed data is trunc To avoid the potential problems, this commit counts the trailing NUL byte in when calling make_header() and adjusts the initrd size accordingly. Now the header becomes 00000070 30 37 30 37 30 31 33 30 31 43 41 30 44 45 30 30 |070701301CA0DE00| 00000080 30 30 38 31 41 34 30 30 30 30 30 33 45 38 30 30 |0081A4000003E800| 00000090 30 30 30 30 36 34 30 30 30 30 30 30 30 31 36 33 |0000640000000163| 000000a0 37 36 45 34 35 32 30 30 30 30 30 30 30 34 30 30 |76E4520000000400| 000000b0 30 30 30 30 30 38 30 30 30 30 30 30 31 33 30 30 |0000080000001300| 000000c0 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000| 000000d0 30 30 30 30 30 37 30 30 30 30 30 30 30 30 74 65 |00000700000000te| ^namesize 000000e0 73 74 31 32 00 00 00 00 61 61 61 61 30 37 30 37 |st12....aaaa0707| ^^ end of the pathname Besides the trailing NUL byte, make_header() pads 3 more NUL bytes, and the user can safely read the pathname without a further check. To conform to the cpio format, the headers for "TRAILER!!!" are also adjusted to include the trailing NUL byte, not ignore it. Reviewed-by: Daniel Kiper <[email protected]> Signed-off-by: Gary Lin <[email protected]> Co-authored-by: Gary Lin <[email protected]>
1 parent 377e3fb commit f43461a

File tree

1 file changed

+19
-8
lines changed
  • GRUB2/MOD_SRC/grub-2.04/grub-core/loader

1 file changed

+19
-8
lines changed

GRUB2/MOD_SRC/grub-2.04/grub-core/loader/linux.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,22 @@ insert_dir (const char *name, struct dir **root,
128128
n->name = grub_strndup (cb, ce - cb);
129129
if (ptr)
130130
{
131+
/*
132+
* Create the substring with the trailing NUL byte
133+
* to be included in the cpio header.
134+
*/
135+
char *tmp_name = grub_strndup (name, ce - name);
136+
if (!tmp_name) {
137+
grub_free (n->name);
138+
grub_free (n);
139+
return grub_errno;
140+
}
131141
grub_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
132-
ptr = make_header (ptr, name, ce - name,
142+
ptr = make_header (ptr, tmp_name, ce - name + 1,
133143
040777, 0);
144+
grub_free (tmp_name);
134145
}
135-
size += ALIGN_UP ((ce - (char *) name)
146+
size += ALIGN_UP ((ce - (char *) name + 1)
136147
+ sizeof (struct newc_head), 4);
137148
*head = n;
138149
cur = n;
@@ -183,7 +194,7 @@ grub_initrd_init (int argc, char *argv[],
183194
}
184195
initrd_ctx->size
185196
+= ALIGN_UP (sizeof (struct newc_head)
186-
+ grub_strlen (initrd_ctx->components[i].newc_name),
197+
+ grub_strlen (initrd_ctx->components[i].newc_name) + 1,
187198
4);
188199
initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
189200
&root, 0);
@@ -194,7 +205,7 @@ grub_initrd_init (int argc, char *argv[],
194205
else if (newc)
195206
{
196207
initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
197-
+ sizeof ("TRAILER!!!") - 1, 4);
208+
+ sizeof ("TRAILER!!!"), 4);
198209
free_dir (root);
199210
root = 0;
200211
newc = 0;
@@ -217,7 +228,7 @@ grub_initrd_init (int argc, char *argv[],
217228
{
218229
initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
219230
initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
220-
+ sizeof ("TRAILER!!!") - 1, 4);
231+
+ sizeof ("TRAILER!!!"), 4);
221232
free_dir (root);
222233
root = 0;
223234
}
@@ -269,14 +280,14 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
269280
ptr += insert_dir (initrd_ctx->components[i].newc_name,
270281
&root, ptr);
271282
ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
272-
grub_strlen (initrd_ctx->components[i].newc_name),
283+
grub_strlen (initrd_ctx->components[i].newc_name) + 1,
273284
0100777,
274285
initrd_ctx->components[i].size);
275286
newc = 1;
276287
}
277288
else if (newc)
278289
{
279-
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
290+
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"),
280291
0, 0);
281292
free_dir (root);
282293
root = 0;
@@ -308,7 +319,7 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
308319
{
309320
grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
310321
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
311-
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
322+
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!"), 0, 0);
312323
}
313324
free_dir (root);
314325
root = 0;

0 commit comments

Comments
 (0)