git: a34668185ba7 - stable/13 - modules: increase MAXMODNAME and provide backward compat

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Thu, 30 Dec 2021 19:22:37 UTC
The branch stable/13 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=a34668185ba7e5428bc6298c633c9d4f8317134b

commit a34668185ba7e5428bc6298c633c9d4f8317134b
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2021-11-17 19:35:46 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2021-12-30 18:26:18 +0000

    modules: increase MAXMODNAME and provide backward compat
    
    With various firmware files used by graphics and wireless drivers
    we are exceeding the current 32 character module name (file path
    in kldxref) length.
    In order to overcome this issue bump it to the maximum path length
    for the next version.
    To be able to MFC provide backward compat support for another version
    of the struct as the offsets for the second half change due to the
    array size increase.
    
    MAXMODNAME being defined to MAXPATHLEN needs param.h to be
    included first.  With only 7 modules (or LinuxKPI module.h) not
    doing that adjust them rather than including param.h in module.h [1].
    
    Reported by:    Greg V (greg unrelenting.technology)
    Sponsored by:   The FreeBSD Foundation
    Suggested by:   imp [1]
    Reviewed by:    imp (and others to different level)
    Differential Revision:  https://reviews.freebsd.org/D32383
    
    (cherry picked from commit df38ada2931f95d07b65b19fcfb4c9845d656ba9)
---
 sys/compat/linuxkpi/common/include/linux/module.h |  1 +
 sys/contrib/rdma/krping/krping_dev.c              |  2 +-
 sys/dev/videomode/videomode.c                     |  1 +
 sys/fs/fuse/fuse_device.c                         |  1 +
 sys/fs/fuse/fuse_io.c                             |  1 +
 sys/fs/fuse/fuse_main.c                           |  1 +
 sys/kern/kern_module.c                            | 94 ++++++++++++++++++-----
 sys/sys/module.h                                  |  4 +-
 sys/x86/cpufreq/hwpstate_intel.c                  |  1 +
 9 files changed, 84 insertions(+), 22 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/module.h b/sys/compat/linuxkpi/common/include/linux/module.h
index 2a4fdc5a11a9..25d775dd8df9 100644
--- a/sys/compat/linuxkpi/common/include/linux/module.h
+++ b/sys/compat/linuxkpi/common/include/linux/module.h
@@ -33,6 +33,7 @@
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/module.h>
 
 #include <linux/list.h>
diff --git a/sys/contrib/rdma/krping/krping_dev.c b/sys/contrib/rdma/krping/krping_dev.c
index 01927419fe33..eea3c772ea4f 100644
--- a/sys/contrib/rdma/krping/krping_dev.c
+++ b/sys/contrib/rdma/krping/krping_dev.c
@@ -14,10 +14,10 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>  /* defines used in kernel.h and module.h */
 #include <sys/module.h>
 #include <sys/systm.h>  /* uprintf */
 #include <sys/errno.h>
-#include <sys/param.h>  /* defines used in kernel.h */
 #include <sys/kernel.h> /* types used in module initialization */
 #include <sys/conf.h>   /* cdevsw struct */
 #include <sys/uio.h>    /* uio struct */
diff --git a/sys/dev/videomode/videomode.c b/sys/dev/videomode/videomode.c
index a1c7f0a82290..aa576d21b623 100644
--- a/sys/dev/videomode/videomode.c
+++ b/sys/dev/videomode/videomode.c
@@ -11,6 +11,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/module.h>
 #include <dev/videomode/videomode.h>
 
diff --git a/sys/fs/fuse/fuse_device.c b/sys/fs/fuse/fuse_device.c
index f8807d6d1c26..157c3802ec7e 100644
--- a/sys/fs/fuse/fuse_device.c
+++ b/sys/fs/fuse/fuse_device.c
@@ -64,6 +64,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/module.h>
 #include <sys/systm.h>
 #include <sys/errno.h>
