fst: hide sockets exposed via Filesystem
This is mostly useful for permissive defaults. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
11
fst/path.go
Normal file
11
fst/path.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package fst
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func deepContainsH(basepath, targpath string) (bool, error) {
|
||||
rel, err := filepath.Rel(basepath, targpath)
|
||||
return err == nil && rel != ".." && !strings.HasPrefix(rel, string([]byte{'.', '.', filepath.Separator})), err
|
||||
}
|
||||
85
fst/path_test.go
Normal file
85
fst/path_test.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package fst
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeepContainsH(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
basepath string
|
||||
targpath string
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "equal abs",
|
||||
basepath: "/run",
|
||||
targpath: "/run",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "equal rel",
|
||||
basepath: "./run",
|
||||
targpath: "run",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "contains abs",
|
||||
basepath: "/run",
|
||||
targpath: "/run/dbus",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "inverse contains abs",
|
||||
basepath: "/run/dbus",
|
||||
targpath: "/run",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "contains rel",
|
||||
basepath: "../run",
|
||||
targpath: "../run/dbus",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "inverse contains rel",
|
||||
basepath: "../run/dbus",
|
||||
targpath: "../run",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "weird abs",
|
||||
basepath: "/run/dbus",
|
||||
targpath: "/run/dbus/../current-system",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "weird rel",
|
||||
basepath: "../run/dbus",
|
||||
targpath: "../run/dbus/../current-system",
|
||||
want: false,
|
||||
},
|
||||
|
||||
{
|
||||
name: "invalid mix",
|
||||
basepath: "/run",
|
||||
targpath: "./run",
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if got, err := deepContainsH(tc.basepath, tc.targpath); (err != nil) != tc.wantErr {
|
||||
t.Errorf("deepContainsH() error = %v, wantErr %v", err, tc.wantErr)
|
||||
} else if got != tc.want {
|
||||
t.Errorf("deepContainsH() = %v, want %v", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,13 @@ package fst
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"path"
|
||||
|
||||
"git.gensokyo.uk/security/fortify/dbus"
|
||||
"git.gensokyo.uk/security/fortify/helper/bwrap"
|
||||
"git.gensokyo.uk/security/fortify/internal/fmsg"
|
||||
"git.gensokyo.uk/security/fortify/internal/linux"
|
||||
)
|
||||
|
||||
@@ -68,7 +73,8 @@ func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
|
||||
DieWithParent: true,
|
||||
AsInit: true,
|
||||
|
||||
// initialise map
|
||||
// initialise unconditionally as Once cannot be justified
|
||||
// for saving such a miniscule amount of memory
|
||||
Chmod: make(bwrap.ChmodConfig),
|
||||
}).
|
||||
SetUID(uid).SetGID(uid).
|
||||
@@ -89,16 +95,85 @@ func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve paths and hide them if they're made available in the sandbox
|
||||
var hidePaths []string
|
||||
sc := os.Paths()
|
||||
hidePaths = append(hidePaths, sc.RuntimePath, sc.SharePath)
|
||||
_, systemBusAddr := dbus.Address()
|
||||
if entries, err := dbus.Parse([]byte(systemBusAddr)); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
// there is usually only one, do not preallocate
|
||||
for _, entry := range entries {
|
||||
if entry.Method != "unix" {
|
||||
continue
|
||||
}
|
||||
for _, pair := range entry.Values {
|
||||
if pair[0] == "path" {
|
||||
if path.IsAbs(pair[1]) {
|
||||
// get parent dir of socket
|
||||
dir := path.Dir(pair[1])
|
||||
if dir == "." || dir == "/" {
|
||||
fmsg.VPrintf("dbus socket %q is in an unusual location", pair[1])
|
||||
}
|
||||
hidePaths = append(hidePaths, dir)
|
||||
} else {
|
||||
fmsg.VPrintf("dbus socket %q is not absolute", pair[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
hidePathMatch := make([]bool, len(hidePaths))
|
||||
for i := range hidePaths {
|
||||
if err := evalSymlinks(os, &hidePaths[i]); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range s.Filesystem {
|
||||
if c == nil {
|
||||
continue
|
||||
}
|
||||
src := c.Src
|
||||
|
||||
if !path.IsAbs(c.Src) {
|
||||
return nil, fmt.Errorf("src path %q is not absolute", c.Src)
|
||||
}
|
||||
|
||||
dest := c.Dst
|
||||
if c.Dst == "" {
|
||||
dest = c.Src
|
||||
} else if !path.IsAbs(dest) {
|
||||
return nil, fmt.Errorf("dst path %q is not absolute", dest)
|
||||
}
|
||||
|
||||
srcH := c.Src
|
||||
if err := evalSymlinks(os, &srcH); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range hidePaths {
|
||||
// skip matched entries
|
||||
if hidePathMatch[i] {
|
||||
continue
|
||||
}
|
||||
|
||||
if ok, err := deepContainsH(srcH, hidePaths[i]); err != nil {
|
||||
return nil, err
|
||||
} else if ok {
|
||||
hidePathMatch[i] = true
|
||||
fmsg.VPrintf("hiding paths from %q", c.Src)
|
||||
}
|
||||
}
|
||||
|
||||
conf.Bind(c.Src, dest, !c.Must, c.Write, c.Device)
|
||||
}
|
||||
|
||||
// hide marked paths before setting up shares
|
||||
for i, ok := range hidePathMatch {
|
||||
if ok {
|
||||
conf.Tmpfs(hidePaths[i], 8192)
|
||||
}
|
||||
conf.Bind(src, dest, !c.Must, c.Write, c.Device)
|
||||
}
|
||||
|
||||
for _, l := range s.Link {
|
||||
@@ -133,3 +208,15 @@ func (s *SandboxConfig) Bwrap(os linux.System) (*bwrap.Config, error) {
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
|
||||
func evalSymlinks(os linux.System, v *string) error {
|
||||
if p, err := os.EvalSymlinks(*v); err != nil {
|
||||
if !errors.Is(err, fs.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
fmsg.VPrintf("path %q does not yet exist", *v)
|
||||
} else {
|
||||
*v = p
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user