diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac092cc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +SOURCES/e100-4.18.0-240.el8.tar.xz diff --git a/.kmod-e100.metadata b/.kmod-e100.metadata new file mode 100644 index 0000000..feedf5c --- /dev/null +++ b/.kmod-e100.metadata @@ -0,0 +1 @@ +0b6b4439f1731d40eaf3adce748994cd1c532636 SOURCES/e100-4.18.0-240.el8.tar.xz diff --git a/SOURCES/0001-e100-fix-length-calculation-in-e100_get_regs_len.patch b/SOURCES/0001-e100-fix-length-calculation-in-e100_get_regs_len.patch new file mode 100644 index 0000000..e99d2e1 --- /dev/null +++ b/SOURCES/0001-e100-fix-length-calculation-in-e100_get_regs_len.patch @@ -0,0 +1,46 @@ +From 4329c8dc110b25d5f04ed20c6821bb60deff279f Mon Sep 17 00:00:00 2001 +From: Jacob Keller +Date: Wed, 8 Sep 2021 10:52:36 -0700 +Subject: [Backport 4329c8dc110b] e100: fix length calculation in + e100_get_regs_len + +commit abf9b902059f ("e100: cleanup unneeded math") tried to simplify +e100_get_regs_len and remove a double 'divide and then multiply' +calculation that the e100_reg_regs_len function did. + +This change broke the size calculation entirely as it failed to account +for the fact that the numbered registers are actually 4 bytes wide and +not 1 byte. This resulted in a significant under allocation of the +register buffer used by e100_get_regs. + +Fix this by properly multiplying the register count by u32 first before +adding the size of the dump buffer. + +Fixes: abf9b902059f ("e100: cleanup unneeded math") +Reported-by: Felicitas Hetzelt +Signed-off-by: Jacob Keller +Signed-off-by: Tony Nguyen +--- + src/e100.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/src/e100.c b/src/e100.c +index 373eb027b925207fdc70b47e413c4055559a2e2d..588a59546d1237e7afb1e6b9bfcce37ecdf03a1c 100644 +--- a/src/e100.c ++++ b/src/e100.c +@@ -2441,7 +2441,11 @@ static void e100_get_drvinfo(struct net_device *netdev, + static int e100_get_regs_len(struct net_device *netdev) + { + struct nic *nic = netdev_priv(netdev); +- return 1 + E100_PHY_REGS + sizeof(nic->mem->dump_buf); ++ ++ /* We know the number of registers, and the size of the dump buffer. ++ * Calculate the total size in bytes. ++ */ ++ return (1 + E100_PHY_REGS) * sizeof(u32) + sizeof(nic->mem->dump_buf); + } + + static void e100_get_regs(struct net_device *netdev, +-- +2.31.1 + diff --git a/SOURCES/0002-e100-fix-buffer-overrun-in-e100_get_regs.patch b/SOURCES/0002-e100-fix-buffer-overrun-in-e100_get_regs.patch new file mode 100644 index 0000000..1e01ed4 --- /dev/null +++ b/SOURCES/0002-e100-fix-buffer-overrun-in-e100_get_regs.patch @@ -0,0 +1,102 @@ +From 51032e6f17ce990d06123ad7307f258c50d25aa7 Mon Sep 17 00:00:00 2001 +From: Jacob Keller +Date: Wed, 8 Sep 2021 10:52:37 -0700 +Subject: [Backport 51032e6f17ce] e100: fix buffer overrun in e100_get_regs + +The e100_get_regs function is used to implement a simple register dump +for the e100 device. The data is broken into a couple of MAC control +registers, and then a series of PHY registers, followed by a memory dump +buffer. + +The total length of the register dump is defined as (1 + E100_PHY_REGS) +* sizeof(u32) + sizeof(nic->mem->dump_buf). + +The logic for filling in the PHY registers uses a convoluted inverted +count for loop which counts from E100_PHY_REGS (0x1C) down to 0, and +assigns the slots 1 + E100_PHY_REGS - i. The first loop iteration will +fill in [1] and the final loop iteration will fill in [1 + 0x1C]. This +is actually one more than the supposed number of PHY registers. + +The memory dump buffer is then filled into the space at +[2 + E100_PHY_REGS] which will cause that memcpy to assign 4 bytes past +the total size. + +The end result is that we overrun the total buffer size allocated by the +kernel, which could lead to a panic or other issues due to memory +corruption. + +It is difficult to determine the actual total number of registers +here. The only 8255x datasheet I could find indicates there are 28 total +MDI registers. However, we're reading 29 here, and reading them in +reverse! + +In addition, the ethtool e100 register dump interface appears to read +the first PHY register to determine if the device is in MDI or MDIx +mode. This doesn't appear to be documented anywhere within the 8255x +datasheet. I can only assume it must be in register 28 (the extra +register we're reading here). + +Lets not change any of the intended meaning of what we copy here. Just +extend the space by 4 bytes to account for the extra register and +continue copying the data out in the same order. + +Change the E100_PHY_REGS value to be the correct total (29) so that the +total register dump size is calculated properly. Fix the offset for +where we copy the dump buffer so that it doesn't overrun the total size. + +Re-write the for loop to use counting up instead of the convoluted +down-counting. Correct the mdio_read offset to use the 0-based register +offsets, but maintain the bizarre reverse ordering so that we have the +ABI expected by applications like ethtool. This requires and additional +subtraction of 1. It seems a bit odd but it makes the flow of assignment +into the register buffer easier to follow. + +Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") +Reported-by: Felicitas Hetzelt +Signed-off-by: Jacob Keller +Tested-by: Jacob Keller +Signed-off-by: Tony Nguyen +--- + src/e100.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +diff --git a/src/e100.c b/src/e100.c +index 588a59546d1237e7afb1e6b9bfcce37ecdf03a1c..09ae1939e6db4c7cc32e89708aa871763a543d91 100644 +--- a/src/e100.c ++++ b/src/e100.c +@@ -2437,7 +2437,7 @@ static void e100_get_drvinfo(struct net_device *netdev, + sizeof(info->bus_info)); + } + +-#define E100_PHY_REGS 0x1C ++#define E100_PHY_REGS 0x1D + static int e100_get_regs_len(struct net_device *netdev) + { + struct nic *nic = netdev_priv(netdev); +@@ -2459,14 +2459,18 @@ static void e100_get_regs(struct net_device *netdev, + buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 | + ioread8(&nic->csr->scb.cmd_lo) << 16 | + ioread16(&nic->csr->scb.status); +- for (i = E100_PHY_REGS; i >= 0; i--) +- buff[1 + E100_PHY_REGS - i] = +- mdio_read(netdev, nic->mii.phy_id, i); ++ for (i = 0; i < E100_PHY_REGS; i++) ++ /* Note that we read the registers in reverse order. This ++ * ordering is the ABI apparently used by ethtool and other ++ * applications. ++ */ ++ buff[1 + i] = mdio_read(netdev, nic->mii.phy_id, ++ E100_PHY_REGS - 1 - i); + memset(nic->mem->dump_buf, 0, sizeof(nic->mem->dump_buf)); + e100_exec_cb(nic, NULL, e100_dump); + msleep(10); +- memcpy(&buff[2 + E100_PHY_REGS], nic->mem->dump_buf, +- sizeof(nic->mem->dump_buf)); ++ memcpy(&buff[1 + E100_PHY_REGS], nic->mem->dump_buf, ++ sizeof(nic->mem->dump_buf)); + } + + static void e100_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) +-- +2.31.1 + diff --git a/SPECS/kmod-e100.spec b/SPECS/kmod-e100.spec new file mode 100644 index 0000000..d80c665 --- /dev/null +++ b/SPECS/kmod-e100.spec @@ -0,0 +1,132 @@ +%global pkg e100 + +%global driver_version 4.18.0-240.el8 + +%global kernel_version 4.18.0-348.el8 + +%global _use_internal_dependency_generator 0 +%global __find_requires /usr/lib/rpm/redhat/find-requires +%global __find_provides /usr/lib/rpm/redhat/find-provides + +%global debug_package %{nil} + +%global __spec_install_post \ + %{?__debug_package:%{__debug_install_post}} \ + %{__arch_install_post} \ + %{__os_install_post} \ + %{__mod_compress_install_post} + +%global __mod_compress_install_post find %{buildroot}/lib/modules -type f -name \*.ko -exec xz \{\} \\; + + +Name: kmod-%{pkg} +Version: 4.18.0.240 +Release: 1%{?dist} +Summary: Intel(R) PRO/100 Ethernet (%{pkg}) driver + +License: GPLv2 +URL: https://www.kernel.org/ + +Source0: %{pkg}-%{driver_version}.tar.xz +Patch1: 0001-e100-fix-length-calculation-in-e100_get_regs_len.patch +Patch2: 0002-e100-fix-buffer-overrun-in-e100_get_regs.patch + +ExclusiveArch: x86_64 + +BuildRequires: elfutils-libelf-devel +BuildRequires: gcc +BuildRequires: kernel-rpm-macros +BuildRequires: kmod +BuildRequires: make +BuildRequires: redhat-rpm-config +BuildRequires: xz + +BuildRequires: kernel-abi-stablelists = %{kernel_version} +BuildRequires: kernel-devel = %{kernel_version} +BuildRequires: kernel-devel-uname-r = %{kernel_version}.%{_arch} + +Requires: kernel >= %{kernel_version} +Requires: kernel-uname-r >= %{kernel_version}.%{_arch} +Requires: kernel-modules >= %{kernel_version} +Requires: kernel-modules-uname-r >= %{kernel_version}.%{_arch} + +Provides: installonlypkg(kernel-module) +Provides: kernel-modules >= %{kernel_version}.%{_arch} + +Requires(post): %{_sbindir}/depmod +Requires(postun): %{_sbindir}/depmod + +Requires(post): %{_sbindir}/weak-modules +Requires(postun): %{_sbindir}/weak-modules + + +%description +This driver supports the Intel(R) PRO/100 family of adapters. + + +%prep +%autosetup -p1 -n %{pkg}-%{driver_version} + + +%build +pushd src +%{__make} -C /usr/src/kernels/%{kernel_version}.%{_arch} %{?_smp_mflags} M=$PWD modules +popd + + +%install +%{__install} -D -t %{buildroot}/lib/modules/%{kernel_version}.%{_arch}/extra/drivers/net/ethernet/intel src/%{pkg}.ko + +# Make .ko objects temporarily executable for automatic stripping +find %{buildroot}/lib/modules -type f -name \*.ko -exec chmod u+x \{\} \+ + + +%clean +%{__rm} -rf %{buildroot} + + +%post +mkdir -p %{_localstatedir}/lib/rpm-state/sig-kmods +printf '%s\n' "/lib/modules/%{kernel_version}.%{_arch}/extra/drivers/net/ethernet/intel/%{pkg}.ko.xz" >> %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-add + + +%preun +mkdir -p %{_localstatedir}/lib/rpm-state/sig-kmods +rpm -ql kmod-%{pkg}-%{?epoch:%{epoch}:}%{version}-%{release}.%{_arch} | grep '/lib/modules/%{kernel_version}.%{_arch}/.*\.ko\.xz$' >> %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-remove + + +%postun +if [ -f %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-remove ] +then + modules=( $(cat %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-remove) ) + rm -f %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-remove + rmdir --ignore-fail-on-non-empty %{_localstatedir}/lib/rpm-state/sig-kmods + printf '%s\n' "${modules[@]}" | %{_sbindir}/weak-modules --remove-modules +fi + + +%pretrans -p +posix.unlink("%{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-add") +posix.unlink("%{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-remove") + + +%posttrans +if [ -f %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-add ] +then + modules=( $(cat %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-add) ) + rm -f %{_localstatedir}/lib/rpm-state/sig-kmods/weak-modules-add + rmdir --ignore-fail-on-non-empty %{_localstatedir}/lib/rpm-state/sig-kmods + printf '%s\n' "${modules[@]}" | %{_sbindir}/weak-modules --add-modules +fi + + +%files +%defattr(644,root,root,755) +/lib/modules/%{kernel_version}.%{_arch} +%license COPYING + + +%changelog +* Tue Jan 18 2022 Kmods SIG - 4.18.0.240-1 +- Use EL kernel source and versioning +- kABI tracking kmod package (kernel >= 4.18.0-348.el8)