diff --git a/pkg/driver/distro/debian.go b/pkg/driver/distro/debian.go index 19ddafc1..fa91374f 100644 --- a/pkg/driver/distro/debian.go +++ b/pkg/driver/distro/debian.go @@ -68,10 +68,13 @@ func (d *debian) FixupKernel(kr kernelrelease.KernelRelease) kernelrelease.Kerne archExtra = fmt.Sprintf("-%s%s", matches[1], matches[2]) } if debianKernelVersionRegex.MatchString(kr.KernelVersion) { + newKV := debianKernelVersionRegex.FindStringSubmatch(kr.KernelVersion)[0] // Real kernel release becomes: "5.10.178-3-rt-amd64" - realKernelReleaseStr := fmt.Sprintf("%s%s", kr.KernelVersion, archExtra) + realKernelReleaseStr := fmt.Sprintf("%s%s", newKV, archExtra) // Parse it once again to a KernelRelease struct kr, _ = driverkernel.FetchInfo(realKernelReleaseStr, "1") + return kr } - return kr + // No substitutions needed; call generic FixupKernel. + return d.generic.FixupKernel(kr) } diff --git a/pkg/driver/distro/debian_test.go b/pkg/driver/distro/debian_test.go index c589e2a0..14afd528 100644 --- a/pkg/driver/distro/debian_test.go +++ b/pkg/driver/distro/debian_test.go @@ -92,37 +92,50 @@ func TestDistroDebianFixup(t *testing.T) { krInput string kvInput string krExpected string + kvExpected string } testCases := []testCase{ { - // Substitution needed since kernelversion contains the real kernelrelease + // Substitution needed since kernelversion contains the real kernelrelease (-rt) krInput: "5.10.0-0.deb10.22-rt-amd64", - kvInput: "5.10.178-3", + kvInput: "#1 SMP PREEMPT_DYNAMIC Debian 5.10.178-3", krExpected: "5.10.178-3-rt-amd64", + kvExpected: "1", }, { - // Substitution needed since kernelversion contains the real kernelrelease - krInput: "5.10.0-0.deb10.22-amd64", - kvInput: "5.10.178-3", - krExpected: "5.10.178-3-amd64", + // Substitution needed since kernelversion contains the real kernelrelease (generic flavor) + krInput: "6.1.0-13-amd64", + kvInput: "#1 SMP PREEMPT_DYNAMIC Debian 6.1.55-1 (2023-09-29)", + krExpected: "6.1.55-1-amd64", + kvExpected: "1", }, { // Substitution NOT needed krInput: "5.10.0-0.deb10.22-amd64", - kvInput: "1", + kvInput: "#1 SMP PREEMPT_DYNAMIC", krExpected: "5.10.0-0.deb10.22-amd64", + kvExpected: "1", }, { - // Substitution NOT needed + // Substitution NOT needed; kernelversion is 39 krInput: "5.10.0-0", - kvInput: "1", + kvInput: "#39 SMP PREEMPT_DYNAMIC", krExpected: "5.10.0-0", + kvExpected: "39", + }, + { + // Substitution NOT needed + krInput: "6.5.3-1~bpo12+1-rt-amd64", + kvInput: "#1 SMP PREEMPT_DYNAMIC", + krExpected: "6.5.3-1~bpo12+1-rt-amd64", + kvExpected: "1", }, { // Substitution NOT needed krInput: "6.5.3-1~bpo12+1-rt-amd64", - kvInput: "1", + kvInput: "malformed", krExpected: "6.5.3-1~bpo12+1-rt-amd64", + kvExpected: "malformed", }, } for _, tCase := range testCases { @@ -131,5 +144,6 @@ func TestDistroDebianFixup(t *testing.T) { kr.KernelVersion = tCase.kvInput fixedKr := deb.FixupKernel(kr) assert.Equal(t, tCase.krExpected, fixedKr.String()) + assert.Equal(t, tCase.kvExpected, fixedKr.KernelVersion) } } diff --git a/pkg/driver/distro/distro.go b/pkg/driver/distro/distro.go index 58931025..4eeae4f5 100644 --- a/pkg/driver/distro/distro.go +++ b/pkg/driver/distro/distro.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "net/http" + "net/url" "os" "os/exec" "path/filepath" @@ -125,7 +126,7 @@ func getOSReleaseDistro(kr *kernelrelease.KernelRelease) (Distro, error) { } func toURL(repo, driverVer, fileName, arch string) string { - return fmt.Sprintf("%s/%s/%s/%s", repo, driverVer, arch, fileName) + return fmt.Sprintf("%s/%s/%s/%s", repo, url.QueryEscape(driverVer), arch, fileName) } func toLocalPath(driverVer, fileName, arch string) string { @@ -138,7 +139,10 @@ func toFilename(d Distro, kr *kernelrelease.KernelRelease, driverName string, dr return fmt.Sprintf("%s_%s_%s_%s%s", driverName, d, fixedKR.String(), fixedKR.KernelVersion, driverType.Extension()) } -func copyDataToLocalPath(destination string, src io.Reader) error { +// copyDataToLocalPath will copy a src Reader to a destination file, creating it and its paths if needed. +// Moreover, it will also take care of closing the reader. +func copyDataToLocalPath(destination string, src io.ReadCloser) error { + defer src.Close() err := os.MkdirAll(filepath.Dir(destination), 0o750) if err != nil { return err @@ -162,6 +166,13 @@ func Build(ctx context.Context, driverType drivertype.DriverType, driverVer string, ) (string, error) { + driverFileName := toFilename(d, &kr, driverName, driverType) + destination := toLocalPath(driverVer, driverFileName, kr.Architecture.ToNonDeb()) + if exist, _ := utils.FileExists(destination); exist { + printer.Logger.Info("Skipping build, driver already present.", printer.Logger.Args("path", destination)) + return destination, nil + } + env, err := d.customizeBuild(ctx, printer, driverType, kr) if err != nil { return "", err @@ -173,15 +184,16 @@ func Build(ctx context.Context, // Copy the path to the expected location. // NOTE: for kmod, this is not useful since the driver will // be loaded directly by dkms. - driverFileName := toFilename(d, &kr, driverName, driverType) - filePath := toLocalPath(driverVer, driverFileName, kr.Architecture.ToNonDeb()) - printer.Logger.Info("Copying built driver to its destination.", printer.Logger.Args("src", path, "dst", filePath)) + printer.Logger.Info("Copying built driver to its destination.", printer.Logger.Args("src", path, "dst", destination)) f, err := os.Open(filepath.Clean(path)) if err != nil { return "", err } - defer f.Close() - return filePath, copyDataToLocalPath(filePath, f) + err = copyDataToLocalPath(destination, f) + if err == nil { + printer.Logger.Info("Driver built.", printer.Logger.Args("path", destination)) + } + return destination, err } // Download will try to download drivers for a distro trying specified repos. @@ -224,7 +236,11 @@ func Download(ctx context.Context, } continue } - return destination, copyDataToLocalPath(destination, resp.Body) + err = copyDataToLocalPath(destination, resp.Body) + if err == nil { + printer.Logger.Info("Driver downloaded.", printer.Logger.Args("path", destination)) + } + return destination, err } return destination, fmt.Errorf("unable to find a prebuilt driver") } diff --git a/pkg/driver/distro/generic.go b/pkg/driver/distro/generic.go index d6bbb023..43f24e8c 100644 --- a/pkg/driver/distro/generic.go +++ b/pkg/driver/distro/generic.go @@ -16,6 +16,8 @@ package driverdistro import ( + "strings" + "github.com/blang/semver" "github.com/falcosecurity/driverkit/pkg/kernelrelease" "golang.org/x/net/context" @@ -41,6 +43,10 @@ func (g *generic) String() string { //nolint:gocritic // the method shall not be able to modify kr func (g *generic) FixupKernel(kr kernelrelease.KernelRelease) kernelrelease.KernelRelease { + // Take eg: "#1 SMP PREEMPT_DYNAMIC Tue, 10 Oct 2023 21:10:21 +0000" and return "1". + kv := strings.TrimLeft(kr.KernelVersion, "#") + kv = strings.Split(kv, " ")[0] + kr.KernelVersion = kv return kr } diff --git a/pkg/driver/distro/ubuntu.go b/pkg/driver/distro/ubuntu.go index b7710acc..e8706a9f 100644 --- a/pkg/driver/distro/ubuntu.go +++ b/pkg/driver/distro/ubuntu.go @@ -58,6 +58,8 @@ func (u *ubuntu) FixupKernel(kr kernelrelease.KernelRelease) kernelrelease.Kerne // and everything starting from the first whitespace, // so that eg: we receive "26~22.04.1-Ubuntu", // therefore we only need to drop "-Ubuntu" suffix + // Take eg: "#1 SMP PREEMPT_DYNAMIC Tue, 10 Oct 2023 21:10:21 +0000" and return "1". + kr = u.generic.FixupKernel(kr) kr.KernelVersion = strings.TrimSuffix(kr.KernelVersion, "-Ubuntu") return kr } diff --git a/pkg/driver/distro/ubuntu_test.go b/pkg/driver/distro/ubuntu_test.go index 07729e8e..bbcb151e 100644 --- a/pkg/driver/distro/ubuntu_test.go +++ b/pkg/driver/distro/ubuntu_test.go @@ -32,43 +32,43 @@ func TestDistroUbuntuInitFixup(t *testing.T) { testCases := []testCase{ { krInput: "5.0.0-1028-aws-5.0", - kvInput: "26~22.04.1-Ubuntu", + kvInput: "#26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:15 UTC 2023", flavorExpected: "ubuntu-aws", kvExpected: "26~22.04.1", }, { krInput: "5.0.0-1028-aws-5.0", - kvInput: "26", + kvInput: "#26", flavorExpected: "ubuntu-aws", kvExpected: "26", }, { krInput: "5.0.0-1028-aws-5.0", - kvInput: "26-Ubuntu", + kvInput: "#26-Ubuntu", flavorExpected: "ubuntu-aws", kvExpected: "26", }, { krInput: "5.0.0", - kvInput: "26", + kvInput: "#26", flavorExpected: "ubuntu-generic", kvExpected: "26", }, { krInput: "6.5.0-9-lowlatency", - kvInput: "9.1", + kvInput: "#9.1", flavorExpected: "ubuntu-lowlatency", kvExpected: "9.1", }, { krInput: "6.5.0-1008-gcp", - kvInput: "8", + kvInput: "#8", flavorExpected: "ubuntu-gcp", kvExpected: "8", }, { krInput: "6.5.0-1008-aws", - kvInput: "8~22.04.1", + kvInput: "#8~22.04.1", flavorExpected: "ubuntu-aws", kvExpected: "8~22.04.1", }, diff --git a/pkg/driver/kernel/kernel.go b/pkg/driver/kernel/kernel.go index 47a947d3..3ee78092 100644 --- a/pkg/driver/kernel/kernel.go +++ b/pkg/driver/kernel/kernel.go @@ -19,7 +19,6 @@ package driverkernel import ( "bytes" "runtime" - "strings" "github.com/falcosecurity/driverkit/pkg/kernelrelease" "golang.org/x/sys/unix" @@ -44,21 +43,10 @@ func FetchInfo(enforcedKR, enforcedKV string) (kernelrelease.KernelRelease, erro kv = enforcedKV } kernelRel := kernelrelease.FromString(kr) - kernelRel.KernelVersion = formatVersion(kv) + kernelRel.KernelVersion = kv kernelRel.Architecture = kernelrelease.Architecture(runtime.GOARCH) // we don't use this, it is used by bpf build to customize the kernel config LOCALVERSION. // Expected value is empty. kernelRel.Extraversion = "" return kernelRel, nil } - -// formatVersion takes a kernelversion string (as taken from `uname -v` -// and extracts the first part of the string. -// Eg: '#1 SMP PREEMPT_DYNAMIC Tue, 10 Oct 2023 21:10:21 +0000' -> '1'. -// Eg: '#26~22.04.1-Ubuntu SMP Mon Apr 24 01:58:15 UTC 2023' -> '26~22.04.1-Ubuntu'. -func formatVersion(kv string) string { - // Take eg: "#1 SMP PREEMPT_DYNAMIC Tue, 10 Oct 2023 21:10:21 +0000" and return "1". - kv = strings.Trim(kv, "#") - kv = strings.Split(kv, " ")[0] - return kv -}