Skip to content

Commit

Permalink
Expose Config.HandledAccessFS. (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
gnoack committed Aug 28, 2021
1 parent 71e1285 commit fd8c035
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 34 deletions.
43 changes: 26 additions & 17 deletions landlock/accessfs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
package landlock

import "strings"
import (
"fmt"
"strings"
)

var flagNames = []string{
"Execute",
"WriteFile",
"ReadFile",
"ReadDir",
"RemoveDir",
"RemoveFile",
"MakeChar",
"MakeDir",
"MakeReg",
"MakeSock",
"MakeFifo",
"MakeBlock",
"MakeSym",
}

// AccessFSSet is a set of Landlockable file system access operations.
type AccessFSSet uint64
Expand All @@ -11,28 +30,18 @@ func (a AccessFSSet) String() string {
}
var b strings.Builder
b.WriteByte('{')
for i, n := range []string{
"Execute",
"WriteFile",
"ReadFile",
"ReadDir",
"RemoveDir",
"RemoveFile",
"MakeChar",
"MakeDir",
"MakeReg",
"MakeSock",
"MakeFifo",
"MakeBlock",
"MakeSym",
} {
for i := 0; i < 64; i++ {
if a&(1<<i) == 0 {
continue
}
if b.Len() > 1 {
b.WriteByte(',')
}
b.WriteString(n)
if i < len(flagNames) {
b.WriteString(flagNames[i])
} else {
b.WriteString(fmt.Sprintf("1<<%v", i))
}
}
b.WriteByte('}')
return b.String()
Expand Down
1 change: 1 addition & 0 deletions landlock/accessfs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestPrettyPrint(t *testing.T) {
{a: ll.AccessFSMakeFifo, want: "{MakeFifo}"},
{a: ll.AccessFSMakeBlock, want: "{MakeBlock}"},
{a: ll.AccessFSMakeSym, want: "{MakeSym}"},
{a: ll.AccessFSReadFile | 1<<63, want: "{ReadFile,1<<63}"},
} {
got := tc.a.String()
if got != tc.want {
Expand Down
35 changes: 25 additions & 10 deletions landlock/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,46 +31,61 @@ const (
var (
// Landlock V1 support (basic file operations).
V1 = Config{
handledAccessFS: abiInfos[1].supportedAccessFS,
HandledAccessFS: abiInfos[1].supportedAccessFS,
}
)

// The Landlock configuration describes the desired set of
// landlockable operations to be restricted.
// landlockable operations to be restricted and the constraints on it
// (e.g. best effort mode).
type Config struct {
handledAccessFS AccessFSSet
// File system operations to restrict when enabling Landlock.
// Needs to stay within the bounds of what go-landlock supports.
HandledAccessFS AccessFSSet
bestEffort bool
}

// validate returns success when the given config is supported by
// go-landlock. (It may still be unsupported by your kernel though.)
func (c Config) validate() error {
safs := highestKnownABIVersion.supportedAccessFS
if !c.handledAccessFS.isSubset(safs) {
return errors.New("unsupported handledAccessFS value")
if !c.HandledAccessFS.isSubset(safs) {
return errors.New("unsupported HandledAccessFS value")
}
return nil
}

// String builds a human-readable representation of the Config.
func (c Config) String() string {
var abi abiInfo
abi := abiInfo{version: -1} // invalid
for _, a := range abiInfos {
if c.handledAccessFS.isSubset(a.supportedAccessFS) {
if c.HandledAccessFS.isSubset(a.supportedAccessFS) {
abi = a
}
}

var desc = c.handledAccessFS.String()
if abi.supportedAccessFS == c.handledAccessFS {
var desc = c.HandledAccessFS.String()
if abi.supportedAccessFS == c.HandledAccessFS {
desc = "all"
}

var bestEffort = ""
if c.bestEffort {
bestEffort = " (best effort)"
}
return fmt.Sprintf("{Landlock V%v; HandledAccessFS: %v%v}", abi.version, desc, bestEffort)

var version string
if abi.version < 0 {
version = "V???"
} else {
version = fmt.Sprintf("V%v", abi.version)
}

errStr := ""
if err := c.validate(); err != nil {
errStr = fmt.Sprintf(" (%v)", err)
}
return fmt.Sprintf("{Landlock %v; HandledAccessFS: %v%v%v}", version, desc, bestEffort, errStr)
}

// BestEffort returns a config that will opportunistically enforce
Expand Down
16 changes: 10 additions & 6 deletions landlock/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ func TestConfigString(t *testing.T) {
want string
}{
{
cfg: Config{handledAccessFS: 0},
cfg: Config{HandledAccessFS: 0},
want: fmt.Sprintf("{Landlock V1; HandledAccessFS: %v}", AccessFSSet(0)),
},
{
cfg: Config{handledAccessFS: ll.AccessFSWriteFile},
cfg: Config{HandledAccessFS: ll.AccessFSWriteFile},
want: "{Landlock V1; HandledAccessFS: {WriteFile}}",
},
{
Expand All @@ -28,6 +28,10 @@ func TestConfigString(t *testing.T) {
cfg: V1.BestEffort(),
want: "{Landlock V1; HandledAccessFS: all (best effort)}",
},
{
cfg: Config{HandledAccessFS: 1<<63},
want: "{Landlock V???; HandledAccessFS: {1<<63} (unsupported HandledAccessFS value)}",
},
} {
got := tc.cfg.String()
if got != tc.want {
Expand All @@ -39,8 +43,8 @@ func TestConfigString(t *testing.T) {
func TestValidateSuccess(t *testing.T) {
for _, c := range []Config{
V1, V1.BestEffort(),
Config{handledAccessFS: ll.AccessFSWriteFile},
Config{handledAccessFS: 0},
Config{HandledAccessFS: ll.AccessFSWriteFile},
Config{HandledAccessFS: 0},
} {
err := c.validate()
if err != nil {
Expand All @@ -51,8 +55,8 @@ func TestValidateSuccess(t *testing.T) {

func TestValidateFailure(t *testing.T) {
for _, c := range []Config{
Config{handledAccessFS: 0xffffffffffffffff},
Config{handledAccessFS: highestKnownABIVersion.supportedAccessFS + 1},
Config{HandledAccessFS: 0xffffffffffffffff},
Config{HandledAccessFS: highestKnownABIVersion.supportedAccessFS + 1},
} {
err := c.validate()
if err == nil {
Expand Down
2 changes: 1 addition & 1 deletion landlock/restrict.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func restrictPaths(c Config, opts ...PathOpt) error {
if err != nil {
return fmt.Errorf("unsupported Landlock config %v (upgrade go-landlock?): %v", c, err)
}
handledAccessFS := c.handledAccessFS
handledAccessFS := c.HandledAccessFS
abi := getSupportedABIVersion()
if c.bestEffort {
handledAccessFS = handledAccessFS.intersect(abi.supportedAccessFS)
Expand Down
12 changes: 12 additions & 0 deletions tests/failure/failure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,15 @@ func TestEmptyAccessRights(t *testing.T) {
t.Errorf("expected error message with «empty access rights», got: %v", err)
}
}

func TestSpecifiedTooManyFlags(t *testing.T) {
cfg := landlock.Config{HandledAccessFS: 1 << 13}
err := cfg.RestrictPaths()
if err == nil {
t.Errorf("%v.RestrictPaths(): expected error, got success", cfg)
}
want := "unsupported Landlock config"
if !strings.Contains(err.Error(), want) {
t.Errorf("%v.RestrictPaths(): expected error with %q, got %q", cfg, want, err.Error())
}
}

0 comments on commit fd8c035

Please sign in to comment.