132 lines
5.2 KiB
Go
132 lines
5.2 KiB
Go
package main
|
|
|
|
// The after-upgrade check, its second part (novox/hq ADR 0508 §4; acceptance 1841/AC5): processes still mapping a
|
|
// replaced file, by unit or container and executable, never a command line or environment; DKMS built for every
|
|
// installed kernel.
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// standInProc is a process table in memory; it records every file read, so nothing else is read.
|
|
type standInProc struct {
|
|
files map[string]string
|
|
links map[string]string
|
|
read []string
|
|
}
|
|
|
|
func (p *standInProc) ReadDir(dir string) ([]string, error) {
|
|
seen := map[string]bool{}
|
|
var names []string
|
|
for f := range p.files {
|
|
if rest, ok := strings.CutPrefix(f, dir+"/"); ok {
|
|
n, _, _ := strings.Cut(rest, "/")
|
|
if !seen[n] {
|
|
seen[n] = true
|
|
names = append(names, n)
|
|
}
|
|
}
|
|
}
|
|
return names, nil
|
|
}
|
|
|
|
func (p *standInProc) ReadFile(name string) ([]byte, error) {
|
|
p.read = append(p.read, name)
|
|
if s, ok := p.files[name]; ok {
|
|
return []byte(s), nil
|
|
}
|
|
return nil, errNoFile
|
|
}
|
|
|
|
func (p *standInProc) Readlink(name string) (string, error) {
|
|
if s, ok := p.links[name]; ok {
|
|
return s, nil
|
|
}
|
|
return "", errNoFile
|
|
}
|
|
|
|
const libcDeleted = "7f2a1c000000-7f2a1c028000 r--p 00000000 103:02 5513 /usr/lib/libc.so.6 (deleted)\n"
|
|
|
|
func TestAProcessMappingAReplacedFileIsNamedByItsUnitOrContainerAndExecutableOnly(t *testing.T) {
|
|
p := &standInProc{files: map[string]string{
|
|
"/proc/1/maps": libcDeleted,
|
|
"/proc/1/cgroup": "0::/init.scope\n",
|
|
"/proc/200/maps": "5600-5700 r-xp 00000000 103:02 77 /usr/bin/sshd\n" + strings.Replace(libcDeleted, "libc.so.6", "libcrypto.so.3", 1),
|
|
"/proc/200/cgroup": "0::/system.slice/sshd.service\n",
|
|
"/proc/201/maps": libcDeleted,
|
|
"/proc/201/cgroup": "0::/system.slice/sshd.service\n",
|
|
"/proc/300/maps": libcDeleted,
|
|
"/proc/300/cgroup": "0::/system.slice/docker-0123456789abcdef0123456789abcdef.scope\n",
|
|
"/proc/400/maps": "7f00-7f10 rw-s 00000000 00:1a 9 /dev/shm/made-up (deleted)\n",
|
|
"/proc/400/cgroup": "0::/system.slice/made-up.service\n",
|
|
"/proc/500/maps": "5600-5700 r-xp 00000000 103:02 77 /usr/bin/made-up\n",
|
|
"/proc/500/cmdline": "made-up --password=secret",
|
|
"/proc/500/environ": "TOKEN=secret",
|
|
"/proc/self/maps": libcDeleted,
|
|
}, links: map[string]string{
|
|
"/proc/1/exe": "/usr/lib/systemd/systemd", "/proc/200/exe": "/usr/bin/sshd (deleted)", "/proc/201/exe": "/usr/bin/sshd (deleted)",
|
|
"/proc/300/exe": "/usr/bin/made-up-server",
|
|
}}
|
|
got, err := MappedDeleted(p, "/proc")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
var said []string
|
|
for _, m := range got {
|
|
said = append(said, m.Unit+"|"+m.Container+"|"+m.Executable)
|
|
}
|
|
if strings.Join(said, " ") != "|0123456789ab|/usr/bin/made-up-server init.scope||/usr/lib/systemd/systemd sshd.service||/usr/bin/sshd" {
|
|
t.Errorf("%v", said)
|
|
}
|
|
for _, r := range p.read {
|
|
if strings.HasSuffix(r, "/cmdline") || strings.HasSuffix(r, "/environ") {
|
|
t.Errorf("read %s: a process is named by its unit and executable, never its command line or environment", r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestADKMSModuleNotBuiltForAnInstalledKernelFailsTheCheck(t *testing.T) {
|
|
m := checkMachine("", "7.2.9-arch1-1")
|
|
table := map[string]Ran{
|
|
"systemctl list-units --state=failed --plain --no-legend --no-pager": {},
|
|
"pacman -Qq": {Stdout: "linux\nlinux-lts\n"},
|
|
"pacman -Qlq -- linux": {Stdout: "/usr/lib/modules/7.2.9-arch1-1/vmlinuz\n"},
|
|
"pacman -Qlq -- linux-lts": {Stdout: "/usr/lib/modules/6.18.54-2-lts/vmlinuz\n"},
|
|
"dkms status": {Stdout: "zfs/2.4.4, 6.18.54-2-lts, x86_64: installed\nzfs/2.4.4, 7.2.8-arch1-2, x86_64: installed\n" +
|
|
"made-up-driver/1.0, 6.18.54-2-lts, x86_64: installed\nxpad/0.4: added\n"},
|
|
}
|
|
m.Run = byLine(table, nil)
|
|
read := m.ReadFile
|
|
m.ReadFile = func(path string) ([]byte, error) {
|
|
if path == "/usr/src/made-up-driver-1.0/dkms.conf" {
|
|
return []byte("BUILD_EXCLUSIVE_KERNEL=\"^6\\.\"\n"), nil
|
|
}
|
|
return read(path)
|
|
}
|
|
u := checkUpgrades(t, m)
|
|
u.Root = &fakeRoot{mapped: []Mapped{{Unit: "sshd.service", Executable: "/usr/bin/sshd"}}}
|
|
c := u.AfterCheck(checkedRun(StepStarted, StepFinished), &Record{})
|
|
if len(c.Unbuilt) != 1 || c.Unbuilt[0] != (DKMSBuild{Module: "zfs", Version: "2.4.4", Kernel: "7.2.9-arch1-1"}) || c.Passed {
|
|
t.Errorf("zfs not built for the new kernel fails the check (made-up-driver excludes it, xpad was never built): %+v", c)
|
|
}
|
|
if len(c.Mapped) != 1 || c.Mapped[0].Unit != "sshd.service" {
|
|
t.Errorf("mapped: %+v", c.Mapped)
|
|
}
|
|
|
|
table["dkms status"] = Ran{Stdout: "zfs/2.4.4, 6.18.54-2-lts, x86_64: installed\nzfs/2.4.4, 7.2.9-arch1-1, x86_64: installed\n"}
|
|
if c := u.AfterCheck(checkedRun(StepStarted, StepFinished), &Record{}); !c.Passed || len(c.Mapped) != 1 {
|
|
t.Errorf("built for every kernel passes; a mapped file is said and does not fail it: %+v", c)
|
|
}
|
|
|
|
u.Root = &fakeRoot{mapsErr: errors.New("the root helper's socket is not there")}
|
|
if c := u.AfterCheck(checkedRun(StepStarted, StepFinished), &Record{}); !strings.Contains(c.MappedError, "socket") {
|
|
t.Errorf("unread mappings are said: %+v", c)
|
|
}
|
|
table["dkms status"] = Ran{Status: 1, Stderr: "dkms: permission denied\n"}
|
|
if c := u.AfterCheck(checkedRun(StepStarted, StepFinished), &Record{}); c.Passed || c.DKMSError == "" {
|
|
t.Errorf("unread DKMS builds do not pass: %+v", c)
|
|
}
|
|
}
|