diff --git a/sys/fs/fuse/fuse_io.c b/sys/fs/fuse/fuse_io.c
index 78398a990d7d..f85d17517ee0 100644
--- a/sys/fs/fuse/fuse_io.c
+++ b/sys/fs/fuse/fuse_io.c
@@ -64,6 +64,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/module.h>
 #include <sys/systm.h>
 #include <sys/errno.h>
diff --git a/sys/fs/fuse/fuse_main.c b/sys/fs/fuse/fuse_main.c
index ac15ad960725..824458db72cb 100644
--- a/sys/fs/fuse/fuse_main.c
+++ b/sys/fs/fuse/fuse_main.c
@@ -64,6 +64,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/module.h>
 #include <sys/systm.h>
 #include <sys/errno.h>
diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c
index 97dca7185319..1798a834dcec 100644
--- a/sys/kern/kern_module.c
+++ b/sys/kern/kern_module.c
@@ -361,11 +361,19 @@ sys_modfnext(struct thread *td, struct modfnext_args *uap)
 
 struct module_stat_v1 {
 	int	version;		/* set to sizeof(struct module_stat) */
-	char	name[MAXMODNAME];
+	char	name[MAXMODNAMEV1V2];
 	int	refs;
 	int	id;
 };
 
+struct module_stat_v2 {
+	int	version;		/* set to sizeof(struct module_stat) */
+	char	name[MAXMODNAMEV1V2];
+	int	refs;
+	int	id;
+	modspecific_t	data;
+};
+
 int
 sys_modstat(struct thread *td, struct modstat_args *uap)
 {
@@ -374,7 +382,9 @@ sys_modstat(struct thread *td, struct modstat_args *uap)
 	int error = 0;
 	int id, namelen, refs, version;
 	struct module_stat *stat;
+	struct module_stat_v2 *stat_v2;
 	char *name;
+	bool is_v1v2;
 
 	MOD_SLOCK;
 	mod = module_lookupbyid(uap->modid);
@@ -394,27 +404,44 @@ sys_modstat(struct thread *td, struct modstat_args *uap)
 	 */
 	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
 		return (error);
-	if (version != sizeof(struct module_stat_v1)
-	    && version != sizeof(struct module_stat))
+	is_v1v2 = (version == sizeof(struct module_stat_v1) ||
+	    version == sizeof(struct module_stat_v2));
+	if (!is_v1v2 && version != sizeof(struct module_stat))
 		return (EINVAL);
 	namelen = strlen(mod->name) + 1;
-	if (namelen > MAXMODNAME)
-		namelen = MAXMODNAME;
+	if (is_v1v2 && namelen > MAXMODNAMEV1V2)
+		namelen = MAXMODNAMEV1V2;
+	else if (namelen > MAXMODNAMEV3)
+		namelen = MAXMODNAMEV3;
 	if ((error = copyout(name, &stat->name[0], namelen)) != 0)
 		return (error);
 
-	if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
-		return (error);
-	if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
-		return (error);
+	/* Extending MAXMODNAME gives an offset change for v3. */
+	if (is_v1v2) {
+		stat_v2 = (struct module_stat_v2 *)stat;
+		if ((error = copyout(&refs, &stat_v2->refs, sizeof(int))) != 0)
+			return (error);
+		if ((error = copyout(&id, &stat_v2->id, sizeof(int))) != 0)
+			return (error);
+	} else {
+		if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
+			return (error);
+		if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
+			return (error);
+	}
 
 	/*
 	 * >v1 stat includes module data.
 	 */
-	if (version == sizeof(struct module_stat))
+	if (version == sizeof(struct module_stat_v2)) {
+		if ((error = copyout(&data, &stat_v2->data,
+		    sizeof(data))) != 0)
+			return (error);
+	} else if (version == sizeof(struct module_stat)) {
 		if ((error = copyout(&data, &stat->data, 
 		    sizeof(data))) != 0)
 			return (error);
+	}
 	td->td_retval[0] = 0;
 	return (error);
 }
