Skip to content

Commit

Permalink
modules_linux: Add support for builtin modules
Browse files Browse the repository at this point in the history
Signed-off-by: l1b0k <[email protected]>
  • Loading branch information
l1b0k committed Jan 20, 2025
1 parent 3c04124 commit ff12ae9
Showing 1 changed file with 396 additions and 0 deletions.
396 changes: 396 additions & 0 deletions policy/cilium/0039-modules_linux-Add-support-for-builtin-modules.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,396 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: TheAifam5 <[email protected]>
Date: Wed, 22 Feb 2023 23:36:50 +0100
Subject: modules_linux: Add support for builtin modules

[ upstream commit 51630941ac2f19db83d3d7a88e2a8a17fcf8e814 ]

Previously, kernel modules names were read from the `/proc/modules` only which prevented k8s linux distribution with kernel modules builtin into the kernel to pass the validation of required kernel modules by Cilium.

This patch adds support for systems with builtin modules by trying to read the kernel module names from following files additionally:
- `/lib/modules/<kernel-version>/modules.builtin`
- `/usr/lib/modules/<kernel-version>/modules.builtin`
- `/usr/lib/debug/lib/modules/<kernel-version>/modules.builtin`

Fixes: #23863

Signed-off-by: Mateusz Paluszkiewicz (TheAifam5) <[email protected]>
Signed-off-by: Tam Mach <[email protected]>
---
pkg/modules/modules_linux.go | 117 ++++++++++++++++++++++++---
pkg/modules/modules_linux_test.go | 129 ++++++++++++++++++++++++++++++
pkg/modules/modules_test.go | 61 --------------
3 files changed, 236 insertions(+), 71 deletions(-)
create mode 100644 pkg/modules/modules_linux_test.go

diff --git a/pkg/modules/modules_linux.go b/pkg/modules/modules_linux.go
index 21dee7eba5..7fdec7105b 100644
--- a/pkg/modules/modules_linux.go
+++ b/pkg/modules/modules_linux.go
@@ -5,22 +5,40 @@ package modules

import (
"bufio"
+ "errors"
"fmt"
"io"
"os"
+ "path/filepath"
"strings"
+
+ linux "golang.org/x/sys/unix"
)

const (
- modulesFilepath = "/proc/modules"
+ loadedModulesFilepath = "/proc/modules"
)

func moduleLoader() string {
return "modprobe"
}

