aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhenlei Huang <zlei@FreeBSD.org>2023-08-22 09:20:10 +0000
committerZhenlei Huang <zlei@FreeBSD.org>2023-09-06 04:17:49 +0000
commit809450c4b53109b6ca8a87054452f2b3b8f711aa (patch)
treefd655bc0d8eb6218e13d52a614618bcf8e2f14ca
parent472fce62bb536b00d7af98d4be73bb8efbdb169b (diff)
downloadsrc-809450c4b53109b6ca8a87054452f2b3b8f711aa.tar.gz
src-809450c4b53109b6ca8a87054452f2b3b8f711aa.zip
geom_linux_lvm: Check the offset of physical volume header
The LVM label is stored on any of the first four sectors, and the PV (physical volume) header is stored within the same sector following the LVM label. The current implementation does not fully check the offset of PV header, when attaching a bad formatted LVM PV the kernel may crash due to out-of-bounds memory read. PR: 266562 Reviewed by: jhb MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D36773 (cherry picked from commit c941b82e1c31a67a025c43cc7bd31f269fa62588)
-rw-r--r--sys/geom/linux_lvm/g_linux_lvm.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/sys/geom/linux_lvm/g_linux_lvm.c b/sys/geom/linux_lvm/g_linux_lvm.c
index 2e4bbcaa045a..dddc3ae9184e 100644
--- a/sys/geom/linux_lvm/g_linux_lvm.c
+++ b/sys/geom/linux_lvm/g_linux_lvm.c
@@ -67,7 +67,8 @@ static int g_llvm_read_label(struct g_consumer *, struct g_llvm_label *);
static int g_llvm_read_md(struct g_consumer *, struct g_llvm_metadata *,
struct g_llvm_label *);
-static int llvm_label_decode(const u_char *, struct g_llvm_label *, int);
+static int llvm_label_decode(const u_char *, struct g_llvm_label *,
+ int, u_int);
static int llvm_md_decode(const u_char *, struct g_llvm_metadata *,
struct g_llvm_label *);
static int llvm_textconf_decode(u_char *, int,
@@ -637,7 +638,8 @@ g_llvm_read_label(struct g_consumer *cp, struct g_llvm_label *ll)
/* Search the four sectors for the LVM label. */
for (i = 0; i < 4; i++) {
- error = llvm_label_decode(&buf[i * pp->sectorsize], ll, i);
+ error = llvm_label_decode(&buf[i * pp->sectorsize], ll, i,
+ pp->sectorsize);
if (error == 0)
break; /* found it */
}
@@ -703,7 +705,8 @@ g_llvm_read_md(struct g_consumer *cp, struct g_llvm_metadata *md,
}
static int
-llvm_label_decode(const u_char *data, struct g_llvm_label *ll, int sector)
+llvm_label_decode(const u_char *data, struct g_llvm_label *ll, int sector,
+ u_int sectorsize)
{
uint64_t off;
char *uuid;
@@ -728,6 +731,13 @@ llvm_label_decode(const u_char *data, struct g_llvm_label *ll, int sector)
return (EINVAL);
}
+ /* XXX The minimal possible size of physical volume header is 88 */
+ if (ll->ll_offset < 32 || ll->ll_offset > sectorsize - 88) {
+ G_LLVM_DEBUG(0, "Invalid physical volume header offset %u",
+ ll->ll_offset);
+ return (EINVAL);
+ }
+
off = ll->ll_offset;
/*
* convert the binary uuid to string format, the format is