tools/bootconfig: Align the bootconfig applied initrd
Subsystems (2)
Masami Hiramatsu
maintainerv2 cover tools/bootconfig: Align the bootconfig applied initrd
Hi,
This is the 2nd version of the bootconfig tool update to align the total size of initrd + bootconfig to 4.
In this version, I've fixed to count the footer size into the total file size.
To adjust the file size, the bootconfig tool adds padding null characters in between the boot configuration data and the footer.
This series include Documentation update. The changing points are
- The bootconfig applied initrd image size is aligned to 4.
- To insert the padding null ('\0') bytes, the size in the footer can be bigger than the actual bootconfig file size.
- But the max size of the boot configuration file is same, because the max size doesn't include the last null characters.
For this version I decided to keep 4 bytes aligned rather than longer size. It will be easy to expand it to e.g. 32 bytes (in this series, we just need to update 3 locations of the code), but I couldn't find any reason to expand it. Only I could found was that the grub can align the filesize to 4, and U-Boot/EDK2 will not change it. So I couldn't say what is the best size.
Anyway, I updated the documentation too, which clearly says that the above changing points, and if the bootloader pass the wrong size, kernel will not find bootconfig from the initrd.
Thank you,
---
Masami Hiramatsu (2):
tools/bootconfig: Align the bootconfig applied initrd image size to 4
Documentation: bootconfig: Update file format on initrd image
tools/bootconfig/main.c | 36 ++++++++++++++++++++++++++++++----- tools/bootconfig/test-bootconfig.sh | 6 +++++- 2 files changed, 36 insertions(+), 6 deletions(-)
--
Masami Hiramatsu (Linaro) <[email protected]>
Masami Hiramatsu
maintainerPATCH v2 1/2 tools/bootconfig: Align the bootconfig applied initrd image size to 4
Align the bootconfig applied initrd image size to 4. To pad the data, bootconfig will use space (0x20) in front of the bootconfig data, and expands its size and update checksum.
---
Changes in v2:
- Fix to add the footer size.
--- tools/bootconfig/main.c | 36 ++++++++++++++++++++++++++++++----- tools/bootconfig/test-bootconfig.sh | 6 +++++- 2 files changed, 36 insertions(+), 6 deletions(-)
include/linux/bootconfig.h +1 -0
@@ -12,6 +12,7 @@#define BOOTCONFIG_MAGIC "#BOOTCONFIG\n"#define BOOTCONFIG_MAGIC_LEN 12 +#define BOOTCONFIG_ALIGN 4/* XBC tree node */ struct xbc_node {
tools/bootconfig/main.c +31 -5
@@ -332,11 +332,14 @@ static int delete_xbc(const char *path)static int apply_xbc (const char *path,const char *xbc_path) { +const char padbuf[BOOTCONFIG_ALIGN ] = {0 }; +size_t total_size;u32 size, csum;char *buf, *data;int ret, fd;const char *msg; -int pos; +struct stat st; +int pos, pad; ret =load_xbc_file (xbc_path, &buf);if (ret <0 ) {
@@ -347,12 +350,10 @@ static int apply_xbc(const char *path, const char *xbc_path) csum =checksum ((unsigned char *)buf, size);/* Prepare xbc_path data */ - data =malloc (size +8 ); + data =malloc (size);if (!data)return -ENOMEM ;strcpy (data, buf); - *(u32 *)(data + size) = size; - *(u32 *)(data + size +4 ) = csum;/* Check the data format */ ret =xbc_init (buf, &msg, &pos);
@@ -387,12 +388,37 @@ static int apply_xbc(const char *path, const char *xbc_path)free (data);return fd; } + +/* To algin up the total size to BOOTCONFIG_ALIGN, get padding size */ + ret =fstat (fd, &st); +if (ret <0 ) { +pr_err ("Failed to get the stat of %s\n" , path); +free (data); +return ret; + } + total_size = st.st_size + size +sizeof (u32) +sizeof (u32) + +BOOTCONFIG_MAGIC_LEN ; + pad =BOOTCONFIG_ALIGN - total_size %BOOTCONFIG_ALIGN ; +/* TODO: Ensure the @path is initramfs/initrd image */ - ret =write (fd, data, size +8 ); + ret =write (fd, data, size);if (ret <0 ) {pr_err ("Failed to apply a boot config: %d\n" , ret); goto out; } + +if (pad !=BOOTCONFIG_ALIGN ) { +/* Write padding null characters */ + ret =write (fd, padbuf, pad); +if (ret <0 ) { +pr_err ("Failed to write padding: %d\n" , ret); + goto out; + } + size += pad; + } + ret =write (fd, &size,sizeof (u32)); + ret =write (fd, &csum,sizeof (u32)); +/* Write a magic word of the bootconfig */ ret =write (fd,BOOTCONFIG_MAGIC ,BOOTCONFIG_MAGIC_LEN );if (ret <0 ) {
tools/bootconfig/test-bootconfig.sh +5 -1
@@ -9,6 +9,7 @@ else TESTDIR=. fi BOOTCONF=${TESTDIR}/bootconfig +ALIGN=4 INITRD=`mktemp ${TESTDIR}/initrd-XXXX` TEMPCONF=`mktemp ${TESTDIR}/temp-XXXX.bconf`
@@ -59,7 +60,10 @@ echo "Show command test" xpass $BOOTCONF $INITRD echo "File size check" -xpass test $new_size -eq $(expr $bconf_size + $initrd_size + 9 + 12) +total_size=$(expr $bconf_size + $initrd_size + 9 + 12 + $ALIGN - 1 ) +total_size=$(expr $total_size / $ALIGN) +total_size=$(expr $total_size \* $ALIGN) +xpass test $new_size -eq $total_size echo "Apply command repeat test" xpass $BOOTCONF -a $TEMPCONF $INITRD
Re: [PATCH v2 1/2] tools/bootconfig: Align the bootconfig applied initrd image size to 4
tools/bootconfig/main.c static int apply_xbc(const char *path, const char *xbc_path) · line 406
Quoted 6 lines · Masami Hiramatsu
/* TODO: Ensure the @path is initramfs/initrd image */tools/bootconfig/main.c +1
-1- ret =write (fd, data, size +8 ); + ret =write (fd, data, size);if (ret <0 ) {pr_err ("Failed to apply a boot config: %d\n" , ret);
Side note: that's not the right error check for a write() call.
The problem predates your patch, so it's independent, I just noticed as I looked at it.
The right error check is
if (ret != size) {because partial writes can happen even with regular files (yeah, it's not POSIX, but NFS is a thing).
And the filesystem filling up is a possibility too, of course.
Quoted 3 lines
tools/bootconfig/main.c +3
-0+/* Write padding null characters */ + ret =write (fd, padbuf, pad); +if (ret <0 ) {
...
tools/bootconfig/main.c static int apply_xbc(const char *path, const char *xbc_path) · line 420
Quoted 2 lines
tools/bootconfig/main.c +2
-0+ ret =write (fd, &size,sizeof (u32)); + ret =write (fd, &csum,sizeof (u32));
Those two guys don't check at all...
Quoted 3 lines
/* Write a magic word of the bootconfig */
ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN);
if (ret < 0) {.. and same comment.
Anyway, I'm not sure this is worth worrying about - even on NFS the partial IO thing is basically non-existent.
But the filesystem full (or file size limit, or whatever) case is real even on POSIX filesystems, and testing for write errors by checking for a negative return is simply incorrect.
Partial writes are an issue (although the _next_ write will then return an error, so you have to be unlucky to hit that partial write on the very last write() that you do and that you test the return value incorrectly).
The fact that it works in all normal circumstances just means that these kinds of bugs tend to stay around, until somebody is really unlocky and then you have inexplicably corrupt files..
Linus
Masami Hiramatsu
maintainerRe: [PATCH v2 1/2] tools/bootconfig: Align the bootconfig applied initrd image size to 4
Quoted 13 lines · On Mon, 16 Nov 2020 10:29:45 -0800 Linus Torvalds…
tools/bootconfig/main.c static int apply_xbc(const char *path, const char *xbc_path) · line 406
Quoted 6 lines · Masami Hiramatsu
/* TODO: Ensure the @path is initramfs/initrd image */tools/bootconfig/main.c +1
-1- ret =write (fd, data, size +8 ); + ret =write (fd, data, size);if (ret <0 ) {pr_err ("Failed to apply a boot config: %d\n" , ret);Side note: that's not the right error check for a
write()call.The problem predates your patch, so it's independent, I just noticed as I looked at it.
Quoted 8 lines
The right error check is
if (ret != size) {because partial writes can happen even with regular files (yeah, it's not POSIX, but NFS is a thing).
And the filesystem filling up is a possibility too, of course.
Yes, and I also found the error message used return code, but it must use errno...
Quoted 9 lines
Quoted 4 lines
tools/bootconfig/main.c +3
-0+/* Write padding null characters */ + ret =write (fd, padbuf, pad); +if (ret <0 ) {...
tools/bootconfig/main.c static int apply_xbc(const char *path, const char *xbc_path) · line 420
Quoted 2 lines
tools/bootconfig/main.c +2
-0+ ret =write (fd, &size,sizeof (u32)); + ret =write (fd, &csum,sizeof (u32));Those two guys don't check at all...
Oops, OK, fix it.
Quoted 14 lines
Quoted 4 lines
/* Write a magic word of the bootconfig */ ret = write(fd, BOOTCONFIG_MAGIC, BOOTCONFIG_MAGIC_LEN); if (ret < 0) {.. and same comment.
Anyway, I'm not sure this is worth worrying about - even on NFS the partial IO thing is basically non-existent.
But the filesystem full (or file size limit, or whatever) case is real even on POSIX filesystems, and testing for write errors by checking for a negative return is simply incorrect.
Quoted 8 lines
Partial writes are an issue (although the _next_ write will then return an error, so you have to be unlucky to hit that partial write on the very last
write()that you do and that you test the return value incorrectly).The fact that it works in all normal circumstances just means that these kinds of bugs tend to stay around, until somebody is really unlocky and then you have inexplicably corrupt files..
Agreed. If I hit the partial write, I need to roll it back. Or bootconfig command can not find the magic word and initrd image may just increase the size with the garbage data.
Thank you!
Signature · 1 line
Masami Hiramatsu <[email protected]>
Masami Hiramatsu
maintainerPATCH v2 2/2 Documentation: bootconfig: Update file format on initrd image
In reply to Masami HiramatsuTo align the total file size, add padding null character when appending the bootconfig to initrd image.
---
0 files changed
Documentation/admin-guide/bootconfig.rst +13 -5
@@ -137,15 +137,22 @@ Boot Kernel With a Boot Config ============================== Since the boot configuration file is loaded with initrd, it will be added -to the end of the initrd (initramfs) image file with size, checksum and -12-byte magic word as below. +to the end of the initrd (initramfs) image file with padding, size, +checksum and 12-byte magic word as below. -[initrd][bootconfig][size(u32)][checksum(u32)][#BOOTCONFIG\n] +[initrd][bootconfig][padding][size(u32)][checksum(u32)][#BOOTCONFIG\n] + +When the boot configuration is added to the initrd image, the total +file size is aligned to 4 bytes. To fill the gap, null characters +(``\0``) will be added. Thus the ``size`` is the length of the bootconfig +file + padding bytes. The Linux kernel decodes the last part of the initrd image in memory to get the boot configuration data. Because of this "piggyback" method, there is no need to change or -update the boot loader and the kernel image itself. +update the boot loader and the kernel image itself as long as the boot +loader passes the correct initrd file size. If by any chance, the boot +loader passes a longer size, the kernel feils to find the bootconfig data. To do this operation, Linux kernel provides "bootconfig" command under tools/bootconfig, which allows admin to apply or delete the config file
@@ -176,7 +183,8 @@ up to 512 key-value pairs. If keys contains 3 words in average, it can contain 256 key-value pairs. In most cases, the number of config items will be under 100 entries and smaller than 8KB, so it would be enough. If the node number exceeds 1024, parser returns an error even if the file -size is smaller than 32KB. +size is smaller than 32KB. (Note that this maximum size is not including +the padding null characters.) Anyway, since bootconfig command verifies it when appending a boot config to initrd image, user can notice it before boot.