@@ -423,7 +450,7 @@ int
 sys_modfind(struct thread *td, struct modfind_args *uap)
 {
 	int error = 0;
-	char name[MAXMODNAME];
+	char name[MAXMODNAMEV3];
 	module_t mod;
 
 	if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
@@ -455,6 +482,14 @@ typedef union modspecific32 {
 	uint32_t	ulongval;
 } modspecific32_t;
 
+struct module_stat32_v2 {
+	int		version;
+	char		name[MAXMODNAMEV1V2];
+	int		refs;
+	int		id;
+	modspecific32_t	data;
+};
+
 struct module_stat32 {
 	int		version;
 	char		name[MAXMODNAME];
@@ -471,7 +506,9 @@ freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
 	int error = 0;
 	int id, namelen, refs, version;
 	struct module_stat32 *stat32;
+	struct module_stat32_v2 *stat32_v2;
 	char *name;
+	bool is_v1v2;
 
 	MOD_SLOCK;
 	mod = module_lookupbyid(uap->modid);
@@ -492,27 +529,44 @@ freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
 
 	if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
 		return (error);
-	if (version != sizeof(struct module_stat_v1)
-	    && version != sizeof(struct module_stat32))
+	is_v1v2 = (version == sizeof(struct module_stat_v1) ||
+	    version == sizeof(struct module_stat32_v2));
+	if (!is_v1v2 && version != sizeof(struct module_stat32))
 		return (EINVAL);
 	namelen = strlen(mod->name) + 1;
-	if (namelen > MAXMODNAME)
-		namelen = MAXMODNAME;
+	if (is_v1v2 && namelen > MAXMODNAMEV1V2)
+		namelen = MAXMODNAMEV1V2;
+	else if (namelen > MAXMODNAMEV3)
+		namelen = MAXMODNAMEV3;
 	if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
 		return (error);
 
-	if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
-		return (error);
-	if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
-		return (error);
+	/* Extending MAXMODNAME gives an offset change for v3. */
+	if (is_v1v2) {
+		stat32_v2 = (struct module_stat32_v2 *)stat32;
+		if ((error = copyout(&refs, &stat32_v2->refs, sizeof(int))) != 0)
+			return (error);
+		if ((error = copyout(&id, &stat32_v2->id, sizeof(int))) != 0)
+			return (error);
+	} else {
+		if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
+			return (error);
+		if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
+			return (error);
+	}
 
 	/*
 	 * >v1 stat includes module data.
 	 */
-	if (version == sizeof(struct module_stat32))
+	if (version == sizeof(struct module_stat32_v2)) {
+		if ((error = copyout(&data32, &stat32_v2->data,
+		    sizeof(data32))) != 0)
+			return (error);
+	} else if (version == sizeof(struct module_stat32)) {
 		if ((error = copyout(&data32, &stat32->data,
 		    sizeof(data32))) != 0)
 			return (error);
+	}
 	td->td_retval[0] = 0;
 	return (error);
 }
diff --git a/sys/sys/module.h b/sys/sys/module.h
index 89377df401a8..efefaf4cb513 100644
--- a/sys/sys/module.h
+++ b/sys/sys/module.h
@@ -253,7 +253,9 @@ extern int mod_debug;
 #endif
 #endif	/* _KERNEL */
 
-#define	MAXMODNAME	32
+#define	MAXMODNAMEV1V2	32
+#define	MAXMODNAMEV3	MAXPATHLEN
+#define	MAXMODNAME	MAXMODNAMEV3
 
 struct module_stat {
 	int		version;	/* set to sizeof(struct module_stat) */
diff --git a/sys/x86/cpufreq/hwpstate_intel.c b/sys/x86/cpufreq/hwpstate_intel.c
index f6e63fdeb854..e3d17aa0bd1c 100644
--- a/sys/x86/cpufreq/hwpstate_intel.c
+++ b/sys/x86/cpufreq/hwpstate_intel.c
@@ -29,6 +29,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/param.h>
 #include <sys/sbuf.h>
 #include <sys/module.h>
 #include <sys/systm.h>