aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2024-12-28 13:23:27 +0900
committerOphestra <cat@gensokyo.uk>2024-12-28 13:23:27 +0900
commit847b667489e661d0e59240d64614a33392d94e0d (patch)
tree88f7f068d762b3cf9f6198de03b4f3e3277dfea3
parentc70f0612ad32f9ba5dc4ecf793aa4553929372d4 (diff)
app: extra acl entries from configuration
Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--fst/config.go25
-rw-r--r--internal/app/seal.go98
-rw-r--r--internal/app/share.go8
-rw-r--r--print.go60
4 files changed, 133 insertions, 58 deletions
diff --git a/fst/config.go b/fst/config.go
index 05b588d6..27e13f04 100644
--- a/fst/config.go
+++ b/fst/config.go
@@ -35,6 +35,8 @@ type ConfinementConfig struct {
Outer string `json:"home"`
// bwrap sandbox confinement configuration
Sandbox *SandboxConfig `json:"sandbox"`
+ // extra acl entries to append
+ ExtraPerms []*ExtraPermConfig `json:"extra_perms,omitempty"`
// reference to a system D-Bus proxy configuration,
// nil value disables system bus proxy
@@ -78,6 +80,29 @@ type SandboxConfig struct {
Override []string `json:"override"`
}
+type ExtraPermConfig struct {
+ Path string `json:"path"`
+ Read bool `json:"r,omitempty"`
+ Write bool `json:"w,omitempty"`
+ Execute bool `json:"x,omitempty"`
+}
+
+func (e *ExtraPermConfig) String() string {
+ buf := make([]byte, 0, 4+len(e.Path))
+ buf = append(buf, '-', '-', '-', ':')
+ buf = append(buf, []byte(e.Path)...)
+ if e.Read {
+ buf[0] = 'r'
+ }
+ if e.Write {
+ buf[1] = 'w'
+ }
+ if e.Execute {
+ buf[2] = 'x'
+ }
+ return string(buf)
+}
+
type FilesystemConfig struct {
// mount point in sandbox, same as src if empty
Dst string `json:"dst,omitempty"`
diff --git a/internal/app/seal.go b/internal/app/seal.go
index 87e62b36..82b7983e 100644
--- a/internal/app/seal.go
+++ b/internal/app/seal.go
@@ -8,6 +8,7 @@ import (
"regexp"
"strconv"
+ "git.gensokyo.uk/security/fortify/acl"
"git.gensokyo.uk/security/fortify/dbus"
"git.gensokyo.uk/security/fortify/fst"
"git.gensokyo.uk/security/fortify/internal/fmsg"
@@ -48,6 +49,8 @@ type appSeal struct {
et system.Enablements
// wayland socket direct access
directWayland bool
+ // extra UpdatePerm ops
+ extraPerms []*sealedExtraPerm
// prevents sharing from happening twice
shared bool
@@ -59,6 +62,11 @@ type appSeal struct {
// protected by upstream mutex
}
+type sealedExtraPerm struct {
+ name string
+ perms acl.Perms
+}
+
// Seal seals the app launch context
func (a *app) Seal(config *fst.Config) error {
a.lock.Lock()
@@ -100,46 +108,66 @@ func (a *app) Seal(config *fst.Config) error {
if config.Confinement.AppID < 0 || config.Confinement.AppID > 9999 {
return fmsg.WrapError(ErrUser,
fmt.Sprintf("aid %d out of range", config.Confinement.AppID))
+ }
+ seal.sys.user = appUser{
+ aid: config.Confinement.AppID,
+ as: strconv.Itoa(config.Confinement.AppID),
+ data: config.Confinement.Outer,
+ home: config.Confinement.Inner,
+ username: config.Confinement.Username,
+ }
+ if seal.sys.user.username == "" {
+ seal.sys.user.username = "chronos"
+ } else if !posixUsername.MatchString(seal.sys.user.username) {
+ return fmsg.WrapError(ErrName,
+ fmt.Sprintf("invalid user name %q", seal.sys.user.username))
+ }
+ if seal.sys.user.data == "" || !path.IsAbs(seal.sys.user.data) {
+ return fmsg.WrapError(ErrHome,
+ fmt.Sprintf("invalid home directory %q", seal.sys.user.data))
+ }
+ if seal.sys.user.home == "" {
+ seal.sys.user.home = seal.sys.user.data
+ }
+
+ // invoke fsu for full uid
+ if u, err := a.os.Uid(seal.sys.user.aid); err != nil {
+ return fmsg.WrapErrorSuffix(err,
+ "cannot obtain uid from fsu:")
} else {
- seal.sys.user = appUser{
- aid: config.Confinement.AppID,
- as: strconv.Itoa(config.Confinement.AppID),
- data: config.Confinement.Outer,
- home: config.Confinement.Inner,
- username: config.Confinement.Username,
- }
- if seal.sys.user.username == "" {
- seal.sys.user.username = "chronos"
- } else if !posixUsername.MatchString(seal.sys.user.username) {
- return fmsg.WrapError(ErrName,
- fmt.Sprintf("invalid user name %q", seal.sys.user.username))
- }
- if seal.sys.user.data == "" || !path.IsAbs(seal.sys.user.data) {
- return fmsg.WrapError(ErrHome,
- fmt.Sprintf("invalid home directory %q", seal.sys.user.data))
- }
- if seal.sys.user.home == "" {
- seal.sys.user.home = seal.sys.user.data
- }
+ seal.sys.user.uid = u
+ seal.sys.user.us = strconv.Itoa(u)
+ }
- // invoke fsu for full uid
- if u, err := a.os.Uid(seal.sys.user.aid); err != nil {
- return fmsg.WrapErrorSuffix(err,
- "cannot obtain uid from fsu:")
+ // resolve supplementary group ids from names
+ seal.sys.user.supp = make([]string, len(config.Confinement.Groups))
+ for i, name := range config.Confinement.Groups {
+ if g, err := a.os.LookupGroup(name); err != nil {
+ return fmsg.WrapError(err,
+ fmt.Sprintf("unknown group %q", name))
} else {
- seal.sys.user.uid = u
- seal.sys.user.us = strconv.Itoa(u)
+ seal.sys.user.supp[i] = g.Gid
}
+ }
- // resolve supplementary group ids from names
- seal.sys.user.supp = make([]string, len(config.Confinement.Groups))
- for i, name := range config.Confinement.Groups {
- if g, err := a.os.LookupGroup(name); err != nil {
- return fmsg.WrapError(err,
- fmt.Sprintf("unknown group %q", name))
- } else {
- seal.sys.user.supp[i] = g.Gid
- }
+ // build extra perms
+ seal.extraPerms = make([]*sealedExtraPerm, len(config.Confinement.ExtraPerms))
+ for i, p := range config.Confinement.ExtraPerms {
+ if p == nil {
+ continue
+ }
+
+ seal.extraPerms[i] = new(sealedExtraPerm)
+ seal.extraPerms[i].name = p.Path
+ seal.extraPerms[i].perms = make(acl.Perms, 0, 3)
+ if p.Read {
+ seal.extraPerms[i].perms = append(seal.extraPerms[i].perms, acl.Read)
+ }
+ if p.Write {
+ seal.extraPerms[i].perms = append(seal.extraPerms[i].perms, acl.Write)
+ }
+ if p.Execute {
+ seal.extraPerms[i].perms = append(seal.extraPerms[i].perms, acl.Execute)
}
}
diff --git a/internal/app/share.go b/internal/app/share.go
index dea55a87..0a18e310 100644
--- a/internal/app/share.go
+++ b/internal/app/share.go
@@ -292,6 +292,14 @@ func (seal *appSeal) setupShares(bus [2]*dbus.Config, os linux.System) error {
seal.sys.bwrap.Tmpfs(dest, 8*1024)
}
+ // append extra perms
+ for _, p := range seal.extraPerms {
+ if p == nil {
+ continue
+ }
+ seal.sys.UpdatePermType(system.User, p.name, p.perms...)
+ }
+
return nil
}
diff --git a/print.go b/print.go
index c3126a40..702f35ea 100644
--- a/print.go
+++ b/print.go
@@ -90,33 +90,47 @@ func printShow(instance *state.State, config *fst.Config, short bool) {
fmt.Fprintf(w, " Command:\t%s\n", strings.Join(config.Command, " "))
fmt.Fprintf(w, "\n")
- if !short && config.Confinement.Sandbox != nil && len(config.Confinement.Sandbox.Filesystem) > 0 {
- fmt.Fprintf(w, "Filesystem:\n")
- for _, f := range config.Confinement.Sandbox.Filesystem {
- if f == nil {
- continue
- }
+ if !short {
+ if config.Confinement.Sandbox != nil && len(config.Confinement.Sandbox.Filesystem) > 0 {
+ fmt.Fprintf(w, "Filesystem\n")
+ for _, f := range config.Confinement.Sandbox.Filesystem {
+ if f == nil {
+ continue
+ }
- expr := new(strings.Builder)
- if f.Device {
- expr.WriteString(" d")
- } else if f.Write {
- expr.WriteString(" w")
- } else {
- expr.WriteString(" ")
- }
- if f.Must {
- expr.WriteString("*")
- } else {
- expr.WriteString("+")
+ expr := new(strings.Builder)
+ expr.Grow(3 + len(f.Src) + 1 + len(f.Dst))
+
+ if f.Device {
+ expr.WriteString(" d")
+ } else if f.Write {
+ expr.WriteString(" w")
+ } else {
+ expr.WriteString(" ")
+ }
+ if f.Must {
+ expr.WriteString("*")
+ } else {
+ expr.WriteString("+")
+ }
+ expr.WriteString(f.Src)
+ if f.Dst != "" {
+ expr.WriteString(":" + f.Dst)
+ }
+ fmt.Fprintf(w, "%s\n", expr.String())
}
- expr.WriteString(f.Src)
- if f.Dst != "" {
- expr.WriteString(":" + f.Dst)
+ fmt.Fprintf(w, "\n")
+ }
+ if len(config.Confinement.ExtraPerms) > 0 {
+ fmt.Fprintf(w, "Extra ACL\n")
+ for _, p := range config.Confinement.ExtraPerms {
+ if p == nil {
+ continue
+ }
+ fmt.Fprintf(w, " %s\n", p.String())
}
- fmt.Fprintf(w, "%s\n", expr.String())
+ fmt.Fprintf(w, "\n")
}
- fmt.Fprintf(w, "\n")
}
printDBus := func(c *dbus.Config) {