test/sandbox: wrap libc getmntent
For checking mounts outcome. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
2d4cabe786
commit
4de4049713
134
test/sandbox/mount.go
Normal file
134
test/sandbox/mount.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package sandbox
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <mntent.h>
|
||||||
|
|
||||||
|
const char *F_PROC_MOUNTS = "";
|
||||||
|
const char *F_SET_TYPE = "r";
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Mntent struct {
|
||||||
|
/* name of mounted filesystem */
|
||||||
|
FSName string `json:"fsname"`
|
||||||
|
/* filesystem path prefix */
|
||||||
|
Dir string `json:"dir"`
|
||||||
|
/* mount type (see mntent.h) */
|
||||||
|
Type string `json:"type"`
|
||||||
|
/* mount options (see mntent.h) */
|
||||||
|
Opts string `json:"opts"`
|
||||||
|
/* dump frequency in days */
|
||||||
|
Freq int `json:"freq"`
|
||||||
|
/* pass number on parallel fsck */
|
||||||
|
Passno int `json:"passno"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Mntent) String() string {
|
||||||
|
return fmt.Sprintf("%s %s %s %s %d %d",
|
||||||
|
e.FSName, e.Dir, e.Type, e.Opts, e.Freq, e.Passno)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IterMounts(name string, f func(e *Mntent)) error {
|
||||||
|
m := new(mounts)
|
||||||
|
m.p = name
|
||||||
|
if err := m.open(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for m.scan() {
|
||||||
|
e := new(Mntent)
|
||||||
|
m.copy(e)
|
||||||
|
f(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
m.close()
|
||||||
|
return m.Err()
|
||||||
|
}
|
||||||
|
|
||||||
|
type mounts struct {
|
||||||
|
p string
|
||||||
|
f *C.FILE
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
ent *C.struct_mntent
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mounts) open() error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
if m.f != nil {
|
||||||
|
panic("open called twice")
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.p == "" {
|
||||||
|
m.p = "/proc/mounts"
|
||||||
|
}
|
||||||
|
|
||||||
|
name := C.CString(m.p)
|
||||||
|
f, err := C.setmntent(name, C.F_SET_TYPE)
|
||||||
|
C.free(unsafe.Pointer(name))
|
||||||
|
|
||||||
|
if f == nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
m.f = f
|
||||||
|
runtime.SetFinalizer(m, (*mounts).close)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mounts) close() {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
if m.f == nil {
|
||||||
|
panic("close called before open")
|
||||||
|
}
|
||||||
|
|
||||||
|
C.endmntent(m.f)
|
||||||
|
runtime.SetFinalizer(m, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mounts) scan() bool {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
if m.f == nil {
|
||||||
|
panic("invalid file")
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ent, m.err = C.getmntent(m.f)
|
||||||
|
return m.ent != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mounts) Err() error {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
|
||||||
|
return m.err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mounts) copy(v *Mntent) {
|
||||||
|
m.mu.RLock()
|
||||||
|
defer m.mu.RUnlock()
|
||||||
|
|
||||||
|
if m.ent == nil {
|
||||||
|
panic("invalid entry")
|
||||||
|
}
|
||||||
|
v.FSName = C.GoString(m.ent.mnt_fsname)
|
||||||
|
v.Dir = C.GoString(m.ent.mnt_dir)
|
||||||
|
v.Type = C.GoString(m.ent.mnt_type)
|
||||||
|
v.Opts = C.GoString(m.ent.mnt_opts)
|
||||||
|
v.Freq = int(m.ent.mnt_freq)
|
||||||
|
v.Passno = int(m.ent.mnt_passno)
|
||||||
|
}
|
112
test/sandbox/mount_test.go
Normal file
112
test/sandbox/mount_test.go
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
package sandbox_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.gensokyo.uk/security/fortify/test/sandbox"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMounts(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
|
||||||
|
sample string
|
||||||
|
want []sandbox.Mntent
|
||||||
|
}{
|
||||||
|
{"fpkg", `tmpfs / tmpfs rw,nosuid,nodev,relatime,uid=1000002,gid=1000002 0 0
|
||||||
|
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
tmpfs /.fortify tmpfs rw,nosuid,nodev,relatime,size=4k,mode=755,uid=1000002,gid=1000002 0 0
|
||||||
|
tmpfs /dev tmpfs rw,nosuid,nodev,relatime,mode=755,uid=1000002,gid=1000002 0 0
|
||||||
|
devtmpfs /dev/null devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
devtmpfs /dev/zero devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
devtmpfs /dev/full devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
devtmpfs /dev/random devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
devtmpfs /dev/urandom devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
devtmpfs /dev/tty devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
devpts /dev/pts devpts rw,nosuid,noexec,relatime,mode=620,ptmxmode=666 0 0
|
||||||
|
mqueue /dev/mqueue mqueue rw,relatime 0 0
|
||||||
|
/dev/disk/by-label/nixos /nix/store ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
/dev/disk/by-label/nixos /.fortify/app ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
/dev/disk/by-label/nixos /etc/resolv.conf ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
sysfs /sys/block sysfs ro,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
sysfs /sys/bus sysfs ro,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
sysfs /sys/class sysfs ro,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
sysfs /sys/dev sysfs ro,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
sysfs /sys/devices sysfs ro,nosuid,nodev,noexec,relatime 0 0
|
||||||
|
/dev/disk/by-label/nixos /.fortify/nixGL ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
devtmpfs /dev/dri devtmpfs rw,nosuid,size=49396k,nr_inodes=121247,mode=755 0 0
|
||||||
|
/dev/disk/by-label/nixos /.fortify/etc ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
tmpfs /run/user tmpfs rw,nosuid,nodev,relatime,size=1024k,mode=755,uid=1000002,gid=1000002 0 0
|
||||||
|
tmpfs /run/user/65534 tmpfs rw,nosuid,nodev,relatime,size=8192k,mode=755,uid=1000002,gid=1000002 0 0
|
||||||
|
/dev/disk/by-label/nixos /tmp ext4 rw,nosuid,nodev,relatime 0 0
|
||||||
|
/dev/disk/by-label/nixos /data/data/org.codeberg.dnkl.foot ext4 rw,nosuid,nodev,relatime 0 0
|
||||||
|
tmpfs /etc/passwd tmpfs ro,nosuid,nodev,relatime,uid=1000002,gid=1000002 0 0
|
||||||
|
tmpfs /etc/group tmpfs ro,nosuid,nodev,relatime,uid=1000002,gid=1000002 0 0
|
||||||
|
/dev/disk/by-label/nixos /run/user/65534/wayland-0 ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
tmpfs /run/user/65534/pulse/native tmpfs ro,nosuid,nodev,relatime,size=98784k,nr_inodes=24696,mode=700,uid=1000,gid=100 0 0
|
||||||
|
/dev/disk/by-label/nixos /run/user/65534/bus ext4 ro,nosuid,nodev,relatime 0 0
|
||||||
|
overlay /.fortify/sbin/fortify overlay ro,nosuid,nodev,relatime,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work,uuid=on 0 0
|
||||||
|
`, []sandbox.Mntent{
|
||||||
|
{"tmpfs", "/", "tmpfs", "rw,nosuid,nodev,relatime,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"proc", "/proc", "proc", "rw,nosuid,nodev,noexec,relatime", 0, 0},
|
||||||
|
{"tmpfs", "/.fortify", "tmpfs", "rw,nosuid,nodev,relatime,size=4k,mode=755,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"tmpfs", "/dev", "tmpfs", "rw,nosuid,nodev,relatime,mode=755,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/null", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/zero", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/full", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/random", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/urandom", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/tty", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"devpts", "/dev/pts", "devpts", "rw,nosuid,noexec,relatime,mode=620,ptmxmode=666", 0, 0},
|
||||||
|
{"mqueue", "/dev/mqueue", "mqueue", "rw,relatime", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/nix/store", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/.fortify/app", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/etc/resolv.conf", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"sysfs", "/sys/block", "sysfs", "ro,nosuid,nodev,noexec,relatime", 0, 0},
|
||||||
|
{"sysfs", "/sys/bus", "sysfs", "ro,nosuid,nodev,noexec,relatime", 0, 0},
|
||||||
|
{"sysfs", "/sys/class", "sysfs", "ro,nosuid,nodev,noexec,relatime", 0, 0},
|
||||||
|
{"sysfs", "/sys/dev", "sysfs", "ro,nosuid,nodev,noexec,relatime", 0, 0},
|
||||||
|
{"sysfs", "/sys/devices", "sysfs", "ro,nosuid,nodev,noexec,relatime", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/.fortify/nixGL", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"devtmpfs", "/dev/dri", "devtmpfs", "rw,nosuid,size=49396k,nr_inodes=121247,mode=755", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/.fortify/etc", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"tmpfs", "/run/user", "tmpfs", "rw,nosuid,nodev,relatime,size=1024k,mode=755,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"tmpfs", "/run/user/65534", "tmpfs", "rw,nosuid,nodev,relatime,size=8192k,mode=755,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/tmp", "ext4", "rw,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/data/data/org.codeberg.dnkl.foot", "ext4", "rw,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"tmpfs", "/etc/passwd", "tmpfs", "ro,nosuid,nodev,relatime,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"tmpfs", "/etc/group", "tmpfs", "ro,nosuid,nodev,relatime,uid=1000002,gid=1000002", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/run/user/65534/wayland-0", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"tmpfs", "/run/user/65534/pulse/native", "tmpfs", "ro,nosuid,nodev,relatime,size=98784k,nr_inodes=24696,mode=700,uid=1000,gid=100", 0, 0},
|
||||||
|
{"/dev/disk/by-label/nixos", "/run/user/65534/bus", "ext4", "ro,nosuid,nodev,relatime", 0, 0},
|
||||||
|
{"overlay", "/.fortify/sbin/fortify", "overlay", "ro,nosuid,nodev,relatime,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work,uuid=on", 0, 0},
|
||||||
|
}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
name := path.Join(t.TempDir(), "sample")
|
||||||
|
if err := os.WriteFile(name, []byte(tc.sample), 0400); err != nil {
|
||||||
|
t.Fatalf("cannot write sample: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
if err := sandbox.IterMounts(name, func(e *sandbox.Mntent) {
|
||||||
|
if i == len(tc.want) {
|
||||||
|
t.Errorf("IterMounts: got more than %d entries", i)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
if *e != tc.want[i] {
|
||||||
|
t.Errorf("IterMounts: entry %d\n got: %s\nwant: %s", i,
|
||||||
|
e, &tc.want[i])
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("IterMounts: error = %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user