On Thu, 2026-07-16 at 16:20 +0800, [email protected] wrote:
> From: Kou Wenqi <[email protected]>
>
> When the -p delimiter is long enough to make the formatted partition
> name exceed PARTNAME_SIZE (128 bytes), three issues occur:
>
> 1. format_partname() fails but snprintf has already written a
> truncated
> name into the buffer. dm_find_part() returns 0 and the caller
> proceeds to dm_addmap() with the truncated name, creating a device
> that was never intended.
>
> 2. dm_find_part() returns early without setting *part_uuid. The
> uninitialized local variable part_uuid then gets passed to
> check_uuid() -> strchr(), causing a SIGSEGV.
>
> 3. The callers cannot distinguish between "partition not found,
> create
> new" and "name construction failed" since both return 0.
>
> Fix by:
> - Having dm_find_part() return -1 when format_partname() fails, with
> an error message printed by dm_find_part() itself, so that callers
> can test the return value directly (negative for error,
> 0 for not found, positive for found)
> - In the ADD/UPDATE loops (both main and container), checking the
> return value: negative means name too long (skip with error count),
> 0 means not found (create), positive means found (reload)
> - In the DELETE loop, only proceeding with removal when
> dm_find_part()
> returns positive (partition found), skipping when it returns zero
> (not found) or negative (error)
> - Initializing part_uuid to NULL in all three partition loop bodies
> (ADD/UPDATE main loop, container partition loop, DELETE loop) so
> that the "if (part_uuid && uuid)" guard correctly skips the UUID
> check when dm_find_part() returns early
>
> Reproduce steps:
>
> # Create test image
> dd if=/dev/zero of=/tmp/vhlg-test.img bs=1M count=10
> parted /tmp/vhlg-test.img mklabel msdos
> parted /tmp/vhlg-test.img mkpart primary ext4 1MiB 5MiB
>
> # Reproduce
> kpartx -a -p $(python3 -c "print('A'*200)") /tmp/vhlg-test.img
>
> # Cleanup
> kpartx -d /tmp/vhlg-test.img
> rm -f /tmp/vhlg-test.img
>
> Signed-off-by: Kou Wenqi <[email protected]>
> ---
> kpartx/devmapper.c | 5 ++---
> kpartx/kpartx.c | 46 ++++++++++++++++++++++++++++++--------------
> --
> 2 files changed, 32 insertions(+), 19 deletions(-)
>
Thanks again. This looks quite good. However, what about this?
enum {
DFP_DEVICE_CREATE = DM_DEVICE_CREATE,
DFP_DEVICE_RELOAD = DM_DEVICE_RELOAD,
DFP_ERR = -1,
};
Then use values of this enum as return values of dm_find_part().
If it returns DFP_ERR, bail out; otherwise use the return value as
"op", like this:
if ((op = dm_find_part(...)) == DFP_ERR)
continue;
If you want to be extra careful, you could add something like
this at the beginning of dm_find_part():
BUILD_BUG_ON(DM_DEVICE_CREATE < 0 || DM_DEVICE_RELOAD < 0);
But I think we can trust that these values will always be positive.
Martin