@@ -35,24 +35,24 @@ type ACL struct {
|
||||
func (a *ACL) Type() Enablement { return a.et }
|
||||
|
||||
func (a *ACL) apply(sys *I) error {
|
||||
sys.println("applying ACL", a)
|
||||
return sys.wrapErrSuffix(acl.Update(a.path, sys.uid, a.perms...),
|
||||
msg.Verbose("applying ACL", a)
|
||||
return wrapErrSuffix(acl.Update(a.path, sys.uid, a.perms...),
|
||||
fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
|
||||
}
|
||||
|
||||
func (a *ACL) revert(sys *I, ec *Criteria) error {
|
||||
if ec.hasType(a) {
|
||||
sys.println("stripping ACL", a)
|
||||
msg.Verbose("stripping ACL", a)
|
||||
err := acl.Update(a.path, sys.uid)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
// the ACL is effectively stripped if the file no longer exists
|
||||
sys.printf("target of ACL %s no longer exists", a)
|
||||
msg.Verbosef("target of ACL %s no longer exists", a)
|
||||
err = nil
|
||||
}
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot strip ACL entry from %q:", a.path))
|
||||
} else {
|
||||
sys.println("skipping ACL", a)
|
||||
msg.Verbose("skipping ACL", a)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath st
|
||||
|
||||
// session bus is mandatory
|
||||
if session == nil {
|
||||
return nil, sys.wrapErr(ErrDBusConfig,
|
||||
return nil, msg.WrapErr(ErrDBusConfig,
|
||||
"attempted to seal message bus proxy without session bus config")
|
||||
}
|
||||
|
||||
@@ -48,12 +48,12 @@ func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath st
|
||||
d.proxy = dbus.New(sessionBus, systemBus)
|
||||
|
||||
defer func() {
|
||||
if sys.IsVerbose() && d.proxy.Sealed() {
|
||||
sys.println("sealed session proxy", session.Args(sessionBus))
|
||||
if msg.IsVerbose() && d.proxy.Sealed() {
|
||||
msg.Verbose("sealed session proxy", session.Args(sessionBus))
|
||||
if system != nil {
|
||||
sys.println("sealed system proxy", system.Args(systemBus))
|
||||
msg.Verbose("sealed system proxy", system.Args(systemBus))
|
||||
}
|
||||
sys.println("message bus proxy final args:", d.proxy)
|
||||
msg.Verbose("message bus proxy final args:", d.proxy)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -62,7 +62,7 @@ func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath st
|
||||
|
||||
// seal dbus proxy
|
||||
d.out = &scanToFmsg{msg: new(strings.Builder)}
|
||||
return d.out.Dump, sys.wrapErrSuffix(d.proxy.Seal(session, system),
|
||||
return d.out.Dump, wrapErrSuffix(d.proxy.Seal(session, system),
|
||||
"cannot seal message bus proxy:")
|
||||
}
|
||||
|
||||
@@ -77,32 +77,32 @@ type DBus struct {
|
||||
func (d *DBus) Type() Enablement { return Process }
|
||||
|
||||
func (d *DBus) apply(sys *I) error {
|
||||
sys.printf("session bus proxy on %q for upstream %q", d.proxy.Session()[1], d.proxy.Session()[0])
|
||||
msg.Verbosef("session bus proxy on %q for upstream %q", d.proxy.Session()[1], d.proxy.Session()[0])
|
||||
if d.system {
|
||||
sys.printf("system bus proxy on %q for upstream %q", d.proxy.System()[1], d.proxy.System()[0])
|
||||
msg.Verbosef("system bus proxy on %q for upstream %q", d.proxy.System()[1], d.proxy.System()[0])
|
||||
}
|
||||
|
||||
// this starts the process and blocks until ready
|
||||
if err := d.proxy.Start(sys.ctx, d.out, true); err != nil {
|
||||
d.out.Dump()
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
"cannot start message bus proxy:")
|
||||
}
|
||||
sys.println("starting message bus proxy", d.proxy)
|
||||
msg.Verbose("starting message bus proxy", d.proxy)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *DBus) revert(sys *I, _ *Criteria) error {
|
||||
func (d *DBus) revert(*I, *Criteria) error {
|
||||
// criteria ignored here since dbus is always process-scoped
|
||||
sys.println("terminating message bus proxy")
|
||||
msg.Verbose("terminating message bus proxy")
|
||||
d.proxy.Close()
|
||||
defer sys.println("message bus proxy exit")
|
||||
defer msg.Verbose("message bus proxy exit")
|
||||
err := d.proxy.Wait()
|
||||
if errors.Is(err, context.Canceled) {
|
||||
sys.println("message bus proxy canceled upstream")
|
||||
msg.Verbose("message bus proxy canceled upstream")
|
||||
err = nil
|
||||
}
|
||||
return sys.wrapErrSuffix(err, "message bus proxy error:")
|
||||
return wrapErrSuffix(err, "message bus proxy error:")
|
||||
}
|
||||
|
||||
func (d *DBus) Is(o Op) bool {
|
||||
|
||||
@@ -25,19 +25,19 @@ type Hardlink struct {
|
||||
|
||||
func (l *Hardlink) Type() Enablement { return l.et }
|
||||
|
||||
func (l *Hardlink) apply(sys *I) error {
|
||||
sys.println("linking", l)
|
||||
return sys.wrapErrSuffix(os.Link(l.src, l.dst),
|
||||
func (l *Hardlink) apply(*I) error {
|
||||
msg.Verbose("linking", l)
|
||||
return wrapErrSuffix(os.Link(l.src, l.dst),
|
||||
fmt.Sprintf("cannot link %q:", l.dst))
|
||||
}
|
||||
|
||||
func (l *Hardlink) revert(sys *I, ec *Criteria) error {
|
||||
func (l *Hardlink) revert(_ *I, ec *Criteria) error {
|
||||
if ec.hasType(l) {
|
||||
sys.printf("removing hard link %q", l.dst)
|
||||
return sys.wrapErrSuffix(os.Remove(l.dst),
|
||||
msg.Verbosef("removing hard link %q", l.dst)
|
||||
return wrapErrSuffix(os.Remove(l.dst),
|
||||
fmt.Sprintf("cannot remove hard link %q:", l.dst))
|
||||
} else {
|
||||
sys.printf("skipping hard link %q", l.dst)
|
||||
msg.Verbosef("skipping hard link %q", l.dst)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,33 +37,33 @@ func (m *Mkdir) Type() Enablement {
|
||||
return m.et
|
||||
}
|
||||
|
||||
func (m *Mkdir) apply(sys *I) error {
|
||||
sys.println("ensuring directory", m)
|
||||
func (m *Mkdir) apply(*I) error {
|
||||
msg.Verbose("ensuring directory", m)
|
||||
|
||||
// create directory
|
||||
err := os.Mkdir(m.path, m.perm)
|
||||
if !errors.Is(err, os.ErrExist) {
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot create directory %q:", m.path))
|
||||
}
|
||||
|
||||
// directory exists, ensure mode
|
||||
return sys.wrapErrSuffix(os.Chmod(m.path, m.perm),
|
||||
return wrapErrSuffix(os.Chmod(m.path, m.perm),
|
||||
fmt.Sprintf("cannot change mode of %q to %s:", m.path, m.perm))
|
||||
}
|
||||
|
||||
func (m *Mkdir) revert(sys *I, ec *Criteria) error {
|
||||
func (m *Mkdir) revert(_ *I, ec *Criteria) error {
|
||||
if !m.ephemeral {
|
||||
// skip non-ephemeral dir and do not log anything
|
||||
return nil
|
||||
}
|
||||
|
||||
if ec.hasType(m) {
|
||||
sys.println("destroying ephemeral directory", m)
|
||||
return sys.wrapErrSuffix(os.Remove(m.path),
|
||||
msg.Verbose("destroying ephemeral directory", m)
|
||||
return wrapErrSuffix(os.Remove(m.path),
|
||||
fmt.Sprintf("cannot remove ephemeral directory %q:", m.path))
|
||||
} else {
|
||||
sys.println("skipping ephemeral directory", m)
|
||||
msg.Verbose("skipping ephemeral directory", m)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
22
system/op.go
22
system/op.go
@@ -60,10 +60,6 @@ func TypeString(e Enablement) string {
|
||||
func New(uid int) (sys *I) {
|
||||
sys = new(I)
|
||||
sys.uid = uid
|
||||
sys.IsVerbose = func() bool { return false }
|
||||
sys.Verbose = func(...any) {}
|
||||
sys.Verbosef = func(string, ...any) {}
|
||||
sys.WrapErr = func(err error, _ ...any) error { return err }
|
||||
return
|
||||
}
|
||||
|
||||
@@ -73,27 +69,13 @@ type I struct {
|
||||
ops []Op
|
||||
ctx context.Context
|
||||
|
||||
IsVerbose func() bool
|
||||
Verbose func(v ...any)
|
||||
Verbosef func(format string, v ...any)
|
||||
WrapErr func(err error, a ...any) error
|
||||
|
||||
// whether sys has been reverted
|
||||
state bool
|
||||
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func (sys *I) UID() int { return sys.uid }
|
||||
func (sys *I) println(v ...any) { sys.Verbose(v...) }
|
||||
func (sys *I) printf(format string, v ...any) { sys.Verbosef(format, v...) }
|
||||
func (sys *I) wrapErr(err error, a ...any) error { return sys.WrapErr(err, a...) }
|
||||
func (sys *I) wrapErrSuffix(err error, a ...any) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return sys.wrapErr(err, append(a, err)...)
|
||||
}
|
||||
func (sys *I) UID() int { return sys.uid }
|
||||
|
||||
// Equal returns whether all [Op] instances held by v is identical to that of sys.
|
||||
func (sys *I) Equal(v *I) bool {
|
||||
@@ -127,7 +109,7 @@ func (sys *I) Commit(ctx context.Context) error {
|
||||
// sp is set to nil when all ops are applied
|
||||
if sp != nil {
|
||||
// rollback partial commit
|
||||
sys.printf("commit faulted after %d ops, rolling back partial commit", len(sp.ops))
|
||||
msg.Verbosef("commit faulted after %d ops, rolling back partial commit", len(sp.ops))
|
||||
if err := sp.Revert(&Criteria{nil}); err != nil {
|
||||
log.Println("errors returned reverting partial commit:", err)
|
||||
}
|
||||
|
||||
20
system/output.go
Normal file
20
system/output.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package system
|
||||
|
||||
import "git.gensokyo.uk/security/fortify/internal/sandbox"
|
||||
|
||||
var msg sandbox.Msg = new(sandbox.DefaultMsg)
|
||||
|
||||
func SetOutput(v sandbox.Msg) {
|
||||
if v == nil {
|
||||
msg = new(sandbox.DefaultMsg)
|
||||
} else {
|
||||
msg = v
|
||||
}
|
||||
}
|
||||
|
||||
func wrapErrSuffix(err error, a ...any) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return msg.WrapErr(err, append(a, err)...)
|
||||
}
|
||||
@@ -31,8 +31,8 @@ type Tmpfile struct {
|
||||
}
|
||||
|
||||
func (t *Tmpfile) Type() Enablement { return Process }
|
||||
func (t *Tmpfile) apply(sys *I) error {
|
||||
sys.println("copying", t)
|
||||
func (t *Tmpfile) apply(*I) error {
|
||||
msg.Verbose("copying", t)
|
||||
|
||||
if t.payload == nil {
|
||||
// this is a misuse of the API; do not return an error message
|
||||
@@ -40,25 +40,25 @@ func (t *Tmpfile) apply(sys *I) error {
|
||||
}
|
||||
|
||||
if b, err := os.Stat(t.src); err != nil {
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot stat %q:", t.src))
|
||||
} else {
|
||||
if b.IsDir() {
|
||||
return sys.wrapErrSuffix(syscall.EISDIR,
|
||||
return wrapErrSuffix(syscall.EISDIR,
|
||||
fmt.Sprintf("%q is a directory", t.src))
|
||||
}
|
||||
if s := b.Size(); s > t.n {
|
||||
return sys.wrapErrSuffix(syscall.ENOMEM,
|
||||
return wrapErrSuffix(syscall.ENOMEM,
|
||||
fmt.Sprintf("file %q is too long: %d > %d",
|
||||
t.src, s, t.n))
|
||||
}
|
||||
}
|
||||
|
||||
if f, err := os.Open(t.src); err != nil {
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot open %q:", t.src))
|
||||
} else if _, err = io.CopyN(t.buf, f, t.n); err != nil {
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot read from %q:", t.src))
|
||||
}
|
||||
|
||||
|
||||
@@ -46,35 +46,35 @@ func (w *Wayland) apply(sys *I) error {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
err = os.ErrNotExist
|
||||
}
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot attach to wayland on %q:", w.src))
|
||||
} else {
|
||||
sys.printf("wayland attached on %q", w.src)
|
||||
msg.Verbosef("wayland attached on %q", w.src)
|
||||
}
|
||||
|
||||
if sp, err := w.conn.Bind(w.dst, w.appID, w.instanceID); err != nil {
|
||||
return sys.wrapErrSuffix(err,
|
||||
return wrapErrSuffix(err,
|
||||
fmt.Sprintf("cannot bind to socket on %q:", w.dst))
|
||||
} else {
|
||||
*w.sync = sp
|
||||
sys.printf("wayland listening on %q", w.dst)
|
||||
return sys.wrapErrSuffix(errors.Join(os.Chmod(w.dst, 0), acl.Update(w.dst, sys.uid, acl.Read, acl.Write, acl.Execute)),
|
||||
msg.Verbosef("wayland listening on %q", w.dst)
|
||||
return wrapErrSuffix(errors.Join(os.Chmod(w.dst, 0), acl.Update(w.dst, sys.uid, acl.Read, acl.Write, acl.Execute)),
|
||||
fmt.Sprintf("cannot chmod socket on %q:", w.dst))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *Wayland) revert(sys *I, ec *Criteria) error {
|
||||
func (w *Wayland) revert(_ *I, ec *Criteria) error {
|
||||
if ec.hasType(w) {
|
||||
sys.printf("removing wayland socket on %q", w.dst)
|
||||
msg.Verbosef("removing wayland socket on %q", w.dst)
|
||||
if err := os.Remove(w.dst); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
return err
|
||||
}
|
||||
|
||||
sys.printf("detaching from wayland on %q", w.src)
|
||||
return sys.wrapErrSuffix(w.conn.Close(),
|
||||
msg.Verbosef("detaching from wayland on %q", w.src)
|
||||
return wrapErrSuffix(w.conn.Close(),
|
||||
fmt.Sprintf("cannot detach from wayland on %q:", w.src))
|
||||
} else {
|
||||
sys.printf("skipping wayland cleanup on %q", w.dst)
|
||||
msg.Verbosef("skipping wayland cleanup on %q", w.dst)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,19 +22,19 @@ func (x XHost) Type() Enablement {
|
||||
return EX11
|
||||
}
|
||||
|
||||
func (x XHost) apply(sys *I) error {
|
||||
sys.printf("inserting entry %s to X11", x)
|
||||
return sys.wrapErrSuffix(xcb.ChangeHosts(xcb.HostModeInsert, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)),
|
||||
func (x XHost) apply(*I) error {
|
||||
msg.Verbosef("inserting entry %s to X11", x)
|
||||
return wrapErrSuffix(xcb.ChangeHosts(xcb.HostModeInsert, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)),
|
||||
fmt.Sprintf("cannot insert entry %s to X11:", x))
|
||||
}
|
||||
|
||||
func (x XHost) revert(sys *I, ec *Criteria) error {
|
||||
func (x XHost) revert(_ *I, ec *Criteria) error {
|
||||
if ec.hasType(x) {
|
||||
sys.printf("deleting entry %s from X11", x)
|
||||
return sys.wrapErrSuffix(xcb.ChangeHosts(xcb.HostModeDelete, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)),
|
||||
msg.Verbosef("deleting entry %s from X11", x)
|
||||
return wrapErrSuffix(xcb.ChangeHosts(xcb.HostModeDelete, xcb.FamilyServerInterpreted, "localuser\x00"+string(x)),
|
||||
fmt.Sprintf("cannot delete entry %s from X11:", x))
|
||||
} else {
|
||||
sys.printf("skipping entry %s in X11", x)
|
||||
msg.Verbosef("skipping entry %s in X11", x)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user