app: set up acl on X11 socket

The socket is typically owned by the priv-user, and inaccessible by the target user, so just allowing access to the directory is not enough. This change fixes this oversight and add checks that will also be useful for merging #1.

Signed-off-by: Ophestra <cat@gensokyo.uk>

# Conflicts:
#	test/sandbox/case/device.nix
#	test/sandbox/case/tty.nix
This commit is contained in:
Ophestra 2025-08-18 02:24:56 +09:00
parent 69a4ab8105
commit 2f1d42c8dd
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
3 changed files with 41 additions and 5 deletions

View File

@ -416,6 +416,22 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
seal.sys.ChangeHosts("#" + seal.user.uid.String()) seal.sys.ChangeHosts("#" + seal.user.uid.String())
seal.env[display] = d seal.env[display] = d
seal.container.Bind(socketDir, socketDir, 0) seal.container.Bind(socketDir, socketDir, 0)
// the socket file at `/tmp/.X11-unix/X%d` is typically owned by the priv user
// and not accessible by the target user
var socketPath *container.Absolute
if len(d) > 1 && d[0] == ':' { // `:%d`
if n, err := strconv.Atoi(d[1:]); err == nil && n >= 0 {
socketPath = socketDir.Append("X" + strconv.Itoa(n))
}
} else if len(d) > 5 && strings.HasPrefix(d, "unix:") { // `unix:%s`
if a, err := container.NewAbs(d[5:]); err == nil {
socketPath = a
}
}
if socketPath != nil {
seal.sys.UpdatePermTypeOptional(system.EX11, socketPath.String(), acl.Read, acl.Write, acl.Execute)
}
} }
} }

View File

@ -21,7 +21,17 @@ func (sys *I) UpdatePermType(et Enablement, path string, perms ...acl.Perm) *I {
sys.lock.Lock() sys.lock.Lock()
defer sys.lock.Unlock() defer sys.lock.Unlock()
sys.ops = append(sys.ops, &ACL{et, path, perms}) sys.ops = append(sys.ops, &ACL{et, path, perms, false})
return sys
}
// UpdatePermTypeOptional appends an acl update Op that silently continues if the target does not exist.
func (sys *I) UpdatePermTypeOptional(et Enablement, path string, perms ...acl.Perm) *I {
sys.lock.Lock()
defer sys.lock.Unlock()
sys.ops = append(sys.ops, &ACL{et, path, perms, true})
return sys return sys
} }
@ -30,14 +40,24 @@ type ACL struct {
et Enablement et Enablement
path string path string
perms acl.Perms perms acl.Perms
// since revert operations are cross-process, the success of apply must not affect the outcome of revert
skipNotExist bool
} }
func (a *ACL) Type() Enablement { return a.et } func (a *ACL) Type() Enablement { return a.et }
func (a *ACL) apply(sys *I) error { func (a *ACL) apply(sys *I) error {
msg.Verbose("applying ACL", a) msg.Verbose("applying ACL", a)
return wrapErrSuffix(acl.Update(a.path, sys.uid, a.perms...), if err := acl.Update(a.path, sys.uid, a.perms...); err != nil {
if !a.skipNotExist || !os.IsNotExist(err) {
return wrapErrSuffix(err,
fmt.Sprintf("cannot apply ACL entry to %q:", a.path)) fmt.Sprintf("cannot apply ACL entry to %q:", a.path))
}
msg.Verbosef("path %q does not exist", a.path)
return nil
}
return nil
} }
func (a *ACL) revert(sys *I, ec *Criteria) error { func (a *ACL) revert(sys *I, ec *Criteria) error {

View File

@ -20,7 +20,7 @@ func TestUpdatePerm(t *testing.T) {
t.Run(tc.path+permSubTestSuffix(tc.perms), func(t *testing.T) { t.Run(tc.path+permSubTestSuffix(tc.perms), func(t *testing.T) {
sys := New(150) sys := New(150)
sys.UpdatePerm(tc.path, tc.perms...) sys.UpdatePerm(tc.path, tc.perms...)
(&tcOp{Process, tc.path}).test(t, sys.ops, []Op{&ACL{Process, tc.path, tc.perms}}, "UpdatePerm") (&tcOp{Process, tc.path}).test(t, sys.ops, []Op{&ACL{Process, tc.path, tc.perms, false}}, "UpdatePerm")
}) })
} }
} }
@ -42,7 +42,7 @@ func TestUpdatePermType(t *testing.T) {
t.Run(tc.path+"_"+TypeString(tc.et)+permSubTestSuffix(tc.perms), func(t *testing.T) { t.Run(tc.path+"_"+TypeString(tc.et)+permSubTestSuffix(tc.perms), func(t *testing.T) {
sys := New(150) sys := New(150)
sys.UpdatePermType(tc.et, tc.path, tc.perms...) sys.UpdatePermType(tc.et, tc.path, tc.perms...)
tc.test(t, sys.ops, []Op{&ACL{tc.et, tc.path, tc.perms}}, "UpdatePermType") tc.test(t, sys.ops, []Op{&ACL{tc.et, tc.path, tc.perms, false}}, "UpdatePermType")
}) })
} }
} }