From 0abf367b1334b76f5e8f989cf0c07b5d00b25868 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 13 Oct 2026 18:55:52 +0900 Subject: internal/acl: skip superfluous acl_set_file This slightly reduces startup latency. Signed-off-by: Ophestra --- internal/acl/acl.go | 84 +++++++++++++++++++--- internal/acl/acl_test.go | 136 +++++++++++++++++++++++------------ internal/acl/libacl-helper.c | 87 ++++++++++++++++------ internal/acl/libacl-helper.go | 40 ----------- internal/acl/libacl-helper.h | 24 ++++++- internal/acl/libacl-helper_test.go | 47 +++++++----- internal/acl/perms.go | 26 +++---- internal/acl/perms_test.go | 20 +++--- internal/outcome/run_test.go | 32 ++++----- internal/outcome/spcontainer.go | 10 +-- internal/outcome/spcontainer_test.go | 10 +-- internal/outcome/spdbus.go | 4 +- internal/outcome/spdbus_test.go | 6 +- internal/outcome/spruntime.go | 2 +- internal/outcome/spruntime_test.go | 8 +-- internal/outcome/sptmpdir.go | 2 +- internal/outcome/sptmpdir_test.go | 2 +- internal/outcome/spwayland.go | 2 +- internal/outcome/spwayland_test.go | 2 +- internal/outcome/spx11.go | 2 +- internal/outcome/spx11_test.go | 4 +- internal/system/acl.go | 17 ++--- internal/system/acl_test.go | 100 +++++++++++++------------- internal/system/dispatcher.go | 6 +- internal/system/dispatcher_test.go | 4 +- internal/system/pipewire.go | 2 +- internal/system/pipewire_test.go | 2 +- internal/system/wayland.go | 2 +- internal/system/wayland_test.go | 4 +- 29 files changed, 412 insertions(+), 275 deletions(-) delete mode 100644 internal/acl/libacl-helper.go (limited to 'internal') diff --git a/internal/acl/acl.go b/internal/acl/acl.go index 366ad533..7718ba3c 100644 --- a/internal/acl/acl.go +++ b/internal/acl/acl.go @@ -7,27 +7,89 @@ package acl #include "libacl-helper.h" */ import "C" +import "os" +// Perm represents acl_perm_t. type Perm C.acl_perm_t const ( - Read Perm = C.ACL_READ - Write Perm = C.ACL_WRITE + // Read represents ACL_READ. + Read Perm = C.ACL_READ + // Write represents ACL_WRITE. + Write Perm = C.ACL_WRITE + // Execute represents ACL_EXECUTE. Execute Perm = C.ACL_EXECUTE ) -// Update replaces ACL_USER entry with qualifier uid. -func Update(name string, uid int, perms ...Perm) error { - var p *Perm - if len(perms) > 0 { - p = &perms[0] +// Status is the outcome of an ACL update operation. +type Status = C.enum_hakurei_acl_status + +// An Error describes an error encountered during [Update]. +type Error struct { + // Pathname of the file to update ACL for. + Path string + // Function that returned the error. + Op Status + // Underlying errno. + Err error +} + +// Unwrap returns an [os.PathError] describing e. +func (e Error) Unwrap() error { + v := os.PathError{Path: e.Path, Err: e.Err} + switch e.Op { + case C.HAKUREI_ACL_OK: + return os.ErrInvalid + + case C.HAKUREI_ACL_GET_FILE: + v.Op = "acl_get_file" + case C.HAKUREI_ACL_GET_TAG_TYPE: + v.Op = "acl_get_tag_type" + case C.HAKUREI_ACL_GET_QUALIFIER: + v.Op = "acl_get_qualifier" + case C.HAKUREI_ACL_DELETE_ENTRY: + v.Op = "acl_delete_entry" + case C.HAKUREI_ACL_CREATE_ENTRY: + v.Op = "acl_create_entry" + case C.HAKUREI_ACL_GET_PERMSET: + v.Op = "acl_get_permset" + case C.HAKUREI_ACL_ADD_PERM: + v.Op = "acl_add_perm" + case C.HAKUREI_ACL_SET_TAG_TYPE: + v.Op = "acl_set_tag_type" + case C.HAKUREI_ACL_SET_QUALIFIER: + v.Op = "acl_set_qualifier" + case C.HAKUREI_ACL_CALC_MASK: + v.Op = "acl_calc_mask" + case C.HAKUREI_ACL_VALID: + v.Op = "acl_valid" + case C.HAKUREI_ACL_SET_FILE: + v.Op = "acl_set_file" + case C.HAKUREI_ACL_GET_PERM: + v.Op = "acl_get_perm" + case C.HAKUREI_ACL_DUP: + v.Op = "acl_dup" + + default: // unreachable + v.Op = "setfacl" } + return &v +} + +// Error returns the message of the resulting [os.PathError]. +func (e Error) Error() string { + return e.Unwrap().Error() +} - r, err := C.hakurei_acl_update_file_by_uid( +// Update replaces ACL_USER entry with qualifier uid. +func Update(name string, uid int, perms Perm) error { + r, err := C.hakurei_update_acl( C.CString(name), C.uid_t(uid), - (*C.acl_perm_t)(p), - C.size_t(len(perms)), + C.acl_perm_t(perms), ) - return newAclPathError(name, int(r), err) + if r == C.HAKUREI_ACL_OK { + return nil + } + return &Error{name, r, err} } diff --git a/internal/acl/acl_test.go b/internal/acl/acl_test.go index 60c4b702..6e84e832 100644 --- a/internal/acl/acl_test.go +++ b/internal/acl/acl_test.go @@ -22,7 +22,7 @@ const testFileName = "acl.test" var ( uid = os.Geteuid() - cred = int32(os.Geteuid()) + cred = int32(uid) ) func TestUpdate(t *testing.T) { @@ -31,7 +31,7 @@ func TestUpdate(t *testing.T) { if err := os.WriteFile(name, nil, 0); err != nil { t.Fatal(err) } - if err := acl.Update(name, os.Geteuid()); errors.Is(err, syscall.ENOTSUP) { + if err := acl.Update(name, uid, 0); errors.Is(err, syscall.ENOTSUP) { t.Skip(err) } } @@ -60,7 +60,7 @@ func TestUpdate(t *testing.T) { }) t.Run("default clear mask", func(t *testing.T) { - if err := acl.Update(testFilePath, uid); err != nil { + if err := acl.Update(testFilePath, uid, 0); err != nil { t.Fatalf("Update: error = %v", err) } if cur = getfacl(t, testFilePath); len(cur) != 4 { @@ -69,7 +69,7 @@ func TestUpdate(t *testing.T) { }) t.Run("default clear consistency", func(t *testing.T) { - if err := acl.Update(testFilePath, uid); err != nil { + if err := acl.Update(testFilePath, uid, 0); err != nil { t.Fatalf("Update: error = %v", err) } if val := getfacl(t, testFilePath); !reflect.DeepEqual(val, cur) { @@ -77,34 +77,78 @@ func TestUpdate(t *testing.T) { } }) - testUpdate(t, testFilePath, "r--", cur, fAclPermRead, acl.Read) - testUpdate(t, testFilePath, "-w-", cur, fAclPermWrite, acl.Write) - testUpdate(t, testFilePath, "--x", cur, fAclPermExecute, acl.Execute) - testUpdate(t, testFilePath, "-wx", cur, fAclPermWrite|fAclPermExecute, acl.Write, acl.Execute) - testUpdate(t, testFilePath, "r-x", cur, fAclPermRead|fAclPermExecute, acl.Read, acl.Execute) - testUpdate(t, testFilePath, "rw-", cur, fAclPermRead|fAclPermWrite, acl.Read, acl.Write) - testUpdate(t, testFilePath, "rwx", cur, fAclPermRead|fAclPermWrite|fAclPermExecute, acl.Read, acl.Write, acl.Execute) + testUpdate(t, testFilePath, "r--", "", cur, acl.Read, true) + testUpdate(t, testFilePath, "-w-", "", cur, acl.Write, true) + testUpdate(t, testFilePath, "--x", "", cur, acl.Execute, true) + + testUpdate( + t, testFilePath, "-wx", "", cur, + acl.Write|acl.Execute, + true, + ) + testUpdate( + t, testFilePath, "r-x", "", cur, + acl.Read|acl.Execute, + true, + ) + testUpdate( + t, testFilePath, "rw-", "", cur, + acl.Read|acl.Write, + true, + ) + testUpdate( + t, testFilePath, "rwx", "", cur, + acl.Read|acl.Write|acl.Execute, + true, + ) + + for i := range 16 { + testUpdate( + t, testFilePath, "r-x", " "+strconv.Itoa(i), cur, + acl.Read|acl.Execute, + false, + ) + } + + testUpdate( + t, testFilePath, "rwx", " cleanup", cur, + acl.Read|acl.Write|acl.Execute, + true, + ) } -func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val fAclPerm, perms ...acl.Perm) { - t.Run(name, func(t *testing.T) { - t.Cleanup(func() { - if err := acl.Update(testFilePath, uid); err != nil { - t.Fatalf("Update: error = %v", err) - } - if v := getfacl(t, testFilePath); !reflect.DeepEqual(v, cur) { - t.Fatalf("Update: %v, want %v", v, cur) - } - }) +func testUpdate( + t *testing.T, + testFilePath, name, suffix string, + cur []*getFACLResp, + perms acl.Perm, + cleanup bool, +) { + t.Run(name+suffix, func(t *testing.T) { + if cleanup { + t.Cleanup(func() { + if err := acl.Update(testFilePath, uid, 0); err != nil { + t.Fatalf("Update: error = %v", err) + } + if v := getfacl(t, testFilePath); !reflect.DeepEqual(v, cur) { + t.Fatalf("Update: %v, want %v", v, cur) + } + }) + } - if err := acl.Update(testFilePath, uid, perms...); err != nil { + if err := acl.Update(testFilePath, uid, perms); err != nil { t.Fatalf("Update: error = %v", err) } r := respByCred(getfacl(t, testFilePath), fAclTypeUser, cred) if r == nil { t.Fatalf("Update did not add an ACL entry") } - if !r.equals(fAclTypeUser, cred, val) { + + if !r.equals(&getFACLResp{ + typ: fAclTypeUser, + cred: cred, + val: perms, + }) { t.Fatalf("Update(%s) = %s", name, r) } }) @@ -113,30 +157,23 @@ func testUpdate(t *testing.T, testFilePath, name string, cur []*getFAclResp, val type ( getFAclInvocation struct { cmd *exec.Cmd - val []*getFAclResp + val []*getFACLResp pe []error } - getFAclResp struct { + getFACLResp struct { typ fAclType cred int32 - val fAclPerm + val acl.Perm raw []byte } - fAclPerm uintptr fAclType uint8 ) const fAclBufSize = 16 -const ( - fAclPermRead fAclPerm = 1 << iota - fAclPermWrite - fAclPermExecute -) - const ( fAclTypeUser fAclType = iota fAclTypeGroup @@ -149,7 +186,13 @@ func (c *getFAclInvocation) run(name string) error { panic("attempted to run twice") } - c.cmd = exec.Command("getfacl", "--omit-header", "--absolute-names", "--numeric", name) + c.cmd = exec.Command( + "getfacl", + "--omit-header", + "--absolute-names", + "--numeric", + name, + ) c.cmd.Stderr = os.Stderr scanErr := make(chan error, 1) @@ -166,18 +209,17 @@ func (c *getFAclInvocation) run(name string) error { return errors.Join(<-scanErr, c.cmd.Wait()) } -func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) { - c.val = make([]*getFAclResp, 0, 4+fAclBufSize) +func (c *getFAclInvocation) parse(r io.Reader, scanErr chan error) { + c.val = make([]*getFACLResp, 0, 4+fAclBufSize) - s := bufio.NewScanner(pipe) + s := bufio.NewScanner(r) for s.Scan() { fields := bytes.SplitN(s.Bytes(), []byte{':'}, 3) if len(fields) != 3 { continue } - resp := getFAclResp{} - + var resp getFACLResp switch string(fields[0]) { case "user": resp.typ = fAclTypeUser @@ -213,7 +255,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) { } else { switch fields[2][0] { case 'r': - resp.val |= fAclPermRead + resp.val |= acl.Read case '-': default: c.pe = append(c.pe, fmt.Errorf("invalid perm %v", fields[2][0])) @@ -221,7 +263,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) { } switch fields[2][1] { case 'w': - resp.val |= fAclPermWrite + resp.val |= acl.Write case '-': default: c.pe = append(c.pe, fmt.Errorf("invalid perm %v", fields[2][1])) @@ -229,7 +271,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) { } switch fields[2][2] { case 'x': - resp.val |= fAclPermExecute + resp.val |= acl.Execute case '-': default: c.pe = append(c.pe, fmt.Errorf("invalid perm %v", fields[2][2])) @@ -244,7 +286,7 @@ func (c *getFAclInvocation) parse(pipe io.Reader, scanErr chan error) { scanErr <- s.Err() } -func (r *getFAclResp) String() string { +func (r *getFACLResp) String() string { if r.raw != nil && len(r.raw) > 0 { return string(r.raw) } @@ -252,11 +294,11 @@ func (r *getFAclResp) String() string { return "(user-initialised resp value)" } -func (r *getFAclResp) equals(typ fAclType, cred int32, val fAclPerm) bool { - return r.typ == typ && r.cred == cred && r.val == val +func (r *getFACLResp) equals(v *getFACLResp) bool { + return r.typ == v.typ && r.cred == v.cred && r.val == v.val } -func getfacl(t *testing.T, name string) []*getFAclResp { +func getfacl(t *testing.T, name string) []*getFACLResp { c := new(getFAclInvocation) if err := c.run(name); err != nil { t.Fatalf("getfacl: error = %v", err) @@ -267,7 +309,7 @@ func getfacl(t *testing.T, name string) []*getFAclResp { return c.val } -func respByCred(v []*getFAclResp, typ fAclType, cred int32) *getFAclResp { +func respByCred(v []*getFACLResp, typ fAclType, cred int32) *getFACLResp { j := -1 for i, r := range v { if r.typ == typ && r.cred == cred { diff --git a/internal/acl/libacl-helper.c b/internal/acl/libacl-helper.c index 259dfb2b..065c1928 100644 --- a/internal/acl/libacl-helper.c +++ b/internal/acl/libacl-helper.c @@ -4,18 +4,22 @@ #include #include -int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, - acl_perm_t *perms, size_t plen) { - int ret; +enum hakurei_acl_status hakurei_update_acl( + const char *path_p, + uid_t uid, + acl_perm_t perms) { + enum hakurei_acl_status ret; + bool v; int i; - acl_t acl; + acl_t acl, acl_d = NULL; acl_entry_t entry; acl_tag_t tag_type; void *qualifier_p; acl_permset_t permset; + acl_perm_t has_perms; - ret = -1; /* acl_get_file */ + ret = HAKUREI_ACL_GET_FILE; acl = acl_get_file(path_p, ACL_TYPE_ACCESS); if (acl == NULL) goto out; @@ -23,13 +27,13 @@ int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, /* prune entries by uid */ for (i = acl_get_entry(acl, ACL_FIRST_ENTRY, &entry); i == 1; i = acl_get_entry(acl, ACL_NEXT_ENTRY, &entry)) { - ret = -2; /* acl_get_tag_type */ + ret = HAKUREI_ACL_GET_TAG_TYPE; if (acl_get_tag_type(entry, &tag_type) != 0) goto out; if (tag_type != ACL_USER) continue; - ret = -3; /* acl_get_qualifier */ + ret = HAKUREI_ACL_GET_QUALIFIER; qualifier_p = acl_get_qualifier(entry); if (qualifier_p == NULL) goto out; @@ -39,52 +43,91 @@ int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, if (!v) continue; - ret = -4; /* acl_delete_entry */ + ret = HAKUREI_ACL_GET_PERMSET; + if (acl_get_permset(entry, &permset) != 0) + goto out; + + if (perms == 0) + goto delete; + + /* this is quite ugly, but the standard makes it impossible to directly + * obtain these bits */ + has_perms = 0; +#define COPY_PERM_BIT(perm) \ + do { \ + ret = HAKUREI_ACL_GET_PERM; \ + i = acl_get_perm(permset, perm); \ + if (i < 0) \ + goto out; \ + if (i > 0) \ + has_perms |= perm; \ + } while (0) + COPY_PERM_BIT(ACL_READ); + COPY_PERM_BIT(ACL_WRITE); + COPY_PERM_BIT(ACL_EXECUTE); + + if (perms == has_perms) { + ret = HAKUREI_ACL_DUP; + acl_d = acl_dup(acl); + if (acl_d == NULL) + goto out; + + ret = HAKUREI_ACL_CALC_MASK; + if (acl_calc_mask(&acl_d) != 0) + goto out; + + ret = HAKUREI_ACL_OK; + if (acl_cmp(acl, acl_d) == 0) + goto out; + } + + delete: + ret = HAKUREI_ACL_DELETE_ENTRY; if (acl_delete_entry(acl, entry) != 0) goto out; } - if (plen == 0) + if (perms == 0) goto set; - ret = -5; /* acl_create_entry */ + ret = HAKUREI_ACL_CREATE_ENTRY; if (acl_create_entry(&acl, &entry) != 0) goto out; - ret = -6; /* acl_get_permset */ + ret = HAKUREI_ACL_GET_PERMSET; if (acl_get_permset(entry, &permset) != 0) goto out; - ret = -7; /* acl_add_perm */ - for (i = 0; i < plen; i++) { - if (acl_add_perm(permset, perms[i]) != 0) - goto out; - } + ret = HAKUREI_ACL_ADD_PERM; + if (acl_add_perm(permset, perms) != 0) + goto out; - ret = -8; /* acl_set_tag_type */ + ret = HAKUREI_ACL_SET_TAG_TYPE; if (acl_set_tag_type(entry, ACL_USER) != 0) goto out; - ret = -9; /* acl_set_qualifier */ + ret = HAKUREI_ACL_SET_QUALIFIER; if (acl_set_qualifier(entry, (void *)&uid) != 0) goto out; set: - ret = -10; /* acl_calc_mask */ + ret = HAKUREI_ACL_CALC_MASK; if (acl_calc_mask(&acl) != 0) goto out; - ret = -11; /* acl_valid */ + ret = HAKUREI_ACL_VALID; if (acl_valid(acl) != 0) goto out; - ret = -12; /* acl_set_file */ + ret = HAKUREI_ACL_SET_FILE; if (acl_set_file(path_p, ACL_TYPE_ACCESS, acl) == 0) - ret = 0; + ret = HAKUREI_ACL_OK; out: free((void *)path_p); if (acl != NULL) acl_free((void *)acl); + if (acl_d != NULL) + acl_free((void *)acl_d); return ret; } diff --git a/internal/acl/libacl-helper.go b/internal/acl/libacl-helper.go deleted file mode 100644 index 22575296..00000000 --- a/internal/acl/libacl-helper.go +++ /dev/null @@ -1,40 +0,0 @@ -package acl - -import "os" - -func newAclPathError(name string, r int, err error) error { - pathError := &os.PathError{Path: name, Err: err} - switch r { - case 0: - return nil - - case -1: - pathError.Op = "acl_get_file" - case -2: - pathError.Op = "acl_get_tag_type" - case -3: - pathError.Op = "acl_get_qualifier" - case -4: - pathError.Op = "acl_delete_entry" - case -5: - pathError.Op = "acl_create_entry" - case -6: - pathError.Op = "acl_get_permset" - case -7: - pathError.Op = "acl_add_perm" - case -8: - pathError.Op = "acl_set_tag_type" - case -9: - pathError.Op = "acl_set_qualifier" - case -10: - pathError.Op = "acl_calc_mask" - case -11: - pathError.Op = "acl_valid" - case -12: - pathError.Op = "acl_set_file" - - default: // unreachable - pathError.Op = "setfacl" - } - return pathError -} diff --git a/internal/acl/libacl-helper.h b/internal/acl/libacl-helper.h index b86eb170..753e1109 100644 --- a/internal/acl/libacl-helper.h +++ b/internal/acl/libacl-helper.h @@ -1,4 +1,24 @@ #include -int hakurei_acl_update_file_by_uid(const char *path_p, uid_t uid, - acl_perm_t *perms, size_t plen); +enum hakurei_acl_status { + HAKUREI_ACL_OK, + HAKUREI_ACL_GET_FILE, + HAKUREI_ACL_GET_TAG_TYPE, + HAKUREI_ACL_GET_QUALIFIER, + HAKUREI_ACL_DELETE_ENTRY, + HAKUREI_ACL_CREATE_ENTRY, + HAKUREI_ACL_GET_PERMSET, + HAKUREI_ACL_ADD_PERM, + HAKUREI_ACL_SET_TAG_TYPE, + HAKUREI_ACL_SET_QUALIFIER, + HAKUREI_ACL_CALC_MASK, + HAKUREI_ACL_VALID, + HAKUREI_ACL_SET_FILE, + HAKUREI_ACL_GET_PERM, + HAKUREI_ACL_DUP, +}; + +enum hakurei_acl_status hakurei_update_acl( + const char *path_p, + uid_t uid, + acl_perm_t perms); diff --git a/internal/acl/libacl-helper_test.go b/internal/acl/libacl-helper_test.go index 13d23a3c..05c43639 100644 --- a/internal/acl/libacl-helper_test.go +++ b/internal/acl/libacl-helper_test.go @@ -1,4 +1,4 @@ -package acl +package acl_test import ( "os" @@ -7,9 +7,12 @@ import ( "testing" "hakurei.app/container" + "hakurei.app/internal/acl" ) -func TestNewAclPathError(t *testing.T) { +func TestError(t *testing.T) { + t.Parallel() + testCases := []struct { name string path string @@ -17,43 +20,51 @@ func TestNewAclPathError(t *testing.T) { err error want error }{ - {"nil", container.Nonexistent, 0, syscall.ENOTRECOVERABLE, nil}, + {"nil", container.Nonexistent, 0, syscall.ENOTRECOVERABLE, os.ErrInvalid}, - {"acl_get_file", container.Nonexistent, -1, syscall.ENOTRECOVERABLE, + {"acl_get_file", container.Nonexistent, 1, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_get_file", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_get_tag_type", container.Nonexistent, -2, syscall.ENOTRECOVERABLE, + {"acl_get_tag_type", container.Nonexistent, 2, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_get_tag_type", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_get_qualifier", container.Nonexistent, -3, syscall.ENOTRECOVERABLE, + {"acl_get_qualifier", container.Nonexistent, 3, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_get_qualifier", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_delete_entry", container.Nonexistent, -4, syscall.ENOTRECOVERABLE, + {"acl_delete_entry", container.Nonexistent, 4, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_delete_entry", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_create_entry", container.Nonexistent, -5, syscall.ENOTRECOVERABLE, + {"acl_create_entry", container.Nonexistent, 5, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_create_entry", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_get_permset", container.Nonexistent, -6, syscall.ENOTRECOVERABLE, + {"acl_get_permset", container.Nonexistent, 6, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_get_permset", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_add_perm", container.Nonexistent, -7, syscall.ENOTRECOVERABLE, + {"acl_add_perm", container.Nonexistent, 7, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_add_perm", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_set_tag_type", container.Nonexistent, -8, syscall.ENOTRECOVERABLE, + {"acl_set_tag_type", container.Nonexistent, 8, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_set_tag_type", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_set_qualifier", container.Nonexistent, -9, syscall.ENOTRECOVERABLE, + {"acl_set_qualifier", container.Nonexistent, 9, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_set_qualifier", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_calc_mask", container.Nonexistent, -10, syscall.ENOTRECOVERABLE, + {"acl_calc_mask", container.Nonexistent, 10, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_calc_mask", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_valid", container.Nonexistent, -11, syscall.ENOTRECOVERABLE, + {"acl_valid", container.Nonexistent, 11, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_valid", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl_set_file", container.Nonexistent, -12, syscall.ENOTRECOVERABLE, + {"acl_set_file", container.Nonexistent, 12, syscall.ENOTRECOVERABLE, &os.PathError{Op: "acl_set_file", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, + {"acl_get_perm", container.Nonexistent, 13, syscall.ENOTRECOVERABLE, + &os.PathError{Op: "acl_get_perm", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, + {"acl_dup", container.Nonexistent, 14, syscall.ENOTRECOVERABLE, + &os.PathError{Op: "acl_dup", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, - {"acl", container.Nonexistent, -13, syscall.ENOTRECOVERABLE, + {"acl", container.Nonexistent, 15, syscall.ENOTRECOVERABLE, &os.PathError{Op: "setfacl", Path: container.Nonexistent, Err: syscall.ENOTRECOVERABLE}}, {"invalid", container.Nonexistent, -0xdead, nil, &os.PathError{Op: "setfacl", Path: container.Nonexistent}}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - err := newAclPathError(tc.path, tc.r, tc.err) + err := acl.Error{ + Path: tc.path, + Op: acl.Status(tc.r), + Err: tc.err, + }.Unwrap() if !reflect.DeepEqual(err, tc.want) { - t.Errorf("newAclPathError: %v, want %v", err, tc.want) + t.Errorf("Unwrap: %v, want %v", err, tc.want) } }) } diff --git a/internal/acl/perms.go b/internal/acl/perms.go index fbc99e82..829b134f 100644 --- a/internal/acl/perms.go +++ b/internal/acl/perms.go @@ -1,18 +1,18 @@ package acl -type Perms []Perm +import "unsafe" -func (ps Perms) String() string { - var s = []byte("---") - for _, p := range ps { - switch p { - case Read: - s[0] = 'r' - case Write: - s[1] = 'w' - case Execute: - s[2] = 'x' - } +// String returns a text representation of perms. +func (perms Perm) String() string { + buf := []byte{'-', '-', '-'} + if perms&Read != 0 { + buf[0] = 'r' } - return string(s) + if perms&Write != 0 { + buf[1] = 'w' + } + if perms&Execute != 0 { + buf[2] = 'x' + } + return unsafe.String(unsafe.SliceData(buf), len(buf)) } diff --git a/internal/acl/perms_test.go b/internal/acl/perms_test.go index 3920046d..9fa24dc8 100644 --- a/internal/acl/perms_test.go +++ b/internal/acl/perms_test.go @@ -7,18 +7,20 @@ import ( ) func TestPerms(t *testing.T) { + t.Parallel() + testCases := []struct { name string - perms acl.Perms + perms acl.Perm }{ - {"---", acl.Perms{}}, - {"r--", acl.Perms{acl.Read}}, - {"-w-", acl.Perms{acl.Write}}, - {"--x", acl.Perms{acl.Execute}}, - {"rw-", acl.Perms{acl.Read, acl.Read, acl.Write}}, - {"r-x", acl.Perms{acl.Read, acl.Execute, acl.Execute}}, - {"-wx", acl.Perms{acl.Write, acl.Write, acl.Execute, acl.Execute}}, - {"rwx", acl.Perms{acl.Read, acl.Write, acl.Execute}}, + {"---", 0}, + {"r--", acl.Read}, + {"-w-", acl.Write}, + {"--x", acl.Execute}, + {"rw-", acl.Read | acl.Write}, + {"r-x", acl.Read | acl.Execute}, + {"-wx", acl.Write | acl.Execute}, + {"rwx", acl.Read | acl.Write | acl.Execute}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/outcome/run_test.go b/internal/outcome/run_test.go index a1d83ec9..e4e33dca 100644 --- a/internal/outcome/run_test.go +++ b/internal/outcome/run_test.go @@ -48,13 +48,13 @@ func TestOutcomeRun(t *testing.T) { Ensure(m("/tmp/hakurei.0/runtime"), 0700). UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute). Ensure(m("/tmp/hakurei.0/runtime/9"), 0700). - UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute). + UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/9"), acl.Read|acl.Write|acl.Execute). // spTmpdirOp Ensure(m("/tmp/hakurei.0/tmpdir"), 0700). UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute). Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700). - UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute). + UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read|acl.Write|acl.Execute). // instance Ephemeral(system.Process, m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), 0711). @@ -84,13 +84,13 @@ func TestOutcomeRun(t *testing.T) { "unix:path=/var/run/dbus/system_bus_socket", "/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket", }, - ).UpdatePerm(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), acl.Read, acl.Write). - UpdatePerm(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), acl.Read, acl.Write). + ).UpdatePerm(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), acl.Read|acl.Write). + UpdatePerm(m("/tmp/hakurei.0/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), acl.Read|acl.Write). // spFilesystemOp Ensure(m("/var/lib/hakurei/u0"), 0700). UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute). - UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), acl.Read, acl.Write, acl.Execute), &container.Params{ + UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), acl.Read|acl.Write|acl.Execute), &container.Params{ Dir: m("/data/data/org.chromium.Chromium"), Env: []string{ @@ -205,11 +205,11 @@ func TestOutcomeRun(t *testing.T) { Ensure(m("/tmp/hakurei.0/runtime"), 0700). UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute). Ensure(m("/tmp/hakurei.0/runtime/0"), 0700). - UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/0"), acl.Read, acl.Write, acl.Execute). + UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/0"), acl.Read|acl.Write|acl.Execute). Ensure(m("/tmp/hakurei.0/tmpdir"), 0700). UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute). Ensure(m("/tmp/hakurei.0/tmpdir/0"), 01700). - UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/0"), acl.Read, acl.Write, acl.Execute), &container.Params{ + UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/0"), acl.Read|acl.Write|acl.Execute), &container.Params{ Dir: m("/home/chronos"), Path: m("/run/current-system/sw/bin/zsh"), @@ -329,9 +329,9 @@ func TestOutcomeRun(t *testing.T) { }, system.New(t.Context(), msg, 10009). Ensure(m("/tmp/hakurei.0"), 0711). Ensure(m("/tmp/hakurei.0/runtime"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute). - Ensure(m("/tmp/hakurei.0/runtime/9"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute). + Ensure(m("/tmp/hakurei.0/runtime/9"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/9"), acl.Read|acl.Write|acl.Execute). Ensure(m("/tmp/hakurei.0/tmpdir"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute). - Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute). + Ensure(m("/tmp/hakurei.0/tmpdir/9"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/9"), acl.Read|acl.Write|acl.Execute). Ephemeral(system.Process, m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c"), 0711). Wayland(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/1971/wayland-0"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c"). PipeWire(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/pipewire"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c"). @@ -371,8 +371,8 @@ func TestOutcomeRun(t *testing.T) { "unix:path=/var/run/dbus/system_bus_socket", "/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket", }). - UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/bus"), acl.Read, acl.Write). - UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket"), acl.Read, acl.Write), &container.Params{ + UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/bus"), acl.Read|acl.Write). + UpdatePerm(m("/tmp/hakurei.0/ebf083d1b175911782d413369b64ce7c/system_bus_socket"), acl.Read|acl.Write), &container.Params{ Dir: m("/home/chronos"), Path: m("/run/current-system/sw/bin/zsh"), @@ -480,12 +480,12 @@ func TestOutcomeRun(t *testing.T) { }, system.New(t.Context(), msg, 10001). Ensure(m("/tmp/hakurei.0"), 0711). Ensure(m("/tmp/hakurei.0/runtime"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime"), acl.Execute). - Ensure(m("/tmp/hakurei.0/runtime/1"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/1"), acl.Read, acl.Write, acl.Execute). + Ensure(m("/tmp/hakurei.0/runtime/1"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/runtime/1"), acl.Read|acl.Write|acl.Execute). Ensure(m("/tmp/hakurei.0/tmpdir"), 0700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir"), acl.Execute). - Ensure(m("/tmp/hakurei.0/tmpdir/1"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/1"), acl.Read, acl.Write, acl.Execute). + Ensure(m("/tmp/hakurei.0/tmpdir/1"), 01700).UpdatePermType(system.User, m("/tmp/hakurei.0/tmpdir/1"), acl.Read|acl.Write|acl.Execute). Ensure(m("/run/user/1971"), 0700).UpdatePermType(system.User, m("/run/user/1971"), acl.Execute). // this is ordered as is because the previous Ensure only calls mkdir if XDG_RUNTIME_DIR is unset Ensure(m("/run/user/1971/hakurei"), 0700).UpdatePermType(system.User, m("/run/user/1971/hakurei"), acl.Execute). - UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read, acl.Write, acl.Execute). + UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read|acl.Write|acl.Execute). Ephemeral(system.Process, m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1"), 0711). PipeWire(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/pipewire"), "org.chromium.Chromium", "8e2c76b066dabe574cf073bdb46eb5c1"). MustProxyDBus(&hst.BusConfig{ @@ -515,8 +515,8 @@ func TestOutcomeRun(t *testing.T) { "unix:path=/var/run/dbus/system_bus_socket", "/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket", }). - UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), acl.Read, acl.Write). - UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket"), acl.Read, acl.Write), &container.Params{ + UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/bus"), acl.Read|acl.Write). + UpdatePerm(m("/tmp/hakurei.0/8e2c76b066dabe574cf073bdb46eb5c1/system_bus_socket"), acl.Read|acl.Write), &container.Params{ Uid: 1971, Gid: 100, diff --git a/internal/outcome/spcontainer.go b/internal/outcome/spcontainer.go index bfa5dbdc..0ddc10ac 100644 --- a/internal/outcome/spcontainer.go +++ b/internal/outcome/spcontainer.go @@ -354,17 +354,17 @@ func flattenExtraPerms(sys *system.I, extraPerms []hst.ExtraPermConfig) { sys.Ensure(p.Path, 0700) } - perms := make(acl.Perms, 0, 3) + var perms acl.Perm if p.Read { - perms = append(perms, acl.Read) + perms |= acl.Read } if p.Write { - perms = append(perms, acl.Write) + perms |= acl.Write } if p.Execute { - perms = append(perms, acl.Execute) + perms |= acl.Execute } - sys.UpdatePermType(system.User, p.Path, perms...) + sys.UpdatePermType(system.User, p.Path, perms) } } diff --git a/internal/outcome/spcontainer_test.go b/internal/outcome/spcontainer_test.go index 7dd47735..d9436cb4 100644 --- a/internal/outcome/spcontainer_test.go +++ b/internal/outcome/spcontainer_test.go @@ -313,7 +313,7 @@ func TestSpFilesystemOp(t *testing.T) { UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute). UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), - acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(needsApplyState(func(state *outcomeStateParams) { + acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(needsApplyState(func(state *outcomeStateParams) { state.filesystem = append(configSmall.Container.Filesystem, hst.FilesystemConfigJSON{}) })), []stub.Call{ // this op configures the container state and does not make calls during toContainer @@ -346,7 +346,7 @@ func TestSpFilesystemOp(t *testing.T) { UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute). UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), - acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(needsApplyState(func(state *outcomeStateParams) { + acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(needsApplyState(func(state *outcomeStateParams) { state.filesystem = configSmall.Container.Filesystem })), []stub.Call{ // this op configures the container state and does not make calls during toContainer @@ -401,7 +401,7 @@ func TestSpFilesystemOp(t *testing.T) { UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute). UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), - acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(needsApplyState(func(state *outcomeStateParams) { + acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(needsApplyState(func(state *outcomeStateParams) { state.filesystem = config.Container.Filesystem[1:] })), []stub.Call{ // this op configures the container state and does not make calls during toContainer @@ -445,14 +445,14 @@ func TestFlattenExtraPerms(t *testing.T) { UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute). UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), - acl.Read, acl.Write, acl.Execute)}, + acl.Read|acl.Write|acl.Execute)}, {"template", hst.Template().ExtraPerms, newI(). Ensure(m("/var/lib/hakurei/u0"), 0700). UpdatePermType(system.User, m("/var/lib/hakurei/u0"), acl.Execute). UpdatePermType(system.User, m("/var/lib/hakurei/u0/org.chromium.Chromium"), - acl.Read, acl.Write, acl.Execute)}, + acl.Read|acl.Write|acl.Execute)}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { diff --git a/internal/outcome/spdbus.go b/internal/outcome/spdbus.go index a50f9cd2..c45dde6c 100644 --- a/internal/outcome/spdbus.go +++ b/internal/outcome/spdbus.go @@ -38,10 +38,10 @@ func (s *spDBusOp) toSystem(state *outcomeStateSys) error { return err } - state.sys.UpdatePerm(sessionPath, acl.Read, acl.Write) + state.sys.UpdatePerm(sessionPath, acl.Read|acl.Write) if state.systemBus != nil { s.ProxySystem = true - state.sys.UpdatePerm(systemPath, acl.Read, acl.Write) + state.sys.UpdatePerm(systemPath, acl.Read|acl.Write) } return nil } diff --git a/internal/outcome/spdbus_test.go b/internal/outcome/spdbus_test.go index 6f357193..0e4704a8 100644 --- a/internal/outcome/spdbus_test.go +++ b/internal/outcome/spdbus_test.go @@ -89,7 +89,7 @@ func TestSpDBusOp(t *testing.T) { ); err != nil { t.Fatalf("cannot prepare sys: %v", err) } - sys.UpdatePerm(m(wantInstancePrefix+"/bus"), acl.Read, acl.Write) + sys.UpdatePerm(m(wantInstancePrefix+"/bus"), acl.Read|acl.Write) return sys }(), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ // this op configures the container state and does not make calls during toContainer @@ -171,8 +171,8 @@ func TestSpDBusOp(t *testing.T) { ); err != nil { t.Fatalf("cannot prepare sys: %v", err) } - sys.UpdatePerm(m(wantInstancePrefix+"/bus"), acl.Read, acl.Write). - UpdatePerm(m(wantInstancePrefix+"/system_bus_socket"), acl.Read, acl.Write) + sys.UpdatePerm(m(wantInstancePrefix+"/bus"), acl.Read|acl.Write). + UpdatePerm(m(wantInstancePrefix+"/system_bus_socket"), acl.Read|acl.Write) return sys }(), sysUsesInstance(nil), nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ // this op configures the container state and does not make calls during toContainer diff --git a/internal/outcome/spruntime.go b/internal/outcome/spruntime.go index c08bfe81..9d36f252 100644 --- a/internal/outcome/spruntime.go +++ b/internal/outcome/spruntime.go @@ -79,7 +79,7 @@ func (s *spRuntimeOp) toSystem(state *outcomeStateSys) error { state.sys.Ensure(runtimeDir, 0700) state.sys.UpdatePermType(system.User, runtimeDir, acl.Execute) state.sys.Ensure(runtimeDirInst, 0700) - state.sys.UpdatePermType(system.User, runtimeDirInst, acl.Read, acl.Write, acl.Execute) + state.sys.UpdatePermType(system.User, runtimeDirInst, acl.Read|acl.Write|acl.Execute) } if state.et&hst.EWayland != 0 { diff --git a/internal/outcome/spruntime_test.go b/internal/outcome/spruntime_test.go index 25f2684c..618fc7ac 100644 --- a/internal/outcome/spruntime_test.go +++ b/internal/outcome/spruntime_test.go @@ -36,7 +36,7 @@ func TestSpRuntimeOp(t *testing.T) { Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime"), 0700). UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime"), acl.Execute). Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), 0700). - UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ + UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ Ops: new(container.Ops). @@ -64,7 +64,7 @@ func TestSpRuntimeOp(t *testing.T) { Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime"), 0700). UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime"), acl.Execute). Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), 0700). - UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ + UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ Ops: new(container.Ops). @@ -92,7 +92,7 @@ func TestSpRuntimeOp(t *testing.T) { Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime"), 0700). UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime"), acl.Execute). Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), 0700). - UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ + UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ Ops: new(container.Ops). @@ -116,7 +116,7 @@ func TestSpRuntimeOp(t *testing.T) { Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime"), 0700). UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime"), acl.Execute). Ensure(m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), 0700). - UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ + UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/runtime/9"), acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ Ops: new(container.Ops). diff --git a/internal/outcome/sptmpdir.go b/internal/outcome/sptmpdir.go index daa6f0de..3acb069f 100644 --- a/internal/outcome/sptmpdir.go +++ b/internal/outcome/sptmpdir.go @@ -22,7 +22,7 @@ func (s spTmpdirOp) toSystem(state *outcomeStateSys) error { state.sys.Ensure(tmpdir, 0700) state.sys.UpdatePermType(system.User, tmpdir, acl.Execute) state.sys.Ensure(tmpdirInst, 01700) - state.sys.UpdatePermType(system.User, tmpdirInst, acl.Read, acl.Write, acl.Execute) + state.sys.UpdatePermType(system.User, tmpdirInst, acl.Read|acl.Write|acl.Execute) } return nil } diff --git a/internal/outcome/sptmpdir_test.go b/internal/outcome/sptmpdir_test.go index 620f51b0..2073ad81 100644 --- a/internal/outcome/sptmpdir_test.go +++ b/internal/outcome/sptmpdir_test.go @@ -24,7 +24,7 @@ func TestSpTmpdirOp(t *testing.T) { Ensure(m("/proc/nonexistent/tmp/hakurei.0/tmpdir"), 0700). UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/tmpdir"), acl.Execute). Ensure(m("/proc/nonexistent/tmp/hakurei.0/tmpdir/9"), 01700). - UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/tmpdir/9"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ + UpdatePermType(system.User, m("/proc/nonexistent/tmp/hakurei.0/tmpdir/9"), acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ Ops: new(container.Ops). diff --git a/internal/outcome/spwayland.go b/internal/outcome/spwayland.go index 3c60ff10..db79d1d2 100644 --- a/internal/outcome/spwayland.go +++ b/internal/outcome/spwayland.go @@ -49,7 +49,7 @@ func (s *spWaylandOp) toSystem(state *outcomeStateSys) error { state.msg.Verbose("direct wayland access, PROCEED WITH CAUTION") state.ensureRuntimeDir() s.SocketPath = socketPath - state.sys.UpdatePermType(hst.EWayland, socketPath, acl.Read, acl.Write, acl.Execute) + state.sys.UpdatePermType(hst.EWayland, socketPath, acl.Read|acl.Write|acl.Execute) } return nil } diff --git a/internal/outcome/spwayland_test.go b/internal/outcome/spwayland_test.go index 7cc4ba84..9bb35512 100644 --- a/internal/outcome/spwayland_test.go +++ b/internal/outcome/spwayland_test.go @@ -69,7 +69,7 @@ func TestSpWaylandOp(t *testing.T) { Ensure(m(wantRunDirPath), 0700). UpdatePermType(system.User, m(wantRunDirPath), acl.Execute). // toSystem - UpdatePermType(hst.EWayland, m("/proc/nonexistent/wayland"), acl.Read, acl.Write, acl.Execute), nil, nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ + UpdatePermType(hst.EWayland, m("/proc/nonexistent/wayland"), acl.Read|acl.Write|acl.Execute), nil, nil, insertsOps(afterSpRuntimeOp(nil)), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ Ops: new(container.Ops). diff --git a/internal/outcome/spx11.go b/internal/outcome/spx11.go index c71ff530..ebd5c77e 100644 --- a/internal/outcome/spx11.go +++ b/internal/outcome/spx11.go @@ -56,7 +56,7 @@ func (s *spX11Op) toSystem(state *outcomeStateSys) error { ), Err: err} } } else { - state.sys.UpdatePermType(hst.EX11, socketPath, acl.Read, acl.Write, acl.Execute) + state.sys.UpdatePermType(hst.EX11, socketPath, acl.Read|acl.Write|acl.Execute) if state.Container.Flags&hst.FHostAbstract == 0 { s.Display = "unix:" + socketPath.String() } diff --git a/internal/outcome/spx11_test.go b/internal/outcome/spx11_test.go index 0ede2d65..d183f798 100644 --- a/internal/outcome/spx11_test.go +++ b/internal/outcome/spx11_test.go @@ -83,7 +83,7 @@ func TestSpX11Op(t *testing.T) { call("lookupEnv", stub.ExpectArgs{"DISPLAY"}, "unix:/tmp/.X11-unix/X0", nil), call("stat", stub.ExpectArgs{"/tmp/.X11-unix/X0"}, (*stubFi)(nil), nil), }, newI(). - UpdatePermType(hst.EX11, m("/tmp/.X11-unix/X0"), acl.Read, acl.Write, acl.Execute). + UpdatePermType(hst.EX11, m("/tmp/.X11-unix/X0"), acl.Read|acl.Write|acl.Execute). ChangeHosts("#10009"), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ @@ -106,7 +106,7 @@ func TestSpX11Op(t *testing.T) { call("lookupEnv", stub.ExpectArgs{"DISPLAY"}, ":0", nil), call("stat", stub.ExpectArgs{"/tmp/.X11-unix/X0"}, (*stubFi)(nil), nil), }, newI(). - UpdatePermType(hst.EX11, m("/tmp/.X11-unix/X0"), acl.Read, acl.Write, acl.Execute). + UpdatePermType(hst.EX11, m("/tmp/.X11-unix/X0"), acl.Read|acl.Write|acl.Execute). ChangeHosts("#10009"), nil, nil, insertsOps(nil), []stub.Call{ // this op configures the container state and does not make calls during toContainer }, &container.Params{ diff --git a/internal/system/acl.go b/internal/system/acl.go index e91f4eb7..7d34fa62 100644 --- a/internal/system/acl.go +++ b/internal/system/acl.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "os" - "slices" "hakurei.app/check" "hakurei.app/hst" @@ -12,14 +11,14 @@ import ( ) // UpdatePerm calls UpdatePermType with the [Process] criteria. -func (sys *I) UpdatePerm(path *check.Absolute, perms ...acl.Perm) *I { - sys.UpdatePermType(Process, path, perms...) +func (sys *I) UpdatePerm(path *check.Absolute, perms acl.Perm) *I { + sys.UpdatePermType(Process, path, perms) return sys } // UpdatePermType maintains [acl.Perms] on a file until its [hst.Enablements] is // no longer satisfied. -func (sys *I) UpdatePermType(et hst.Enablements, path *check.Absolute, perms ...acl.Perm) *I { +func (sys *I) UpdatePermType(et hst.Enablements, path *check.Absolute, perms acl.Perm) *I { sys.ops = append(sys.ops, &aclUpdateOp{et, path.String(), perms}) return sys } @@ -28,20 +27,20 @@ func (sys *I) UpdatePermType(et hst.Enablements, path *check.Absolute, perms ... type aclUpdateOp struct { et hst.Enablements path string - perms acl.Perms + perms acl.Perm } func (a *aclUpdateOp) Type() hst.Enablements { return a.et } func (a *aclUpdateOp) apply(sys *I) error { sys.msg.Verbose("applying ACL", a) - return newOpError("acl", sys.aclUpdate(a.path, sys.uid, a.perms...), false) + return newOpError("acl", sys.aclUpdate(a.path, sys.uid, a.perms), false) } func (a *aclUpdateOp) revert(sys *I, ec *Criteria) error { if ec.hasType(a.Type()) { sys.msg.Verbose("stripping ACL", a) - err := sys.aclUpdate(a.path, sys.uid) + err := sys.aclUpdate(a.path, sys.uid, 0) if errors.Is(err, os.ErrNotExist) { // the ACL is effectively stripped if the file no longer exists sys.msg.Verbosef("target of ACL %s no longer exists", a) @@ -57,9 +56,7 @@ func (a *aclUpdateOp) revert(sys *I, ec *Criteria) error { func (a *aclUpdateOp) Is(o Op) bool { target, ok := o.(*aclUpdateOp) return ok && a != nil && target != nil && - a.et == target.et && - a.path == target.path && - slices.Equal(a.perms, target.perms) + *a == *target } func (a *aclUpdateOp) Path() string { return a.path } diff --git a/internal/system/acl_test.go b/internal/system/acl_test.go index 01f9d9b1..a340e234 100644 --- a/internal/system/acl_test.go +++ b/internal/system/acl_test.go @@ -15,45 +15,45 @@ func TestACLUpdateOp(t *testing.T) { checkOpBehaviour(t, 0, []opBehaviourTestCase{ {"apply aclUpdate", 0xbeef, 0xff, - &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, stub.UniqueError(1)), + &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}, []stub.Call{ + call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, stub.UniqueError(1)), }, &OpError{Op: "acl", Err: stub.UniqueError(1)}, nil, nil}, {"revert aclUpdate", 0xbeef, 0xff, - &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil), + &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}, []stub.Call{ + call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, nil), }, nil, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, ([]acl.Perm)(nil)}, nil, stub.UniqueError(0)), + call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Perm(0)}, nil, stub.UniqueError(0)), }, &OpError{Op: "acl", Err: stub.UniqueError(0), Revert: true}}, {"success revert skip", 0xbeef, Process, - &aclUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil), + &aclUpdateOp{User, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}, []stub.Call{ + call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{User, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, nil), }, nil, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"skipping ACL", &aclUpdateOp{User, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), + call("verbose", stub.ExpectArgs{[]any{"skipping ACL", &aclUpdateOp{User, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), }, nil}, {"success revert aclUpdate ENOENT", 0xbeef, 0xff, - &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil), + &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}, []stub.Call{ + call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, nil), }, nil, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, ([]acl.Perm)(nil)}, nil, &os.PathError{Op: "acl_get_file", Path: "/proc/nonexistent", Err: syscall.ENOENT}), - call("verbosef", stub.ExpectArgs{"target of ACL %s no longer exists", []any{&aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), + call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Perm(0)}, nil, &os.PathError{Op: "acl_get_file", Path: "/proc/nonexistent", Err: syscall.ENOENT}), + call("verbosef", stub.ExpectArgs{"target of ACL %s no longer exists", []any{&aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), }, nil}, {"success", 0xbeef, 0xff, - &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil), + &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}, []stub.Call{ + call("verbose", stub.ExpectArgs{[]any{"applying ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, nil), }, nil, []stub.Call{ - call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{acl.Read, acl.Write, acl.Execute}}}}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, ([]acl.Perm)(nil)}, nil, nil), + call("verbose", stub.ExpectArgs{[]any{"stripping ACL", &aclUpdateOp{Process, "/proc/nonexistent", acl.Read | acl.Write | acl.Execute}}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/proc/nonexistent", 0xbeef, acl.Perm(0)}, nil, nil), }, nil}, }) @@ -63,28 +63,28 @@ func TestACLUpdateOp(t *testing.T) { func(_ *testing.T, sys *I) { sys. UpdatePerm(m("/run/user/1971/hakurei"), acl.Execute). - UpdatePerm(m("/tmp/hakurei.0/tmpdir/150"), acl.Read, acl.Write, acl.Execute) + UpdatePerm(m("/tmp/hakurei.0/tmpdir/150"), acl.Read|acl.Write|acl.Execute) }, []Op{ - &aclUpdateOp{Process, "/run/user/1971/hakurei", []acl.Perm{acl.Execute}}, - &aclUpdateOp{Process, "/tmp/hakurei.0/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, + &aclUpdateOp{Process, "/run/user/1971/hakurei", acl.Execute}, + &aclUpdateOp{Process, "/tmp/hakurei.0/tmpdir/150", acl.Read | acl.Write | acl.Execute}, }, stub.Expect{}}, {"tmpdirp", 0xbeef, func(_ *testing.T, sys *I) { sys.UpdatePermType(User, m("/tmp/hakurei.0/tmpdir"), acl.Execute) }, []Op{ - &aclUpdateOp{User, "/tmp/hakurei.0/tmpdir", []acl.Perm{acl.Execute}}, + &aclUpdateOp{User, "/tmp/hakurei.0/tmpdir", acl.Execute}, }, stub.Expect{}}, {"tmpdir", 0xbeef, func(_ *testing.T, sys *I) { - sys.UpdatePermType(User, m("/tmp/hakurei.0/tmpdir/150"), acl.Read, acl.Write, acl.Execute) + sys.UpdatePermType(User, m("/tmp/hakurei.0/tmpdir/150"), acl.Read|acl.Write|acl.Execute) }, []Op{ - &aclUpdateOp{User, "/tmp/hakurei.0/tmpdir/150", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, + &aclUpdateOp{User, "/tmp/hakurei.0/tmpdir/150", acl.Read | acl.Write | acl.Execute}, }, stub.Expect{}}, {"share", 0xbeef, func(_ *testing.T, sys *I) { sys.UpdatePermType(Process, m("/run/user/1971/hakurei/fcb8a12f7c482d183ade8288c3de78b5"), acl.Execute) }, []Op{ - &aclUpdateOp{Process, "/run/user/1971/hakurei/fcb8a12f7c482d183ade8288c3de78b5", []acl.Perm{acl.Execute}}, + &aclUpdateOp{Process, "/run/user/1971/hakurei/fcb8a12f7c482d183ade8288c3de78b5", acl.Execute}, }, stub.Expect{}}, {"passwd", 0xbeef, func(_ *testing.T, sys *I) { @@ -92,14 +92,14 @@ func TestACLUpdateOp(t *testing.T) { UpdatePermType(Process, m("/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/passwd"), acl.Read). UpdatePermType(Process, m("/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/group"), acl.Read) }, []Op{ - &aclUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/passwd", []acl.Perm{acl.Read}}, - &aclUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/group", []acl.Perm{acl.Read}}, + &aclUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/passwd", acl.Read}, + &aclUpdateOp{Process, "/tmp/hakurei.0/fcb8a12f7c482d183ade8288c3de78b5/group", acl.Read}, }, stub.Expect{}}, {"wayland", 0xbeef, func(_ *testing.T, sys *I) { - sys.UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read, acl.Write, acl.Execute) + sys.UpdatePermType(hst.EWayland, m("/run/user/1971/wayland-0"), acl.Read|acl.Write|acl.Execute) }, []Op{ - &aclUpdateOp{hst.EWayland, "/run/user/1971/wayland-0", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, + &aclUpdateOp{hst.EWayland, "/run/user/1971/wayland-0", acl.Read | acl.Write | acl.Execute}, }, stub.Expect{}}, }) @@ -110,75 +110,75 @@ func TestACLUpdateOp(t *testing.T) { {"et differs", &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, &aclUpdateOp{ hst.EX11, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, false}, {"path differs", &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-1", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, false}, {"perms differs", &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write}, + acl.Read | acl.Write, }, false}, {"equals", &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, &aclUpdateOp{ hst.EWayland, "/run/user/1971/wayland-0", - []acl.Perm{acl.Read, acl.Write, acl.Execute}, + acl.Read | acl.Write | acl.Execute, }, true}, }) checkOpMeta(t, []opMetaTestCase{ {"clear", - &aclUpdateOp{Process, "/proc/nonexistent", []acl.Perm{}}, + &aclUpdateOp{Process, "/proc/nonexistent", 0}, Process, "/proc/nonexistent", `--- type: process path: "/proc/nonexistent"`}, {"read", - &aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0", []acl.Perm{acl.Read}}, + &aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0", acl.Read}, User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0", `r-- type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/0"`}, {"write", - &aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1", []acl.Perm{acl.Write}}, + &aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1", acl.Write}, User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1", `-w- type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/1"`}, {"execute", - &aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2", []acl.Perm{acl.Execute}}, + &aclUpdateOp{User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2", acl.Execute}, User, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2", `--x type: user path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/2"`}, {"wayland", - &aclUpdateOp{hst.EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", []acl.Perm{acl.Read, acl.Write}}, + &aclUpdateOp{hst.EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", acl.Read | acl.Write}, hst.EWayland, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland", `rw- type: wayland path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/wayland"`}, {"x11", - &aclUpdateOp{hst.EX11, "/tmp/.X11-unix/X0", []acl.Perm{acl.Read, acl.Execute}}, + &aclUpdateOp{hst.EX11, "/tmp/.X11-unix/X0", acl.Read | acl.Execute}, hst.EX11, "/tmp/.X11-unix/X0", `r-x type: x11 path: "/tmp/.X11-unix/X0"`}, {"dbus", - &aclUpdateOp{hst.EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", []acl.Perm{acl.Write, acl.Execute}}, + &aclUpdateOp{hst.EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", acl.Write | acl.Execute}, hst.EDBus, "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus", `-wx type: dbus path: "/tmp/hakurei.0/27d81d567f8fae7f33278eec45da9446/bus"`}, {"pulseaudio", - &aclUpdateOp{hst.EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", []acl.Perm{acl.Read, acl.Write, acl.Execute}}, + &aclUpdateOp{hst.EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", acl.Read | acl.Write | acl.Execute}, hst.EPulse, "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse", `rwx type: pulseaudio path: "/run/user/1971/hakurei/27d81d567f8fae7f33278eec45da9446/pulse"`}, }) diff --git a/internal/system/dispatcher.go b/internal/system/dispatcher.go index 8f70b0c0..5a222176 100644 --- a/internal/system/dispatcher.go +++ b/internal/system/dispatcher.go @@ -50,7 +50,7 @@ type syscallDispatcher interface { println(v ...any) // aclUpdate provides [acl.Update]. - aclUpdate(name string, uid int, perms ...acl.Perm) error + aclUpdate(name string, uid int, perms acl.Perm) error // waylandNew provides [wayland.New]. waylandNew(displayPath, bindPath *check.Absolute, appID, instanceID string) (io.Closer, error) @@ -85,8 +85,8 @@ func (k direct) remove(name string) error { return os.Remove(na func (k direct) println(v ...any) { log.Println(v...) } -func (k direct) aclUpdate(name string, uid int, perms ...acl.Perm) error { - return acl.Update(name, uid, perms...) +func (k direct) aclUpdate(name string, uid int, perms acl.Perm) error { + return acl.Update(name, uid, perms) } func (k direct) waylandNew(displayPath, bindPath *check.Absolute, appID, instanceID string) (io.Closer, error) { diff --git a/internal/system/dispatcher_test.go b/internal/system/dispatcher_test.go index 3bf14e75..6ffd0dfa 100644 --- a/internal/system/dispatcher_test.go +++ b/internal/system/dispatcher_test.go @@ -280,7 +280,7 @@ func (k *kstub) println(v ...any) { } } -func (k *kstub) aclUpdate(name string, uid int, perms ...acl.Perm) error { +func (k *kstub) aclUpdate(name string, uid int, perms acl.Perm) error { k.Helper() expect := k.Expects("aclUpdate") @@ -293,7 +293,7 @@ func (k *kstub) aclUpdate(name string, uid int, perms ...acl.Perm) error { return expect.Error( stub.CheckArgReflect(k.Stub, "name", nameVal, 0), stub.CheckArg(k.Stub, "uid", uid, 1), - stub.CheckArgReflect(k.Stub, "perms", perms, 2)) + stub.CheckArg(k.Stub, "perms", perms, 2)) } func (k *kstub) waylandNew(displayPath, bindPath *check.Absolute, appID, instanceID string) (io.Closer, error) { diff --git a/internal/system/pipewire.go b/internal/system/pipewire.go index c2d7b396..427013a4 100644 --- a/internal/system/pipewire.go +++ b/internal/system/pipewire.go @@ -73,7 +73,7 @@ func (p *pipewireOp) apply(sys *I) (err error) { return newOpError("pipewire", err, false) } - if err = sys.aclUpdate(p.dst.String(), sys.uid, acl.Read, acl.Write, acl.Execute); err != nil { + if err = sys.aclUpdate(p.dst.String(), sys.uid, acl.Read|acl.Write|acl.Execute); err != nil { if closeErr := p.scc.Close(); closeErr != nil { return newOpError("pipewire", errors.Join(err, closeErr), false) } diff --git a/internal/system/pipewire_test.go b/internal/system/pipewire_test.go index f0ca0b34..5953681e 100644 --- a/internal/system/pipewire_test.go +++ b/internal/system/pipewire_test.go @@ -423,7 +423,7 @@ func TestPipeWireOp(t *testing.T) { call("verbosef", stub.ExpectArgs{"pipewire pathname socket on %q", []any{ignoreValue{}}}, nil, nil), call("chmod", stub.ExpectArgs{ignoreValue{}, os.FileMode(0)}, nil, nil), - call("aclUpdate", stub.ExpectArgs{ignoreValue{}, 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{ignoreValue{}, 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, nil), }, nil, []stub.Call{ call("verbosef", stub.ExpectArgs{"hanging up pipewire socket on %q", []any{ignoreValue{}}}, nil, nil), }, nil}, diff --git a/internal/system/wayland.go b/internal/system/wayland.go index c22c3fdf..e86c3159 100644 --- a/internal/system/wayland.go +++ b/internal/system/wayland.go @@ -42,7 +42,7 @@ func (w *waylandOp) apply(sys *I) (err error) { return newOpError("wayland", err, false) } - if err = sys.aclUpdate(w.dst.String(), sys.uid, acl.Read, acl.Write, acl.Execute); err != nil { + if err = sys.aclUpdate(w.dst.String(), sys.uid, acl.Read|acl.Write|acl.Execute); err != nil { if closeErr := w.ctx.Close(); closeErr != nil { return newOpError("wayland", errors.Join(err, closeErr), false) } diff --git a/internal/system/wayland_test.go b/internal/system/wayland_test.go index 76e6cc93..a9d29378 100644 --- a/internal/system/wayland_test.go +++ b/internal/system/wayland_test.go @@ -32,7 +32,7 @@ func TestWaylandOp(t *testing.T) { call("waylandNew", stub.ExpectArgs{m("/run/user/1971/wayland-0"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c"}, nil, nil), call("verbosef", stub.ExpectArgs{"wayland pathname socket on %q via %q", []any{m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/1971/wayland-0")}}, nil, nil), call("chmod", stub.ExpectArgs{"/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", os.FileMode(0)}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, stub.UniqueError(2)), + call("aclUpdate", stub.ExpectArgs{"/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, stub.UniqueError(2)), }, &OpError{Op: "wayland", Err: stub.UniqueError(2)}, nil, nil}, {"success", 0xbeef, 0xff, &waylandOp{nil, @@ -44,7 +44,7 @@ func TestWaylandOp(t *testing.T) { call("waylandNew", stub.ExpectArgs{m("/run/user/1971/wayland-0"), m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland"), "org.chromium.Chromium", "ebf083d1b175911782d413369b64ce7c"}, nil, nil), call("verbosef", stub.ExpectArgs{"wayland pathname socket on %q via %q", []any{m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland"), m("/run/user/1971/wayland-0")}}, nil, nil), call("chmod", stub.ExpectArgs{"/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", os.FileMode(0)}, nil, nil), - call("aclUpdate", stub.ExpectArgs{"/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", 0xbeef, []acl.Perm{acl.Read, acl.Write, acl.Execute}}, nil, nil), + call("aclUpdate", stub.ExpectArgs{"/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland", 0xbeef, acl.Read | acl.Write | acl.Execute}, nil, nil), }, nil, []stub.Call{ call("verbosef", stub.ExpectArgs{"hanging up wayland socket on %q", []any{m("/tmp/hakurei.1971/ebf083d1b175911782d413369b64ce7c/wayland")}}, nil, nil), }, nil}, -- cgit v1.3.1