-// parseModulesFile returns the list of loaded kernel modules names.
-func parseModulesFile(r io.Reader) ([]string, error) {
+// kernelRelease returns the release string of the running kernel.
+// Its format depends on the Linux distribution and corresponds to directory
+// names in /lib/modules by convention. Some examples are 5.15.17-1-lts and
+// 4.19.0-16-amd64.
+// Note: copied from /vendor/github.com/cilium/ebpf/internal/version.go
+func kernelRelease() (string, error) {
+ var uname linux.Utsname
+ if err := linux.Uname(&uname); err != nil {
+ return "", fmt.Errorf("uname failed: %w", err)
+ }
+
+ return linux.ByteSliceToString(uname.Release[:]), nil
+}
+
+// parseLoadedModulesFile returns the list of loaded kernel modules names.
+func parseLoadedModulesFile(r io.Reader) ([]string, error) {
var result []string

scanner := bufio.NewScanner(r)
@@ -45,15 +63,94 @@ func parseModulesFile(r io.Reader) ([]string, error) {
return result, nil
}

-// listModules returns the list of loaded kernel modules names parsed from
-// /proc/modules.
-func listModules() ([]string, error) {
- fModules, err := os.Open(modulesFilepath)
+// parseBuiltinModulesFile returns the list of builtin kernel modules names.
+func parseBuiltinModulesFile(r io.Reader) ([]string, error) {
+ var result []string
+
+ scanner := bufio.NewScanner(r)
+ scanner.Split(bufio.ScanLines)
+
+ for scanner.Scan() {
+ modulePathRaw := scanner.Text()
+ moduleFileName := filepath.Base(modulePathRaw)
+ moduleFileExt := filepath.Ext(modulePathRaw)
+ moduleName := strings.TrimSuffix(moduleFileName, moduleFileExt)
+ result = append(result, moduleName)
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return result, nil
+}
+
+// listLoadedModules returns the parsed list of loaded kernel modules names.
+func listLoadedModules() ([]string, error) {
+ fModules, err := os.Open(loadedModulesFilepath)
if err != nil {
return nil, fmt.Errorf(
- "failed to open modules information at %s: %s",
- modulesFilepath, err)
+ "failed to open loaded modules information at %s: %w",
+ loadedModulesFilepath, err)
}
defer fModules.Close()
- return parseModulesFile(fModules)
+ return parseLoadedModulesFile(fModules)
+}
+
+// listBuiltinModules returns the parsed list of builtin kernel modules names.
+func listBuiltinModules() ([]string, error) {
+ var result []string
+
+ locations := []string{
+ "/lib/modules/%s/modules.builtin",
+ "/usr/lib/modules/%s/modules.builtin",
+ "/usr/lib/debug/lib/modules/%s/modules.builtin",
+ }
+
+ release, err := kernelRelease()
+ if err != nil {
+ return nil, err
+ }
+
+ for _, location := range locations {
+ fModulePath := fmt.Sprintf(location, release)
+
+ fModules, err := os.Open(fModulePath)
+ if errors.Is(err, os.ErrNotExist) {
+ continue
+ }
+
+ if err != nil {
+ return nil, fmt.Errorf(
+ "failed to open builtin modules information at %s: %w",
+ fModulePath, err)
+ }
+
+ defer fModules.Close()
+
+ result, err = parseBuiltinModulesFile(fModules)
+ if err != nil {
+ return nil, err
+ }
+
+ break
+ }
+
+ return result, nil
+}
+
+// listModules returns the list of loaded kernel modules names parsed from
+// /proc/modules and from /lib/modules/<version>/modules.builtin.
+func listModules() ([]string, error) {
+ loadedModules, err := listLoadedModules()
+ if err != nil {
+ return nil, fmt.Errorf("failed to retrieve loaded modules names: %w", err)
+ }
+
+ builtinModules, err := listBuiltinModules()
+ if err != nil {
+ return nil, fmt.Errorf("failed to retrieve builtin modules names: %w", err)
+ }
+
+ return append(loadedModules, builtinModules...), nil
}
diff --git a/pkg/modules/modules_linux_test.go b/pkg/modules/modules_linux_test.go
new file mode 100644
index 0000000000..caff016be0
--- /dev/null
+++ b/pkg/modules/modules_linux_test.go
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: Apache-2.0
+// Copyright Authors of Cilium
+
+package modules
+
+import (
+ "bytes"
+
+ . "gopkg.in/check.v1"
+
+ "github.com/cilium/cilium/pkg/checker"
+)
+
+const (
+ loadedModulesContent = `ebtable_nat 16384 1 - Live 0x0000000000000000
+ebtable_broute 16384 1 - Live 0x0000000000000000
+bridge 172032 1 ebtable_broute, Live 0x0000000000000000
+ip6table_nat 16384 1 - Live 0x0000000000000000
+nf_nat_ipv6 16384 1 ip6table_nat, Live 0x0000000000000000
+ip6table_mangle 16384 1 - Live 0x0000000000000000
+ip6table_raw 16384 1 - Live 0x0000000000000000
+ip6table_security 16384 1 - Live 0x0000000000000000
+iptable_nat 16384 1 - Live 0x0000000000000000
+nf_nat_ipv4 16384 1 iptable_nat, Live 0x0000000000000000
+iptable_mangle 16384 1 - Live 0x0000000000000000
+iptable_raw 16384 1 - Live 0x0000000000000000
+iptable_security 16384 1 - Live 0x0000000000000000
+ebtable_filter 16384 1 - Live 0x0000000000000000
+ebtables 36864 3 ebtable_nat,ebtable_broute,ebtable_filter, Live 0x0000000000000000
+ip6table_filter 16384 1 - Live 0x0000000000000000
+ip6_tables 28672 5 ip6table_nat,ip6table_mangle,ip6table_raw,ip6table_security,ip6table_filter, Live 0x0000000000000000
+iptable_filter 16384 1 - Live 0x0000000000000000
+ip_tables 28672 5 iptable_nat,iptable_mangle,iptable_raw,iptable_security,iptable_filter, Live 0x0000000000000000
+x_tables 40960 23 xt_multiport,xt_nat,xt_addrtype,xt_mark,xt_comment,xt_CHECKSUM,ipt_MASQUERADE,xt_tcpudp,ip6t_rpfilter,ip6t_REJECT,ipt_REJECT,xt_conntrack,ip6table_mangle,ip6table_raw,ip6table_security,iptable_mangle,iptable_raw,iptable_security,ebtables,ip6table_filter,ip6_tables,iptable_filter,ip_tables, Live 0x0000000000000000`
+
+ builtinModulesContent = `kernel/net/bridge/netfilter/ebtable_nat.ko
+kernel/net/bridge/netfilter/ebtable_broute.ko
+kernel/net/bridge/bridge.ko
+kernel/net/ipv6/netfilter/ip6table_nat.ko
+kernel/net/ipv6/netfilter/nf_nat_ipv6.ko
+kernel/net/ipv6/netfilter/ip6table_mangle.ko
+kernel/net/ipv6/netfilter/ip6table_raw.ko
+kernel/net/ipv6/netfilter/ip6table_security.ko
+kernel/net/ipv4/netfilter/iptable_nat.ko
+kernel/net/ipv4/netfilter/nf_nat_ipv4.ko
+kernel/net/ipv4/netfilter/iptable_mangle.ko
+kernel/net/ipv4/netfilter/iptable_raw.ko
+kernel/net/ipv4/netfilter/iptable_security.ko
+kernel/net/bridge/netfilter/ebtable_filter.ko
+kernel/net/bridge/netfilter/ebtables.ko
+kernel/net/ipv6/netfilter/ip6table_filter.ko
+kernel/net/ipv6/netfilter/ip6_tables.ko
+kernel/net/ipv4/netfilter/iptable_filter.ko
+kernel/net/ipv4/netfilter/ip_tables.ko
+kernel/net/netfilter/x_tables.ko`
+)
+
+type ModulesLinuxTestSuite struct{}
+
+var _ = Suite(&ModulesLinuxTestSuite{})
+
+func (s *ModulesLinuxTestSuite) TestParseLoadedModuleFile(c *C) {
+ expectedLength := 20
+ expectedModules := []string{
+ "ebtable_nat",
+ "ebtable_broute",
+ "bridge",
+ "ip6table_nat",
+ "nf_nat_ipv6",
+ "ip6table_mangle",
+ "ip6table_raw",
+ "ip6table_security",
+ "iptable_nat",
+ "nf_nat_ipv4",
+ "iptable_mangle",
+ "iptable_raw",
+ "iptable_security",
+ "ebtable_filter",
+ "ebtables",
+ "ip6table_filter",
+ "ip6_tables",
+ "iptable_filter",
+ "ip_tables",
+ "x_tables",
+ }
+
+ r := bytes.NewBuffer([]byte(loadedModulesContent))
+ moduleInfos, err := parseLoadedModulesFile(r)
+ c.Assert(err, IsNil)
+ c.Assert(moduleInfos, HasLen, expectedLength)
+ c.Assert(moduleInfos, checker.DeepEquals, expectedModules)
+}
+
+func (s *ModulesLinuxTestSuite) TestParseBuiltinModuleFile(c *C) {
+ expectedLength := 20
+ expectedModules := []string{
+ "ebtable_nat",
+ "ebtable_broute",
+ "bridge",
+ "ip6table_nat",
+ "nf_nat_ipv6",
+ "ip6table_mangle",
+ "ip6table_raw",
+ "ip6table_security",
+ "iptable_nat",
+ "nf_nat_ipv4",
+ "iptable_mangle",
+ "iptable_raw",
+ "iptable_security",
+ "ebtable_filter",
+ "ebtables",
+ "ip6table_filter",
+ "ip6_tables",
+ "iptable_filter",
+ "ip_tables",
+ "x_tables",
+ }
+
+ r := bytes.NewBuffer([]byte(builtinModulesContent))
+ moduleInfos, err := parseBuiltinModulesFile(r)
+ c.Assert(err, IsNil)
+ c.Assert(moduleInfos, HasLen, expectedLength)
+ c.Assert(moduleInfos, checker.DeepEquals, expectedModules)
+}
+
+func (s *ModulesLinuxTestSuite) TestListModules(c *C) {
+ _, err := listModules()
+ c.Assert(err, IsNil)
+}
diff --git a/pkg/modules/modules_test.go b/pkg/modules/modules_test.go
index 382eb8d780..6bff3ef799 100644
--- a/pkg/modules/modules_test.go
+++ b/pkg/modules/modules_test.go
@@ -6,7 +6,6 @@
package modules

import (
- "bytes"
"testing"

. "gopkg.in/check.v1"
@@ -14,29 +13,6 @@ import (
"github.com/cilium/cilium/pkg/checker"
)

-const (
- modulesContent = `ebtable_nat 16384 1 - Live 0x0000000000000000
-ebtable_broute 16384 1 - Live 0x0000000000000000
-bridge 172032 1 ebtable_broute, Live 0x0000000000000000
-ip6table_nat 16384 1 - Live 0x0000000000000000
-nf_nat_ipv6 16384 1 ip6table_nat, Live 0x0000000000000000
-ip6table_mangle 16384 1 - Live 0x0000000000000000
-ip6table_raw 16384 1 - Live 0x0000000000000000
-ip6table_security 16384 1 - Live 0x0000000000000000
-iptable_nat 16384 1 - Live 0x0000000000000000
-nf_nat_ipv4 16384 1 iptable_nat, Live 0x0000000000000000
-iptable_mangle 16384 1 - Live 0x0000000000000000
-iptable_raw 16384 1 - Live 0x0000000000000000
-iptable_security 16384 1 - Live 0x0000000000000000
-ebtable_filter 16384 1 - Live 0x0000000000000000
-ebtables 36864 3 ebtable_nat,ebtable_broute,ebtable_filter, Live 0x0000000000000000
-ip6table_filter 16384 1 - Live 0x0000000000000000
-ip6_tables 28672 5 ip6table_nat,ip6table_mangle,ip6table_raw,ip6table_security,ip6table_filter, Live 0x0000000000000000
-iptable_filter 16384 1 - Live 0x0000000000000000
-ip_tables 28672 5 iptable_nat,iptable_mangle,iptable_raw,iptable_security,iptable_filter, Live 0x0000000000000000
-x_tables 40960 23 xt_multiport,xt_nat,xt_addrtype,xt_mark,xt_comment,xt_CHECKSUM,ipt_MASQUERADE,xt_tcpudp,ip6t_rpfilter,ip6t_REJECT,ipt_REJECT,xt_conntrack,ip6table_mangle,ip6table_raw,ip6table_security,iptable_mangle,iptable_raw,iptable_security,ebtables,ip6table_filter,ip6_tables,iptable_filter,ip_tables, Live 0x0000000000000000`
-)
-
// Hook up gocheck into the "go test" runner.
func Test(t *testing.T) {
TestingT(t)
@@ -116,40 +92,3 @@ func (s *ModulesTestSuite) TestFindModules(c *C) {
c.Assert(diff, checker.DeepEquals, tc.expectedDiff)
}
}
-
-func (s *ModulesTestSuite) TestParseModuleFile(c *C) {
- expectedLength := 20
- expectedModules := []string{
- "ebtable_nat",
- "ebtable_broute",
- "bridge",
- "ip6table_nat",
- "nf_nat_ipv6",
- "ip6table_mangle",
- "ip6table_raw",
- "ip6table_security",
- "iptable_nat",
- "nf_nat_ipv4",
- "iptable_mangle",
- "iptable_raw",
- "iptable_security",
- "ebtable_filter",
- "ebtables",
- "ip6table_filter",
- "ip6_tables",
- "iptable_filter",
- "ip_tables",
- "x_tables",
- }
-
- r := bytes.NewBuffer([]byte(modulesContent))
- moduleInfos, err := parseModulesFile(r)
- c.Assert(err, IsNil)
- c.Assert(moduleInfos, HasLen, expectedLength)
- c.Assert(moduleInfos, checker.DeepEquals, expectedModules)
-}
-
-func (s *ModulesTestSuite) TestListModules(c *C) {
- _, err := listModules()
- c.Assert(err, IsNil)
-}
--
2.39.5 (Apple Git-154)

0 comments on commit ff12ae9

Please sign in to comment.