]> git.proxmox.com Git - mirror_zfs.git/commitdiff
zvols: prevent overflow of minor device numbers
authorFabian-Gruenbichler <f.gruenbichler@proxmox.com>
Fri, 29 Mar 2024 21:37:40 +0000 (22:37 +0100)
committerGitHub <noreply@github.com>
Fri, 29 Mar 2024 21:37:40 +0000 (14:37 -0700)
currently, the linux kernel allows 2^20 minor devices per major device
number.  ZFS reserves blocks of 2^4 minors per zvol: 1 for the zvol
itself, the other 15 for the first partitions of that zvol. as a result,
only 2^16 such blocks are available for use.

there are no checks in place to avoid overflowing into the major device
number when more than 2^16 zvols are allocated (with volmode=dev or
default). instead of ignoring this limit, which comes with all sorts of
weird knock-on effects, detect this situation and simply fail allocating
the zvol block device early on.

without this safeguard, the kernel will reject the attempt to create an
already existing block device, but ZFS doesn't handle this error and
gets confused about which zvol occupies which minor slot, potentially
resulting in kernel NULL derefs and other issues later on.

Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
Closes #16006

module/os/linux/zfs/zvol_os.c

index 8d5d1f06fce95d3cf11a1ba1628cfffa841d469d..26cc63d426eb1c93f534cf1a96f52fc8767a9879 100644 (file)
@@ -1314,6 +1314,13 @@ zvol_os_create_minor(const char *name)
        if (idx < 0)
                return (SET_ERROR(-idx));
        minor = idx << ZVOL_MINOR_BITS;
+       if (MINOR(minor) != minor) {
+               /* too many partitions can cause an overflow */
+               zfs_dbgmsg("zvol: create minor overflow: %s, minor %u/%u",
+                   name, minor, MINOR(minor));
+               ida_simple_remove(&zvol_ida, idx);
+               return (SET_ERROR(EINVAL));
+       }
 
        zv = zvol_find_by_name_hash(name, hash, RW_NONE);
        if (zv) {