From c75700fe04251b6d93240fb36ec423ed22b5d59d Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Thu, 12 Apr 2018 09:09:46 +0200 Subject: [PATCH] ebpf: check for known faulty Ubuntu kernel The Ubuntu Xenial update to kernel 4.4.0-119.143 from 4.4.0-116.140 did include a regression in the eBPF code. A basic `bpf_map_lookup_elem` call as found in the tcptracer-bpf library used by Scope leads to a kernel panic. As a result, Scope / the system crashes during startup when the tcptracer is initialized. The Scope bug report can be found here: https://github.com/weaveworks/scope/issues/3131 To avoid crashes and gently fallback to procfs (as Scope already does for systems not supporting eBPF), update `isKernelSupported()` and explicitly check for Ubuntu Kernel versions with the problem. Once the bug is fixed and an update published, the `abiNumber` check in `isKernelSupported()` can and should be updated with an upper limit. The Ubuntu bug report can be found here: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1763454 --- probe/endpoint/ebpf.go | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/probe/endpoint/ebpf.go b/probe/endpoint/ebpf.go index 7b4b10fdeb..ac50fdb94a 100644 --- a/probe/endpoint/ebpf.go +++ b/probe/endpoint/ebpf.go @@ -53,16 +53,28 @@ type EbpfTracker struct { closedDuringInit map[fourTuple]struct{} } -var releaseRegex = regexp.MustCompile(`^(\d+)\.(\d+).*$`) +// releaseRegex should match all possible variations of a common Linux +// version string: +// - 4.1 +// - 4.22-foo +// - 4.1.2-foo +// - 4.1.2-33.44+bar +// - etc. +// For example, on a Ubuntu system the vendor specific release part +// (after the first `-`) could look like: +// '.-' or +// '-' +// See https://wiki.ubuntu.com/Kernel/FAQ +var releaseRegex = regexp.MustCompile(`^(\d+)\.(\d+)\.?(\d*)-?(\d*)(.*)$`) func isKernelSupported() error { - release, _, err := host.GetKernelReleaseAndVersion() + release, version, err := host.GetKernelReleaseAndVersion() if err != nil { return err } releaseParts := releaseRegex.FindStringSubmatch(release) - if len(releaseParts) != 3 { + if len(releaseParts) != 6 { return fmt.Errorf("got invalid release version %q (expected format '4.4[.2-1]')", release) } @@ -84,6 +96,24 @@ func isKernelSupported() error { return fmt.Errorf("got kernel %s but need kernel >=4.4", release) } + if strings.Contains(version, "Ubuntu") { + // Check for specific Ubuntu kernel versions with + // known issues. + + abiNumber, err := strconv.Atoi(releaseParts[4]) + if err != nil { + // By now we know it's at least kernel 4.4 and + // not "119-ish", so allow it. + return nil + } + // TODO: give the check an upper limit once the bug is fixed + if major == 4 && minor == 4 && abiNumber >= 119 { + // https://github.com/weaveworks/scope/issues/3131 + // https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1763454 + return fmt.Errorf("got Ubuntu kernel %s with known bug", release) + } + } + return nil }