已合并
修复kpartx -p coredump问题 #325
已合并
kouwq创建于 7月23日
5 个文件变更+321-4
@@ -0,0 +1,37 @@
1+From f474bdf9d016e580baea54f1c3d7282b6623ffdd Mon Sep 17 00:00:00 2001
2+From: Martin Wilck <mwilck@suse.com>
3+Date: Fri, 17 Jul 2026 12:05:31 +0200
4+Subject: [PATCH] test-kpartx: add test for over-long partition separator
5+ 
6+kpartx can crash if an over-long partition separator is used.
7+Add a test case for that. This test case will fail without
8+the subsequent commit.
9+ 
10+Signed-off-by: Martin Wilck <mwilck@suse.com>
11+---
12+ kpartx/test-kpartx | 11 +++++++++++
13+ 1 file changed, 11 insertions(+)
14+ 
15+diff --git a/kpartx/test-kpartx b/kpartx/test-kpartx
16+index d3c9aef..125aa69 100755
17+--- a/kpartx/test-kpartx
18++++ b/kpartx/test-kpartx
19+@@ -332,4 +332,15 @@ $KPARTX -d $KPARTX_OPTS $FILE4
20+ # /dev/$loop is _not_ automatically deleted
21+ [[ -b /dev/${loop} ]]
22+
23++step "test kpartx creation with very long partition separator"
24++# Overlong, invalid partition separator
25++LONG_SEP="part---01.part---02.part---03.part---04.part---05.part---06.part---07.part---08.part---09.part---10.part---11.part---12.part---13.part---14.part---15.part---16.part---17.part---18.part---19.part---20."
26++ERR=0
27++# This kpartx command should return with error 1 (for a single partitition!)
28++# and print the error message below.
29++# Without the fix for overlong partition separator, kpartx crashes.
30++$KPARTX -a -p "$LONG_SEP" "$LO1" 2>"$WORKDIR/long_sep.out" || ERR=$?
31++[[ $ERR = 1 ]]
32++grep -q 'partition name too long for partition 1' "$WORKDIR/long_sep.out"
33++
34+ OK=yes
35+--
36+2.43.0
37+ 
@@ -0,0 +1,225 @@
1+From 030710318a9d991724cdb908c8519702cd9cbc35 Mon Sep 17 00:00:00 2001
2+From: Kou Wenqi <kouwenqi@kylinos.cn>
3+Date: Fri, 17 Jul 2026 11:34:43 +0800
4+Subject: [PATCH] kpartx: fix crash and truncated device creation with long -p
5+ delimiter
6+ 
7+When the -p delimiter is long enough to make the formatted partition
8+name exceed PARTNAME_SIZE (128 bytes), three issues occur:
9+ 
10+1. format_partname() fails but snprintf has already written a truncated
11+ name into the buffer. dm_find_part() returns 0 and the caller
12+ proceeds to dm_addmap() with the truncated name, creating a device
13+ that was never intended.
14+ 
15+2. dm_find_part() returns early without setting *part_uuid. The
16+ uninitialized local variable part_uuid then gets passed to
17+ check_uuid() -> strchr(), causing a SIGSEGV.
18+ 
19+3. The callers cannot distinguish between 'partition not found, create
20+ new' and 'name construction failed' since both return 0.
21+ 
22+Fix by:
23+- Having dm_find_part() return DFP_ERR when format_partname() fails,
24+ with an error message printed by dm_find_part() itself
25+- Defining an enum to represent the return values of dm_find_part():
26+ 
27+ enum {
28+ DFP_DEVICE_CREATE = DM_DEVICE_CREATE,
29+ DFP_DEVICE_RELOAD = DM_DEVICE_RELOAD,
30+ DFP_ERR = -1
31+ };
32+ 
33+ This enum is placed in kpartx/devmapper.h, which now also includes
34+ <libdevmapper.h> directly to make the header self-contained.
35+ dm_find_part() uses these enum values explicitly in all return
36+ statements.
37+- In the ADD/UPDATE loops (both main and container), assigning the
38+ return value directly to 'op' and checking for DFP_ERR to handle
39+ errors
40+- In the DELETE loop, checking the return value against
41+ DFP_DEVICE_RELOAD to proceed with removal, skipping on error or
42+ not-found
43+- Initializing part_uuid to NULL in all three partition loop bodies
44+ (ADD/UPDATE main loop, container partition loop, DELETE loop) so
45+ that the 'if (part_uuid && uuid)' guard correctly skips the UUID
46+ check when dm_find_part() returns early
47+ 
48+Reproduce steps (now also in the test-kpartx script):
49+ 
50+ # Create test image
51+ dd if=/dev/zero of=/tmp/vhlg-test.img bs=1M count=10
52+ parted /tmp/vhlg-test.img mklabel msdos
53+ parted /tmp/vhlg-test.img mkpart primary ext4 1MiB 5MiB
54+ 
55+ # Reproduce
56+ kpartx -a -p $(python3 -c "print('A'*200)") /tmp/vhlg-test.img
57+ 
58+ # Cleanup
59+ kpartx -d /tmp/vhlg-test.img
60+ rm -f /tmp/vhlg-test.img
61+ 
62+[mwilck: removed version history from commit message]
63+ 
64+Signed-off-by: Kou Wenqi <kouwenqi@kylinos.cn>
65+Reviewed-by: Martin Wilck <mwilck@suse.com>
66+---
67+ kpartx/devmapper.c | 17 +++++++++--------
68+ kpartx/devmapper.h | 9 +++++++++
69+ kpartx/kpartx.c | 38 ++++++++++++++++++++++----------------
70+ 3 files changed, 40 insertions(+), 24 deletions(-)
71+ 
72+diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c
73+index f12762c..9d9b5af 100644
74+--- a/kpartx/devmapper.c
75++++ b/kpartx/devmapper.c
76+@@ -658,18 +658,19 @@ int dm_find_part(const char *parent, const char *delim, int part,
77+ char dev_t[32];
78+
79+ if (!format_partname(name, namesiz, parent, delim, part)) {
80+- if (verbose)
81+- fprintf(stderr, "partname too small\n");
82+- return 0;
83++ fprintf(stderr, "partition name too long for partition %d\n", part);
84++ return DFP_ERR;
85+ }
86+
87+ r = dm_map_present(name, part_uuid);
88+- if (r == 1 || parent_uuid == NULL || *parent_uuid == '\0')
89+- return r;
90++ if (r == 1)
91++ return DFP_DEVICE_RELOAD;
92++ if (parent_uuid == NULL || *parent_uuid == '\0')
93++ return DFP_DEVICE_CREATE;
94+
95+ uuid = make_prefixed_uuid(part, parent_uuid);
96+ if (!uuid)
97+- return 0;
98++ return DFP_DEVICE_CREATE;
99+
100+ tmp = dm_find_uuid(uuid);
101+ if (tmp == NULL)
102+@@ -702,14 +703,14 @@ int dm_find_part(const char *parent, const char *delim, int part,
103+ if (r == 1) {
104+ free(tmp);
105+ *part_uuid = uuid;
106+- return 1;
107++ return DFP_DEVICE_RELOAD;
108+ }
109+ if (verbose)
110+ fprintf(stderr, "renaming %s->%s failed\n", tmp, name);
111+ out:
112+ free(uuid);
113+ free(tmp);
114+- return r;
115++ return DFP_DEVICE_CREATE;
116+ }
117+
118+ char *nondm_create_uuid(dev_t devt)
119+diff --git a/kpartx/devmapper.h b/kpartx/devmapper.h
120+index 701bdf6..6b71bab 100644
121+--- a/kpartx/devmapper.h
122++++ b/kpartx/devmapper.h
123+@@ -1,6 +1,8 @@
124+ #ifndef _KPARTX_DEVMAPPER_H
125+ #define _KPARTX_DEVMAPPER_H
126+
127++#include <libdevmapper.h>
128++
129+ #ifdef DM_SUBSYSTEM_UDEV_FLAG0
130+ #define MPATH_UDEV_RELOAD_FLAG DM_SUBSYSTEM_UDEV_FLAG0
131+ #else
132+@@ -18,6 +20,13 @@ dev_t dm_get_first_dep(char *devname);
133+ char * dm_mapuuid(const char *mapname);
134+ int dm_devn (const char * mapname, unsigned int *major, unsigned int *minor);
135+ int dm_remove_partmaps (char * mapname, char *uuid, dev_t devt, int verbose);
136++
137++enum {
138++ DFP_DEVICE_CREATE = DM_DEVICE_CREATE,
139++ DFP_DEVICE_RELOAD = DM_DEVICE_RELOAD,
140++ DFP_ERR = -1
141++};
142++
143+ int dm_find_part(const char *parent, const char *delim, int part,
144+ const char *parent_uuid,
145+ char *name, size_t namesiz, char **part_uuid, int verbose);
146+diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
147+index 46cb76b..6faadf5 100644
148+--- a/kpartx/kpartx.c
149++++ b/kpartx/kpartx.c
150+@@ -495,7 +495,7 @@ main(int argc, char **argv){
151+ case UPDATE:
152+ /* ADD and UPDATE share the same code that adds new partitions. */
153+ for (j = 0, c = 0; j < n; j++) {
154+- char *part_uuid, *reason;
155++ char *part_uuid = NULL, *reason;
156+
157+ if (slices[j].size == 0)
158+ continue;
159+@@ -512,10 +512,13 @@ main(int argc, char **argv){
160+ exit(1);
161+ }
162+
163+- op = (dm_find_part(mapname, delim, j + 1, uuid,
164+- partname, sizeof(partname),
165+- &part_uuid, verbose) ?
166+- DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
167++ op = dm_find_part(mapname, delim, j + 1, uuid,
168++ partname, sizeof(partname),
169++ &part_uuid, verbose);
170++ if (op == DFP_ERR) {
171++ r++;
172++ continue;
173++ }
174+
175+ if (part_uuid && uuid) {
176+ if (check_uuid(uuid, part_uuid, &reason) != 0) {
177+@@ -558,7 +561,7 @@ main(int argc, char **argv){
178+ d = c;
179+ while (c) {
180+ for (j = 0; j < n; j++) {
181+- char *part_uuid, *reason;
182++ char *part_uuid = NULL, *reason;
183+ int k = slices[j].container - 1;
184+
185+ if (slices[j].size == 0)
186+@@ -584,11 +587,14 @@ main(int argc, char **argv){
187+ exit(1);
188+ }
189+
190+- op = (dm_find_part(mapname, delim, j + 1, uuid,
191+- partname,
192+- sizeof(partname),
193+- &part_uuid, verbose) ?
194+- DM_DEVICE_RELOAD : DM_DEVICE_CREATE);
195++ op = dm_find_part(mapname, delim,
196++ j + 1, uuid, partname,
197++ sizeof(partname),
198++ &part_uuid, verbose);
199++ if (op == DFP_ERR) {
200++ r++;
201++ continue;
202++ }
203+
204+ if (part_uuid && uuid) {
205+ if (check_uuid(uuid, part_uuid, &reason) != 0) {
206+@@ -628,11 +634,11 @@ main(int argc, char **argv){
207+ }
208+
209+ for (j = MAXSLICES-1; j >= 0; j--) {
210+- char *part_uuid, *reason;
211+- if (slices[j].size ||
212+- !dm_find_part(mapname, delim, j + 1, uuid,
213+- partname, sizeof(partname),
214+- &part_uuid, verbose))
215++ char *part_uuid = NULL, *reason;
216++ int res = dm_find_part(mapname, delim, j + 1, uuid,
217++ partname, sizeof(partname),
218++ &part_uuid, verbose);
219++ if (slices[j].size || res != DFP_DEVICE_RELOAD)
220+ continue;
221+
222+ if (part_uuid && uuid) {
223+--
224+2.43.0
225+ 
@@ -0,0 +1,49 @@
1+From eedf032d0c5ca3b4adc5c75863270d82f6b41e15 Mon Sep 17 00:00:00 2001
2+From: Benjamin Marzinski <bmarzins@redhat.com>
3+Date: Tue, 21 Jul 2026 02:27:24 -0400
4+Subject: [PATCH] kpartx: check slice size before looking for partition to
5+ remove
6+ 
7+After commit 03071031 ("kpartx: fix crash and truncated device creation
8+with long -p delimiter"), when attempting to remove deleted partitions
9+on kpartx -u, kpartx started calling dm_find_part() to check if the
10+partition existed before checking if the slice size was 0 (and thus
11+should get removed). The problem is that if dm_find_part() returns
12+DFP_DEVICE_RELOAD because the partition device exists, part_uuid gets
13+allocated, and if the slices[j].size is non-zero and the partition
14+device shouldn't be removed, part_uuid wasn't getting freed. Fix this by
15+reverting to checking the slice size first.
16+ 
17+Fixes: 03071031 ("kpartx: fix crash and truncated device creation
18+with long -p delimiter")
19+ 
20+Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
21+Reviewed-by: Martin Wilck <mwilck@suse.com>
22+Reviewed-by: Kou Wenqi <kouwenqi@kylinos.cn>
23+---
24+ kpartx/kpartx.c | 9 +++++----
25+ 1 file changed, 5 insertions(+), 4 deletions(-)
26+ 
27+diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
28+index fc8f9e5e..370d09a1 100644
29+--- a/kpartx/kpartx.c
30++++ b/kpartx/kpartx.c
31+@@ -577,10 +577,11 @@ main(int argc, char **argv){
32+
33+ for (j = MAXSLICES-1; j >= 0; j--) {
34+ char *part_uuid = NULL, *reason;
35+- int res = dm_find_part(mapname, delim, j + 1, uuid,
36+- partname, sizeof(partname),
37+- &part_uuid, verbose);
38+- if (slices[j].size || res != DFP_DEVICE_RELOAD)
39++
40++ if (slices[j].size ||
41++ dm_find_part(mapname, delim, j + 1, uuid, partname,
42++ sizeof(partname), &part_uuid,
43++ verbose) != DFP_DEVICE_RELOAD)
44+ continue;
45+
46+ if (part_uuid && uuid) {
47+--
48+2.43.0
49+ 
@@ -2,7 +2,7 @@
2 2 
3Name: multipath-tools3Name: multipath-tools
4Version: 0.8.44Version: 0.8.4
5-Release: 445+Release: 45
6Summary: Tools to manage multipath devices with the device-mapper6Summary: Tools to manage multipath devices with the device-mapper
7License: GPL-2.0-or-later and LGPL-2.0-only7License: GPL-2.0-or-later and LGPL-2.0-only
8URL: http://christophe.varoqui.free.fr/8URL: http://christophe.varoqui.free.fr/
@@ -77,6 +77,9 @@ Patch65: 0065-libmultipath-fix-sysfs-dev_loss_tmo-parsing.patch
77Patch66: 0066-fix-incorrect-identification-of-the-local-system-dis.patch77Patch66: 0066-fix-incorrect-identification-of-the-local-system-dis.patch
78Patch67: 0067-libmultipath-avoid-temporarily-enabling-queueing-on-.patch78Patch67: 0067-libmultipath-avoid-temporarily-enabling-queueing-on-.patch
79Patch68: 0068-multipathd-Make-sure-to-disable-queueing-if-recovery.patch79Patch68: 0068-multipathd-Make-sure-to-disable-queueing-if-recovery.patch
80+Patch69: 0069-test-kpartx-add-test-for-over-long-partition-separat.patch
81+Patch70: 0070-kpartx-fix-crash-and-truncated-device-creation-with-.patch
82+Patch71: 0071-kpartx-check-slice-size-before-looking-for-partition.patch
80 83 
81BuildRequires: multipath-tools, libcmocka, libcmocka-devel84BuildRequires: multipath-tools, libcmocka, libcmocka-devel
82BuildRequires: gcc, libaio-devel, userspace-rcu-devel, device-mapper-devel >= 1.02.8985BuildRequires: gcc, libaio-devel, userspace-rcu-devel, device-mapper-devel >= 1.02.89
@@ -118,7 +121,7 @@ Obsoletes: libdmmp
118 121 
119%description devel122%description devel
120This package contains the development libraries for %{name}123This package contains the development libraries for %{name}
121-that are %{name}'s libbmpathpersist and libmpathcmd libraries.124+that are %{name}'s libmpathpersist and libmpathcmd libraries.
122 125 
123%package help126%package help
124Summary: Including man files for multipath-tools.127Summary: Including man files for multipath-tools.
@@ -225,6 +228,9 @@ fi
225 228 
226 229 
227%changelog230%changelog
231+* Thu Jul 23 2026 kouwenqi <kouwenqi@kylinos.cn> - 0.8.4-45
232+- kpartx: fix crash and truncated device creation with long -p delimiter
233+ 
228* Mon Jul 06 2026 wuguanghao <wuguanghao3@huawei.com> - 0.8.4-44234* Mon Jul 06 2026 wuguanghao <wuguanghao3@huawei.com> - 0.8.4-44
229- backport patches from community235- backport patches from community
230 236 
@@ -429,7 +435,7 @@ fi
429- SUG:NA435- SUG:NA
430- DESC:package rewrap436- DESC:package rewrap
431 437 
432-* Thu Dec 25 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.7.7-10438+* Wed Dec 25 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.7.7-10
433- reupload patches439- reupload patches
434 440 
435* Wed Dec 25 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.7.7-9441* Wed Dec 25 2019 openEuler Buildteam <buildteam@openeuler.org> - 0.7.7-9
@@ -10,7 +10,7 @@
10# man page10# man page
11 11 
12## By default, devices with vendor = "IBM" and product = "S/390.*" are12## By default, devices with vendor = "IBM" and product = "S/390.*" are
13-## blacklisted. To enable mulitpathing on these devies, uncomment the13+## blacklisted. To enable multipathing on these devies, uncomment the
14## following lines.14## following lines.
15#blacklist_exceptions {15#blacklist_exceptions {
16# device {16# device {