Compare commits
72 Commits
c5aefe5e9d
...
v0.3.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
17ffdb2dcf
|
|||
|
ac34635890
|
|||
|
9dec9dbc4b
|
|||
|
2f74adc8bd
|
|||
|
d7e0104ae4
|
|||
|
bb92e3ada9
|
|||
|
fad419c2a2
|
|||
|
b1a1e73238
|
|||
|
38e9128a8c
|
|||
|
7ee702a44e
|
|||
|
3d188ef884
|
|||
|
34ccda84b2
|
|||
|
042013bb04
|
|||
|
5c2b63a7f1
|
|||
|
9fd97e71d0
|
|||
|
fba201c995
|
|||
|
7f27a6dc51
|
|||
|
b65aba9446
|
|||
|
becaf8b6d7
|
|||
|
54c0d6bf48
|
|||
|
c1399f5030
|
|||
|
9ac63aac0c
|
|||
|
cb9ebf0e15
|
|||
|
9a2a7b749f
|
|||
|
ec5cb9400c
|
|||
|
ae66b3d2fb
|
|||
|
149bc3671a
|
|||
|
24435694a5
|
|||
|
1c168babf2
|
|||
|
0edcb7c1d3
|
|||
|
0e5ca74b98
|
|||
|
23ae7822bf
|
|||
|
898b5aed3d
|
|||
|
7c3c3135d8
|
|||
|
f33aea9ff9
|
|||
|
e7fc311d0b
|
|||
|
f5274067f6
|
|||
|
e7161f8e61
|
|||
|
6931ad95c3
|
|||
|
2ba599b399
|
|||
|
d3d3417125
|
|||
|
651cdf9ccb
|
|||
|
68ff0a2ba6
|
|||
|
6a0ecced90
|
|||
|
b667fea1cb
|
|||
|
b25ade5f3d
|
|||
|
ebdcff1049
|
|||
|
46c5ce4936
|
|||
|
36f8064905
|
|||
|
eeb9f98e5b
|
|||
|
3f9f331501
|
|||
|
2563391086
|
|||
|
a0b4e47acc
|
|||
|
a52f7038e5
|
|||
|
274686d10d
|
|||
|
65342d588f
|
|||
|
5e5826459e
|
|||
|
4a463b7f03
|
|||
|
dacd9550e0
|
|||
|
546b00429f
|
|||
|
86f4219062
|
|||
|
fe2929d5f7
|
|||
|
470e545d27
|
|||
|
8d3381821f
|
|||
|
e9d00b9071
|
|||
|
4f41afee0f
|
|||
|
7de593e816
|
|||
|
2442eda8d9
|
|||
|
05488bfb8f
|
|||
|
dd94818f20
|
|||
|
0fd357e7f6
|
|||
|
57231d4acf
|
@@ -18,8 +18,8 @@ import (
|
|||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
"hakurei.app/internal/app"
|
"hakurei.app/internal/env"
|
||||||
"hakurei.app/internal/app/state"
|
"hakurei.app/internal/outcome"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
"hakurei.app/system/dbus"
|
"hakurei.app/system/dbus"
|
||||||
)
|
)
|
||||||
@@ -50,22 +50,28 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
|
Flag(&flagVerbose, "v", command.BoolFlag(false), "Increase log verbosity").
|
||||||
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
|
Flag(&flagJSON, "json", command.BoolFlag(false), "Serialise output in JSON when applicable")
|
||||||
|
|
||||||
c.Command("shim", command.UsageInternal, func([]string) error { app.Shim(msg); return errSuccess })
|
c.Command("shim", command.UsageInternal, func([]string) error { outcome.Shim(msg); return errSuccess })
|
||||||
|
|
||||||
c.Command("app", "Load and start container from configuration file", func(args []string) error {
|
{
|
||||||
if len(args) < 1 {
|
var (
|
||||||
log.Fatal("app requires at least 1 argument")
|
flagIdentifierFile int
|
||||||
}
|
)
|
||||||
|
c.NewCommand("app", "Load and start container from configuration file", func(args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
log.Fatal("app requires at least 1 argument")
|
||||||
|
}
|
||||||
|
|
||||||
// config extraArgs...
|
config := tryPath(msg, args[0])
|
||||||
config := tryPath(msg, args[0])
|
if config != nil && config.Container != nil {
|
||||||
if config != nil && config.Container != nil {
|
config.Container.Args = append(config.Container.Args, args[1:]...)
|
||||||
config.Container.Args = append(config.Container.Args, args[1:]...)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
app.Main(ctx, msg, config)
|
outcome.Main(ctx, msg, config, flagIdentifierFile)
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
})
|
}).
|
||||||
|
Flag(&flagIdentifierFile, "identifier-fd", command.IntFlag(-1),
|
||||||
|
"Write identifier of current instance to fd after successful startup")
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var (
|
var (
|
||||||
@@ -86,7 +92,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
)
|
)
|
||||||
|
|
||||||
c.NewCommand("run", "Configure and start a permissive container", func(args []string) error {
|
c.NewCommand("run", "Configure and start a permissive container", func(args []string) error {
|
||||||
if flagIdentity < hst.IdentityMin || flagIdentity > hst.IdentityMax {
|
if flagIdentity < hst.IdentityStart || flagIdentity > hst.IdentityEnd {
|
||||||
log.Fatalf("identity %d out of range", flagIdentity)
|
log.Fatalf("identity %d out of range", flagIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +101,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
passwd *user.User
|
passwd *user.User
|
||||||
passwdOnce sync.Once
|
passwdOnce sync.Once
|
||||||
passwdFunc = func() {
|
passwdFunc = func() {
|
||||||
us := strconv.Itoa(app.HsuUid(new(app.Hsu).MustID(msg), flagIdentity))
|
us := strconv.Itoa(hst.ToUser(new(outcome.Hsu).MustID(msg), flagIdentity))
|
||||||
if u, err := user.LookupId(us); err != nil {
|
if u, err := user.LookupId(us); err != nil {
|
||||||
msg.Verbosef("cannot look up uid %s", us)
|
msg.Verbosef("cannot look up uid %s", us)
|
||||||
passwd = &user.User{
|
passwd = &user.User{
|
||||||
@@ -257,7 +263,7 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Main(ctx, msg, config)
|
outcome.Main(ctx, msg, config, -1)
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}).
|
}).
|
||||||
Flag(&flagDBusConfigSession, "dbus-config", command.StringFlag("builtin"),
|
Flag(&flagDBusConfigSession, "dbus-config", command.StringFlag("builtin"),
|
||||||
@@ -293,7 +299,10 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var flagShort bool
|
var (
|
||||||
|
flagShort bool
|
||||||
|
flagNoStore bool
|
||||||
|
)
|
||||||
c.NewCommand("show", "Show live or local app configuration", func(args []string) error {
|
c.NewCommand("show", "Show live or local app configuration", func(args []string) error {
|
||||||
switch len(args) {
|
switch len(args) {
|
||||||
case 0: // system
|
case 0: // system
|
||||||
@@ -301,10 +310,23 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
|
|
||||||
case 1: // instance
|
case 1: // instance
|
||||||
name := args[0]
|
name := args[0]
|
||||||
config, entry := tryShort(msg, name)
|
|
||||||
if config == nil {
|
var (
|
||||||
config = tryPath(msg, name)
|
config *hst.Config
|
||||||
|
entry *hst.State
|
||||||
|
)
|
||||||
|
if !flagNoStore {
|
||||||
|
var sc hst.Paths
|
||||||
|
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
|
||||||
|
entry = tryIdentifier(msg, name, outcome.NewStore(&sc))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if entry == nil {
|
||||||
|
config = tryPath(msg, name)
|
||||||
|
} else {
|
||||||
|
config = entry.Config
|
||||||
|
}
|
||||||
|
|
||||||
if !printShowInstance(os.Stdout, time.Now().UTC(), entry, config, flagShort, flagJSON) {
|
if !printShowInstance(os.Stdout, time.Now().UTC(), entry, config, flagShort, flagJSON) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
@@ -313,15 +335,17 @@ func buildCommand(ctx context.Context, msg message.Msg, early *earlyHardeningErr
|
|||||||
log.Fatal("show requires 1 argument")
|
log.Fatal("show requires 1 argument")
|
||||||
}
|
}
|
||||||
return errSuccess
|
return errSuccess
|
||||||
}).Flag(&flagShort, "short", command.BoolFlag(false), "Omit filesystem information")
|
}).
|
||||||
|
Flag(&flagShort, "short", command.BoolFlag(false), "Omit filesystem information").
|
||||||
|
Flag(&flagNoStore, "no-store", command.BoolFlag(false), "Do not attempt to match from active instances")
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var flagShort bool
|
var flagShort bool
|
||||||
c.NewCommand("ps", "List active instances", func(args []string) error {
|
c.NewCommand("ps", "List active instances", func(args []string) error {
|
||||||
var sc hst.Paths
|
var sc hst.Paths
|
||||||
app.CopyPaths().Copy(&sc, new(app.Hsu).MustID(nil))
|
env.CopyPaths().Copy(&sc, new(outcome.Hsu).MustID(nil))
|
||||||
printPs(os.Stdout, time.Now().UTC(), state.NewMulti(msg, sc.RunDirPath.String()), flagShort, flagJSON)
|
printPs(msg, os.Stdout, time.Now().UTC(), outcome.NewStore(&sc), flagShort, flagJSON)
|
||||||
return errSuccess
|
return errSuccess
|
||||||
}).Flag(&flagShort, "short", command.BoolFlag(false), "Print instance id")
|
}).Flag(&flagShort, "short", command.BoolFlag(false), "Print instance id")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ Flags:
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
out := new(bytes.Buffer)
|
out := new(bytes.Buffer)
|
||||||
c := buildCommand(t.Context(), message.NewMsg(nil), new(earlyHardeningErrs), out)
|
c := buildCommand(t.Context(), message.New(nil), new(earlyHardeningErrs), out)
|
||||||
if err := c.Parse(tc.args); !errors.Is(err, command.ErrHelp) && !errors.Is(err, flag.ErrHelp) {
|
if err := c.Parse(tc.args); !errors.Is(err, command.ErrHelp) && !errors.Is(err, flag.ErrHelp) {
|
||||||
t.Errorf("Parse: error = %v; want %v",
|
t.Errorf("Parse: error = %v; want %v",
|
||||||
err, command.ErrHelp)
|
err, command.ErrHelp)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func main() {
|
|||||||
|
|
||||||
log.SetPrefix("hakurei: ")
|
log.SetPrefix("hakurei: ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
msg := message.NewMsg(log.Default())
|
msg := message.New(log.Default())
|
||||||
|
|
||||||
early := earlyHardeningErrs{
|
early := earlyHardeningErrs{
|
||||||
yamaLSM: container.SetPtracer(0),
|
yamaLSM: container.SetPtracer(0),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -10,11 +11,14 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal/app"
|
"hakurei.app/internal/outcome"
|
||||||
"hakurei.app/internal/app/state"
|
"hakurei.app/internal/store"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// tryPath attempts to read [hst.Config] from multiple sources.
|
||||||
|
// tryPath reads from [os.Stdin] if name has value "-".
|
||||||
|
// Otherwise, name is passed to tryFd, and if that returns nil, name is passed to [os.Open].
|
||||||
func tryPath(msg message.Msg, name string) (config *hst.Config) {
|
func tryPath(msg message.Msg, name string) (config *hst.Config) {
|
||||||
var r io.ReadCloser
|
var r io.ReadCloser
|
||||||
config = new(hst.Config)
|
config = new(hst.Config)
|
||||||
@@ -42,6 +46,7 @@ func tryPath(msg message.Msg, name string) (config *hst.Config) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tryFd returns a [io.ReadCloser] if name represents an integer corresponding to a valid file descriptor.
|
||||||
func tryFd(msg message.Msg, name string) io.ReadCloser {
|
func tryFd(msg message.Msg, name string) io.ReadCloser {
|
||||||
if v, err := strconv.Atoi(name); err != nil {
|
if v, err := strconv.Atoi(name); err != nil {
|
||||||
if !errors.Is(err, strconv.ErrSyntax) {
|
if !errors.Is(err, strconv.ErrSyntax) {
|
||||||
@@ -49,22 +54,50 @@ func tryFd(msg message.Msg, name string) io.ReadCloser {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
|
if v < 3 { // reject standard streams
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
msg.Verbosef("trying config stream from %d", v)
|
msg.Verbosef("trying config stream from %d", v)
|
||||||
fd := uintptr(v)
|
fd := uintptr(v)
|
||||||
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 {
|
if _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_GETFD, 0); errno != 0 {
|
||||||
if errors.Is(errno, syscall.EBADF) {
|
if errors.Is(errno, syscall.EBADF) { // reject bad fd
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
log.Fatalf("cannot get fd %d: %v", fd, errno)
|
log.Fatalf("cannot get fd %d: %v", fd, errno)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if outcome.IsPollDescriptor(fd) { // reject runtime internals
|
||||||
|
log.Fatalf("invalid config stream %d", fd)
|
||||||
|
}
|
||||||
|
|
||||||
return os.NewFile(fd, strconv.Itoa(v))
|
return os.NewFile(fd, strconv.Itoa(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryShort(msg message.Msg, name string) (config *hst.Config, entry *state.State) {
|
// shortLengthMin is the minimum length a short form identifier can have and still be interpreted as an identifier.
|
||||||
likePrefix := false
|
const shortLengthMin = 1 << 3
|
||||||
if len(name) <= 32 {
|
|
||||||
likePrefix = true
|
// shortIdentifier returns an eight character short representation of [hst.ID] from its random bytes.
|
||||||
|
func shortIdentifier(id *hst.ID) string {
|
||||||
|
return shortIdentifierString(id.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
// shortIdentifierString implements shortIdentifier on an arbitrary string.
|
||||||
|
func shortIdentifierString(s string) string {
|
||||||
|
return s[len(hst.ID{}) : len(hst.ID{})+shortLengthMin]
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryIdentifier attempts to match [hst.State] from a [hex] representation of [hst.ID] or a prefix of its lower half.
|
||||||
|
func tryIdentifier(msg message.Msg, name string, s *store.Store) *hst.State {
|
||||||
|
const (
|
||||||
|
likeShort = 1 << iota
|
||||||
|
likeFull
|
||||||
|
)
|
||||||
|
|
||||||
|
var likely uintptr
|
||||||
|
if len(name) >= shortLengthMin && len(name) <= len(hst.ID{}) { // half the hex representation
|
||||||
|
// cannot safely decode here due to unknown alignment
|
||||||
for _, c := range name {
|
for _, c := range name {
|
||||||
if c >= '0' && c <= '9' {
|
if c >= '0' && c <= '9' {
|
||||||
continue
|
continue
|
||||||
@@ -72,35 +105,68 @@ func tryShort(msg message.Msg, name string) (config *hst.Config, entry *state.St
|
|||||||
if c >= 'a' && c <= 'f' {
|
if c >= 'a' && c <= 'f' {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
likePrefix = false
|
return nil
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
likely |= likeShort
|
||||||
|
} else if len(name) == hex.EncodedLen(len(hst.ID{})) {
|
||||||
|
likely |= likeFull
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to match from state store
|
if likely == 0 {
|
||||||
if likePrefix && len(name) >= 8 {
|
return nil
|
||||||
msg.Verbose("argument looks like prefix")
|
}
|
||||||
|
|
||||||
var sc hst.Paths
|
entries, copyError := s.All()
|
||||||
app.CopyPaths().Copy(&sc, new(app.Hsu).MustID(nil))
|
defer func() {
|
||||||
s := state.NewMulti(msg, sc.RunDirPath.String())
|
if err := copyError(); err != nil {
|
||||||
if entries, err := state.Join(s); err != nil {
|
msg.GetLogger().Println(getMessage("cannot iterate over store:", err))
|
||||||
log.Printf("cannot join store: %v", err)
|
}
|
||||||
// drop to fetch from file
|
}()
|
||||||
} else {
|
|
||||||
for id := range entries {
|
switch {
|
||||||
v := id.String()
|
case likely&likeShort != 0:
|
||||||
if strings.HasPrefix(v, name) {
|
msg.Verbose("argument looks like short identifier")
|
||||||
// match, use config from this state entry
|
for eh := range entries {
|
||||||
entry = entries[id]
|
if eh.DecodeErr != nil {
|
||||||
config = entry.Config
|
msg.Verbose(getMessage("skipping instance:", eh.DecodeErr))
|
||||||
break
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(eh.ID.String()[len(hst.ID{}):], name) {
|
||||||
|
var entry hst.State
|
||||||
|
if _, err := eh.Load(&entry); err != nil {
|
||||||
|
msg.GetLogger().Println(getMessage("cannot load state entry:", err))
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
return &entry
|
||||||
msg.Verbosef("instance %s skipped", v)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return nil
|
||||||
|
|
||||||
return
|
case likely&likeFull != 0:
|
||||||
|
var likelyID hst.ID
|
||||||
|
if likelyID.UnmarshalText([]byte(name)) != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
msg.Verbose("argument looks like identifier")
|
||||||
|
for eh := range entries {
|
||||||
|
if eh.DecodeErr != nil {
|
||||||
|
msg.Verbose(getMessage("skipping instance:", eh.DecodeErr))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if eh.ID == likelyID {
|
||||||
|
var entry hst.State
|
||||||
|
if _, err := eh.Load(&entry); err != nil {
|
||||||
|
msg.GetLogger().Println(getMessage("cannot load state entry:", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return &entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
117
cmd/hakurei/parse_test.go
Normal file
117
cmd/hakurei/parse_test.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"hakurei.app/container/check"
|
||||||
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/store"
|
||||||
|
"hakurei.app/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestShortIdentifier(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
id := hst.ID{
|
||||||
|
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||||
|
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
|
||||||
|
}
|
||||||
|
|
||||||
|
const want = "fedcba98"
|
||||||
|
if got := shortIdentifier(&id); got != want {
|
||||||
|
t.Errorf("shortIdentifier: %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTryIdentifier(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
msg := message.New(nil)
|
||||||
|
id := hst.ID{
|
||||||
|
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||||
|
0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
|
||||||
|
}
|
||||||
|
withBase := func(extra ...hst.State) []hst.State {
|
||||||
|
return append([]hst.State{
|
||||||
|
{ID: (hst.ID)(bytes.Repeat([]byte{0xaa}, len(hst.ID{}))), PID: 0xbeef, ShimPID: 0xcafe, Config: hst.Template(), Time: time.Unix(0, 0xdeadbeef0)},
|
||||||
|
{ID: (hst.ID)(bytes.Repeat([]byte{0xab}, len(hst.ID{}))), PID: 0x1beef, ShimPID: 0x1cafe, Config: hst.Template(), Time: time.Unix(0, 0xdeadbeef1)},
|
||||||
|
{ID: (hst.ID)(bytes.Repeat([]byte{0xf0}, len(hst.ID{}))), PID: 0x2beef, ShimPID: 0x2cafe, Config: hst.Template(), Time: time.Unix(0, 0xdeadbeef2)},
|
||||||
|
|
||||||
|
{ID: (hst.ID)(bytes.Repeat([]byte{0xfe}, len(hst.ID{}))), PID: 0xbed, ShimPID: 0xfff, Config: func() *hst.Config {
|
||||||
|
template := hst.Template()
|
||||||
|
template.Identity = hst.IdentityEnd
|
||||||
|
return template
|
||||||
|
}(), Time: time.Unix(0, 0xcafebabe0)},
|
||||||
|
{ID: (hst.ID)(bytes.Repeat([]byte{0xfc}, len(hst.ID{}))), PID: 0x1bed, ShimPID: 0x1fff, Config: func() *hst.Config {
|
||||||
|
template := hst.Template()
|
||||||
|
template.Identity = 0xfc
|
||||||
|
return template
|
||||||
|
}(), Time: time.Unix(0, 0xcafebabe1)},
|
||||||
|
{ID: (hst.ID)(bytes.Repeat([]byte{0xce}, len(hst.ID{}))), PID: 0x2bed, ShimPID: 0x2fff, Config: func() *hst.Config {
|
||||||
|
template := hst.Template()
|
||||||
|
template.Identity = 0xce
|
||||||
|
return template
|
||||||
|
}(), Time: time.Unix(0, 0xcafebabe2)},
|
||||||
|
}, extra...)
|
||||||
|
}
|
||||||
|
sampleEntry := hst.State{
|
||||||
|
ID: id,
|
||||||
|
PID: 0xcafe,
|
||||||
|
ShimPID: 0xdead,
|
||||||
|
Config: hst.Template(),
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
s string
|
||||||
|
data []hst.State
|
||||||
|
want *hst.State
|
||||||
|
}{
|
||||||
|
{"likely entries fault", "ffffffff", nil, nil},
|
||||||
|
|
||||||
|
{"likely short too short", "ff", nil, nil},
|
||||||
|
{"likely short too long", "fffffffffffffffff", nil, nil},
|
||||||
|
{"likely short invalid lower", "fffffff\x00", nil, nil},
|
||||||
|
{"likely short invalid higher", "0000000\xff", nil, nil},
|
||||||
|
{"short no match", "fedcba98", withBase(), nil},
|
||||||
|
{"short match", "fedcba98", withBase(sampleEntry), &sampleEntry},
|
||||||
|
{"short match single", "fedcba98", []hst.State{sampleEntry}, &sampleEntry},
|
||||||
|
{"short match longer", "fedcba98765", withBase(sampleEntry), &sampleEntry},
|
||||||
|
|
||||||
|
{"likely long invalid", "0123456789abcdeffedcba987654321\x00", nil, nil},
|
||||||
|
{"long no match", "0123456789abcdeffedcba9876543210", withBase(), nil},
|
||||||
|
{"long match", "0123456789abcdeffedcba9876543210", withBase(sampleEntry), &sampleEntry},
|
||||||
|
{"long match single", "0123456789abcdeffedcba9876543210", []hst.State{sampleEntry}, &sampleEntry},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
base := check.MustAbs(t.TempDir()).Append("store")
|
||||||
|
s := store.New(base)
|
||||||
|
for i := range tc.data {
|
||||||
|
if h, err := s.Handle(tc.data[i].Identity); err != nil {
|
||||||
|
t.Fatalf("Handle: error = %v", err)
|
||||||
|
} else {
|
||||||
|
var unlock func()
|
||||||
|
if unlock, err = h.Lock(); err != nil {
|
||||||
|
t.Fatalf("Lock: error = %v", err)
|
||||||
|
}
|
||||||
|
_, err = h.Save(&tc.data[i])
|
||||||
|
unlock()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Save: error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store must not be written to beyond this point
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
got := tryIdentifier(msg, tc.s, store.New(base))
|
||||||
|
if !reflect.DeepEqual(got, tc.want) {
|
||||||
|
t.Errorf("tryIdentifier: %#v, want %#v", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
@@ -12,8 +13,9 @@ import (
|
|||||||
|
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal"
|
"hakurei.app/internal"
|
||||||
"hakurei.app/internal/app"
|
"hakurei.app/internal/env"
|
||||||
"hakurei.app/internal/app/state"
|
"hakurei.app/internal/outcome"
|
||||||
|
"hakurei.app/internal/store"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,8 +24,8 @@ func printShowSystem(output io.Writer, short, flagJSON bool) {
|
|||||||
t := newPrinter(output)
|
t := newPrinter(output)
|
||||||
defer t.MustFlush()
|
defer t.MustFlush()
|
||||||
|
|
||||||
info := &hst.Info{Version: internal.Version(), User: new(app.Hsu).MustID(nil)}
|
info := &hst.Info{Version: internal.Version(), User: new(outcome.Hsu).MustID(nil)}
|
||||||
app.CopyPaths().Copy(&info.Paths, info.User)
|
env.CopyPaths().Copy(&info.Paths, info.User)
|
||||||
|
|
||||||
if flagJSON {
|
if flagJSON {
|
||||||
encodeJSON(log.Fatal, output, short, info)
|
encodeJSON(log.Fatal, output, short, info)
|
||||||
@@ -38,11 +40,12 @@ func printShowSystem(output io.Writer, short, flagJSON bool) {
|
|||||||
t.Printf("RunDirPath:\t%s\n", info.RunDirPath)
|
t.Printf("RunDirPath:\t%s\n", info.RunDirPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// printShowInstance writes a representation of [state.State] or [hst.Config] to output.
|
// printShowInstance writes a representation of [hst.State] or [hst.Config] to output.
|
||||||
func printShowInstance(
|
func printShowInstance(
|
||||||
output io.Writer, now time.Time,
|
output io.Writer, now time.Time,
|
||||||
instance *state.State, config *hst.Config,
|
instance *hst.State, config *hst.Config,
|
||||||
short, flagJSON bool) (valid bool) {
|
short, flagJSON bool,
|
||||||
|
) (valid bool) {
|
||||||
valid = true
|
valid = true
|
||||||
|
|
||||||
if flagJSON {
|
if flagJSON {
|
||||||
@@ -64,9 +67,14 @@ func printShowInstance(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config == nil {
|
||||||
|
// nothing to print
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if instance != nil {
|
if instance != nil {
|
||||||
t.Printf("State\n")
|
t.Printf("State\n")
|
||||||
t.Printf(" Instance:\t%s (%d)\n", instance.ID.String(), instance.PID)
|
t.Printf(" Instance:\t%s (%d -> %d)\n", instance.ID.String(), instance.PID, instance.ShimPID)
|
||||||
t.Printf(" Uptime:\t%s\n", now.Sub(instance.Time).Round(time.Second).String())
|
t.Printf(" Uptime:\t%s\n", now.Sub(instance.Time).Round(time.Second).String())
|
||||||
t.Printf("\n")
|
t.Printf("\n")
|
||||||
}
|
}
|
||||||
@@ -82,14 +90,13 @@ func printShowInstance(
|
|||||||
t.Printf(" Groups:\t%s\n", strings.Join(config.Groups, ", "))
|
t.Printf(" Groups:\t%s\n", strings.Join(config.Groups, ", "))
|
||||||
}
|
}
|
||||||
if config.Container != nil {
|
if config.Container != nil {
|
||||||
params := config.Container
|
if config.Container.Home != nil {
|
||||||
if params.Home != nil {
|
t.Printf(" Home:\t%s\n", config.Container.Home)
|
||||||
t.Printf(" Home:\t%s\n", params.Home)
|
|
||||||
}
|
}
|
||||||
if params.Hostname != "" {
|
if config.Container.Hostname != "" {
|
||||||
t.Printf(" Hostname:\t%s\n", params.Hostname)
|
t.Printf(" Hostname:\t%s\n", config.Container.Hostname)
|
||||||
}
|
}
|
||||||
flags := params.Flags.String()
|
flags := config.Container.Flags.String()
|
||||||
|
|
||||||
// this is included in the upper hst.Config struct but is relevant here
|
// this is included in the upper hst.Config struct but is relevant here
|
||||||
const flagDirectWayland = "directwl"
|
const flagDirectWayland = "directwl"
|
||||||
@@ -103,11 +110,11 @@ func printShowInstance(
|
|||||||
}
|
}
|
||||||
t.Printf(" Flags:\t%s\n", flags)
|
t.Printf(" Flags:\t%s\n", flags)
|
||||||
|
|
||||||
if params.Path != nil {
|
if config.Container.Path != nil {
|
||||||
t.Printf(" Path:\t%s\n", params.Path)
|
t.Printf(" Path:\t%s\n", config.Container.Path)
|
||||||
}
|
}
|
||||||
if len(params.Args) > 0 {
|
if len(config.Container.Args) > 0 {
|
||||||
t.Printf(" Arguments:\t%s\n", strings.Join(params.Args, " "))
|
t.Printf(" Arguments:\t%s\n", strings.Join(config.Container.Args, " "))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Printf("\n")
|
t.Printf("\n")
|
||||||
@@ -167,57 +174,52 @@ func printShowInstance(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// printPs writes a representation of active instances to output.
|
// printPs writes a representation of active instances to output.
|
||||||
func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON bool) {
|
func printPs(msg message.Msg, output io.Writer, now time.Time, s *store.Store, short, flagJSON bool) {
|
||||||
var entries state.Entries
|
f := func(a func(eh *store.EntryHandle)) {
|
||||||
if e, err := state.Join(s); err != nil {
|
entries, copyError := s.All()
|
||||||
log.Fatalf("cannot join store: %v", err)
|
for eh := range entries {
|
||||||
} else {
|
a(eh)
|
||||||
entries = e
|
}
|
||||||
}
|
if err := copyError(); err != nil {
|
||||||
if err := s.Close(); err != nil {
|
msg.GetLogger().Println(getMessage("cannot iterate over store:", err))
|
||||||
log.Printf("cannot close store: %v", err)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !short && flagJSON {
|
if short { // short output requires identifier only
|
||||||
es := make(map[string]*state.State, len(entries))
|
var identifiers []*hst.ID
|
||||||
for id, instance := range entries {
|
f(func(eh *store.EntryHandle) {
|
||||||
es[id.String()] = instance
|
if _, err := eh.Load(nil); err != nil { // passes through decode error
|
||||||
|
msg.GetLogger().Println(getMessage("cannot validate state entry header:", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
identifiers = append(identifiers, &eh.ID)
|
||||||
|
})
|
||||||
|
slices.SortFunc(identifiers, func(a, b *hst.ID) int { return bytes.Compare(a[:], b[:]) })
|
||||||
|
|
||||||
|
if flagJSON {
|
||||||
|
encodeJSON(log.Fatal, output, short, identifiers)
|
||||||
|
} else {
|
||||||
|
for _, id := range identifiers {
|
||||||
|
mustPrintln(output, shortIdentifier(id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
encodeJSON(log.Fatal, output, short, es)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort state entries by id string to ensure consistency between runs
|
// long output requires full instance state
|
||||||
exp := make([]*expandedStateEntry, 0, len(entries))
|
var instances []*hst.State
|
||||||
for id, instance := range entries {
|
f(func(eh *store.EntryHandle) {
|
||||||
// gracefully skip nil states
|
var state hst.State
|
||||||
if instance == nil {
|
if _, err := eh.Load(&state); err != nil { // passes through decode error
|
||||||
log.Printf("got invalid state entry %s", id.String())
|
msg.GetLogger().Println(getMessage("cannot load state entry:", err))
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
instances = append(instances, &state)
|
||||||
|
})
|
||||||
|
slices.SortFunc(instances, func(a, b *hst.State) int { return bytes.Compare(a.ID[:], b.ID[:]) })
|
||||||
|
|
||||||
// gracefully skip inconsistent states
|
if flagJSON {
|
||||||
if id != instance.ID {
|
encodeJSON(log.Fatal, output, short, instances)
|
||||||
log.Printf("possible store corruption: entry %s has id %s",
|
|
||||||
id.String(), instance.ID.String())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
exp = append(exp, &expandedStateEntry{s: id.String(), State: instance})
|
|
||||||
}
|
|
||||||
slices.SortFunc(exp, func(a, b *expandedStateEntry) int { return a.Time.Compare(b.Time) })
|
|
||||||
|
|
||||||
if short {
|
|
||||||
if flagJSON {
|
|
||||||
v := make([]string, len(exp))
|
|
||||||
for i, e := range exp {
|
|
||||||
v[i] = e.s
|
|
||||||
}
|
|
||||||
encodeJSON(log.Fatal, output, short, v)
|
|
||||||
} else {
|
|
||||||
for _, e := range exp {
|
|
||||||
mustPrintln(output, e.s[:8])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,33 +227,21 @@ func printPs(output io.Writer, now time.Time, s state.Store, short, flagJSON boo
|
|||||||
defer t.MustFlush()
|
defer t.MustFlush()
|
||||||
|
|
||||||
t.Println("\tInstance\tPID\tApplication\tUptime")
|
t.Println("\tInstance\tPID\tApplication\tUptime")
|
||||||
for _, e := range exp {
|
for _, instance := range instances {
|
||||||
if len(e.s) != 1<<5 {
|
|
||||||
// unreachable
|
|
||||||
log.Printf("possible store corruption: invalid instance string %s", e.s)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
as := "(No configuration information)"
|
as := "(No configuration information)"
|
||||||
if e.Config != nil {
|
if instance.Config != nil {
|
||||||
as = strconv.Itoa(e.Config.Identity)
|
as = strconv.Itoa(instance.Config.Identity)
|
||||||
id := e.Config.ID
|
id := instance.Config.ID
|
||||||
if id == "" {
|
if id == "" {
|
||||||
id = "app.hakurei." + e.s[:8]
|
id = "app.hakurei." + shortIdentifier(&instance.ID)
|
||||||
}
|
}
|
||||||
as += " (" + id + ")"
|
as += " (" + id + ")"
|
||||||
}
|
}
|
||||||
t.Printf("\t%s\t%d\t%s\t%s\n",
|
t.Printf("\t%s\t%d\t%s\t%s\n",
|
||||||
e.s[:8], e.PID, as, now.Sub(e.Time).Round(time.Second).String())
|
shortIdentifier(&instance.ID), instance.PID, as, now.Sub(instance.Time).Round(time.Second).String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandedStateEntry stores [state.State] alongside a string representation of its [state.ID].
|
|
||||||
type expandedStateEntry struct {
|
|
||||||
s string
|
|
||||||
*state.State
|
|
||||||
}
|
|
||||||
|
|
||||||
// newPrinter returns a configured, wrapped [tabwriter.Writer].
|
// newPrinter returns a configured, wrapped [tabwriter.Writer].
|
||||||
func newPrinter(output io.Writer) *tp { return &tp{tabwriter.NewWriter(output, 0, 1, 4, ' ', 0)} }
|
func newPrinter(output io.Writer) *tp { return &tp{tabwriter.NewWriter(output, 0, 1, 4, ' ', 0)} }
|
||||||
|
|
||||||
@@ -289,3 +279,11 @@ func mustPrintln(output io.Writer, a ...any) {
|
|||||||
log.Fatalf("cannot print: %v", err)
|
log.Fatalf("cannot print: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getMessage returns a [message.Error] message if available, or err prefixed with fallback otherwise.
|
||||||
|
func getMessage(fallback string, err error) string {
|
||||||
|
if m, ok := message.GetMessage(err); ok {
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
return fmt.Sprintln(fallback, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,26 +1,48 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/internal/app/state"
|
"hakurei.app/internal/store"
|
||||||
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testID = state.ID{
|
testID = hst.ID{
|
||||||
0x8e, 0x2c, 0x76, 0xb0,
|
0x8e, 0x2c, 0x76, 0xb0,
|
||||||
0x66, 0xda, 0xbe, 0x57,
|
0x66, 0xda, 0xbe, 0x57,
|
||||||
0x4c, 0xf0, 0x73, 0xbd,
|
0x4c, 0xf0, 0x73, 0xbd,
|
||||||
0xb4, 0x6e, 0xb5, 0xc1,
|
0xb4, 0x6e, 0xb5, 0xc1,
|
||||||
}
|
}
|
||||||
testState = &state.State{
|
testState = hst.State{
|
||||||
ID: testID,
|
ID: testID,
|
||||||
PID: 0xDEADBEEF,
|
PID: 0xcafe,
|
||||||
Config: hst.Template(),
|
ShimPID: 0xdead,
|
||||||
Time: testAppTime,
|
Config: hst.Template(),
|
||||||
|
Time: testAppTime,
|
||||||
|
}
|
||||||
|
testStateSmall = hst.State{
|
||||||
|
ID: (hst.ID)(bytes.Repeat([]byte{0xaa}, len(hst.ID{}))),
|
||||||
|
PID: 0xbeef,
|
||||||
|
ShimPID: 0xcafe,
|
||||||
|
Config: &hst.Config{
|
||||||
|
Enablements: hst.NewEnablements(hst.EWayland | hst.EPulse),
|
||||||
|
Identity: 1,
|
||||||
|
Container: &hst.ContainerConfig{
|
||||||
|
Shell: check.MustAbs("/bin/sh"),
|
||||||
|
Home: check.MustAbs("/data/data/uk.gensokyo.cat"),
|
||||||
|
Path: check.MustAbs("/usr/bin/cat"),
|
||||||
|
Args: []string{"cat"},
|
||||||
|
Flags: hst.FUserns,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Time: time.Unix(0, 0xdeadbeef).UTC(),
|
||||||
}
|
}
|
||||||
testTime = time.Unix(3752, 1).UTC()
|
testTime = time.Unix(3752, 1).UTC()
|
||||||
testAppTime = time.Unix(0, 9).UTC()
|
testAppTime = time.Unix(0, 9).UTC()
|
||||||
@@ -31,12 +53,13 @@ func TestPrintShowInstance(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
instance *state.State
|
instance *hst.State
|
||||||
config *hst.Config
|
config *hst.Config
|
||||||
short, json bool
|
short, json bool
|
||||||
want string
|
want string
|
||||||
valid bool
|
valid bool
|
||||||
}{
|
}{
|
||||||
|
{"nil", nil, nil, false, false, "Error: invalid configuration!\n\n", false},
|
||||||
{"config", nil, hst.Template(), false, false, `App
|
{"config", nil, hst.Template(), false, false, `App
|
||||||
Identity: 9 (org.chromium.Chromium)
|
Identity: 9 (org.chromium.Chromium)
|
||||||
Enablements: wayland, dbus, pulseaudio
|
Enablements: wayland, dbus, pulseaudio
|
||||||
@@ -130,8 +153,8 @@ Session bus
|
|||||||
|
|
||||||
`, false},
|
`, false},
|
||||||
|
|
||||||
{"instance", testState, hst.Template(), false, false, `State
|
{"instance", &testState, hst.Template(), false, false, `State
|
||||||
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
|
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (51966 -> 57005)
|
||||||
Uptime: 1h2m32s
|
Uptime: 1h2m32s
|
||||||
|
|
||||||
App
|
App
|
||||||
@@ -170,10 +193,10 @@ System bus
|
|||||||
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
|
Talk: ["org.bluez" "org.freedesktop.Avahi" "org.freedesktop.UPower"]
|
||||||
|
|
||||||
`, true},
|
`, true},
|
||||||
{"instance pd", testState, new(hst.Config), false, false, `Error: configuration missing container state!
|
{"instance pd", &testState, new(hst.Config), false, false, `Error: configuration missing container state!
|
||||||
|
|
||||||
State
|
State
|
||||||
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (3735928559)
|
Instance: 8e2c76b066dabe574cf073bdb46eb5c1 (51966 -> 57005)
|
||||||
Uptime: 1h2m32s
|
Uptime: 1h2m32s
|
||||||
|
|
||||||
App
|
App
|
||||||
@@ -184,174 +207,156 @@ App
|
|||||||
|
|
||||||
{"json nil", nil, nil, false, true, `null
|
{"json nil", nil, nil, false, true, `null
|
||||||
`, true},
|
`, true},
|
||||||
{"json instance", testState, nil, false, true, `{
|
{"json instance", &testState, nil, false, true, `{
|
||||||
"instance": [
|
"instance": "8e2c76b066dabe574cf073bdb46eb5c1",
|
||||||
142,
|
"pid": 51966,
|
||||||
44,
|
"shim_pid": 57005,
|
||||||
118,
|
"id": "org.chromium.Chromium",
|
||||||
176,
|
"enablements": {
|
||||||
102,
|
"wayland": true,
|
||||||
218,
|
"dbus": true,
|
||||||
190,
|
"pulse": true
|
||||||
87,
|
},
|
||||||
76,
|
"session_bus": {
|
||||||
240,
|
"see": null,
|
||||||
115,
|
"talk": [
|
||||||
189,
|
"org.freedesktop.Notifications",
|
||||||
180,
|
"org.freedesktop.FileManager1",
|
||||||
110,
|
"org.freedesktop.ScreenSaver",
|
||||||
181,
|
"org.freedesktop.secrets",
|
||||||
193
|
"org.kde.kwalletd5",
|
||||||
|
"org.kde.kwalletd6",
|
||||||
|
"org.gnome.SessionManager"
|
||||||
|
],
|
||||||
|
"own": [
|
||||||
|
"org.chromium.Chromium.*",
|
||||||
|
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||||
|
"org.mpris.MediaPlayer2.chromium.*"
|
||||||
|
],
|
||||||
|
"call": {
|
||||||
|
"org.freedesktop.portal.*": "*"
|
||||||
|
},
|
||||||
|
"broadcast": {
|
||||||
|
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||||
|
},
|
||||||
|
"filter": true
|
||||||
|
},
|
||||||
|
"system_bus": {
|
||||||
|
"see": null,
|
||||||
|
"talk": [
|
||||||
|
"org.bluez",
|
||||||
|
"org.freedesktop.Avahi",
|
||||||
|
"org.freedesktop.UPower"
|
||||||
|
],
|
||||||
|
"own": null,
|
||||||
|
"call": null,
|
||||||
|
"broadcast": null,
|
||||||
|
"filter": true
|
||||||
|
},
|
||||||
|
"extra_perms": [
|
||||||
|
{
|
||||||
|
"ensure": true,
|
||||||
|
"path": "/var/lib/hakurei/u0",
|
||||||
|
"x": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
|
"r": true,
|
||||||
|
"w": true,
|
||||||
|
"x": true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"pid": 3735928559,
|
"identity": 9,
|
||||||
"config": {
|
"groups": [
|
||||||
"id": "org.chromium.Chromium",
|
"video",
|
||||||
"enablements": {
|
"dialout",
|
||||||
"wayland": true,
|
"plugdev"
|
||||||
"dbus": true,
|
],
|
||||||
"pulse": true
|
"container": {
|
||||||
|
"hostname": "localhost",
|
||||||
|
"wait_delay": -1,
|
||||||
|
"env": {
|
||||||
|
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||||
|
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
||||||
|
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
||||||
},
|
},
|
||||||
"session_bus": {
|
"filesystem": [
|
||||||
"see": null,
|
|
||||||
"talk": [
|
|
||||||
"org.freedesktop.Notifications",
|
|
||||||
"org.freedesktop.FileManager1",
|
|
||||||
"org.freedesktop.ScreenSaver",
|
|
||||||
"org.freedesktop.secrets",
|
|
||||||
"org.kde.kwalletd5",
|
|
||||||
"org.kde.kwalletd6",
|
|
||||||
"org.gnome.SessionManager"
|
|
||||||
],
|
|
||||||
"own": [
|
|
||||||
"org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.chromium.*"
|
|
||||||
],
|
|
||||||
"call": {
|
|
||||||
"org.freedesktop.portal.*": "*"
|
|
||||||
},
|
|
||||||
"broadcast": {
|
|
||||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
|
||||||
},
|
|
||||||
"filter": true
|
|
||||||
},
|
|
||||||
"system_bus": {
|
|
||||||
"see": null,
|
|
||||||
"talk": [
|
|
||||||
"org.bluez",
|
|
||||||
"org.freedesktop.Avahi",
|
|
||||||
"org.freedesktop.UPower"
|
|
||||||
],
|
|
||||||
"own": null,
|
|
||||||
"call": null,
|
|
||||||
"broadcast": null,
|
|
||||||
"filter": true
|
|
||||||
},
|
|
||||||
"extra_perms": [
|
|
||||||
{
|
{
|
||||||
"ensure": true,
|
"type": "bind",
|
||||||
"path": "/var/lib/hakurei/u0",
|
"dst": "/",
|
||||||
"x": true
|
"src": "/var/lib/hakurei/base/org.debian",
|
||||||
|
"write": true,
|
||||||
|
"special": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
"type": "bind",
|
||||||
"r": true,
|
"dst": "/etc/",
|
||||||
"w": true,
|
"src": "/etc/",
|
||||||
"x": true
|
"special": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ephemeral",
|
||||||
|
"dst": "/tmp/",
|
||||||
|
"write": true,
|
||||||
|
"perm": 493
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "overlay",
|
||||||
|
"dst": "/nix/store",
|
||||||
|
"lower": [
|
||||||
|
"/var/lib/hakurei/base/org.nixos/ro-store"
|
||||||
|
],
|
||||||
|
"upper": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper",
|
||||||
|
"work": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "link",
|
||||||
|
"dst": "/run/current-system",
|
||||||
|
"linkname": "/run/current-system",
|
||||||
|
"dereference": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "link",
|
||||||
|
"dst": "/run/opengl-driver",
|
||||||
|
"linkname": "/run/opengl-driver",
|
||||||
|
"dereference": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"dst": "/data/data/org.chromium.Chromium",
|
||||||
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
|
"write": true,
|
||||||
|
"ensure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"src": "/dev/dri",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"identity": 9,
|
"username": "chronos",
|
||||||
"groups": [
|
"shell": "/run/current-system/sw/bin/zsh",
|
||||||
"video",
|
"home": "/data/data/org.chromium.Chromium",
|
||||||
"dialout",
|
"path": "/run/current-system/sw/bin/chromium",
|
||||||
"plugdev"
|
"args": [
|
||||||
|
"chromium",
|
||||||
|
"--ignore-gpu-blocklist",
|
||||||
|
"--disable-smooth-scrolling",
|
||||||
|
"--enable-features=UseOzonePlatform",
|
||||||
|
"--ozone-platform=wayland"
|
||||||
],
|
],
|
||||||
"container": {
|
"seccomp_compat": true,
|
||||||
"hostname": "localhost",
|
"devel": true,
|
||||||
"wait_delay": -1,
|
"userns": true,
|
||||||
"env": {
|
"host_net": true,
|
||||||
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
"host_abstract": true,
|
||||||
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
"tty": true,
|
||||||
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
"multiarch": true,
|
||||||
},
|
"map_real_uid": true,
|
||||||
"filesystem": [
|
"device": true,
|
||||||
{
|
"share_runtime": true,
|
||||||
"type": "bind",
|
"share_tmpdir": true
|
||||||
"dst": "/",
|
|
||||||
"src": "/var/lib/hakurei/base/org.debian",
|
|
||||||
"write": true,
|
|
||||||
"special": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "bind",
|
|
||||||
"dst": "/etc/",
|
|
||||||
"src": "/etc/",
|
|
||||||
"special": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "ephemeral",
|
|
||||||
"dst": "/tmp/",
|
|
||||||
"write": true,
|
|
||||||
"perm": 493
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "overlay",
|
|
||||||
"dst": "/nix/store",
|
|
||||||
"lower": [
|
|
||||||
"/var/lib/hakurei/base/org.nixos/ro-store"
|
|
||||||
],
|
|
||||||
"upper": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper",
|
|
||||||
"work": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"dst": "/run/current-system",
|
|
||||||
"linkname": "/run/current-system",
|
|
||||||
"dereference": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"dst": "/run/opengl-driver",
|
|
||||||
"linkname": "/run/opengl-driver",
|
|
||||||
"dereference": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "bind",
|
|
||||||
"dst": "/data/data/org.chromium.Chromium",
|
|
||||||
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
|
||||||
"write": true,
|
|
||||||
"ensure": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "bind",
|
|
||||||
"src": "/dev/dri",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "chronos",
|
|
||||||
"shell": "/run/current-system/sw/bin/zsh",
|
|
||||||
"home": "/data/data/org.chromium.Chromium",
|
|
||||||
"path": "/run/current-system/sw/bin/chromium",
|
|
||||||
"args": [
|
|
||||||
"chromium",
|
|
||||||
"--ignore-gpu-blocklist",
|
|
||||||
"--disable-smooth-scrolling",
|
|
||||||
"--enable-features=UseOzonePlatform",
|
|
||||||
"--ozone-platform=wayland"
|
|
||||||
],
|
|
||||||
"seccomp_compat": true,
|
|
||||||
"devel": true,
|
|
||||||
"userns": true,
|
|
||||||
"host_net": true,
|
|
||||||
"host_abstract": true,
|
|
||||||
"tty": true,
|
|
||||||
"multiarch": true,
|
|
||||||
"map_real_uid": true,
|
|
||||||
"device": true,
|
|
||||||
"share_runtime": true,
|
|
||||||
"share_tmpdir": true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"time": "1970-01-01T00:00:00.000000009Z"
|
"time": "1970-01-01T00:00:00.000000009Z"
|
||||||
}
|
}
|
||||||
@@ -530,220 +535,243 @@ func TestPrintPs(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
entries state.Entries
|
data []hst.State
|
||||||
short, json bool
|
short, json bool
|
||||||
want string
|
want, log string
|
||||||
}{
|
}{
|
||||||
{"no entries", make(state.Entries), false, false, " Instance PID Application Uptime\n"},
|
{"no entries", []hst.State{}, false, false, " Instance PID Application Uptime\n", ""},
|
||||||
{"no entries short", make(state.Entries), true, false, ""},
|
{"no entries short", []hst.State{}, true, false, "", ""},
|
||||||
{"nil instance", state.Entries{testID: nil}, false, false, " Instance PID Application Uptime\n"},
|
|
||||||
{"state corruption", state.Entries{state.ID{}: testState}, false, false, " Instance PID Application Uptime\n"},
|
|
||||||
|
|
||||||
{"valid pd", state.Entries{testID: &state.State{ID: testID, PID: 1 << 8, Config: new(hst.Config), Time: testAppTime}}, false, false, ` Instance PID Application Uptime
|
{"invalid config", []hst.State{{ID: testID, PID: 1 << 8, Config: new(hst.Config), Time: testAppTime}}, false, false, " Instance PID Application Uptime\n", "check: configuration missing container state\n"},
|
||||||
8e2c76b0 256 0 (app.hakurei.8e2c76b0) 1h2m32s
|
|
||||||
`},
|
|
||||||
|
|
||||||
{"valid", state.Entries{testID: testState}, false, false, ` Instance PID Application Uptime
|
{"valid", []hst.State{testStateSmall, testState}, false, false, ` Instance PID Application Uptime
|
||||||
8e2c76b0 3735928559 9 (org.chromium.Chromium) 1h2m32s
|
4cf073bd 51966 9 (org.chromium.Chromium) 1h2m32s
|
||||||
`},
|
aaaaaaaa 48879 1 (app.hakurei.aaaaaaaa) 1h2m28s
|
||||||
{"valid short", state.Entries{testID: testState}, true, false, "8e2c76b0\n"},
|
`, ""},
|
||||||
{"valid json", state.Entries{testID: testState}, false, true, `{
|
{"valid single", []hst.State{testState}, false, false, ` Instance PID Application Uptime
|
||||||
"8e2c76b066dabe574cf073bdb46eb5c1": {
|
4cf073bd 51966 9 (org.chromium.Chromium) 1h2m32s
|
||||||
"instance": [
|
`, ""},
|
||||||
142,
|
|
||||||
44,
|
{"valid short", []hst.State{testStateSmall, testState}, true, false, "4cf073bd\naaaaaaaa\n", ""},
|
||||||
118,
|
{"valid short single", []hst.State{testState}, true, false, "4cf073bd\n", ""},
|
||||||
176,
|
|
||||||
102,
|
{"valid json", []hst.State{testState, testStateSmall}, false, true, `[
|
||||||
218,
|
{
|
||||||
190,
|
"instance": "8e2c76b066dabe574cf073bdb46eb5c1",
|
||||||
87,
|
"pid": 51966,
|
||||||
76,
|
"shim_pid": 57005,
|
||||||
240,
|
"id": "org.chromium.Chromium",
|
||||||
115,
|
"enablements": {
|
||||||
189,
|
"wayland": true,
|
||||||
180,
|
"dbus": true,
|
||||||
110,
|
"pulse": true
|
||||||
181,
|
},
|
||||||
193
|
"session_bus": {
|
||||||
|
"see": null,
|
||||||
|
"talk": [
|
||||||
|
"org.freedesktop.Notifications",
|
||||||
|
"org.freedesktop.FileManager1",
|
||||||
|
"org.freedesktop.ScreenSaver",
|
||||||
|
"org.freedesktop.secrets",
|
||||||
|
"org.kde.kwalletd5",
|
||||||
|
"org.kde.kwalletd6",
|
||||||
|
"org.gnome.SessionManager"
|
||||||
|
],
|
||||||
|
"own": [
|
||||||
|
"org.chromium.Chromium.*",
|
||||||
|
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
||||||
|
"org.mpris.MediaPlayer2.chromium.*"
|
||||||
|
],
|
||||||
|
"call": {
|
||||||
|
"org.freedesktop.portal.*": "*"
|
||||||
|
},
|
||||||
|
"broadcast": {
|
||||||
|
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
||||||
|
},
|
||||||
|
"filter": true
|
||||||
|
},
|
||||||
|
"system_bus": {
|
||||||
|
"see": null,
|
||||||
|
"talk": [
|
||||||
|
"org.bluez",
|
||||||
|
"org.freedesktop.Avahi",
|
||||||
|
"org.freedesktop.UPower"
|
||||||
|
],
|
||||||
|
"own": null,
|
||||||
|
"call": null,
|
||||||
|
"broadcast": null,
|
||||||
|
"filter": true
|
||||||
|
},
|
||||||
|
"extra_perms": [
|
||||||
|
{
|
||||||
|
"ensure": true,
|
||||||
|
"path": "/var/lib/hakurei/u0",
|
||||||
|
"x": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
|
"r": true,
|
||||||
|
"w": true,
|
||||||
|
"x": true
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"pid": 3735928559,
|
"identity": 9,
|
||||||
"config": {
|
"groups": [
|
||||||
"id": "org.chromium.Chromium",
|
"video",
|
||||||
"enablements": {
|
"dialout",
|
||||||
"wayland": true,
|
"plugdev"
|
||||||
"dbus": true,
|
],
|
||||||
"pulse": true
|
"container": {
|
||||||
|
"hostname": "localhost",
|
||||||
|
"wait_delay": -1,
|
||||||
|
"env": {
|
||||||
|
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
||||||
|
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
||||||
|
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
||||||
},
|
},
|
||||||
"session_bus": {
|
"filesystem": [
|
||||||
"see": null,
|
|
||||||
"talk": [
|
|
||||||
"org.freedesktop.Notifications",
|
|
||||||
"org.freedesktop.FileManager1",
|
|
||||||
"org.freedesktop.ScreenSaver",
|
|
||||||
"org.freedesktop.secrets",
|
|
||||||
"org.kde.kwalletd5",
|
|
||||||
"org.kde.kwalletd6",
|
|
||||||
"org.gnome.SessionManager"
|
|
||||||
],
|
|
||||||
"own": [
|
|
||||||
"org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.org.chromium.Chromium.*",
|
|
||||||
"org.mpris.MediaPlayer2.chromium.*"
|
|
||||||
],
|
|
||||||
"call": {
|
|
||||||
"org.freedesktop.portal.*": "*"
|
|
||||||
},
|
|
||||||
"broadcast": {
|
|
||||||
"org.freedesktop.portal.*": "@/org/freedesktop/portal/*"
|
|
||||||
},
|
|
||||||
"filter": true
|
|
||||||
},
|
|
||||||
"system_bus": {
|
|
||||||
"see": null,
|
|
||||||
"talk": [
|
|
||||||
"org.bluez",
|
|
||||||
"org.freedesktop.Avahi",
|
|
||||||
"org.freedesktop.UPower"
|
|
||||||
],
|
|
||||||
"own": null,
|
|
||||||
"call": null,
|
|
||||||
"broadcast": null,
|
|
||||||
"filter": true
|
|
||||||
},
|
|
||||||
"extra_perms": [
|
|
||||||
{
|
{
|
||||||
"ensure": true,
|
"type": "bind",
|
||||||
"path": "/var/lib/hakurei/u0",
|
"dst": "/",
|
||||||
"x": true
|
"src": "/var/lib/hakurei/base/org.debian",
|
||||||
|
"write": true,
|
||||||
|
"special": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
"type": "bind",
|
||||||
"r": true,
|
"dst": "/etc/",
|
||||||
"w": true,
|
"src": "/etc/",
|
||||||
"x": true
|
"special": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ephemeral",
|
||||||
|
"dst": "/tmp/",
|
||||||
|
"write": true,
|
||||||
|
"perm": 493
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "overlay",
|
||||||
|
"dst": "/nix/store",
|
||||||
|
"lower": [
|
||||||
|
"/var/lib/hakurei/base/org.nixos/ro-store"
|
||||||
|
],
|
||||||
|
"upper": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper",
|
||||||
|
"work": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "link",
|
||||||
|
"dst": "/run/current-system",
|
||||||
|
"linkname": "/run/current-system",
|
||||||
|
"dereference": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "link",
|
||||||
|
"dst": "/run/opengl-driver",
|
||||||
|
"linkname": "/run/opengl-driver",
|
||||||
|
"dereference": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"dst": "/data/data/org.chromium.Chromium",
|
||||||
|
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
||||||
|
"write": true,
|
||||||
|
"ensure": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "bind",
|
||||||
|
"src": "/dev/dri",
|
||||||
|
"dev": true,
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"identity": 9,
|
"username": "chronos",
|
||||||
"groups": [
|
"shell": "/run/current-system/sw/bin/zsh",
|
||||||
"video",
|
"home": "/data/data/org.chromium.Chromium",
|
||||||
"dialout",
|
"path": "/run/current-system/sw/bin/chromium",
|
||||||
"plugdev"
|
"args": [
|
||||||
|
"chromium",
|
||||||
|
"--ignore-gpu-blocklist",
|
||||||
|
"--disable-smooth-scrolling",
|
||||||
|
"--enable-features=UseOzonePlatform",
|
||||||
|
"--ozone-platform=wayland"
|
||||||
],
|
],
|
||||||
"container": {
|
"seccomp_compat": true,
|
||||||
"hostname": "localhost",
|
"devel": true,
|
||||||
"wait_delay": -1,
|
"userns": true,
|
||||||
"env": {
|
"host_net": true,
|
||||||
"GOOGLE_API_KEY": "AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
"host_abstract": true,
|
||||||
"GOOGLE_DEFAULT_CLIENT_ID": "77185425430.apps.googleusercontent.com",
|
"tty": true,
|
||||||
"GOOGLE_DEFAULT_CLIENT_SECRET": "OTJgUOQcT7lO7GsGZq2G4IlT"
|
"multiarch": true,
|
||||||
},
|
"map_real_uid": true,
|
||||||
"filesystem": [
|
"device": true,
|
||||||
{
|
"share_runtime": true,
|
||||||
"type": "bind",
|
"share_tmpdir": true
|
||||||
"dst": "/",
|
|
||||||
"src": "/var/lib/hakurei/base/org.debian",
|
|
||||||
"write": true,
|
|
||||||
"special": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "bind",
|
|
||||||
"dst": "/etc/",
|
|
||||||
"src": "/etc/",
|
|
||||||
"special": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "ephemeral",
|
|
||||||
"dst": "/tmp/",
|
|
||||||
"write": true,
|
|
||||||
"perm": 493
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "overlay",
|
|
||||||
"dst": "/nix/store",
|
|
||||||
"lower": [
|
|
||||||
"/var/lib/hakurei/base/org.nixos/ro-store"
|
|
||||||
],
|
|
||||||
"upper": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/upper",
|
|
||||||
"work": "/var/lib/hakurei/nix/u0/org.chromium.Chromium/rw-store/work"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"dst": "/run/current-system",
|
|
||||||
"linkname": "/run/current-system",
|
|
||||||
"dereference": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "link",
|
|
||||||
"dst": "/run/opengl-driver",
|
|
||||||
"linkname": "/run/opengl-driver",
|
|
||||||
"dereference": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "bind",
|
|
||||||
"dst": "/data/data/org.chromium.Chromium",
|
|
||||||
"src": "/var/lib/hakurei/u0/org.chromium.Chromium",
|
|
||||||
"write": true,
|
|
||||||
"ensure": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "bind",
|
|
||||||
"src": "/dev/dri",
|
|
||||||
"dev": true,
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"username": "chronos",
|
|
||||||
"shell": "/run/current-system/sw/bin/zsh",
|
|
||||||
"home": "/data/data/org.chromium.Chromium",
|
|
||||||
"path": "/run/current-system/sw/bin/chromium",
|
|
||||||
"args": [
|
|
||||||
"chromium",
|
|
||||||
"--ignore-gpu-blocklist",
|
|
||||||
"--disable-smooth-scrolling",
|
|
||||||
"--enable-features=UseOzonePlatform",
|
|
||||||
"--ozone-platform=wayland"
|
|
||||||
],
|
|
||||||
"seccomp_compat": true,
|
|
||||||
"devel": true,
|
|
||||||
"userns": true,
|
|
||||||
"host_net": true,
|
|
||||||
"host_abstract": true,
|
|
||||||
"tty": true,
|
|
||||||
"multiarch": true,
|
|
||||||
"map_real_uid": true,
|
|
||||||
"device": true,
|
|
||||||
"share_runtime": true,
|
|
||||||
"share_tmpdir": true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"time": "1970-01-01T00:00:00.000000009Z"
|
"time": "1970-01-01T00:00:00.000000009Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"instance": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
"pid": 48879,
|
||||||
|
"shim_pid": 51966,
|
||||||
|
"enablements": {
|
||||||
|
"wayland": true,
|
||||||
|
"pulse": true
|
||||||
|
},
|
||||||
|
"identity": 1,
|
||||||
|
"groups": null,
|
||||||
|
"container": {
|
||||||
|
"env": null,
|
||||||
|
"filesystem": null,
|
||||||
|
"shell": "/bin/sh",
|
||||||
|
"home": "/data/data/uk.gensokyo.cat",
|
||||||
|
"path": "/usr/bin/cat",
|
||||||
|
"args": [
|
||||||
|
"cat"
|
||||||
|
],
|
||||||
|
"userns": true,
|
||||||
|
"map_real_uid": false
|
||||||
|
},
|
||||||
|
"time": "1970-01-01T00:00:03.735928559Z"
|
||||||
}
|
}
|
||||||
}
|
]
|
||||||
`},
|
`, ""},
|
||||||
{"valid short json", state.Entries{testID: testState}, true, true, `["8e2c76b066dabe574cf073bdb46eb5c1"]
|
{"valid short json", []hst.State{testStateSmall, testState}, true, true, `["8e2c76b066dabe574cf073bdb46eb5c1","aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"]
|
||||||
`},
|
`, ""},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
s := store.New(check.MustAbs(t.TempDir()).Append("store"))
|
||||||
|
for i := range tc.data {
|
||||||
|
if h, err := s.Handle(tc.data[i].Identity); err != nil {
|
||||||
|
t.Fatalf("Handle: error = %v", err)
|
||||||
|
} else {
|
||||||
|
var unlock func()
|
||||||
|
if unlock, err = h.Lock(); err != nil {
|
||||||
|
t.Fatalf("Lock: error = %v", err)
|
||||||
|
}
|
||||||
|
_, err = h.Save(&tc.data[i])
|
||||||
|
unlock()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Save: error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// store must not be written to beyond this point
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
output := new(strings.Builder)
|
var printBuf, logBuf bytes.Buffer
|
||||||
printPs(output, testTime, stubStore(tc.entries), tc.short, tc.json)
|
msg := message.New(log.New(&logBuf, "check: ", 0))
|
||||||
if got := output.String(); got != tc.want {
|
msg.SwapVerbose(true)
|
||||||
t.Errorf("printPs: got\n%s\nwant\n%s",
|
printPs(msg, &printBuf, testTime, s, tc.short, tc.json)
|
||||||
got, tc.want)
|
if got := printBuf.String(); got != tc.want {
|
||||||
|
t.Errorf("printPs:\n%s\nwant\n%s", got, tc.want)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if got := logBuf.String(); got != tc.log {
|
||||||
|
t.Errorf("msg:\n%s\nwant\n%s", got, tc.log)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// stubStore implements [state.Store] and returns test samples via [state.Joiner].
|
|
||||||
type stubStore state.Entries
|
|
||||||
|
|
||||||
func (s stubStore) Join() (state.Entries, error) { return state.Entries(s), nil }
|
|
||||||
func (s stubStore) Do(int, func(c state.Cursor)) (bool, error) { panic("unreachable") }
|
|
||||||
func (s stubStore) List() ([]int, error) { panic("unreachable") }
|
|
||||||
func (s stubStore) Close() error { return nil }
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ var (
|
|||||||
func main() {
|
func main() {
|
||||||
log.SetPrefix("hpkg: ")
|
log.SetPrefix("hpkg: ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
msg := message.NewMsg(log.Default())
|
msg := message.New(log.Default())
|
||||||
|
|
||||||
if err := os.Setenv("SHELL", pathShell.String()); err != nil {
|
if err := os.Setenv("SHELL", pathShell.String()); err != nil {
|
||||||
log.Fatalf("cannot set $SHELL: %v", err)
|
log.Fatalf("cannot set $SHELL: %v", err)
|
||||||
|
|||||||
@@ -58,15 +58,13 @@ def check_state(name, enablements):
|
|||||||
instances = json.loads(machine.succeed("sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 hakurei --json ps"))
|
instances = json.loads(machine.succeed("sudo -u alice -i XDG_RUNTIME_DIR=/run/user/1000 hakurei --json ps"))
|
||||||
if len(instances) != 1:
|
if len(instances) != 1:
|
||||||
raise Exception(f"unexpected state length {len(instances)}")
|
raise Exception(f"unexpected state length {len(instances)}")
|
||||||
instance = next(iter(instances.values()))
|
instance = instances[0]
|
||||||
|
|
||||||
config = instance['config']
|
if len(instance['container']['args']) != 1 or not (instance['container']['args'][0].startswith("/nix/store/")) or f"hakurei-{name}-" not in (instance['container']['args'][0]):
|
||||||
|
raise Exception(f"unexpected args {instance['container']['args']}")
|
||||||
|
|
||||||
if len(config['container']['args']) != 1 or not (config['container']['args'][0].startswith("/nix/store/")) or f"hakurei-{name}-" not in (config['container']['args'][0]):
|
if instance['enablements'] != enablements:
|
||||||
raise Exception(f"unexpected args {config['container']['args']}")
|
raise Exception(f"unexpected enablements {instance['enablements']}")
|
||||||
|
|
||||||
if config['enablements'] != enablements:
|
|
||||||
raise Exception(f"unexpected enablements {config['enablements']}")
|
|
||||||
|
|
||||||
|
|
||||||
start_all()
|
start_all()
|
||||||
@@ -94,15 +92,19 @@ machine.wait_for_file("/tmp/hakurei.0/tmpdir/2/success-client")
|
|||||||
collect_state_ui("app_wayland")
|
collect_state_ui("app_wayland")
|
||||||
check_state("foot", {"wayland": True, "dbus": True, "pulse": True})
|
check_state("foot", {"wayland": True, "dbus": True, "pulse": True})
|
||||||
# Verify acl on XDG_RUNTIME_DIR:
|
# Verify acl on XDG_RUNTIME_DIR:
|
||||||
print(machine.succeed("getfacl --absolute-names --omit-header --numeric /run/user/1000 | grep 1000002"))
|
print(machine.succeed("getfacl --absolute-names --omit-header --numeric /run/user/1000 | grep 10002"))
|
||||||
machine.send_chars("exit\n")
|
machine.send_chars("exit\n")
|
||||||
machine.wait_until_fails("pgrep foot")
|
machine.wait_until_fails("pgrep foot")
|
||||||
# Verify acl cleanup on XDG_RUNTIME_DIR:
|
# Verify acl cleanup on XDG_RUNTIME_DIR:
|
||||||
machine.wait_until_fails("getfacl --absolute-names --omit-header --numeric /run/user/1000 | grep 1000002")
|
machine.wait_until_fails("getfacl --absolute-names --omit-header --numeric /run/user/1000 | grep 10002")
|
||||||
|
|
||||||
# Exit Sway and verify process exit status 0:
|
# Exit Sway and verify process exit status 0:
|
||||||
swaymsg("exit", succeed=False)
|
swaymsg("exit", succeed=False)
|
||||||
machine.wait_for_file("/tmp/sway-exit-ok")
|
machine.wait_for_file("/tmp/sway-exit-ok")
|
||||||
|
|
||||||
# Print hakurei runDir contents:
|
# Print hakurei share and rundir contents:
|
||||||
|
print(machine.succeed("find /tmp/hakurei.0 "
|
||||||
|
+ "-path '/tmp/hakurei.0/runtime/*/*' -prune -o "
|
||||||
|
+ "-path '/tmp/hakurei.0/tmpdir/*/*' -prune -o "
|
||||||
|
+ "-print"))
|
||||||
print(machine.succeed("find /run/user/1000/hakurei"))
|
print(machine.succeed("find /run/user/1000/hakurei"))
|
||||||
16
cmd/hsu/hst.go
Normal file
16
cmd/hsu/hst.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
/* copied from hst and must never be changed */
|
||||||
|
|
||||||
|
const (
|
||||||
|
userOffset = 100000
|
||||||
|
rangeSize = userOffset / 10
|
||||||
|
|
||||||
|
identityStart = 0
|
||||||
|
identityEnd = appEnd - appStart
|
||||||
|
|
||||||
|
appStart = rangeSize * 1
|
||||||
|
appEnd = appStart + rangeSize - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func toUser(userid, appid uint32) uint32 { return userid*userOffset + appStart + appid }
|
||||||
@@ -16,15 +16,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
hsuConfFile = "/etc/hsurc"
|
// envIdentity is the name of the environment variable holding a
|
||||||
envShim = "HAKUREI_SHIM"
|
// single byte representing the shim setup pipe file descriptor.
|
||||||
envIdentity = "HAKUREI_IDENTITY"
|
envShim = "HAKUREI_SHIM"
|
||||||
envGroups = "HAKUREI_GROUPS"
|
// envGroups holds a ' ' separated list of string representations of
|
||||||
|
// supplementary group gid. Membership requirements are enforced.
|
||||||
PR_SET_NO_NEW_PRIVS = 0x26
|
envGroups = "HAKUREI_GROUPS"
|
||||||
|
|
||||||
identityMin = 0
|
|
||||||
identityMax = 9999
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// hakureiPath is the absolute path to Hakurei.
|
// hakureiPath is the absolute path to Hakurei.
|
||||||
@@ -33,6 +30,7 @@ const (
|
|||||||
var hakureiPath string
|
var hakureiPath string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
const PR_SET_NO_NEW_PRIVS = 0x26
|
||||||
runtime.LockOSThread()
|
runtime.LockOSThread()
|
||||||
|
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
@@ -68,13 +66,8 @@ func main() {
|
|||||||
toolPath = p
|
toolPath = p
|
||||||
}
|
}
|
||||||
|
|
||||||
// uid = 1000000 +
|
|
||||||
// id * 10000 +
|
|
||||||
// identity
|
|
||||||
uid := 1000000
|
|
||||||
|
|
||||||
// refuse to run if hsurc is not protected correctly
|
// refuse to run if hsurc is not protected correctly
|
||||||
if s, err := os.Stat(hsuConfFile); err != nil {
|
if s, err := os.Stat(hsuConfPath); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
} else if s.Mode().Perm() != 0400 {
|
} else if s.Mode().Perm() != 0400 {
|
||||||
log.Fatal("bad hsurc perm")
|
log.Fatal("bad hsurc perm")
|
||||||
@@ -83,25 +76,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// authenticate before accepting user input
|
// authenticate before accepting user input
|
||||||
var id int
|
userid := mustParseConfig(puid)
|
||||||
if f, err := os.Open(hsuConfFile); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
} else if v, ok := mustParseConfig(f, puid); !ok {
|
|
||||||
log.Fatalf("uid %d is not in the hsurc file", puid)
|
|
||||||
} else {
|
|
||||||
id = v
|
|
||||||
if err = f.Close(); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
uid += id * 10000
|
|
||||||
}
|
|
||||||
|
|
||||||
// pass through setup fd to shim
|
// pass through setup fd to shim
|
||||||
var shimSetupFd string
|
var shimSetupFd string
|
||||||
if s, ok := os.LookupEnv(envShim); !ok {
|
if s, ok := os.LookupEnv(envShim); !ok {
|
||||||
// hakurei requests hsurc user id
|
// hakurei requests hsurc user id
|
||||||
fmt.Print(id)
|
fmt.Print(userid)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
|
} else if len(s) != 1 || s[0] > '9' || s[0] < '3' {
|
||||||
log.Fatal("HAKUREI_SHIM holds an invalid value")
|
log.Fatal("HAKUREI_SHIM holds an invalid value")
|
||||||
@@ -109,13 +90,22 @@ func main() {
|
|||||||
shimSetupFd = s
|
shimSetupFd = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// allowed identity range 0 to 9999
|
// start is going ahead at this point
|
||||||
if as, ok := os.LookupEnv(envIdentity); !ok {
|
identity := mustReadIdentity()
|
||||||
log.Fatal("HAKUREI_IDENTITY not set")
|
|
||||||
} else if identity, err := parseUint32Fast(as); err != nil || identity < identityMin || identity > identityMax {
|
const (
|
||||||
log.Fatal("invalid identity")
|
// first possible uid outcome
|
||||||
} else {
|
uidStart = 10000
|
||||||
uid += identity
|
// last possible uid outcome
|
||||||
|
uidEnd = 999919999
|
||||||
|
)
|
||||||
|
|
||||||
|
// cast to int for use with library functions
|
||||||
|
uid := int(toUser(userid, identity))
|
||||||
|
|
||||||
|
// final bounds check to catch any bugs
|
||||||
|
if uid < uidStart || uid >= uidEnd {
|
||||||
|
panic("uid out of bounds")
|
||||||
}
|
}
|
||||||
|
|
||||||
// supplementary groups
|
// supplementary groups
|
||||||
@@ -145,11 +135,6 @@ func main() {
|
|||||||
suppGroups = []int{uid}
|
suppGroups = []int{uid}
|
||||||
}
|
}
|
||||||
|
|
||||||
// final bounds check to catch any bugs
|
|
||||||
if uid < 1000000 || uid >= 2000000 {
|
|
||||||
panic("uid out of bounds")
|
|
||||||
}
|
|
||||||
|
|
||||||
// careful! users in the allowlist is effectively allowed to drop groups via hsu
|
// careful! users in the allowlist is effectively allowed to drop groups via hsu
|
||||||
|
|
||||||
if err := syscall.Setresgid(uid, uid, uid); err != nil {
|
if err := syscall.Setresgid(uid, uid, uid); err != nil {
|
||||||
|
|||||||
104
cmd/hsu/parse.go
104
cmd/hsu/parse.go
@@ -6,62 +6,128 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseUint32Fast(s string) (int, error) {
|
const (
|
||||||
|
// useridStart is the first userid.
|
||||||
|
useridStart = 0
|
||||||
|
// useridEnd is the last userid.
|
||||||
|
useridEnd = useridStart + rangeSize - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// parseUint32Fast parses a string representation of an unsigned 32-bit integer value
|
||||||
|
// using the fast path only. This limits the range of values it is defined in.
|
||||||
|
func parseUint32Fast(s string) (uint32, error) {
|
||||||
sLen := len(s)
|
sLen := len(s)
|
||||||
if sLen < 1 {
|
if sLen < 1 {
|
||||||
return -1, errors.New("zero length string")
|
return 0, errors.New("zero length string")
|
||||||
}
|
}
|
||||||
if sLen > 10 {
|
if sLen > 10 {
|
||||||
return -1, errors.New("string too long")
|
return 0, errors.New("string too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
n := 0
|
var n uint32
|
||||||
for i, ch := range []byte(s) {
|
for i, ch := range []byte(s) {
|
||||||
ch -= '0'
|
ch -= '0'
|
||||||
if ch > 9 {
|
if ch > 9 {
|
||||||
return -1, fmt.Errorf("invalid character '%s' at index %d", string(ch+'0'), i)
|
return 0, fmt.Errorf("invalid character '%s' at index %d", string(ch+'0'), i)
|
||||||
}
|
}
|
||||||
n = n*10 + int(ch)
|
n = n*10 + uint32(ch)
|
||||||
}
|
}
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseConfig(r io.Reader, puid int) (fid int, ok bool, err error) {
|
// parseConfig reads a list of allowed users from r until it encounters puid or [io.EOF].
|
||||||
|
//
|
||||||
|
// Each line of the file specifies a hakurei userid to kernel uid mapping. A line consists
|
||||||
|
// of the string representation of the uid of the user wishing to start hakurei containers,
|
||||||
|
// followed by a space, followed by the string representation of its userid. Duplicate uid
|
||||||
|
// entries are ignored, with the first occurrence taking effect.
|
||||||
|
//
|
||||||
|
// All string representations are parsed by calling parseUint32Fast.
|
||||||
|
func parseConfig(r io.Reader, puid uint32) (userid uint32, ok bool, err error) {
|
||||||
s := bufio.NewScanner(r)
|
s := bufio.NewScanner(r)
|
||||||
var line, puid0 int
|
var (
|
||||||
|
line uintptr
|
||||||
|
puid0 uint32
|
||||||
|
)
|
||||||
for s.Scan() {
|
for s.Scan() {
|
||||||
line++
|
line++
|
||||||
|
|
||||||
// <puid> <fid>
|
// <puid> <userid>
|
||||||
lf := strings.SplitN(s.Text(), " ", 2)
|
lf := strings.SplitN(s.Text(), " ", 2)
|
||||||
if len(lf) != 2 {
|
if len(lf) != 2 {
|
||||||
return -1, false, fmt.Errorf("invalid entry on line %d", line)
|
return useridEnd + 1, false, fmt.Errorf("invalid entry on line %d", line)
|
||||||
}
|
}
|
||||||
|
|
||||||
puid0, err = parseUint32Fast(lf[0])
|
puid0, err = parseUint32Fast(lf[0])
|
||||||
if err != nil || puid0 < 1 {
|
if err != nil || puid0 < 1 {
|
||||||
return -1, false, fmt.Errorf("invalid parent uid on line %d", line)
|
return useridEnd + 1, false, fmt.Errorf("invalid parent uid on line %d", line)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = puid0 == puid
|
ok = puid0 == puid
|
||||||
if ok {
|
if ok {
|
||||||
// allowed fid range 0 to 99
|
// userid bound to a range, uint32 size allows this to be increased if needed
|
||||||
if fid, err = parseUint32Fast(lf[1]); err != nil || fid < 0 || fid > 99 {
|
if userid, err = parseUint32Fast(lf[1]); err != nil ||
|
||||||
return -1, false, fmt.Errorf("invalid identity on line %d", line)
|
userid < useridStart || userid > useridEnd {
|
||||||
|
return useridEnd + 1, false, fmt.Errorf("invalid userid on line %d", line)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1, false, s.Err()
|
return useridEnd + 1, false, s.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustParseConfig(r io.Reader, puid int) (int, bool) {
|
// hsuConfPath is an absolute pathname to the hsu configuration file.
|
||||||
fid, ok, err := parseConfig(r, puid)
|
// Its contents are interpreted by parseConfig.
|
||||||
if err != nil {
|
const hsuConfPath = "/etc/hsurc"
|
||||||
|
|
||||||
|
// mustParseConfig calls parseConfig to interpret the contents of hsuConfPath,
|
||||||
|
// terminating the program if an error is encountered, the syntax is incorrect,
|
||||||
|
// or the current user is not authorised to use hsu because its uid is missing.
|
||||||
|
//
|
||||||
|
// Therefore, code after this function call can assume an authenticated state.
|
||||||
|
//
|
||||||
|
// mustParseConfig returns the userid value of the current user.
|
||||||
|
func mustParseConfig(puid int) (userid uint32) {
|
||||||
|
if puid > math.MaxUint32 {
|
||||||
|
log.Fatalf("got impossible uid %d", puid)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
if f, err := os.Open(hsuConfPath); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else if userid, ok, err = parseConfig(f, uint32(puid)); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
} else if err = f.Close(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
return fid, ok
|
if !ok {
|
||||||
|
log.Fatalf("uid %d is not in the hsurc file", puid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// envIdentity is the name of the environment variable holding a
|
||||||
|
// string representation of the current application identity.
|
||||||
|
var envIdentity = "HAKUREI_IDENTITY"
|
||||||
|
|
||||||
|
// mustReadIdentity calls parseUint32Fast to interpret the value stored in envIdentity,
|
||||||
|
// terminating the program if the value is not set, malformed, or out of bounds.
|
||||||
|
func mustReadIdentity() uint32 {
|
||||||
|
// ranges defined in hst and copied to this package to avoid importing hst
|
||||||
|
if as, ok := os.LookupEnv(envIdentity); !ok {
|
||||||
|
log.Fatal("HAKUREI_IDENTITY not set")
|
||||||
|
panic("unreachable")
|
||||||
|
} else if identity, err := parseUint32Fast(as); err != nil ||
|
||||||
|
identity < identityStart || identity > identityEnd {
|
||||||
|
log.Fatal("invalid identity")
|
||||||
|
panic("unreachable")
|
||||||
|
} else {
|
||||||
|
return identity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
@@ -39,22 +40,20 @@ func TestParseUint32Fast(t *testing.T) {
|
|||||||
t.Run("range", func(t *testing.T) {
|
t.Run("range", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
testRange := func(i, end int) {
|
testRange := func(i, end uint32) {
|
||||||
for ; i < end; i++ {
|
for ; i < end; i++ {
|
||||||
s := strconv.Itoa(i)
|
s := strconv.Itoa(int(i))
|
||||||
w := i
|
w := i
|
||||||
t.Run("parse "+s, func(t *testing.T) {
|
t.Run("parse "+s, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
v, err := parseUint32Fast(s)
|
v, err := parseUint32Fast(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("parseUint32Fast(%q): error = %v",
|
t.Errorf("parseUint32Fast(%q): error = %v", s, err)
|
||||||
s, err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if v != w {
|
if v != w {
|
||||||
t.Errorf("parseUint32Fast(%q): got %v",
|
t.Errorf("parseUint32Fast(%q): got %v", s, v)
|
||||||
s, v)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -63,7 +62,7 @@ func TestParseUint32Fast(t *testing.T) {
|
|||||||
|
|
||||||
testRange(0, 2500)
|
testRange(0, 2500)
|
||||||
testRange(23002500, 23005000)
|
testRange(23002500, 23005000)
|
||||||
testRange(7890002500, 7890005000)
|
testRange(math.MaxUint32-2500, math.MaxUint32)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,14 +71,14 @@ func TestParseConfig(t *testing.T) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
puid, want int
|
puid, want uint32
|
||||||
wantErr string
|
wantErr string
|
||||||
rc string
|
rc string
|
||||||
}{
|
}{
|
||||||
{"empty", 0, -1, "", ``},
|
{"empty", 0, useridEnd + 1, "", ``},
|
||||||
{"invalid field", 0, -1, "invalid entry on line 1", `9`},
|
{"invalid field", 0, useridEnd + 1, "invalid entry on line 1", `9`},
|
||||||
{"invalid puid", 0, -1, "invalid parent uid on line 1", `f 9`},
|
{"invalid puid", 0, useridEnd + 1, "invalid parent uid on line 1", `f 9`},
|
||||||
{"invalid fid", 1000, -1, "invalid identity on line 1", `1000 f`},
|
{"invalid userid", 1000, useridEnd + 1, "invalid userid on line 1", `1000 f`},
|
||||||
{"match", 1000, 0, "", `1000 0`},
|
{"match", 1000, 0, "", `1000 0`},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,25 +86,21 @@ func TestParseConfig(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
fid, ok, err := parseConfig(bytes.NewBufferString(tc.rc), tc.puid)
|
userid, ok, err := parseConfig(bytes.NewBufferString(tc.rc), tc.puid)
|
||||||
if err == nil && tc.wantErr != "" {
|
if err == nil && tc.wantErr != "" {
|
||||||
t.Errorf("parseConfig: error = %v; wantErr %q",
|
t.Errorf("parseConfig: error = %v; want %q", err, tc.wantErr)
|
||||||
err, tc.wantErr)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err != nil && err.Error() != tc.wantErr {
|
if err != nil && err.Error() != tc.wantErr {
|
||||||
t.Errorf("parseConfig: error = %q; wantErr %q",
|
t.Errorf("parseConfig: error = %q; want %q", err, tc.wantErr)
|
||||||
err, tc.wantErr)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ok == (tc.want == -1) {
|
if ok == (tc.want == useridEnd+1) {
|
||||||
t.Errorf("parseConfig: ok = %v; want %v",
|
t.Errorf("parseConfig: ok = %v; want %v", ok, tc.want)
|
||||||
ok, tc.want)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if fid != tc.want {
|
if userid != tc.want {
|
||||||
t.Errorf("parseConfig: fid = %v; want %v",
|
t.Errorf("parseConfig: %v; want %v", userid, tc.want)
|
||||||
fid, tc.want)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/comp"
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
@@ -23,14 +23,14 @@ func TestAutoRootOp(t *testing.T) {
|
|||||||
checkOpBehaviour(t, []opBehaviourTestCase{
|
checkOpBehaviour(t, []opBehaviourTestCase{
|
||||||
{"readdir", &Params{ParentPerm: 0750}, &AutoRootOp{
|
{"readdir", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("readdir", stub.ExpectArgs{"/"}, stubDir(), stub.UniqueError(2)),
|
call("readdir", stub.ExpectArgs{"/"}, stubDir(), stub.UniqueError(2)),
|
||||||
}, stub.UniqueError(2), nil, nil},
|
}, stub.UniqueError(2), nil, nil},
|
||||||
|
|
||||||
{"early", &Params{ParentPerm: 0750}, &AutoRootOp{
|
{"early", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
||||||
@@ -39,7 +39,7 @@ func TestAutoRootOp(t *testing.T) {
|
|||||||
|
|
||||||
{"apply", &Params{ParentPerm: 0750}, &AutoRootOp{
|
{"apply", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
||||||
@@ -60,7 +60,7 @@ func TestAutoRootOp(t *testing.T) {
|
|||||||
|
|
||||||
{"success pd", &Params{ParentPerm: 0750}, &AutoRootOp{
|
{"success pd", &Params{ParentPerm: 0750}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
call("readdir", stub.ExpectArgs{"/"}, stubDir("bin", "dev", "etc", "home", "lib64",
|
||||||
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
"lost+found", "mnt", "nix", "proc", "root", "run", "srv", "sys", "tmp", "usr", "var"), nil),
|
||||||
@@ -127,10 +127,10 @@ func TestAutoRootOp(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
checkOpsBuilder(t, []opsBuilderTestCase{
|
checkOpsBuilder(t, []opsBuilderTestCase{
|
||||||
{"pd", new(Ops).Root(check.MustAbs("/"), comp.BindWritable), Ops{
|
{"pd", new(Ops).Root(check.MustAbs("/"), std.BindWritable), Ops{
|
||||||
&AutoRootOp{
|
&AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
})
|
})
|
||||||
@@ -140,42 +140,42 @@ func TestAutoRootOp(t *testing.T) {
|
|||||||
|
|
||||||
{"internal ne", &AutoRootOp{
|
{"internal ne", &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, &AutoRootOp{
|
}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
resolved: []*BindMountOp{new(BindMountOp)},
|
resolved: []*BindMountOp{new(BindMountOp)},
|
||||||
}, true},
|
}, true},
|
||||||
|
|
||||||
{"flags differs", &AutoRootOp{
|
{"flags differs", &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice,
|
Flags: std.BindWritable | std.BindDevice,
|
||||||
}, &AutoRootOp{
|
}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, false},
|
}, false},
|
||||||
|
|
||||||
{"host differs", &AutoRootOp{
|
{"host differs", &AutoRootOp{
|
||||||
Host: check.MustAbs("/tmp/"),
|
Host: check.MustAbs("/tmp/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, &AutoRootOp{
|
}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, false},
|
}, false},
|
||||||
|
|
||||||
{"equals", &AutoRootOp{
|
{"equals", &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, &AutoRootOp{
|
}, &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, true},
|
}, true},
|
||||||
})
|
})
|
||||||
|
|
||||||
checkOpMeta(t, []opMetaTestCase{
|
checkOpMeta(t, []opMetaTestCase{
|
||||||
{"root", &AutoRootOp{
|
{"root", &AutoRootOp{
|
||||||
Host: check.MustAbs("/"),
|
Host: check.MustAbs("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}, "setting up", `auto root "/" flags 0x2`},
|
}, "setting up", `auto root "/" flags 0x2`},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
_ "unsafe"
|
_ "unsafe" // for go:linkname
|
||||||
|
|
||||||
. "hakurei.app/container/check"
|
. "hakurei.app/container/check"
|
||||||
)
|
)
|
||||||
@@ -147,7 +147,7 @@ func TestAbsoluteIs(t *testing.T) {
|
|||||||
|
|
||||||
type sCheck struct {
|
type sCheck struct {
|
||||||
Pathname *Absolute `json:"val"`
|
Pathname *Absolute `json:"val"`
|
||||||
Magic int `json:"magic"`
|
Magic uint64 `json:"magic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCodecAbsolute(t *testing.T) {
|
func TestCodecAbsolute(t *testing.T) {
|
||||||
@@ -169,19 +169,19 @@ func TestCodecAbsolute(t *testing.T) {
|
|||||||
{"good", MustAbs("/etc"),
|
{"good", MustAbs("/etc"),
|
||||||
nil,
|
nil,
|
||||||
"\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\b\xff\x80\x00\x04/etc",
|
"\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\b\xff\x80\x00\x04/etc",
|
||||||
",\xff\x83\x03\x01\x01\x06sCheck\x01\xff\x84\x00\x01\x02\x01\bPathname\x01\xff\x80\x00\x01\x05Magic\x01\x04\x00\x00\x00\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\x10\xff\x84\x01\x04/etc\x01\xfb\x01\x81\xda\x00\x00\x00",
|
",\xff\x83\x03\x01\x01\x06sCheck\x01\xff\x84\x00\x01\x02\x01\bPathname\x01\xff\x80\x00\x01\x05Magic\x01\x06\x00\x00\x00\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\x0f\xff\x84\x01\x04/etc\x01\xfc\xc0\xed\x00\x00\x00",
|
||||||
|
|
||||||
`"/etc"`, `{"val":"/etc","magic":3236757504}`},
|
`"/etc"`, `{"val":"/etc","magic":3236757504}`},
|
||||||
{"not absolute", nil,
|
{"not absolute", nil,
|
||||||
&AbsoluteError{Pathname: "etc"},
|
&AbsoluteError{Pathname: "etc"},
|
||||||
"\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\a\xff\x80\x00\x03etc",
|
"\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\a\xff\x80\x00\x03etc",
|
||||||
",\xff\x83\x03\x01\x01\x06sCheck\x01\xff\x84\x00\x01\x02\x01\bPathname\x01\xff\x80\x00\x01\x05Magic\x01\x04\x00\x00\x00\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\x0f\xff\x84\x01\x03etc\x01\xfb\x01\x81\xda\x00\x00\x00",
|
",\xff\x83\x03\x01\x01\x06sCheck\x01\xff\x84\x00\x01\x02\x01\bPathname\x01\xff\x80\x00\x01\x05Magic\x01\x06\x00\x00\x00\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\x0f\xff\x84\x01\x03etc\x01\xfb\x01\x81\xda\x00\x00\x00",
|
||||||
|
|
||||||
`"etc"`, `{"val":"etc","magic":3236757504}`},
|
`"etc"`, `{"val":"etc","magic":3236757504}`},
|
||||||
{"zero", nil,
|
{"zero", nil,
|
||||||
new(AbsoluteError),
|
new(AbsoluteError),
|
||||||
"\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\x04\xff\x80\x00\x00",
|
"\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\x04\xff\x80\x00\x00",
|
||||||
",\xff\x83\x03\x01\x01\x06sCheck\x01\xff\x84\x00\x01\x02\x01\bPathname\x01\xff\x80\x00\x01\x05Magic\x01\x04\x00\x00\x00\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\f\xff\x84\x01\x00\x01\xfb\x01\x81\xda\x00\x00\x00",
|
",\xff\x83\x03\x01\x01\x06sCheck\x01\xff\x84\x00\x01\x02\x01\bPathname\x01\xff\x80\x00\x01\x05Magic\x01\x06\x00\x00\x00\t\x7f\x05\x01\x02\xff\x82\x00\x00\x00\f\xff\x84\x01\x00\x01\xfb\x01\x81\xda\x00\x00\x00",
|
||||||
`""`, `{"val":"","magic":3236757504}`},
|
`""`, `{"val":"","magic":3236757504}`},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,20 +11,24 @@ import (
|
|||||||
"os/exec"
|
"os/exec"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
. "syscall"
|
. "syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/comp"
|
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// CancelSignal is the signal expected by container init on context cancel.
|
// CancelSignal is the signal expected by container init on context cancel.
|
||||||
// A custom [Container.Cancel] function must eventually deliver this signal.
|
// A custom [Container.Cancel] function must eventually deliver this signal.
|
||||||
CancelSignal = SIGTERM
|
CancelSignal = SIGUSR2
|
||||||
|
|
||||||
|
// Timeout for writing initParams to Container.setup.
|
||||||
|
initSetupTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -37,8 +41,8 @@ type (
|
|||||||
// with behaviour identical to its [exec.Cmd] counterpart.
|
// with behaviour identical to its [exec.Cmd] counterpart.
|
||||||
ExtraFiles []*os.File
|
ExtraFiles []*os.File
|
||||||
|
|
||||||
// param encoder for shim and init
|
// param pipe for shim and init
|
||||||
setup *gob.Encoder
|
setup *os.File
|
||||||
// cancels cmd
|
// cancels cmd
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
// closed after Wait returns
|
// closed after Wait returns
|
||||||
@@ -82,11 +86,11 @@ type (
|
|||||||
*Ops
|
*Ops
|
||||||
|
|
||||||
// Seccomp system call filter rules.
|
// Seccomp system call filter rules.
|
||||||
SeccompRules []seccomp.NativeRule
|
SeccompRules []std.NativeRule
|
||||||
// Extra seccomp flags.
|
// Extra seccomp flags.
|
||||||
SeccompFlags seccomp.ExportFlag
|
SeccompFlags seccomp.ExportFlag
|
||||||
// Seccomp presets. Has no effect unless SeccompRules is zero-length.
|
// Seccomp presets. Has no effect unless SeccompRules is zero-length.
|
||||||
SeccompPresets comp.FilterPreset
|
SeccompPresets std.FilterPreset
|
||||||
// Do not load seccomp program.
|
// Do not load seccomp program.
|
||||||
SeccompDisable bool
|
SeccompDisable bool
|
||||||
|
|
||||||
@@ -140,11 +144,18 @@ func (e *StartError) Error() string {
|
|||||||
// Message returns a user-facing error message.
|
// Message returns a user-facing error message.
|
||||||
func (e *StartError) Message() string {
|
func (e *StartError) Message() string {
|
||||||
if e.Passthrough {
|
if e.Passthrough {
|
||||||
|
var (
|
||||||
|
numError *strconv.NumError
|
||||||
|
)
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errors.As(e.Err, new(*os.PathError)),
|
case errors.As(e.Err, new(*os.PathError)),
|
||||||
errors.As(e.Err, new(*os.SyscallError)):
|
errors.As(e.Err, new(*os.SyscallError)):
|
||||||
return "cannot " + e.Err.Error()
|
return "cannot " + e.Err.Error()
|
||||||
|
|
||||||
|
case errors.As(e.Err, &numError) && numError != nil:
|
||||||
|
return "cannot parse " + strconv.Quote(numError.Num) + ": " + numError.Err.Error()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return e.Err.Error()
|
return e.Err.Error()
|
||||||
}
|
}
|
||||||
@@ -155,6 +166,39 @@ func (e *StartError) Message() string {
|
|||||||
return "cannot " + e.Error()
|
return "cannot " + e.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for ensureCloseOnExec
|
||||||
|
var (
|
||||||
|
closeOnExecOnce sync.Once
|
||||||
|
closeOnExecErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
// ensureCloseOnExec ensures all currently open file descriptors have the syscall.FD_CLOEXEC flag set.
|
||||||
|
// This is only ran once as it is intended to handle files left open by the parent, and any file opened
|
||||||
|
// on this side should already have syscall.FD_CLOEXEC set.
|
||||||
|
func ensureCloseOnExec() error {
|
||||||
|
closeOnExecOnce.Do(func() {
|
||||||
|
const fdPrefixPath = "/proc/self/fd/"
|
||||||
|
|
||||||
|
var entries []os.DirEntry
|
||||||
|
if entries, closeOnExecErr = os.ReadDir(fdPrefixPath); closeOnExecErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var fd int
|
||||||
|
for _, ent := range entries {
|
||||||
|
if fd, closeOnExecErr = strconv.Atoi(ent.Name()); closeOnExecErr != nil {
|
||||||
|
break // not reached
|
||||||
|
}
|
||||||
|
CloseOnExec(fd)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if closeOnExecErr == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &StartError{Fatal: true, Step: "set FD_CLOEXEC on all open files", Err: closeOnExecErr, Passthrough: true}
|
||||||
|
}
|
||||||
|
|
||||||
// Start starts the container init. The init process blocks until Serve is called.
|
// Start starts the container init. The init process blocks until Serve is called.
|
||||||
func (p *Container) Start() error {
|
func (p *Container) Start() error {
|
||||||
if p == nil || p.cmd == nil ||
|
if p == nil || p.cmd == nil ||
|
||||||
@@ -165,6 +209,10 @@ func (p *Container) Start() error {
|
|||||||
return errors.New("container: already started")
|
return errors.New("container: already started")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := ensureCloseOnExec(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// map to overflow id to work around ownership checks
|
// map to overflow id to work around ownership checks
|
||||||
if p.Uid < 1 {
|
if p.Uid < 1 {
|
||||||
p.Uid = OverflowUid(p.msg)
|
p.Uid = OverflowUid(p.msg)
|
||||||
@@ -174,7 +222,7 @@ func (p *Container) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !p.RetainSession {
|
if !p.RetainSession {
|
||||||
p.SeccompPresets |= comp.PresetDenyTTY
|
p.SeccompPresets |= std.PresetDenyTTY
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.AdoptWaitDelay == 0 {
|
if p.AdoptWaitDelay == 0 {
|
||||||
@@ -228,10 +276,10 @@ func (p *Container) Start() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// place setup pipe before user supplied extra files, this is later restored by init
|
// place setup pipe before user supplied extra files, this is later restored by init
|
||||||
if fd, e, err := Setup(&p.cmd.ExtraFiles); err != nil {
|
if fd, f, err := Setup(&p.cmd.ExtraFiles); err != nil {
|
||||||
return &StartError{true, "set up params stream", err, false, false}
|
return &StartError{true, "set up params stream", err, false, false}
|
||||||
} else {
|
} else {
|
||||||
p.setup = e
|
p.setup = f
|
||||||
p.cmd.Env = []string{setupEnv + "=" + strconv.Itoa(fd)}
|
p.cmd.Env = []string{setupEnv + "=" + strconv.Itoa(fd)}
|
||||||
}
|
}
|
||||||
p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, p.ExtraFiles...)
|
p.cmd.ExtraFiles = append(p.cmd.ExtraFiles, p.ExtraFiles...)
|
||||||
@@ -310,6 +358,9 @@ func (p *Container) Serve() error {
|
|||||||
|
|
||||||
setup := p.setup
|
setup := p.setup
|
||||||
p.setup = nil
|
p.setup = nil
|
||||||
|
if err := setup.SetDeadline(time.Now().Add(initSetupTimeout)); err != nil {
|
||||||
|
return &StartError{true, "set init pipe deadline", err, false, true}
|
||||||
|
}
|
||||||
|
|
||||||
if p.Path == nil {
|
if p.Path == nil {
|
||||||
p.cancel()
|
p.cancel()
|
||||||
@@ -321,18 +372,17 @@ func (p *Container) Serve() error {
|
|||||||
p.Dir = fhs.AbsRoot
|
p.Dir = fhs.AbsRoot
|
||||||
}
|
}
|
||||||
if p.SeccompRules == nil {
|
if p.SeccompRules == nil {
|
||||||
p.SeccompRules = make([]seccomp.NativeRule, 0)
|
p.SeccompRules = make([]std.NativeRule, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
err := setup.Encode(
|
err := gob.NewEncoder(setup).Encode(&initParams{
|
||||||
&initParams{
|
p.Params,
|
||||||
p.Params,
|
Getuid(),
|
||||||
Getuid(),
|
Getgid(),
|
||||||
Getgid(),
|
len(p.ExtraFiles),
|
||||||
len(p.ExtraFiles),
|
p.msg.IsVerbose(),
|
||||||
p.msg.IsVerbose(),
|
})
|
||||||
},
|
_ = setup.Close()
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.cancel()
|
p.cancel()
|
||||||
}
|
}
|
||||||
@@ -399,7 +449,7 @@ func (p *Container) ProcessState() *os.ProcessState {
|
|||||||
// New returns the address to a new instance of [Container] that requires further initialisation before use.
|
// New returns the address to a new instance of [Container] that requires further initialisation before use.
|
||||||
func New(ctx context.Context, msg message.Msg) *Container {
|
func New(ctx context.Context, msg message.Msg) *Container {
|
||||||
if msg == nil {
|
if msg == nil {
|
||||||
msg = message.NewMsg(nil)
|
msg = message.New(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &Container{ctx: ctx, msg: msg, Params: Params{Ops: new(Ops)}}
|
p := &Container{ctx: ctx, msg: msg, Params: Params{Ops: new(Ops)}}
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ import (
|
|||||||
"hakurei.app/command"
|
"hakurei.app/command"
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/comp"
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/container/vfs"
|
"hakurei.app/container/vfs"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
"hakurei.app/ldd"
|
"hakurei.app/ldd"
|
||||||
@@ -44,8 +44,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Fatal: true,
|
Fatal: true,
|
||||||
Step: "set up params stream",
|
Step: "set up params stream",
|
||||||
Err: container.ErrReceiveEnv,
|
Err: container.ErrReceiveEnv,
|
||||||
},
|
}, "set up params stream: environment variable not set",
|
||||||
"set up params stream: environment variable not set",
|
|
||||||
container.ErrReceiveEnv, syscall.EBADF,
|
container.ErrReceiveEnv, syscall.EBADF,
|
||||||
"cannot set up params stream: environment variable not set"},
|
"cannot set up params stream: environment variable not set"},
|
||||||
|
|
||||||
@@ -53,8 +52,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Fatal: true,
|
Fatal: true,
|
||||||
Step: "set up params stream",
|
Step: "set up params stream",
|
||||||
Err: &os.SyscallError{Syscall: "pipe2", Err: syscall.EBADF},
|
Err: &os.SyscallError{Syscall: "pipe2", Err: syscall.EBADF},
|
||||||
},
|
}, "set up params stream pipe2: bad file descriptor",
|
||||||
"set up params stream pipe2: bad file descriptor",
|
|
||||||
syscall.EBADF, os.ErrInvalid,
|
syscall.EBADF, os.ErrInvalid,
|
||||||
"cannot set up params stream pipe2: bad file descriptor"},
|
"cannot set up params stream pipe2: bad file descriptor"},
|
||||||
|
|
||||||
@@ -62,16 +60,14 @@ func TestStartError(t *testing.T) {
|
|||||||
Fatal: true,
|
Fatal: true,
|
||||||
Step: "prctl(PR_SET_NO_NEW_PRIVS)",
|
Step: "prctl(PR_SET_NO_NEW_PRIVS)",
|
||||||
Err: syscall.EPERM,
|
Err: syscall.EPERM,
|
||||||
},
|
}, "prctl(PR_SET_NO_NEW_PRIVS): operation not permitted",
|
||||||
"prctl(PR_SET_NO_NEW_PRIVS): operation not permitted",
|
|
||||||
syscall.EPERM, syscall.EACCES,
|
syscall.EPERM, syscall.EACCES,
|
||||||
"cannot prctl(PR_SET_NO_NEW_PRIVS): operation not permitted"},
|
"cannot prctl(PR_SET_NO_NEW_PRIVS): operation not permitted"},
|
||||||
|
|
||||||
{"landlock abi", &container.StartError{
|
{"landlock abi", &container.StartError{
|
||||||
Step: "get landlock ABI",
|
Step: "get landlock ABI",
|
||||||
Err: syscall.ENOSYS,
|
Err: syscall.ENOSYS,
|
||||||
},
|
}, "get landlock ABI: function not implemented",
|
||||||
"get landlock ABI: function not implemented",
|
|
||||||
syscall.ENOSYS, syscall.ENOEXEC,
|
syscall.ENOSYS, syscall.ENOEXEC,
|
||||||
"cannot get landlock ABI: function not implemented"},
|
"cannot get landlock ABI: function not implemented"},
|
||||||
|
|
||||||
@@ -79,8 +75,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Step: "kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET",
|
Step: "kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET",
|
||||||
Err: syscall.ENOSYS,
|
Err: syscall.ENOSYS,
|
||||||
Origin: true,
|
Origin: true,
|
||||||
},
|
}, "kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET",
|
||||||
"kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET",
|
|
||||||
syscall.ENOSYS, syscall.ENOSPC,
|
syscall.ENOSYS, syscall.ENOSPC,
|
||||||
"kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET"},
|
"kernel version too old for LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET"},
|
||||||
|
|
||||||
@@ -88,8 +83,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Fatal: true,
|
Fatal: true,
|
||||||
Step: "create landlock ruleset",
|
Step: "create landlock ruleset",
|
||||||
Err: syscall.EBADFD,
|
Err: syscall.EBADFD,
|
||||||
},
|
}, "create landlock ruleset: file descriptor in bad state",
|
||||||
"create landlock ruleset: file descriptor in bad state",
|
|
||||||
syscall.EBADFD, syscall.EBADF,
|
syscall.EBADFD, syscall.EBADF,
|
||||||
"cannot create landlock ruleset: file descriptor in bad state"},
|
"cannot create landlock ruleset: file descriptor in bad state"},
|
||||||
|
|
||||||
@@ -97,8 +91,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Fatal: true,
|
Fatal: true,
|
||||||
Step: "enforce landlock ruleset",
|
Step: "enforce landlock ruleset",
|
||||||
Err: syscall.ENOTRECOVERABLE,
|
Err: syscall.ENOTRECOVERABLE,
|
||||||
},
|
}, "enforce landlock ruleset: state not recoverable",
|
||||||
"enforce landlock ruleset: state not recoverable",
|
|
||||||
syscall.ENOTRECOVERABLE, syscall.ETIMEDOUT,
|
syscall.ENOTRECOVERABLE, syscall.ETIMEDOUT,
|
||||||
"cannot enforce landlock ruleset: state not recoverable"},
|
"cannot enforce landlock ruleset: state not recoverable"},
|
||||||
|
|
||||||
@@ -109,8 +102,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Path: "/proc/nonexistent",
|
Path: "/proc/nonexistent",
|
||||||
Err: syscall.ENOENT,
|
Err: syscall.ENOENT,
|
||||||
}, Passthrough: true,
|
}, Passthrough: true,
|
||||||
},
|
}, "fork/exec /proc/nonexistent: no such file or directory",
|
||||||
"fork/exec /proc/nonexistent: no such file or directory",
|
|
||||||
syscall.ENOENT, syscall.ENOSYS,
|
syscall.ENOENT, syscall.ENOSYS,
|
||||||
"cannot fork/exec /proc/nonexistent: no such file or directory"},
|
"cannot fork/exec /proc/nonexistent: no such file or directory"},
|
||||||
|
|
||||||
@@ -120,11 +112,19 @@ func TestStartError(t *testing.T) {
|
|||||||
Syscall: "open",
|
Syscall: "open",
|
||||||
Err: syscall.ENOSYS,
|
Err: syscall.ENOSYS,
|
||||||
}, Passthrough: true,
|
}, Passthrough: true,
|
||||||
},
|
}, "open: function not implemented",
|
||||||
"open: function not implemented",
|
|
||||||
syscall.ENOSYS, syscall.ENOENT,
|
syscall.ENOSYS, syscall.ENOENT,
|
||||||
"cannot open: function not implemented"},
|
"cannot open: function not implemented"},
|
||||||
|
|
||||||
|
{"start FD_CLOEXEC", &container.StartError{
|
||||||
|
Fatal: true,
|
||||||
|
Step: "set FD_CLOEXEC on all open files",
|
||||||
|
Err: func() error { _, err := strconv.Atoi("invalid"); return err }(),
|
||||||
|
Passthrough: true,
|
||||||
|
}, `strconv.Atoi: parsing "invalid": invalid syntax`,
|
||||||
|
strconv.ErrSyntax, os.ErrInvalid,
|
||||||
|
`cannot parse "invalid": invalid syntax`},
|
||||||
|
|
||||||
{"start other", &container.StartError{
|
{"start other", &container.StartError{
|
||||||
Step: "start container init",
|
Step: "start container init",
|
||||||
Err: &net.OpError{
|
Err: &net.OpError{
|
||||||
@@ -132,8 +132,7 @@ func TestStartError(t *testing.T) {
|
|||||||
Net: "unix",
|
Net: "unix",
|
||||||
Err: syscall.ECONNREFUSED,
|
Err: syscall.ECONNREFUSED,
|
||||||
}, Passthrough: true,
|
}, Passthrough: true,
|
||||||
},
|
}, "dial unix: connection refused",
|
||||||
"dial unix: connection refused",
|
|
||||||
syscall.ECONNREFUSED, syscall.ECONNABORTED,
|
syscall.ECONNREFUSED, syscall.ECONNABORTED,
|
||||||
"dial unix: connection refused"},
|
"dial unix: connection refused"},
|
||||||
}
|
}
|
||||||
@@ -204,22 +203,22 @@ var containerTestCases = []struct {
|
|||||||
uid int
|
uid int
|
||||||
gid int
|
gid int
|
||||||
|
|
||||||
rules []seccomp.NativeRule
|
rules []std.NativeRule
|
||||||
flags seccomp.ExportFlag
|
flags seccomp.ExportFlag
|
||||||
presets comp.FilterPreset
|
presets std.FilterPreset
|
||||||
}{
|
}{
|
||||||
{"minimal", true, false, false, true,
|
{"minimal", true, false, false, true,
|
||||||
emptyOps, emptyMnt,
|
emptyOps, emptyMnt,
|
||||||
1000, 100, nil, 0, comp.PresetStrict},
|
1000, 100, nil, 0, std.PresetStrict},
|
||||||
{"allow", true, true, true, false,
|
{"allow", true, true, true, false,
|
||||||
emptyOps, emptyMnt,
|
emptyOps, emptyMnt,
|
||||||
1000, 100, nil, 0, comp.PresetExt | comp.PresetDenyDevel},
|
1000, 100, nil, 0, std.PresetExt | std.PresetDenyDevel},
|
||||||
{"no filter", false, true, true, true,
|
{"no filter", false, true, true, true,
|
||||||
emptyOps, emptyMnt,
|
emptyOps, emptyMnt,
|
||||||
1000, 100, nil, 0, comp.PresetExt},
|
1000, 100, nil, 0, std.PresetExt},
|
||||||
{"custom rules", true, true, true, false,
|
{"custom rules", true, true, true, false,
|
||||||
emptyOps, emptyMnt,
|
emptyOps, emptyMnt,
|
||||||
1, 31, []seccomp.NativeRule{{Syscall: seccomp.ScmpSyscall(syscall.SYS_SETUID), Errno: seccomp.ScmpErrno(syscall.EPERM)}}, 0, comp.PresetExt},
|
1, 31, []std.NativeRule{{Syscall: std.ScmpSyscall(syscall.SYS_SETUID), Errno: std.ScmpErrno(syscall.EPERM)}}, 0, std.PresetExt},
|
||||||
|
|
||||||
{"tmpfs", true, false, false, true,
|
{"tmpfs", true, false, false, true,
|
||||||
earlyOps(new(container.Ops).
|
earlyOps(new(container.Ops).
|
||||||
@@ -228,7 +227,7 @@ var containerTestCases = []struct {
|
|||||||
earlyMnt(
|
earlyMnt(
|
||||||
ent("/", hst.PrivateTmp, "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", ignore),
|
ent("/", hst.PrivateTmp, "rw,nosuid,nodev,relatime", "tmpfs", "ephemeral", ignore),
|
||||||
),
|
),
|
||||||
9, 9, nil, 0, comp.PresetStrict},
|
9, 9, nil, 0, std.PresetStrict},
|
||||||
|
|
||||||
{"dev", true, true /* go test output is not a tty */, false, false,
|
{"dev", true, true /* go test output is not a tty */, false, false,
|
||||||
earlyOps(new(container.Ops).
|
earlyOps(new(container.Ops).
|
||||||
@@ -246,7 +245,7 @@ var containerTestCases = []struct {
|
|||||||
ent("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
|
ent("/", "/dev/mqueue", "rw,nosuid,nodev,noexec,relatime", "mqueue", "mqueue", "rw"),
|
||||||
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||||
),
|
),
|
||||||
1971, 100, nil, 0, comp.PresetStrict},
|
1971, 100, nil, 0, std.PresetStrict},
|
||||||
|
|
||||||
{"dev no mqueue", true, true /* go test output is not a tty */, false, false,
|
{"dev no mqueue", true, true /* go test output is not a tty */, false, false,
|
||||||
earlyOps(new(container.Ops).
|
earlyOps(new(container.Ops).
|
||||||
@@ -263,7 +262,7 @@ var containerTestCases = []struct {
|
|||||||
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
|
ent("/", "/dev/pts", "rw,nosuid,noexec,relatime", "devpts", "devpts", "rw,mode=620,ptmxmode=666"),
|
||||||
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
ent("/", "/dev/shm", "rw,nosuid,nodev,relatime", "tmpfs", "tmpfs", ignore),
|
||||||
),
|
),
|
||||||
1971, 100, nil, 0, comp.PresetStrict},
|
1971, 100, nil, 0, std.PresetStrict},
|
||||||
|
|
||||||
{"overlay", true, false, false, true,
|
{"overlay", true, false, false, true,
|
||||||
func(t *testing.T) (*container.Ops, context.Context) {
|
func(t *testing.T) (*container.Ops, context.Context) {
|
||||||
@@ -300,7 +299,7 @@ var containerTestCases = []struct {
|
|||||||
",redirect_dir=nofollow,uuid=on,userxattr"),
|
",redirect_dir=nofollow,uuid=on,userxattr"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
1 << 3, 1 << 14, nil, 0, comp.PresetStrict},
|
1 << 3, 1 << 14, nil, 0, std.PresetStrict},
|
||||||
|
|
||||||
{"overlay ephemeral", true, false, false, true,
|
{"overlay ephemeral", true, false, false, true,
|
||||||
func(t *testing.T) (*container.Ops, context.Context) {
|
func(t *testing.T) (*container.Ops, context.Context) {
|
||||||
@@ -324,7 +323,7 @@ var containerTestCases = []struct {
|
|||||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay", ignore),
|
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay", ignore),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
1 << 3, 1 << 14, nil, 0, comp.PresetStrict},
|
1 << 3, 1 << 14, nil, 0, std.PresetStrict},
|
||||||
|
|
||||||
{"overlay readonly", true, false, false, true,
|
{"overlay readonly", true, false, false, true,
|
||||||
func(t *testing.T) (*container.Ops, context.Context) {
|
func(t *testing.T) (*container.Ops, context.Context) {
|
||||||
@@ -352,7 +351,7 @@ var containerTestCases = []struct {
|
|||||||
",redirect_dir=nofollow,userxattr"),
|
",redirect_dir=nofollow,userxattr"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
1 << 3, 1 << 14, nil, 0, comp.PresetStrict},
|
1 << 3, 1 << 14, nil, 0, std.PresetStrict},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestContainer(t *testing.T) {
|
func TestContainer(t *testing.T) {
|
||||||
@@ -556,13 +555,13 @@ func testContainerCancel(
|
|||||||
|
|
||||||
func TestContainerString(t *testing.T) {
|
func TestContainerString(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
msg := message.NewMsg(nil)
|
msg := message.New(nil)
|
||||||
c := container.NewCommand(t.Context(), msg, check.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env")
|
c := container.NewCommand(t.Context(), msg, check.MustAbs("/run/current-system/sw/bin/ldd"), "ldd", "/usr/bin/env")
|
||||||
c.SeccompFlags |= seccomp.AllowMultiarch
|
c.SeccompFlags |= seccomp.AllowMultiarch
|
||||||
c.SeccompRules = seccomp.Preset(
|
c.SeccompRules = seccomp.Preset(
|
||||||
comp.PresetExt|comp.PresetDenyNS|comp.PresetDenyTTY,
|
std.PresetExt|std.PresetDenyNS|std.PresetDenyTTY,
|
||||||
c.SeccompFlags)
|
c.SeccompFlags)
|
||||||
c.SeccompPresets = comp.PresetStrict
|
c.SeccompPresets = std.PresetStrict
|
||||||
want := `argv: ["ldd" "/usr/bin/env"], filter: true, rules: 65, flags: 0x1, presets: 0xf`
|
want := `argv: ["ldd" "/usr/bin/env"], filter: true, rules: 65, flags: 0x1, presets: 0xf`
|
||||||
if got := c.String(); got != want {
|
if got := c.String(); got != want {
|
||||||
t.Errorf("String: %s, want %s", got, want)
|
t.Errorf("String: %s, want %s", got, want)
|
||||||
@@ -721,7 +720,8 @@ func TestMain(m *testing.M) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) {
|
func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) {
|
||||||
msg := message.NewMsg(nil)
|
msg := message.New(nil)
|
||||||
|
msg.SwapVerbose(testing.Verbose())
|
||||||
c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...)
|
c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...)
|
||||||
c.Env = append(c.Env, envDoCheck+"=1")
|
c.Env = append(c.Env, envDoCheck+"=1")
|
||||||
c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0)
|
c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,7 +63,7 @@ type syscallDispatcher interface {
|
|||||||
ensureFile(name string, perm, pperm os.FileMode) error
|
ensureFile(name string, perm, pperm os.FileMode) error
|
||||||
|
|
||||||
// seccompLoad provides [seccomp.Load].
|
// seccompLoad provides [seccomp.Load].
|
||||||
seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error
|
seccompLoad(rules []std.NativeRule, flags seccomp.ExportFlag) error
|
||||||
// notify provides [signal.Notify].
|
// notify provides [signal.Notify].
|
||||||
notify(c chan<- os.Signal, sig ...os.Signal)
|
notify(c chan<- os.Signal, sig ...os.Signal)
|
||||||
// start starts [os/exec.Cmd].
|
// start starts [os/exec.Cmd].
|
||||||
@@ -164,7 +165,7 @@ func (direct) ensureFile(name string, perm, pperm os.FileMode) error {
|
|||||||
return ensureFile(name, perm, pperm)
|
return ensureFile(name, perm, pperm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (direct) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
func (direct) seccompLoad(rules []std.NativeRule, flags seccomp.ExportFlag) error {
|
||||||
return seccomp.Load(rules, flags)
|
return seccomp.Load(rules, flags)
|
||||||
}
|
}
|
||||||
func (direct) notify(c chan<- os.Signal, sig ...os.Signal) { signal.Notify(c, sig...) }
|
func (direct) notify(c chan<- os.Signal, sig ...os.Signal) { signal.Notify(c, sig...) }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
"hakurei.app/message"
|
"hakurei.app/message"
|
||||||
)
|
)
|
||||||
@@ -456,7 +457,7 @@ func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error {
|
|||||||
stub.CheckArg(k.Stub, "pperm", pperm, 2))
|
stub.CheckArg(k.Stub, "pperm", pperm, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *kstub) seccompLoad(rules []seccomp.NativeRule, flags seccomp.ExportFlag) error {
|
func (k *kstub) seccompLoad(rules []std.NativeRule, flags seccomp.ExportFlag) error {
|
||||||
k.Helper()
|
k.Helper()
|
||||||
return k.Expects("seccompLoad").Error(
|
return k.Expects("seccompLoad").Error(
|
||||||
stub.CheckArgReflect(k.Stub, "rules", rules, 0),
|
stub.CheckArgReflect(k.Stub, "rules", rules, 0),
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ func TestMessageFromError(t *testing.T) {
|
|||||||
{"state", OpStateError("overlay"),
|
{"state", OpStateError("overlay"),
|
||||||
"impossible overlay state reached", true},
|
"impossible overlay state reached", true},
|
||||||
|
|
||||||
{"vfs parse", &vfs.DecoderError{Op: "parse", Line: 0xdeadbeef, Err: &strconv.NumError{Func: "Atoi", Num: "meow", Err: strconv.ErrSyntax}},
|
{"vfs parse", &vfs.DecoderError{Op: "parse", Line: 0xdead, Err: &strconv.NumError{Func: "Atoi", Num: "meow", Err: strconv.ErrSyntax}},
|
||||||
`cannot parse mountinfo at line 3735928559: numeric field "meow" invalid syntax`, true},
|
`cannot parse mountinfo at line 57005: numeric field "meow" invalid syntax`, true},
|
||||||
|
|
||||||
{"tmpfs", TmpfsSizeError(-1),
|
{"tmpfs", TmpfsSizeError(-1),
|
||||||
"tmpfs size -1 out of bounds", true},
|
"tmpfs size -1 out of bounds", true},
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package container
|
package container
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@@ -14,8 +16,13 @@ var (
|
|||||||
|
|
||||||
func copyExecutable(msg message.Msg) {
|
func copyExecutable(msg message.Msg) {
|
||||||
if name, err := os.Executable(); err != nil {
|
if name, err := os.Executable(); err != nil {
|
||||||
msg.BeforeExit()
|
m := fmt.Sprintf("cannot read executable path: %v", err)
|
||||||
msg.GetLogger().Fatalf("cannot read executable path: %v", err)
|
if msg != nil {
|
||||||
|
msg.BeforeExit()
|
||||||
|
msg.GetLogger().Fatal(m)
|
||||||
|
} else {
|
||||||
|
log.Fatal(m)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
executable = name
|
executable = name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
func TestExecutable(t *testing.T) {
|
func TestExecutable(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
for i := 0; i < 16; i++ {
|
for i := 0; i < 16; i++ {
|
||||||
if got := container.MustExecutable(message.NewMsg(nil)); got != os.Args[0] {
|
if got := container.MustExecutable(message.New(nil)); got != os.Args[0] {
|
||||||
t.Errorf("MustExecutable: %q, want %q", got, os.Args[0])
|
t.Errorf("MustExecutable: %q, want %q", got, os.Args[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package fhs
|
package fhs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "unsafe"
|
_ "unsafe" // for go:linkname
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -330,6 +330,10 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
k.umask(oldmask)
|
k.umask(oldmask)
|
||||||
|
|
||||||
|
if err := closeSetup(); err != nil {
|
||||||
|
k.fatalf(msg, "cannot close setup pipe: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
cmd := exec.Command(params.Path.String())
|
cmd := exec.Command(params.Path.String())
|
||||||
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
||||||
cmd.Args = params.Args
|
cmd.Args = params.Args
|
||||||
@@ -341,12 +345,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
if err := k.start(cmd); err != nil {
|
if err := k.start(cmd); err != nil {
|
||||||
k.fatalf(msg, "%v", err)
|
k.fatalf(msg, "%v", err)
|
||||||
}
|
}
|
||||||
msg.Suspend()
|
|
||||||
|
|
||||||
if err := closeSetup(); err != nil {
|
|
||||||
k.printf(msg, "cannot close setup pipe: %v", err)
|
|
||||||
// not fatal
|
|
||||||
}
|
|
||||||
|
|
||||||
type winfo struct {
|
type winfo struct {
|
||||||
wpid int
|
wpid int
|
||||||
@@ -390,7 +388,8 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
|
|
||||||
// handle signals to dump withheld messages
|
// handle signals to dump withheld messages
|
||||||
sig := make(chan os.Signal, 2)
|
sig := make(chan os.Signal, 2)
|
||||||
k.notify(sig, os.Interrupt, CancelSignal)
|
k.notify(sig, CancelSignal,
|
||||||
|
os.Interrupt, SIGTERM, SIGQUIT)
|
||||||
|
|
||||||
// closed after residualProcessTimeout has elapsed after initial process death
|
// closed after residualProcessTimeout has elapsed after initial process death
|
||||||
timeout := make(chan struct{})
|
timeout := make(chan struct{})
|
||||||
@@ -399,11 +398,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case s := <-sig:
|
case s := <-sig:
|
||||||
if msg.Resume() {
|
|
||||||
msg.Verbosef("%s after process start", s.String())
|
|
||||||
} else {
|
|
||||||
msg.Verbosef("got %s", s.String())
|
|
||||||
}
|
|
||||||
if s == CancelSignal && params.ForwardCancel && cmd.Process != nil {
|
if s == CancelSignal && params.ForwardCancel && cmd.Process != nil {
|
||||||
msg.Verbose("forwarding context cancellation")
|
msg.Verbose("forwarding context cancellation")
|
||||||
if err := k.signal(cmd, os.Interrupt); err != nil {
|
if err := k.signal(cmd, os.Interrupt); err != nil {
|
||||||
@@ -411,6 +405,16 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s == SIGTERM || s == SIGQUIT {
|
||||||
|
msg.Verbosef("got %s, forwarding to initial process", s.String())
|
||||||
|
if err := k.signal(cmd, s); err != nil {
|
||||||
|
k.printf(msg, "cannot forward signal: %v", err)
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.Verbosef("got %s", s.String())
|
||||||
msg.BeforeExit()
|
msg.BeforeExit()
|
||||||
k.exit(0)
|
k.exit(0)
|
||||||
|
|
||||||
@@ -422,8 +426,15 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if w.wpid == cmd.Process.Pid {
|
if w.wpid == cmd.Process.Pid {
|
||||||
// initial process exited, output is most likely available again
|
// start timeout early
|
||||||
msg.Resume()
|
go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
|
||||||
|
|
||||||
|
// close initial process files; this also keeps them alive
|
||||||
|
for _, f := range extraFiles {
|
||||||
|
if err := f.Close(); err != nil {
|
||||||
|
msg.Verbose(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case w.wstatus.Exited():
|
case w.wstatus.Exited():
|
||||||
@@ -438,8 +449,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
|
|||||||
r = 255
|
r = 255
|
||||||
msg.Verbosef("initial process exited with status %#x", w.wstatus)
|
msg.Verbosef("initial process exited with status %#x", w.wstatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case <-timeout:
|
case <-timeout:
|
||||||
@@ -459,7 +468,7 @@ func TryArgv0(msg message.Msg) {
|
|||||||
if msg == nil {
|
if msg == nil {
|
||||||
log.SetPrefix(initName + ": ")
|
log.SetPrefix(initName + ": ")
|
||||||
log.SetFlags(0)
|
log.SetFlags(0)
|
||||||
msg = message.NewMsg(log.Default())
|
msg = message.New(log.Default())
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(os.Args) > 0 && path.Base(os.Args[0]) == initName {
|
if len(os.Args) > 0 && path.Base(os.Args[0]) == initName {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/comp"
|
"hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { gob.Register(new(BindMountOp)) }
|
func init() { gob.Register(new(BindMountOp)) }
|
||||||
@@ -29,18 +29,18 @@ type BindMountOp struct {
|
|||||||
func (b *BindMountOp) Valid() bool {
|
func (b *BindMountOp) Valid() bool {
|
||||||
return b != nil &&
|
return b != nil &&
|
||||||
b.Source != nil && b.Target != nil &&
|
b.Source != nil && b.Target != nil &&
|
||||||
b.Flags&(comp.BindOptional|comp.BindEnsure) != (comp.BindOptional|comp.BindEnsure)
|
b.Flags&(std.BindOptional|std.BindEnsure) != (std.BindOptional|std.BindEnsure)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
||||||
if b.Flags&comp.BindEnsure != 0 {
|
if b.Flags&std.BindEnsure != 0 {
|
||||||
if err := k.mkdirAll(b.Source.String(), 0700); err != nil {
|
if err := k.mkdirAll(b.Source.String(), 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if pathname, err := k.evalSymlinks(b.Source.String()); err != nil {
|
if pathname, err := k.evalSymlinks(b.Source.String()); err != nil {
|
||||||
if os.IsNotExist(err) && b.Flags&comp.BindOptional != 0 {
|
if os.IsNotExist(err) && b.Flags&std.BindOptional != 0 {
|
||||||
// leave sourceFinal as nil
|
// leave sourceFinal as nil
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@ func (b *BindMountOp) early(_ *setupState, k syscallDispatcher) error {
|
|||||||
|
|
||||||
func (b *BindMountOp) apply(state *setupState, k syscallDispatcher) error {
|
func (b *BindMountOp) apply(state *setupState, k syscallDispatcher) error {
|
||||||
if b.sourceFinal == nil {
|
if b.sourceFinal == nil {
|
||||||
if b.Flags&comp.BindOptional == 0 {
|
if b.Flags&std.BindOptional == 0 {
|
||||||
// unreachable
|
// unreachable
|
||||||
return OpStateError("bind")
|
return OpStateError("bind")
|
||||||
}
|
}
|
||||||
@@ -76,10 +76,10 @@ func (b *BindMountOp) apply(state *setupState, k syscallDispatcher) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var flags uintptr = syscall.MS_REC
|
var flags uintptr = syscall.MS_REC
|
||||||
if b.Flags&comp.BindWritable == 0 {
|
if b.Flags&std.BindWritable == 0 {
|
||||||
flags |= syscall.MS_RDONLY
|
flags |= syscall.MS_RDONLY
|
||||||
}
|
}
|
||||||
if b.Flags&comp.BindDevice == 0 {
|
if b.Flags&std.BindDevice == 0 {
|
||||||
flags |= syscall.MS_NODEV
|
flags |= syscall.MS_NODEV
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/comp"
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"skip optional", new(Params), &BindMountOp{
|
{"skip optional", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/bin/"),
|
Source: check.MustAbs("/bin/"),
|
||||||
Target: check.MustAbs("/bin/"),
|
Target: check.MustAbs("/bin/"),
|
||||||
Flags: comp.BindOptional,
|
Flags: std.BindOptional,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "", syscall.ENOENT),
|
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "", syscall.ENOENT),
|
||||||
}, nil, nil, nil},
|
}, nil, nil, nil},
|
||||||
@@ -33,7 +33,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"success optional", new(Params), &BindMountOp{
|
{"success optional", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/bin/"),
|
Source: check.MustAbs("/bin/"),
|
||||||
Target: check.MustAbs("/bin/"),
|
Target: check.MustAbs("/bin/"),
|
||||||
Flags: comp.BindOptional,
|
Flags: std.BindOptional,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
@@ -46,7 +46,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"ensureFile device", new(Params), &BindMountOp{
|
{"ensureFile device", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/dev/null"),
|
Source: check.MustAbs("/dev/null"),
|
||||||
Target: check.MustAbs("/dev/null"),
|
Target: check.MustAbs("/dev/null"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice,
|
Flags: std.BindWritable | std.BindDevice,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
@@ -57,7 +57,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"mkdirAll ensure", new(Params), &BindMountOp{
|
{"mkdirAll ensure", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/bin/"),
|
Source: check.MustAbs("/bin/"),
|
||||||
Target: check.MustAbs("/bin/"),
|
Target: check.MustAbs("/bin/"),
|
||||||
Flags: comp.BindEnsure,
|
Flags: std.BindEnsure,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, stub.UniqueError(4)),
|
call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, stub.UniqueError(4)),
|
||||||
}, stub.UniqueError(4), nil, nil},
|
}, stub.UniqueError(4), nil, nil},
|
||||||
@@ -65,7 +65,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"success ensure", new(Params), &BindMountOp{
|
{"success ensure", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/bin/"),
|
Source: check.MustAbs("/bin/"),
|
||||||
Target: check.MustAbs("/usr/bin/"),
|
Target: check.MustAbs("/usr/bin/"),
|
||||||
Flags: comp.BindEnsure,
|
Flags: std.BindEnsure,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/bin/", os.FileMode(0700)}, nil, nil),
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/bin/"}, "/usr/bin", nil),
|
||||||
@@ -79,7 +79,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"success device ro", new(Params), &BindMountOp{
|
{"success device ro", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/dev/null"),
|
Source: check.MustAbs("/dev/null"),
|
||||||
Target: check.MustAbs("/dev/null"),
|
Target: check.MustAbs("/dev/null"),
|
||||||
Flags: comp.BindDevice,
|
Flags: std.BindDevice,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
@@ -92,7 +92,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"success device", new(Params), &BindMountOp{
|
{"success device", new(Params), &BindMountOp{
|
||||||
Source: check.MustAbs("/dev/null"),
|
Source: check.MustAbs("/dev/null"),
|
||||||
Target: check.MustAbs("/dev/null"),
|
Target: check.MustAbs("/dev/null"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice,
|
Flags: std.BindWritable | std.BindDevice,
|
||||||
}, []stub.Call{
|
}, []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/dev/null"}, "/dev/null", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
@@ -182,7 +182,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"zero", new(BindMountOp), false},
|
{"zero", new(BindMountOp), false},
|
||||||
{"nil source", &BindMountOp{Target: check.MustAbs("/")}, false},
|
{"nil source", &BindMountOp{Target: check.MustAbs("/")}, false},
|
||||||
{"nil target", &BindMountOp{Source: check.MustAbs("/")}, false},
|
{"nil target", &BindMountOp{Source: check.MustAbs("/")}, false},
|
||||||
{"flag optional ensure", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/"), Flags: comp.BindOptional | comp.BindEnsure}, false},
|
{"flag optional ensure", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/"), Flags: std.BindOptional | std.BindEnsure}, false},
|
||||||
{"valid", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/")}, true},
|
{"valid", &BindMountOp{Source: check.MustAbs("/"), Target: check.MustAbs("/")}, true},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -217,7 +217,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
}, &BindMountOp{
|
}, &BindMountOp{
|
||||||
Source: check.MustAbs("/etc/"),
|
Source: check.MustAbs("/etc/"),
|
||||||
Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"),
|
Target: check.MustAbs("/etc/.host/048090b6ed8f9ebb10e275ff5d8c0659"),
|
||||||
Flags: comp.BindOptional,
|
Flags: std.BindOptional,
|
||||||
}, false},
|
}, false},
|
||||||
|
|
||||||
{"source differs", &BindMountOp{
|
{"source differs", &BindMountOp{
|
||||||
@@ -256,7 +256,7 @@ func TestBindMountOp(t *testing.T) {
|
|||||||
{"hostdev", &BindMountOp{
|
{"hostdev", &BindMountOp{
|
||||||
Source: check.MustAbs("/dev/"),
|
Source: check.MustAbs("/dev/"),
|
||||||
Target: check.MustAbs("/dev/"),
|
Target: check.MustAbs("/dev/"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice,
|
Flags: std.BindWritable | std.BindDevice,
|
||||||
}, "mounting", `"/dev/" flags 0x6`},
|
}, "mounting", `"/dev/" flags 0x6`},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
// include/uapi/linux/landlock.h
|
// include/uapi/linux/landlock.h
|
||||||
@@ -14,7 +14,8 @@ const (
|
|||||||
LANDLOCK_CREATE_RULESET_VERSION = 1 << iota
|
LANDLOCK_CREATE_RULESET_VERSION = 1 << iota
|
||||||
)
|
)
|
||||||
|
|
||||||
type LandlockAccessFS uintptr
|
// LandlockAccessFS is bitmask of handled filesystem actions.
|
||||||
|
type LandlockAccessFS uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LANDLOCK_ACCESS_FS_EXECUTE LandlockAccessFS = 1 << iota
|
LANDLOCK_ACCESS_FS_EXECUTE LandlockAccessFS = 1 << iota
|
||||||
@@ -105,7 +106,8 @@ func (f LandlockAccessFS) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LandlockAccessNet uintptr
|
// LandlockAccessNet is bitmask of handled network actions.
|
||||||
|
type LandlockAccessNet uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LANDLOCK_ACCESS_NET_BIND_TCP LandlockAccessNet = 1 << iota
|
LANDLOCK_ACCESS_NET_BIND_TCP LandlockAccessNet = 1 << iota
|
||||||
@@ -140,7 +142,8 @@ func (f LandlockAccessNet) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LandlockScope uintptr
|
// LandlockScope is bitmask of scopes restricting a Landlock domain from accessing outside resources.
|
||||||
|
type LandlockScope uint64
|
||||||
|
|
||||||
const (
|
const (
|
||||||
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET LandlockScope = 1 << iota
|
LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET LandlockScope = 1 << iota
|
||||||
@@ -175,6 +178,7 @@ func (f LandlockScope) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RulesetAttr is equivalent to struct landlock_ruleset_attr.
|
||||||
type RulesetAttr struct {
|
type RulesetAttr struct {
|
||||||
// Bitmask of handled filesystem actions.
|
// Bitmask of handled filesystem actions.
|
||||||
HandledAccessFS LandlockAccessFS
|
HandledAccessFS LandlockAccessFS
|
||||||
@@ -212,7 +216,7 @@ func (rulesetAttr *RulesetAttr) Create(flags uintptr) (fd int, err error) {
|
|||||||
size = unsafe.Sizeof(*rulesetAttr)
|
size = unsafe.Sizeof(*rulesetAttr)
|
||||||
}
|
}
|
||||||
|
|
||||||
rulesetFd, _, errno := syscall.Syscall(seccomp.SYS_LANDLOCK_CREATE_RULESET, pointer, size, flags)
|
rulesetFd, _, errno := syscall.Syscall(std.SYS_LANDLOCK_CREATE_RULESET, pointer, size, flags)
|
||||||
fd = int(rulesetFd)
|
fd = int(rulesetFd)
|
||||||
err = errno
|
err = errno
|
||||||
|
|
||||||
@@ -231,7 +235,7 @@ func LandlockGetABI() (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func LandlockRestrictSelf(rulesetFd int, flags uintptr) error {
|
func LandlockRestrictSelf(rulesetFd int, flags uintptr) error {
|
||||||
r, _, errno := syscall.Syscall(seccomp.SYS_LANDLOCK_RESTRICT_SELF, uintptr(rulesetFd), flags, 0)
|
r, _, errno := syscall.Syscall(std.SYS_LANDLOCK_RESTRICT_SELF, uintptr(rulesetFd), flags, 0)
|
||||||
if r != 0 {
|
if r != 0 {
|
||||||
return errno
|
return errno
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ func TestRemount(t *testing.T) {
|
|||||||
403 397 0:63 / /host/run/user/1000 rw,nosuid,nodev,relatime master:295 - tmpfs tmpfs rw,size=401060k,nr_inodes=100265,mode=700,uid=1000,gid=100
|
403 397 0:63 / /host/run/user/1000 rw,nosuid,nodev,relatime master:295 - tmpfs tmpfs rw,size=401060k,nr_inodes=100265,mode=700,uid=1000,gid=100
|
||||||
404 254 0:46 / /host/mnt/cwd rw,relatime master:96 - overlay overlay rw,lowerdir=/mnt/.ro-cwd,upperdir=/tmp/.cwd/upper,workdir=/tmp/.cwd/work
|
404 254 0:46 / /host/mnt/cwd rw,relatime master:96 - overlay overlay rw,lowerdir=/mnt/.ro-cwd,upperdir=/tmp/.cwd/upper,workdir=/tmp/.cwd/work
|
||||||
405 254 0:47 / /host/mnt/src rw,relatime master:99 - overlay overlay rw,lowerdir=/nix/store/ihcrl3zwvp2002xyylri2wz0drwajx4z-ns0pa7q2b1jpx9pbf1l9352x6rniwxjn-source,upperdir=/tmp/.src/upper,workdir=/tmp/.src/work
|
405 254 0:47 / /host/mnt/src rw,relatime master:99 - overlay overlay rw,lowerdir=/nix/store/ihcrl3zwvp2002xyylri2wz0drwajx4z-ns0pa7q2b1jpx9pbf1l9352x6rniwxjn-source,upperdir=/tmp/.src/upper,workdir=/tmp/.src/work
|
||||||
407 253 0:65 / / rw,nosuid,nodev,relatime - tmpfs rootfs rw,uid=1000000,gid=1000000
|
407 253 0:65 / / rw,nosuid,nodev,relatime - tmpfs rootfs rw,uid=10000,gid=10000
|
||||||
408 407 0:65 /sysroot /sysroot rw,nosuid,nodev,relatime - tmpfs rootfs rw,uid=1000000,gid=1000000
|
408 407 0:65 /sysroot /sysroot rw,nosuid,nodev,relatime - tmpfs rootfs rw,uid=10000,gid=10000
|
||||||
409 408 253:0 /bin /sysroot/bin rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
409 408 253:0 /bin /sysroot/bin rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
410 408 253:0 /home /sysroot/home rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
410 408 253:0 /home /sysroot/home rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
411 408 253:0 /lib64 /sysroot/lib64 rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
411 408 253:0 /lib64 /sysroot/lib64 rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
@@ -91,24 +91,24 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, stub.UniqueError(5)),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, stub.UniqueError(5)),
|
||||||
}}, &os.PathError{Op: "open", Path: "/sysroot/nix", Err: stub.UniqueError(5)}},
|
}}, &os.PathError{Op: "open", Path: "/sysroot/nix", Err: stub.UniqueError(5)}},
|
||||||
|
|
||||||
{"readlink", func(k *kstub) error {
|
{"readlink", func(k *kstub) error {
|
||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", stub.UniqueError(4)),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", stub.UniqueError(4)),
|
||||||
}}, stub.UniqueError(4)},
|
}}, stub.UniqueError(4)},
|
||||||
|
|
||||||
{"close", func(k *kstub) error {
|
{"close", func(k *kstub) error {
|
||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, stub.UniqueError(3)),
|
call("close", stub.ExpectArgs{0xdead}, nil, stub.UniqueError(3)),
|
||||||
}}, &os.PathError{Op: "close", Path: "/sysroot/nix", Err: stub.UniqueError(3)}},
|
}}, &os.PathError{Op: "close", Path: "/sysroot/nix", Err: stub.UniqueError(3)}},
|
||||||
|
|
||||||
{"mountinfo no match", func(k *kstub) error {
|
{"mountinfo no match", func(k *kstub) error {
|
||||||
@@ -116,9 +116,9 @@ func TestRemount(t *testing.T) {
|
|||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/.hakurei", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/.hakurei", nil),
|
||||||
call("verbosef", stub.ExpectArgs{"target resolves to %q", []any{"/sysroot/.hakurei"}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"target resolves to %q", []any{"/sysroot/.hakurei"}}, nil, nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/.hakurei", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/.hakurei", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/.hakurei", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/.hakurei", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
}}, &vfs.DecoderError{Op: "unfold", Line: -1, Err: vfs.UnfoldTargetError("/sysroot/.hakurei")}},
|
}}, &vfs.DecoderError{Op: "unfold", Line: -1, Err: vfs.UnfoldTargetError("/sysroot/.hakurei")}},
|
||||||
|
|
||||||
@@ -126,9 +126,9 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile("\x00"), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile("\x00"), nil),
|
||||||
}}, &vfs.DecoderError{Op: "parse", Line: 0, Err: vfs.ErrMountInfoFields}},
|
}}, &vfs.DecoderError{Op: "parse", Line: 0, Err: vfs.ErrMountInfoFields}},
|
||||||
|
|
||||||
@@ -136,9 +136,9 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, stub.UniqueError(2)),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, stub.UniqueError(2)),
|
||||||
}}, stub.UniqueError(2)},
|
}}, stub.UniqueError(2)},
|
||||||
@@ -147,9 +147,9 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, stub.UniqueError(1)),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, stub.UniqueError(1)),
|
||||||
@@ -170,9 +170,9 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, syscall.EACCES),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, syscall.EACCES),
|
||||||
@@ -183,9 +183,9 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
}}, nil},
|
}}, nil},
|
||||||
@@ -194,9 +194,9 @@ func TestRemount(t *testing.T) {
|
|||||||
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
return newProcPaths(k, hostPath).remount(nil, "/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/nix"}, "/sysroot/nix", nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
@@ -208,9 +208,9 @@ func TestRemount(t *testing.T) {
|
|||||||
}, stub.Expect{Calls: []stub.Call{
|
}, stub.Expect{Calls: []stub.Call{
|
||||||
call("evalSymlinks", stub.ExpectArgs{"/sysroot/.nix"}, "/sysroot/NIX", nil),
|
call("evalSymlinks", stub.ExpectArgs{"/sysroot/.nix"}, "/sysroot/NIX", nil),
|
||||||
call("verbosef", stub.ExpectArgs{"target resolves to %q", []any{"/sysroot/NIX"}}, nil, nil),
|
call("verbosef", stub.ExpectArgs{"target resolves to %q", []any{"/sysroot/NIX"}}, nil, nil),
|
||||||
call("open", stub.ExpectArgs{"/sysroot/NIX", 0x280000, uint32(0)}, 0xdeadbeef, nil),
|
call("open", stub.ExpectArgs{"/sysroot/NIX", 0x280000, uint32(0)}, 0xdead, nil),
|
||||||
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil),
|
call("readlink", stub.ExpectArgs{"/host/proc/self/fd/57005"}, "/sysroot/nix", nil),
|
||||||
call("close", stub.ExpectArgs{0xdeadbeef}, nil, nil),
|
call("close", stub.ExpectArgs{0xdead}, nil, nil),
|
||||||
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
call("openNew", stub.ExpectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, nil),
|
call("mount", stub.ExpectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, nil),
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Setup appends the read end of a pipe for setup params transmission and returns its fd.
|
// Setup appends the read end of a pipe for setup params transmission and returns its fd.
|
||||||
func Setup(extraFiles *[]*os.File) (int, *gob.Encoder, error) {
|
func Setup(extraFiles *[]*os.File) (int, *os.File, error) {
|
||||||
if r, w, err := os.Pipe(); err != nil {
|
if r, w, err := os.Pipe(); err != nil {
|
||||||
return -1, nil, err
|
return -1, nil, err
|
||||||
} else {
|
} else {
|
||||||
fd := 3 + len(*extraFiles)
|
fd := 3 + len(*extraFiles)
|
||||||
*extraFiles = append(*extraFiles, r)
|
*extraFiles = append(*extraFiles, r)
|
||||||
return fd, gob.NewEncoder(w), nil
|
return fd, w, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package container_test
|
package container_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/gob"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -55,16 +56,20 @@ func TestSetupReceive(t *testing.T) {
|
|||||||
t.Run("setup receive", func(t *testing.T) {
|
t.Run("setup receive", func(t *testing.T) {
|
||||||
check := func(t *testing.T, useNilFdp bool) {
|
check := func(t *testing.T, useNilFdp bool) {
|
||||||
const key = "TEST_SETUP_RECEIVE"
|
const key = "TEST_SETUP_RECEIVE"
|
||||||
payload := []int{syscall.MS_MGC_VAL, syscall.MS_MGC_MSK, syscall.MS_ASYNC, syscall.MS_ACTIVE}
|
payload := []uint64{syscall.MS_MGC_VAL, syscall.MS_MGC_MSK, syscall.MS_ASYNC, syscall.MS_ACTIVE}
|
||||||
|
|
||||||
encoderDone := make(chan error, 1)
|
encoderDone := make(chan error, 1)
|
||||||
extraFiles := make([]*os.File, 0, 1)
|
extraFiles := make([]*os.File, 0, 1)
|
||||||
if fd, encoder, err := container.Setup(&extraFiles); err != nil {
|
deadline, _ := t.Deadline()
|
||||||
|
if fd, f, err := container.Setup(&extraFiles); err != nil {
|
||||||
t.Fatalf("Setup: error = %v", err)
|
t.Fatalf("Setup: error = %v", err)
|
||||||
} else if fd != 3 {
|
} else if fd != 3 {
|
||||||
t.Fatalf("Setup: fd = %d, want 3", fd)
|
t.Fatalf("Setup: fd = %d, want 3", fd)
|
||||||
} else {
|
} else {
|
||||||
go func() { encoderDone <- encoder.Encode(payload) }()
|
if err = f.SetDeadline(deadline); err != nil {
|
||||||
|
t.Fatal(err.Error())
|
||||||
|
}
|
||||||
|
go func() { encoderDone <- gob.NewEncoder(f).Encode(payload) }()
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(extraFiles) != 1 {
|
if len(extraFiles) != 1 {
|
||||||
@@ -81,7 +86,7 @@ func TestSetupReceive(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gotPayload []int
|
gotPayload []uint64
|
||||||
fdp *uintptr
|
fdp *uintptr
|
||||||
)
|
)
|
||||||
if !useNilFdp {
|
if !useNilFdp {
|
||||||
|
|||||||
@@ -173,8 +173,8 @@ func TestProcPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
t.Run("fd", func(t *testing.T) {
|
t.Run("fd", func(t *testing.T) {
|
||||||
want := "/host/proc/self/fd/9223372036854775807"
|
want := "/host/proc/self/fd/2147483647"
|
||||||
if got := hostProc.fd(math.MaxInt64); got != want {
|
if got := hostProc.fd(math.MaxInt32); got != want {
|
||||||
t.Errorf("stdout: %q, want %q", got, want)
|
t.Errorf("stdout: %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import (
|
|||||||
"runtime/cgo"
|
"runtime/cgo"
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrInvalidRules is returned for a zero-length rules slice.
|
// ErrInvalidRules is returned for a zero-length rules slice.
|
||||||
@@ -54,22 +56,16 @@ func (e *LibraryError) Is(err error) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// ScmpSyscall represents a syscall number passed to libseccomp via [NativeRule.Syscall].
|
// scmpUint is equivalent to [std.ScmpUint].
|
||||||
ScmpSyscall = C.int
|
scmpUint = C.uint
|
||||||
// ScmpErrno represents an errno value passed to libseccomp via [NativeRule.Errno].
|
// scmpInt is equivalent to [std.ScmpInt].
|
||||||
ScmpErrno = C.int
|
scmpInt = C.int
|
||||||
|
|
||||||
|
// syscallRule is equivalent to [std.NativeRule].
|
||||||
|
syscallRule = C.struct_hakurei_syscall_rule
|
||||||
)
|
)
|
||||||
|
|
||||||
// A NativeRule specifies an arch-specific action taken by seccomp under certain conditions.
|
// ExportFlag configures filter behaviour that are not implemented as rules.
|
||||||
type NativeRule struct {
|
|
||||||
// Syscall is the arch-dependent syscall number to act against.
|
|
||||||
Syscall ScmpSyscall
|
|
||||||
// Errno is the errno value to return when the condition is satisfied.
|
|
||||||
Errno ScmpErrno
|
|
||||||
// Arg is the optional struct scmp_arg_cmp passed to libseccomp.
|
|
||||||
Arg *ScmpArgCmp
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExportFlag = C.hakurei_export_flag
|
type ExportFlag = C.hakurei_export_flag
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -102,9 +98,9 @@ func hakurei_scmp_allocate(f C.uintptr_t, len C.size_t) (buf unsafe.Pointer) {
|
|||||||
return cgo.Handle(f).Value().(cbAllocateBuffer)(len)
|
return cgo.Handle(f).Value().(cbAllocateBuffer)(len)
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeFilter generates a bpf program from a slice of [NativeRule] and writes the resulting byte slice to p.
|
// makeFilter generates a bpf program from a slice of [std.NativeRule] and writes the resulting byte slice to p.
|
||||||
// The filter is installed to the current process if p is nil.
|
// The filter is installed to the current process if p is nil.
|
||||||
func makeFilter(rules []NativeRule, flags ExportFlag, p *[]byte) error {
|
func makeFilter(rules []std.NativeRule, flags ExportFlag, p *[]byte) error {
|
||||||
if len(rules) == 0 {
|
if len(rules) == 0 {
|
||||||
return ErrInvalidRules
|
return ErrInvalidRules
|
||||||
}
|
}
|
||||||
@@ -152,7 +148,7 @@ func makeFilter(rules []NativeRule, flags ExportFlag, p *[]byte) error {
|
|||||||
res, err := C.hakurei_scmp_make_filter(
|
res, err := C.hakurei_scmp_make_filter(
|
||||||
&ret, C.uintptr_t(allocateP),
|
&ret, C.uintptr_t(allocateP),
|
||||||
arch, multiarch,
|
arch, multiarch,
|
||||||
(*C.struct_hakurei_syscall_rule)(unsafe.Pointer(&rules[0])),
|
(*syscallRule)(unsafe.Pointer(&rules[0])),
|
||||||
C.size_t(len(rules)),
|
C.size_t(len(rules)),
|
||||||
flags,
|
flags,
|
||||||
)
|
)
|
||||||
@@ -167,20 +163,27 @@ func makeFilter(rules []NativeRule, flags ExportFlag, p *[]byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export generates a bpf program from a slice of [NativeRule].
|
// Export generates a bpf program from a slice of [std.NativeRule].
|
||||||
// Errors returned by libseccomp is wrapped in [LibraryError].
|
// Errors returned by libseccomp is wrapped in [LibraryError].
|
||||||
func Export(rules []NativeRule, flags ExportFlag) (data []byte, err error) {
|
func Export(rules []std.NativeRule, flags ExportFlag) (data []byte, err error) {
|
||||||
err = makeFilter(rules, flags, &data)
|
err = makeFilter(rules, flags, &data)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load generates a bpf program from a slice of [NativeRule] and enforces it on the current process.
|
// Load generates a bpf program from a slice of [std.NativeRule] and enforces it on the current process.
|
||||||
// Errors returned by libseccomp is wrapped in [LibraryError].
|
// Errors returned by libseccomp is wrapped in [LibraryError].
|
||||||
func Load(rules []NativeRule, flags ExportFlag) error { return makeFilter(rules, flags, nil) }
|
func Load(rules []std.NativeRule, flags ExportFlag) error { return makeFilter(rules, flags, nil) }
|
||||||
|
|
||||||
// ScmpCompare is the equivalent of scmp_compare;
|
type (
|
||||||
// Comparison operators
|
// Comparison operators.
|
||||||
type ScmpCompare = C.enum_scmp_compare
|
scmpCompare = C.enum_scmp_compare
|
||||||
|
|
||||||
|
// Argument datum.
|
||||||
|
scmpDatum = C.scmp_datum_t
|
||||||
|
|
||||||
|
// Argument / Value comparison definition.
|
||||||
|
scmpArgCmp = C.struct_scmp_arg_cmp
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_SCMP_CMP_MIN = C._SCMP_CMP_MIN
|
_SCMP_CMP_MIN = C._SCMP_CMP_MIN
|
||||||
@@ -203,33 +206,19 @@ const (
|
|||||||
_SCMP_CMP_MAX = C._SCMP_CMP_MAX
|
_SCMP_CMP_MAX = C._SCMP_CMP_MAX
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScmpDatum is the equivalent of scmp_datum_t;
|
|
||||||
// Argument datum
|
|
||||||
type ScmpDatum uint64
|
|
||||||
|
|
||||||
// ScmpArgCmp is the equivalent of struct scmp_arg_cmp;
|
|
||||||
// Argument / Value comparison definition
|
|
||||||
type ScmpArgCmp struct {
|
|
||||||
// argument number, starting at 0
|
|
||||||
Arg C.uint
|
|
||||||
// the comparison op, e.g. SCMP_CMP_*
|
|
||||||
Op ScmpCompare
|
|
||||||
|
|
||||||
DatumA, DatumB ScmpDatum
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// PersonaLinux is passed in a [ScmpDatum] for filtering calls to syscall.SYS_PERSONALITY.
|
// PersonaLinux is passed in a [std.ScmpDatum] for filtering calls to syscall.SYS_PERSONALITY.
|
||||||
PersonaLinux = C.PER_LINUX
|
PersonaLinux = C.PER_LINUX
|
||||||
// PersonaLinux32 is passed in a [ScmpDatum] for filtering calls to syscall.SYS_PERSONALITY.
|
// PersonaLinux32 is passed in a [std.ScmpDatum] for filtering calls to syscall.SYS_PERSONALITY.
|
||||||
PersonaLinux32 = C.PER_LINUX32
|
PersonaLinux32 = C.PER_LINUX32
|
||||||
)
|
)
|
||||||
|
|
||||||
// syscallResolveName resolves a syscall number by name via seccomp_syscall_resolve_name.
|
// syscallResolveName resolves a syscall number by name via seccomp_syscall_resolve_name.
|
||||||
// This function is only for testing the lookup tables and included here for convenience.
|
// This function is only for testing the lookup tables and included here for convenience.
|
||||||
func syscallResolveName(s string) (trap int) {
|
func syscallResolveName(s string) (num std.ScmpSyscall, ok bool) {
|
||||||
v := C.CString(s)
|
v := C.CString(s)
|
||||||
trap = int(C.seccomp_syscall_resolve_name(v))
|
num = std.ScmpSyscall(C.seccomp_syscall_resolve_name(v))
|
||||||
C.free(unsafe.Pointer(v))
|
C.free(unsafe.Pointer(v))
|
||||||
|
ok = num != C.__NR_SCMP_ERROR
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
. "hakurei.app/container/comp"
|
|
||||||
. "hakurei.app/container/seccomp"
|
. "hakurei.app/container/seccomp"
|
||||||
|
. "hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLibraryError(t *testing.T) {
|
func TestLibraryError(t *testing.T) {
|
||||||
|
|||||||
@@ -5,32 +5,32 @@ package seccomp
|
|||||||
import (
|
import (
|
||||||
. "syscall"
|
. "syscall"
|
||||||
|
|
||||||
"hakurei.app/container/comp"
|
. "hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Preset(presets comp.FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
func Preset(presets FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
||||||
allowedPersonality := PersonaLinux
|
allowedPersonality := PersonaLinux
|
||||||
if presets&comp.PresetLinux32 != 0 {
|
if presets&PresetLinux32 != 0 {
|
||||||
allowedPersonality = PersonaLinux32
|
allowedPersonality = PersonaLinux32
|
||||||
}
|
}
|
||||||
presetDevelFinal := presetDevel(ScmpDatum(allowedPersonality))
|
presetDevelFinal := presetDevel(ScmpDatum(allowedPersonality))
|
||||||
|
|
||||||
l := len(presetCommon)
|
l := len(presetCommon)
|
||||||
if presets&comp.PresetDenyNS != 0 {
|
if presets&PresetDenyNS != 0 {
|
||||||
l += len(presetNamespace)
|
l += len(presetNamespace)
|
||||||
}
|
}
|
||||||
if presets&comp.PresetDenyTTY != 0 {
|
if presets&PresetDenyTTY != 0 {
|
||||||
l += len(presetTTY)
|
l += len(presetTTY)
|
||||||
}
|
}
|
||||||
if presets&comp.PresetDenyDevel != 0 {
|
if presets&PresetDenyDevel != 0 {
|
||||||
l += len(presetDevelFinal)
|
l += len(presetDevelFinal)
|
||||||
}
|
}
|
||||||
if flags&AllowMultiarch == 0 {
|
if flags&AllowMultiarch == 0 {
|
||||||
l += len(presetEmu)
|
l += len(presetEmu)
|
||||||
}
|
}
|
||||||
if presets&comp.PresetExt != 0 {
|
if presets&PresetExt != 0 {
|
||||||
l += len(presetCommonExt)
|
l += len(presetCommonExt)
|
||||||
if presets&comp.PresetDenyNS != 0 {
|
if presets&PresetDenyNS != 0 {
|
||||||
l += len(presetNamespaceExt)
|
l += len(presetNamespaceExt)
|
||||||
}
|
}
|
||||||
if flags&AllowMultiarch == 0 {
|
if flags&AllowMultiarch == 0 {
|
||||||
@@ -40,21 +40,21 @@ func Preset(presets comp.FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
|||||||
|
|
||||||
rules = make([]NativeRule, 0, l)
|
rules = make([]NativeRule, 0, l)
|
||||||
rules = append(rules, presetCommon...)
|
rules = append(rules, presetCommon...)
|
||||||
if presets&comp.PresetDenyNS != 0 {
|
if presets&PresetDenyNS != 0 {
|
||||||
rules = append(rules, presetNamespace...)
|
rules = append(rules, presetNamespace...)
|
||||||
}
|
}
|
||||||
if presets&comp.PresetDenyTTY != 0 {
|
if presets&PresetDenyTTY != 0 {
|
||||||
rules = append(rules, presetTTY...)
|
rules = append(rules, presetTTY...)
|
||||||
}
|
}
|
||||||
if presets&comp.PresetDenyDevel != 0 {
|
if presets&PresetDenyDevel != 0 {
|
||||||
rules = append(rules, presetDevelFinal...)
|
rules = append(rules, presetDevelFinal...)
|
||||||
}
|
}
|
||||||
if flags&AllowMultiarch == 0 {
|
if flags&AllowMultiarch == 0 {
|
||||||
rules = append(rules, presetEmu...)
|
rules = append(rules, presetEmu...)
|
||||||
}
|
}
|
||||||
if presets&comp.PresetExt != 0 {
|
if presets&PresetExt != 0 {
|
||||||
rules = append(rules, presetCommonExt...)
|
rules = append(rules, presetCommonExt...)
|
||||||
if presets&comp.PresetDenyNS != 0 {
|
if presets&PresetDenyNS != 0 {
|
||||||
rules = append(rules, presetNamespaceExt...)
|
rules = append(rules, presetNamespaceExt...)
|
||||||
}
|
}
|
||||||
if flags&AllowMultiarch == 0 {
|
if flags&AllowMultiarch == 0 {
|
||||||
@@ -68,121 +68,121 @@ func Preset(presets comp.FilterPreset, flags ExportFlag) (rules []NativeRule) {
|
|||||||
var (
|
var (
|
||||||
presetCommon = []NativeRule{
|
presetCommon = []NativeRule{
|
||||||
/* Block dmesg */
|
/* Block dmesg */
|
||||||
{ScmpSyscall(SYS_SYSLOG), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SYSLOG, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
/* Useless old syscall */
|
/* Useless old syscall */
|
||||||
{ScmpSyscall(SYS_USELIB), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_USELIB, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
/* Don't allow disabling accounting */
|
/* Don't allow disabling accounting */
|
||||||
{ScmpSyscall(SYS_ACCT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_ACCT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
/* Don't allow reading current quota use */
|
/* Don't allow reading current quota use */
|
||||||
{ScmpSyscall(SYS_QUOTACTL), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_QUOTACTL, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
|
|
||||||
/* Don't allow access to the kernel keyring */
|
/* Don't allow access to the kernel keyring */
|
||||||
{ScmpSyscall(SYS_ADD_KEY), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_ADD_KEY, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_KEYCTL), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_KEYCTL, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_REQUEST_KEY), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_REQUEST_KEY, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
|
|
||||||
/* Scary VM/NUMA ops */
|
/* Scary VM/NUMA ops */
|
||||||
{ScmpSyscall(SYS_MOVE_PAGES), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_MOVE_PAGES, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_MBIND), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_MBIND, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_GET_MEMPOLICY), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_GET_MEMPOLICY, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SET_MEMPOLICY), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SET_MEMPOLICY, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_MIGRATE_PAGES), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_MIGRATE_PAGES, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hakurei: project-specific extensions */
|
/* hakurei: project-specific extensions */
|
||||||
presetCommonExt = []NativeRule{
|
presetCommonExt = []NativeRule{
|
||||||
/* system calls for changing the system clock */
|
/* system calls for changing the system clock */
|
||||||
{ScmpSyscall(SYS_ADJTIMEX), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_ADJTIMEX, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CLOCK_ADJTIME), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CLOCK_ADJTIME, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CLOCK_ADJTIME64), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CLOCK_ADJTIME64, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CLOCK_SETTIME), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CLOCK_SETTIME, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CLOCK_SETTIME64), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CLOCK_SETTIME64, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETTIMEOFDAY), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETTIMEOFDAY, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
|
|
||||||
/* loading and unloading of kernel modules */
|
/* loading and unloading of kernel modules */
|
||||||
{ScmpSyscall(SYS_DELETE_MODULE), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_DELETE_MODULE, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FINIT_MODULE), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_FINIT_MODULE, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_INIT_MODULE), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_INIT_MODULE, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
|
|
||||||
/* system calls for rebooting and reboot preparation */
|
/* system calls for rebooting and reboot preparation */
|
||||||
{ScmpSyscall(SYS_KEXEC_FILE_LOAD), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_KEXEC_FILE_LOAD, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_KEXEC_LOAD), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_KEXEC_LOAD, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_REBOOT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_REBOOT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
|
|
||||||
/* system calls for enabling/disabling swap devices */
|
/* system calls for enabling/disabling swap devices */
|
||||||
{ScmpSyscall(SYS_SWAPOFF), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SWAPOFF, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SWAPON), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SWAPON, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
presetNamespace = []NativeRule{
|
presetNamespace = []NativeRule{
|
||||||
/* Don't allow subnamespace setups: */
|
/* Don't allow subnamespace setups: */
|
||||||
{ScmpSyscall(SYS_UNSHARE), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_UNSHARE, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETNS), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETNS, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_MOUNT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_MOUNT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_UMOUNT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_UMOUNT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_UMOUNT2), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_UMOUNT2, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_PIVOT_ROOT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_PIVOT_ROOT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CHROOT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CHROOT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CLONE), ScmpErrno(EPERM),
|
{Syscall: SNR_CLONE, Errno: ScmpErrno(EPERM),
|
||||||
&ScmpArgCmp{cloneArg, SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, CLONE_NEWUSER}},
|
Arg: &ScmpArgCmp{Arg: cloneArg, Op: SCMP_CMP_MASKED_EQ, DatumA: CLONE_NEWUSER, DatumB: CLONE_NEWUSER}},
|
||||||
|
|
||||||
/* seccomp can't look into clone3()'s struct clone_args to check whether
|
/* seccomp can't look into clone3()'s struct clone_args to check whether
|
||||||
* the flags are OK, so we have no choice but to block clone3().
|
* the flags are OK, so we have no choice but to block clone3().
|
||||||
* Return ENOSYS so user-space will fall back to clone().
|
* Return ENOSYS so user-space will fall back to clone().
|
||||||
* (CVE-2021-41133; see also https://github.com/moby/moby/commit/9f6b562d)
|
* (CVE-2021-41133; see also https://github.com/moby/moby/commit/9f6b562d)
|
||||||
*/
|
*/
|
||||||
{ScmpSyscall(SYS_CLONE3), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_CLONE3, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
|
|
||||||
/* New mount manipulation APIs can also change our VFS. There's no
|
/* New mount manipulation APIs can also change our VFS. There's no
|
||||||
* legitimate reason to do these in the sandbox, so block all of them
|
* legitimate reason to do these in the sandbox, so block all of them
|
||||||
* rather than thinking about which ones might be dangerous.
|
* rather than thinking about which ones might be dangerous.
|
||||||
* (CVE-2021-41133) */
|
* (CVE-2021-41133) */
|
||||||
{ScmpSyscall(SYS_OPEN_TREE), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_OPEN_TREE, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_MOVE_MOUNT), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_MOVE_MOUNT, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FSOPEN), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_FSOPEN, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FSCONFIG), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_FSCONFIG, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FSMOUNT), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_FSMOUNT, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FSPICK), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_FSPICK, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_MOUNT_SETATTR), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_MOUNT_SETATTR, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hakurei: project-specific extensions */
|
/* hakurei: project-specific extensions */
|
||||||
presetNamespaceExt = []NativeRule{
|
presetNamespaceExt = []NativeRule{
|
||||||
/* changing file ownership */
|
/* changing file ownership */
|
||||||
{ScmpSyscall(SYS_CHOWN), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CHOWN, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_CHOWN32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_CHOWN32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FCHOWN), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_FCHOWN, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FCHOWN32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_FCHOWN32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_FCHOWNAT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_FCHOWNAT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_LCHOWN), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_LCHOWN, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_LCHOWN32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_LCHOWN32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
|
|
||||||
/* system calls for changing user ID and group ID credentials */
|
/* system calls for changing user ID and group ID credentials */
|
||||||
{ScmpSyscall(SYS_SETGID), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETGID, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETGID32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETGID32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETGROUPS), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETGROUPS, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETGROUPS32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETGROUPS32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETREGID), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETREGID, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETREGID32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETREGID32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETRESGID), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETRESGID, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETRESGID32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETRESGID32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETRESUID), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETRESUID, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETRESUID32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETRESUID32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETREUID), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETREUID, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETREUID32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETREUID32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETUID), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETUID, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SETUID32), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_SETUID32, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
presetTTY = []NativeRule{
|
presetTTY = []NativeRule{
|
||||||
/* Don't allow faking input to the controlling tty (CVE-2017-5226) */
|
/* Don't allow faking input to the controlling tty (CVE-2017-5226) */
|
||||||
{ScmpSyscall(SYS_IOCTL), ScmpErrno(EPERM),
|
{Syscall: SNR_IOCTL, Errno: ScmpErrno(EPERM),
|
||||||
&ScmpArgCmp{1, SCMP_CMP_MASKED_EQ, 0xFFFFFFFF, TIOCSTI}},
|
Arg: &ScmpArgCmp{Arg: 1, Op: SCMP_CMP_MASKED_EQ, DatumA: 0xFFFFFFFF, DatumB: TIOCSTI}},
|
||||||
/* In the unlikely event that the controlling tty is a Linux virtual
|
/* In the unlikely event that the controlling tty is a Linux virtual
|
||||||
* console (/dev/tty2 or similar), copy/paste operations have an effect
|
* console (/dev/tty2 or similar), copy/paste operations have an effect
|
||||||
* similar to TIOCSTI (CVE-2023-28100) */
|
* similar to TIOCSTI (CVE-2023-28100) */
|
||||||
{ScmpSyscall(SYS_IOCTL), ScmpErrno(EPERM),
|
{Syscall: SNR_IOCTL, Errno: ScmpErrno(EPERM),
|
||||||
&ScmpArgCmp{1, SCMP_CMP_MASKED_EQ, 0xFFFFFFFF, TIOCLINUX}},
|
Arg: &ScmpArgCmp{Arg: 1, Op: SCMP_CMP_MASKED_EQ, DatumA: 0xFFFFFFFF, DatumB: TIOCLINUX}},
|
||||||
}
|
}
|
||||||
|
|
||||||
presetEmu = []NativeRule{
|
presetEmu = []NativeRule{
|
||||||
@@ -190,15 +190,15 @@ var (
|
|||||||
* so it's disabled as a hardening measure.
|
* so it's disabled as a hardening measure.
|
||||||
* However, it is required to run old 16-bit applications
|
* However, it is required to run old 16-bit applications
|
||||||
* as well as some Wine patches, so it's allowed in multiarch. */
|
* as well as some Wine patches, so it's allowed in multiarch. */
|
||||||
{ScmpSyscall(SYS_MODIFY_LDT), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_MODIFY_LDT, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
/* hakurei: project-specific extensions */
|
/* hakurei: project-specific extensions */
|
||||||
presetEmuExt = []NativeRule{
|
presetEmuExt = []NativeRule{
|
||||||
{ScmpSyscall(SYS_SUBPAGE_PROT), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_SUBPAGE_PROT, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_SWITCH_ENDIAN), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_SWITCH_ENDIAN, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_VM86), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_VM86, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
{ScmpSyscall(SYS_VM86OLD), ScmpErrno(ENOSYS), nil},
|
{Syscall: SNR_VM86OLD, Errno: ScmpErrno(ENOSYS), Arg: nil},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -206,11 +206,11 @@ func presetDevel(allowedPersonality ScmpDatum) []NativeRule {
|
|||||||
return []NativeRule{
|
return []NativeRule{
|
||||||
/* Profiling operations; we expect these to be done by tools from outside
|
/* Profiling operations; we expect these to be done by tools from outside
|
||||||
* the sandbox. In particular perf has been the source of many CVEs. */
|
* the sandbox. In particular perf has been the source of many CVEs. */
|
||||||
{ScmpSyscall(SYS_PERF_EVENT_OPEN), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_PERF_EVENT_OPEN, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
/* Don't allow you to switch to bsd emulation or whatnot */
|
/* Don't allow you to switch to bsd emulation or whatnot */
|
||||||
{ScmpSyscall(SYS_PERSONALITY), ScmpErrno(EPERM),
|
{Syscall: SNR_PERSONALITY, Errno: ScmpErrno(EPERM),
|
||||||
&ScmpArgCmp{0, SCMP_CMP_NE, allowedPersonality, 0}},
|
Arg: &ScmpArgCmp{Arg: 0, Op: SCMP_CMP_NE, DatumA: allowedPersonality}},
|
||||||
|
|
||||||
{ScmpSyscall(SYS_PTRACE), ScmpErrno(EPERM), nil},
|
{Syscall: SNR_PTRACE, Errno: ScmpErrno(EPERM), Arg: nil},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
container/seccomp/presets_386_test.go
Normal file
27
container/seccomp/presets_386_test.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package seccomp_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "hakurei.app/container/seccomp"
|
||||||
|
. "hakurei.app/container/std"
|
||||||
|
)
|
||||||
|
|
||||||
|
var bpfExpected = bpfLookup{
|
||||||
|
{AllowMultiarch | AllowCAN |
|
||||||
|
AllowBluetooth, PresetExt |
|
||||||
|
PresetDenyNS | PresetDenyTTY | PresetDenyDevel |
|
||||||
|
PresetLinux32}: toHash(
|
||||||
|
"e67735d24caba42b6801e829ea4393727a36c5e37b8a51e5648e7886047e8454484ff06872aaef810799c29cbd0c1b361f423ad0ef518e33f68436372cc90eb1"),
|
||||||
|
|
||||||
|
{0, 0}: toHash(
|
||||||
|
"5dbcc08a4a1ccd8c12dd0cf6d9817ea6d4f40246e1db7a60e71a50111c4897d69f6fb6d710382d70c18910c2e4fa2d2aeb2daed835dd2fabe3f71def628ade59"),
|
||||||
|
{0, PresetExt}: toHash(
|
||||||
|
"d6c0f130dbb5c793d1c10f730455701875778138bd2d03ca009d674842fd97a10815a8c539b76b7801a73de19463938701216b756c053ec91cfe304cba04a0ed"),
|
||||||
|
{0, PresetStrict}: toHash(
|
||||||
|
"af7d7b66f2e83f9a850472170c1b83d1371426faa9d0dee4e85b179d3ec75ca92828cb8529eb3012b559497494b2eab4d4b140605e3a26c70dfdbe5efe33c105"),
|
||||||
|
{0, PresetDenyNS | PresetDenyTTY | PresetDenyDevel}: toHash(
|
||||||
|
"adfb4397e6eeae8c477d315d58204aae854d60071687b8df4c758e297780e02deee1af48328cef80e16e4d6ab1a66ef13e42247c3475cf447923f15cbc17a6a6"),
|
||||||
|
{0, PresetExt | PresetDenyDevel}: toHash(
|
||||||
|
"5d641321460cf54a7036a40a08e845082e1f6d65b9dee75db85ef179f2732f321b16aee2258b74273b04e0d24562e8b1e727930a7e787f41eb5c8aaa0bc22793"),
|
||||||
|
{0, PresetExt | PresetDenyNS | PresetDenyDevel}: toHash(
|
||||||
|
"b1f802d39de5897b1e4cb0e82a199f53df0a803ea88e2fd19491fb8c90387c9e2eaa7e323f565fecaa0202a579eb050531f22e6748e04cfd935b8faac35983ec"),
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package seccomp_test
|
package seccomp_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "hakurei.app/container/comp"
|
|
||||||
. "hakurei.app/container/seccomp"
|
. "hakurei.app/container/seccomp"
|
||||||
|
. "hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bpfExpected = bpfLookup{
|
var bpfExpected = bpfLookup{
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package seccomp_test
|
package seccomp_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "hakurei.app/container/comp"
|
|
||||||
. "hakurei.app/container/seccomp"
|
. "hakurei.app/container/seccomp"
|
||||||
|
. "hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
var bpfExpected = bpfLookup{
|
var bpfExpected = bpfLookup{
|
||||||
@@ -4,14 +4,14 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
|
||||||
"hakurei.app/container/comp"
|
|
||||||
"hakurei.app/container/seccomp"
|
"hakurei.app/container/seccomp"
|
||||||
|
"hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
bpfPreset = struct {
|
bpfPreset = struct {
|
||||||
seccomp.ExportFlag
|
seccomp.ExportFlag
|
||||||
comp.FilterPreset
|
std.FilterPreset
|
||||||
}
|
}
|
||||||
bpfLookup map[bpfPreset][sha512.Size]byte
|
bpfLookup map[bpfPreset][sha512.Size]byte
|
||||||
)
|
)
|
||||||
63
container/seccomp/std_test.go
Normal file
63
container/seccomp/std_test.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package seccomp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"hakurei.app/container/std"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSyscallResolveName(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for name, want := range std.Syscalls() {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// this checks the std implementation against libseccomp.
|
||||||
|
if got, ok := syscallResolveName(name); !ok || got != want {
|
||||||
|
t.Errorf("syscallResolveName(%q) = %d, want %d", name, got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRuleType(t *testing.T) {
|
||||||
|
assertKind[std.ScmpUint, scmpUint](t)
|
||||||
|
assertKind[std.ScmpInt, scmpInt](t)
|
||||||
|
|
||||||
|
assertSize[std.NativeRule, syscallRule](t)
|
||||||
|
assertKind[std.ScmpDatum, scmpDatum](t)
|
||||||
|
assertKind[std.ScmpCompare, scmpCompare](t)
|
||||||
|
assertSize[std.ScmpArgCmp, scmpArgCmp](t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertSize asserts that native and equivalent are of the same size.
|
||||||
|
func assertSize[native, equivalent any](t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
got, want := unsafe.Sizeof(*new(native)), unsafe.Sizeof(*new(equivalent))
|
||||||
|
if got != want {
|
||||||
|
t.Fatalf("%s: %d, want %d", reflect.TypeFor[native]().Name(), got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// assertKind asserts that native and equivalent are of the same kind.
|
||||||
|
func assertKind[native, equivalent any](t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
assertSize[native, equivalent](t)
|
||||||
|
nativeType, equivalentType := reflect.TypeFor[native](), reflect.TypeFor[equivalent]()
|
||||||
|
got, want := nativeType.Kind(), equivalentType.Kind()
|
||||||
|
|
||||||
|
if got == reflect.Invalid || want == reflect.Invalid {
|
||||||
|
t.Fatalf("%s: invalid call to assertKind", nativeType.Name())
|
||||||
|
}
|
||||||
|
if got == reflect.Struct {
|
||||||
|
t.Fatalf("%s: struct is unsupported by assertKind", nativeType.Name())
|
||||||
|
}
|
||||||
|
if got != want {
|
||||||
|
t.Fatalf("%s: %s, want %s", nativeType.Name(), nativeType.Kind(), equivalentType.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package seccomp
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo linux pkg-config: --static libseccomp
|
|
||||||
|
|
||||||
#include <seccomp.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
var syscallNumExtra = map[string]int{
|
|
||||||
"umount": SYS_UMOUNT,
|
|
||||||
"subpage_prot": SYS_SUBPAGE_PROT,
|
|
||||||
"switch_endian": SYS_SWITCH_ENDIAN,
|
|
||||||
"vm86": SYS_VM86,
|
|
||||||
"vm86old": SYS_VM86OLD,
|
|
||||||
"clock_adjtime64": SYS_CLOCK_ADJTIME64,
|
|
||||||
"clock_settime64": SYS_CLOCK_SETTIME64,
|
|
||||||
"chown32": SYS_CHOWN32,
|
|
||||||
"fchown32": SYS_FCHOWN32,
|
|
||||||
"lchown32": SYS_LCHOWN32,
|
|
||||||
"setgid32": SYS_SETGID32,
|
|
||||||
"setgroups32": SYS_SETGROUPS32,
|
|
||||||
"setregid32": SYS_SETREGID32,
|
|
||||||
"setresgid32": SYS_SETRESGID32,
|
|
||||||
"setresuid32": SYS_SETRESUID32,
|
|
||||||
"setreuid32": SYS_SETREUID32,
|
|
||||||
"setuid32": SYS_SETUID32,
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
SYS_UMOUNT = C.__SNR_umount
|
|
||||||
SYS_SUBPAGE_PROT = C.__SNR_subpage_prot
|
|
||||||
SYS_SWITCH_ENDIAN = C.__SNR_switch_endian
|
|
||||||
SYS_VM86 = C.__SNR_vm86
|
|
||||||
SYS_VM86OLD = C.__SNR_vm86old
|
|
||||||
SYS_CLOCK_ADJTIME64 = C.__SNR_clock_adjtime64
|
|
||||||
SYS_CLOCK_SETTIME64 = C.__SNR_clock_settime64
|
|
||||||
SYS_CHOWN32 = C.__SNR_chown32
|
|
||||||
SYS_FCHOWN32 = C.__SNR_fchown32
|
|
||||||
SYS_LCHOWN32 = C.__SNR_lchown32
|
|
||||||
SYS_SETGID32 = C.__SNR_setgid32
|
|
||||||
SYS_SETGROUPS32 = C.__SNR_setgroups32
|
|
||||||
SYS_SETREGID32 = C.__SNR_setregid32
|
|
||||||
SYS_SETRESGID32 = C.__SNR_setresgid32
|
|
||||||
SYS_SETRESUID32 = C.__SNR_setresuid32
|
|
||||||
SYS_SETREUID32 = C.__SNR_setreuid32
|
|
||||||
SYS_SETUID32 = C.__SNR_setuid32
|
|
||||||
)
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package seccomp
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo linux pkg-config: --static libseccomp
|
|
||||||
|
|
||||||
#include <seccomp.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import "syscall"
|
|
||||||
|
|
||||||
const (
|
|
||||||
SYS_NEWFSTATAT = syscall.SYS_FSTATAT
|
|
||||||
)
|
|
||||||
|
|
||||||
var syscallNumExtra = map[string]int{
|
|
||||||
"uselib": SYS_USELIB,
|
|
||||||
"clock_adjtime64": SYS_CLOCK_ADJTIME64,
|
|
||||||
"clock_settime64": SYS_CLOCK_SETTIME64,
|
|
||||||
"umount": SYS_UMOUNT,
|
|
||||||
"chown": SYS_CHOWN,
|
|
||||||
"chown32": SYS_CHOWN32,
|
|
||||||
"fchown32": SYS_FCHOWN32,
|
|
||||||
"lchown": SYS_LCHOWN,
|
|
||||||
"lchown32": SYS_LCHOWN32,
|
|
||||||
"setgid32": SYS_SETGID32,
|
|
||||||
"setgroups32": SYS_SETGROUPS32,
|
|
||||||
"setregid32": SYS_SETREGID32,
|
|
||||||
"setresgid32": SYS_SETRESGID32,
|
|
||||||
"setresuid32": SYS_SETRESUID32,
|
|
||||||
"setreuid32": SYS_SETREUID32,
|
|
||||||
"setuid32": SYS_SETUID32,
|
|
||||||
"modify_ldt": SYS_MODIFY_LDT,
|
|
||||||
"subpage_prot": SYS_SUBPAGE_PROT,
|
|
||||||
"switch_endian": SYS_SWITCH_ENDIAN,
|
|
||||||
"vm86": SYS_VM86,
|
|
||||||
"vm86old": SYS_VM86OLD,
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
SYS_USELIB = C.__SNR_uselib
|
|
||||||
SYS_CLOCK_ADJTIME64 = C.__SNR_clock_adjtime64
|
|
||||||
SYS_CLOCK_SETTIME64 = C.__SNR_clock_settime64
|
|
||||||
SYS_UMOUNT = C.__SNR_umount
|
|
||||||
SYS_CHOWN = C.__SNR_chown
|
|
||||||
SYS_CHOWN32 = C.__SNR_chown32
|
|
||||||
SYS_FCHOWN32 = C.__SNR_fchown32
|
|
||||||
SYS_LCHOWN = C.__SNR_lchown
|
|
||||||
SYS_LCHOWN32 = C.__SNR_lchown32
|
|
||||||
SYS_SETGID32 = C.__SNR_setgid32
|
|
||||||
SYS_SETGROUPS32 = C.__SNR_setgroups32
|
|
||||||
SYS_SETREGID32 = C.__SNR_setregid32
|
|
||||||
SYS_SETRESGID32 = C.__SNR_setresgid32
|
|
||||||
SYS_SETRESUID32 = C.__SNR_setresuid32
|
|
||||||
SYS_SETREUID32 = C.__SNR_setreuid32
|
|
||||||
SYS_SETUID32 = C.__SNR_setuid32
|
|
||||||
SYS_MODIFY_LDT = C.__SNR_modify_ldt
|
|
||||||
SYS_SUBPAGE_PROT = C.__SNR_subpage_prot
|
|
||||||
SYS_SWITCH_ENDIAN = C.__SNR_switch_endian
|
|
||||||
SYS_VM86 = C.__SNR_vm86
|
|
||||||
SYS_VM86OLD = C.__SNR_vm86old
|
|
||||||
)
|
|
||||||
@@ -1,459 +0,0 @@
|
|||||||
// mksysnum_linux.pl /usr/include/asm/unistd_64.h
|
|
||||||
// Code generated by the command above; DO NOT EDIT.
|
|
||||||
|
|
||||||
package seccomp
|
|
||||||
|
|
||||||
import . "syscall"
|
|
||||||
|
|
||||||
var syscallNum = map[string]int{
|
|
||||||
"read": SYS_READ,
|
|
||||||
"write": SYS_WRITE,
|
|
||||||
"open": SYS_OPEN,
|
|
||||||
"close": SYS_CLOSE,
|
|
||||||
"stat": SYS_STAT,
|
|
||||||
"fstat": SYS_FSTAT,
|
|
||||||
"lstat": SYS_LSTAT,
|
|
||||||
"poll": SYS_POLL,
|
|
||||||
"lseek": SYS_LSEEK,
|
|
||||||
"mmap": SYS_MMAP,
|
|
||||||
"mprotect": SYS_MPROTECT,
|
|
||||||
"munmap": SYS_MUNMAP,
|
|
||||||
"brk": SYS_BRK,
|
|
||||||
"rt_sigaction": SYS_RT_SIGACTION,
|
|
||||||
"rt_sigprocmask": SYS_RT_SIGPROCMASK,
|
|
||||||
"rt_sigreturn": SYS_RT_SIGRETURN,
|
|
||||||
"ioctl": SYS_IOCTL,
|
|
||||||
"pread64": SYS_PREAD64,
|
|
||||||
"pwrite64": SYS_PWRITE64,
|
|
||||||
"readv": SYS_READV,
|
|
||||||
"writev": SYS_WRITEV,
|
|
||||||
"access": SYS_ACCESS,
|
|
||||||
"pipe": SYS_PIPE,
|
|
||||||
"select": SYS_SELECT,
|
|
||||||
"sched_yield": SYS_SCHED_YIELD,
|
|
||||||
"mremap": SYS_MREMAP,
|
|
||||||
"msync": SYS_MSYNC,
|
|
||||||
"mincore": SYS_MINCORE,
|
|
||||||
"madvise": SYS_MADVISE,
|
|
||||||
"shmget": SYS_SHMGET,
|
|
||||||
"shmat": SYS_SHMAT,
|
|
||||||
"shmctl": SYS_SHMCTL,
|
|
||||||
"dup": SYS_DUP,
|
|
||||||
"dup2": SYS_DUP2,
|
|
||||||
"pause": SYS_PAUSE,
|
|
||||||
"nanosleep": SYS_NANOSLEEP,
|
|
||||||
"getitimer": SYS_GETITIMER,
|
|
||||||
"alarm": SYS_ALARM,
|
|
||||||
"setitimer": SYS_SETITIMER,
|
|
||||||
"getpid": SYS_GETPID,
|
|
||||||
"sendfile": SYS_SENDFILE,
|
|
||||||
"socket": SYS_SOCKET,
|
|
||||||
"connect": SYS_CONNECT,
|
|
||||||
"accept": SYS_ACCEPT,
|
|
||||||
"sendto": SYS_SENDTO,
|
|
||||||
"recvfrom": SYS_RECVFROM,
|
|
||||||
"sendmsg": SYS_SENDMSG,
|
|
||||||
"recvmsg": SYS_RECVMSG,
|
|
||||||
"shutdown": SYS_SHUTDOWN,
|
|
||||||
"bind": SYS_BIND,
|
|
||||||
"listen": SYS_LISTEN,
|
|
||||||
"getsockname": SYS_GETSOCKNAME,
|
|
||||||
"getpeername": SYS_GETPEERNAME,
|
|
||||||
"socketpair": SYS_SOCKETPAIR,
|
|
||||||
"setsockopt": SYS_SETSOCKOPT,
|
|
||||||
"getsockopt": SYS_GETSOCKOPT,
|
|
||||||
"clone": SYS_CLONE,
|
|
||||||
"fork": SYS_FORK,
|
|
||||||
"vfork": SYS_VFORK,
|
|
||||||
"execve": SYS_EXECVE,
|
|
||||||
"exit": SYS_EXIT,
|
|
||||||
"wait4": SYS_WAIT4,
|
|
||||||
"kill": SYS_KILL,
|
|
||||||
"uname": SYS_UNAME,
|
|
||||||
"semget": SYS_SEMGET,
|
|
||||||
"semop": SYS_SEMOP,
|
|
||||||
"semctl": SYS_SEMCTL,
|
|
||||||
"shmdt": SYS_SHMDT,
|
|
||||||
"msgget": SYS_MSGGET,
|
|
||||||
"msgsnd": SYS_MSGSND,
|
|
||||||
"msgrcv": SYS_MSGRCV,
|
|
||||||
"msgctl": SYS_MSGCTL,
|
|
||||||
"fcntl": SYS_FCNTL,
|
|
||||||
"flock": SYS_FLOCK,
|
|
||||||
"fsync": SYS_FSYNC,
|
|
||||||
"fdatasync": SYS_FDATASYNC,
|
|
||||||
"truncate": SYS_TRUNCATE,
|
|
||||||
"ftruncate": SYS_FTRUNCATE,
|
|
||||||
"getdents": SYS_GETDENTS,
|
|
||||||
"getcwd": SYS_GETCWD,
|
|
||||||
"chdir": SYS_CHDIR,
|
|
||||||
"fchdir": SYS_FCHDIR,
|
|
||||||
"rename": SYS_RENAME,
|
|
||||||
"mkdir": SYS_MKDIR,
|
|
||||||
"rmdir": SYS_RMDIR,
|
|
||||||
"creat": SYS_CREAT,
|
|
||||||
"link": SYS_LINK,
|
|
||||||
"unlink": SYS_UNLINK,
|
|
||||||
"symlink": SYS_SYMLINK,
|
|
||||||
"readlink": SYS_READLINK,
|
|
||||||
"chmod": SYS_CHMOD,
|
|
||||||
"fchmod": SYS_FCHMOD,
|
|
||||||
"chown": SYS_CHOWN,
|
|
||||||
"fchown": SYS_FCHOWN,
|
|
||||||
"lchown": SYS_LCHOWN,
|
|
||||||
"umask": SYS_UMASK,
|
|
||||||
"gettimeofday": SYS_GETTIMEOFDAY,
|
|
||||||
"getrlimit": SYS_GETRLIMIT,
|
|
||||||
"getrusage": SYS_GETRUSAGE,
|
|
||||||
"sysinfo": SYS_SYSINFO,
|
|
||||||
"times": SYS_TIMES,
|
|
||||||
"ptrace": SYS_PTRACE,
|
|
||||||
"getuid": SYS_GETUID,
|
|
||||||
"syslog": SYS_SYSLOG,
|
|
||||||
"getgid": SYS_GETGID,
|
|
||||||
"setuid": SYS_SETUID,
|
|
||||||
"setgid": SYS_SETGID,
|
|
||||||
"geteuid": SYS_GETEUID,
|
|
||||||
"getegid": SYS_GETEGID,
|
|
||||||
"setpgid": SYS_SETPGID,
|
|
||||||
"getppid": SYS_GETPPID,
|
|
||||||
"getpgrp": SYS_GETPGRP,
|
|
||||||
"setsid": SYS_SETSID,
|
|
||||||
"setreuid": SYS_SETREUID,
|
|
||||||
"setregid": SYS_SETREGID,
|
|
||||||
"getgroups": SYS_GETGROUPS,
|
|
||||||
"setgroups": SYS_SETGROUPS,
|
|
||||||
"setresuid": SYS_SETRESUID,
|
|
||||||
"getresuid": SYS_GETRESUID,
|
|
||||||
"setresgid": SYS_SETRESGID,
|
|
||||||
"getresgid": SYS_GETRESGID,
|
|
||||||
"getpgid": SYS_GETPGID,
|
|
||||||
"setfsuid": SYS_SETFSUID,
|
|
||||||
"setfsgid": SYS_SETFSGID,
|
|
||||||
"getsid": SYS_GETSID,
|
|
||||||
"capget": SYS_CAPGET,
|
|
||||||
"capset": SYS_CAPSET,
|
|
||||||
"rt_sigpending": SYS_RT_SIGPENDING,
|
|
||||||
"rt_sigtimedwait": SYS_RT_SIGTIMEDWAIT,
|
|
||||||
"rt_sigqueueinfo": SYS_RT_SIGQUEUEINFO,
|
|
||||||
"rt_sigsuspend": SYS_RT_SIGSUSPEND,
|
|
||||||
"sigaltstack": SYS_SIGALTSTACK,
|
|
||||||
"utime": SYS_UTIME,
|
|
||||||
"mknod": SYS_MKNOD,
|
|
||||||
"uselib": SYS_USELIB,
|
|
||||||
"personality": SYS_PERSONALITY,
|
|
||||||
"ustat": SYS_USTAT,
|
|
||||||
"statfs": SYS_STATFS,
|
|
||||||
"fstatfs": SYS_FSTATFS,
|
|
||||||
"sysfs": SYS_SYSFS,
|
|
||||||
"getpriority": SYS_GETPRIORITY,
|
|
||||||
"setpriority": SYS_SETPRIORITY,
|
|
||||||
"sched_setparam": SYS_SCHED_SETPARAM,
|
|
||||||
"sched_getparam": SYS_SCHED_GETPARAM,
|
|
||||||
"sched_setscheduler": SYS_SCHED_SETSCHEDULER,
|
|
||||||
"sched_getscheduler": SYS_SCHED_GETSCHEDULER,
|
|
||||||
"sched_get_priority_max": SYS_SCHED_GET_PRIORITY_MAX,
|
|
||||||
"sched_get_priority_min": SYS_SCHED_GET_PRIORITY_MIN,
|
|
||||||
"sched_rr_get_interval": SYS_SCHED_RR_GET_INTERVAL,
|
|
||||||
"mlock": SYS_MLOCK,
|
|
||||||
"munlock": SYS_MUNLOCK,
|
|
||||||
"mlockall": SYS_MLOCKALL,
|
|
||||||
"munlockall": SYS_MUNLOCKALL,
|
|
||||||
"vhangup": SYS_VHANGUP,
|
|
||||||
"modify_ldt": SYS_MODIFY_LDT,
|
|
||||||
"pivot_root": SYS_PIVOT_ROOT,
|
|
||||||
"_sysctl": SYS__SYSCTL,
|
|
||||||
"prctl": SYS_PRCTL,
|
|
||||||
"arch_prctl": SYS_ARCH_PRCTL,
|
|
||||||
"adjtimex": SYS_ADJTIMEX,
|
|
||||||
"setrlimit": SYS_SETRLIMIT,
|
|
||||||
"chroot": SYS_CHROOT,
|
|
||||||
"sync": SYS_SYNC,
|
|
||||||
"acct": SYS_ACCT,
|
|
||||||
"settimeofday": SYS_SETTIMEOFDAY,
|
|
||||||
"mount": SYS_MOUNT,
|
|
||||||
"umount2": SYS_UMOUNT2,
|
|
||||||
"swapon": SYS_SWAPON,
|
|
||||||
"swapoff": SYS_SWAPOFF,
|
|
||||||
"reboot": SYS_REBOOT,
|
|
||||||
"sethostname": SYS_SETHOSTNAME,
|
|
||||||
"setdomainname": SYS_SETDOMAINNAME,
|
|
||||||
"iopl": SYS_IOPL,
|
|
||||||
"ioperm": SYS_IOPERM,
|
|
||||||
"create_module": SYS_CREATE_MODULE,
|
|
||||||
"init_module": SYS_INIT_MODULE,
|
|
||||||
"delete_module": SYS_DELETE_MODULE,
|
|
||||||
"get_kernel_syms": SYS_GET_KERNEL_SYMS,
|
|
||||||
"query_module": SYS_QUERY_MODULE,
|
|
||||||
"quotactl": SYS_QUOTACTL,
|
|
||||||
"nfsservctl": SYS_NFSSERVCTL,
|
|
||||||
"getpmsg": SYS_GETPMSG,
|
|
||||||
"putpmsg": SYS_PUTPMSG,
|
|
||||||
"afs_syscall": SYS_AFS_SYSCALL,
|
|
||||||
"tuxcall": SYS_TUXCALL,
|
|
||||||
"security": SYS_SECURITY,
|
|
||||||
"gettid": SYS_GETTID,
|
|
||||||
"readahead": SYS_READAHEAD,
|
|
||||||
"setxattr": SYS_SETXATTR,
|
|
||||||
"lsetxattr": SYS_LSETXATTR,
|
|
||||||
"fsetxattr": SYS_FSETXATTR,
|
|
||||||
"getxattr": SYS_GETXATTR,
|
|
||||||
"lgetxattr": SYS_LGETXATTR,
|
|
||||||
"fgetxattr": SYS_FGETXATTR,
|
|
||||||
"listxattr": SYS_LISTXATTR,
|
|
||||||
"llistxattr": SYS_LLISTXATTR,
|
|
||||||
"flistxattr": SYS_FLISTXATTR,
|
|
||||||
"removexattr": SYS_REMOVEXATTR,
|
|
||||||
"lremovexattr": SYS_LREMOVEXATTR,
|
|
||||||
"fremovexattr": SYS_FREMOVEXATTR,
|
|
||||||
"tkill": SYS_TKILL,
|
|
||||||
"time": SYS_TIME,
|
|
||||||
"futex": SYS_FUTEX,
|
|
||||||
"sched_setaffinity": SYS_SCHED_SETAFFINITY,
|
|
||||||
"sched_getaffinity": SYS_SCHED_GETAFFINITY,
|
|
||||||
"set_thread_area": SYS_SET_THREAD_AREA,
|
|
||||||
"io_setup": SYS_IO_SETUP,
|
|
||||||
"io_destroy": SYS_IO_DESTROY,
|
|
||||||
"io_getevents": SYS_IO_GETEVENTS,
|
|
||||||
"io_submit": SYS_IO_SUBMIT,
|
|
||||||
"io_cancel": SYS_IO_CANCEL,
|
|
||||||
"get_thread_area": SYS_GET_THREAD_AREA,
|
|
||||||
"lookup_dcookie": SYS_LOOKUP_DCOOKIE,
|
|
||||||
"epoll_create": SYS_EPOLL_CREATE,
|
|
||||||
"epoll_ctl_old": SYS_EPOLL_CTL_OLD,
|
|
||||||
"epoll_wait_old": SYS_EPOLL_WAIT_OLD,
|
|
||||||
"remap_file_pages": SYS_REMAP_FILE_PAGES,
|
|
||||||
"getdents64": SYS_GETDENTS64,
|
|
||||||
"set_tid_address": SYS_SET_TID_ADDRESS,
|
|
||||||
"restart_syscall": SYS_RESTART_SYSCALL,
|
|
||||||
"semtimedop": SYS_SEMTIMEDOP,
|
|
||||||
"fadvise64": SYS_FADVISE64,
|
|
||||||
"timer_create": SYS_TIMER_CREATE,
|
|
||||||
"timer_settime": SYS_TIMER_SETTIME,
|
|
||||||
"timer_gettime": SYS_TIMER_GETTIME,
|
|
||||||
"timer_getoverrun": SYS_TIMER_GETOVERRUN,
|
|
||||||
"timer_delete": SYS_TIMER_DELETE,
|
|
||||||
"clock_settime": SYS_CLOCK_SETTIME,
|
|
||||||
"clock_gettime": SYS_CLOCK_GETTIME,
|
|
||||||
"clock_getres": SYS_CLOCK_GETRES,
|
|
||||||
"clock_nanosleep": SYS_CLOCK_NANOSLEEP,
|
|
||||||
"exit_group": SYS_EXIT_GROUP,
|
|
||||||
"epoll_wait": SYS_EPOLL_WAIT,
|
|
||||||
"epoll_ctl": SYS_EPOLL_CTL,
|
|
||||||
"tgkill": SYS_TGKILL,
|
|
||||||
"utimes": SYS_UTIMES,
|
|
||||||
"vserver": SYS_VSERVER,
|
|
||||||
"mbind": SYS_MBIND,
|
|
||||||
"set_mempolicy": SYS_SET_MEMPOLICY,
|
|
||||||
"get_mempolicy": SYS_GET_MEMPOLICY,
|
|
||||||
"mq_open": SYS_MQ_OPEN,
|
|
||||||
"mq_unlink": SYS_MQ_UNLINK,
|
|
||||||
"mq_timedsend": SYS_MQ_TIMEDSEND,
|
|
||||||
"mq_timedreceive": SYS_MQ_TIMEDRECEIVE,
|
|
||||||
"mq_notify": SYS_MQ_NOTIFY,
|
|
||||||
"mq_getsetattr": SYS_MQ_GETSETATTR,
|
|
||||||
"kexec_load": SYS_KEXEC_LOAD,
|
|
||||||
"waitid": SYS_WAITID,
|
|
||||||
"add_key": SYS_ADD_KEY,
|
|
||||||
"request_key": SYS_REQUEST_KEY,
|
|
||||||
"keyctl": SYS_KEYCTL,
|
|
||||||
"ioprio_set": SYS_IOPRIO_SET,
|
|
||||||
"ioprio_get": SYS_IOPRIO_GET,
|
|
||||||
"inotify_init": SYS_INOTIFY_INIT,
|
|
||||||
"inotify_add_watch": SYS_INOTIFY_ADD_WATCH,
|
|
||||||
"inotify_rm_watch": SYS_INOTIFY_RM_WATCH,
|
|
||||||
"migrate_pages": SYS_MIGRATE_PAGES,
|
|
||||||
"openat": SYS_OPENAT,
|
|
||||||
"mkdirat": SYS_MKDIRAT,
|
|
||||||
"mknodat": SYS_MKNODAT,
|
|
||||||
"fchownat": SYS_FCHOWNAT,
|
|
||||||
"futimesat": SYS_FUTIMESAT,
|
|
||||||
"newfstatat": SYS_NEWFSTATAT,
|
|
||||||
"unlinkat": SYS_UNLINKAT,
|
|
||||||
"renameat": SYS_RENAMEAT,
|
|
||||||
"linkat": SYS_LINKAT,
|
|
||||||
"symlinkat": SYS_SYMLINKAT,
|
|
||||||
"readlinkat": SYS_READLINKAT,
|
|
||||||
"fchmodat": SYS_FCHMODAT,
|
|
||||||
"faccessat": SYS_FACCESSAT,
|
|
||||||
"pselect6": SYS_PSELECT6,
|
|
||||||
"ppoll": SYS_PPOLL,
|
|
||||||
"unshare": SYS_UNSHARE,
|
|
||||||
"set_robust_list": SYS_SET_ROBUST_LIST,
|
|
||||||
"get_robust_list": SYS_GET_ROBUST_LIST,
|
|
||||||
"splice": SYS_SPLICE,
|
|
||||||
"tee": SYS_TEE,
|
|
||||||
"sync_file_range": SYS_SYNC_FILE_RANGE,
|
|
||||||
"vmsplice": SYS_VMSPLICE,
|
|
||||||
"move_pages": SYS_MOVE_PAGES,
|
|
||||||
"utimensat": SYS_UTIMENSAT,
|
|
||||||
"epoll_pwait": SYS_EPOLL_PWAIT,
|
|
||||||
"signalfd": SYS_SIGNALFD,
|
|
||||||
"timerfd_create": SYS_TIMERFD_CREATE,
|
|
||||||
"eventfd": SYS_EVENTFD,
|
|
||||||
"fallocate": SYS_FALLOCATE,
|
|
||||||
"timerfd_settime": SYS_TIMERFD_SETTIME,
|
|
||||||
"timerfd_gettime": SYS_TIMERFD_GETTIME,
|
|
||||||
"accept4": SYS_ACCEPT4,
|
|
||||||
"signalfd4": SYS_SIGNALFD4,
|
|
||||||
"eventfd2": SYS_EVENTFD2,
|
|
||||||
"epoll_create1": SYS_EPOLL_CREATE1,
|
|
||||||
"dup3": SYS_DUP3,
|
|
||||||
"pipe2": SYS_PIPE2,
|
|
||||||
"inotify_init1": SYS_INOTIFY_INIT1,
|
|
||||||
"preadv": SYS_PREADV,
|
|
||||||
"pwritev": SYS_PWRITEV,
|
|
||||||
"rt_tgsigqueueinfo": SYS_RT_TGSIGQUEUEINFO,
|
|
||||||
"perf_event_open": SYS_PERF_EVENT_OPEN,
|
|
||||||
"recvmmsg": SYS_RECVMMSG,
|
|
||||||
"fanotify_init": SYS_FANOTIFY_INIT,
|
|
||||||
"fanotify_mark": SYS_FANOTIFY_MARK,
|
|
||||||
"prlimit64": SYS_PRLIMIT64,
|
|
||||||
"name_to_handle_at": SYS_NAME_TO_HANDLE_AT,
|
|
||||||
"open_by_handle_at": SYS_OPEN_BY_HANDLE_AT,
|
|
||||||
"clock_adjtime": SYS_CLOCK_ADJTIME,
|
|
||||||
"syncfs": SYS_SYNCFS,
|
|
||||||
"sendmmsg": SYS_SENDMMSG,
|
|
||||||
"setns": SYS_SETNS,
|
|
||||||
"getcpu": SYS_GETCPU,
|
|
||||||
"process_vm_readv": SYS_PROCESS_VM_READV,
|
|
||||||
"process_vm_writev": SYS_PROCESS_VM_WRITEV,
|
|
||||||
"kcmp": SYS_KCMP,
|
|
||||||
"finit_module": SYS_FINIT_MODULE,
|
|
||||||
"sched_setattr": SYS_SCHED_SETATTR,
|
|
||||||
"sched_getattr": SYS_SCHED_GETATTR,
|
|
||||||
"renameat2": SYS_RENAMEAT2,
|
|
||||||
"seccomp": SYS_SECCOMP,
|
|
||||||
"getrandom": SYS_GETRANDOM,
|
|
||||||
"memfd_create": SYS_MEMFD_CREATE,
|
|
||||||
"kexec_file_load": SYS_KEXEC_FILE_LOAD,
|
|
||||||
"bpf": SYS_BPF,
|
|
||||||
"execveat": SYS_EXECVEAT,
|
|
||||||
"userfaultfd": SYS_USERFAULTFD,
|
|
||||||
"membarrier": SYS_MEMBARRIER,
|
|
||||||
"mlock2": SYS_MLOCK2,
|
|
||||||
"copy_file_range": SYS_COPY_FILE_RANGE,
|
|
||||||
"preadv2": SYS_PREADV2,
|
|
||||||
"pwritev2": SYS_PWRITEV2,
|
|
||||||
"pkey_mprotect": SYS_PKEY_MPROTECT,
|
|
||||||
"pkey_alloc": SYS_PKEY_ALLOC,
|
|
||||||
"pkey_free": SYS_PKEY_FREE,
|
|
||||||
"statx": SYS_STATX,
|
|
||||||
"io_pgetevents": SYS_IO_PGETEVENTS,
|
|
||||||
"rseq": SYS_RSEQ,
|
|
||||||
"uretprobe": SYS_URETPROBE,
|
|
||||||
"pidfd_send_signal": SYS_PIDFD_SEND_SIGNAL,
|
|
||||||
"io_uring_setup": SYS_IO_URING_SETUP,
|
|
||||||
"io_uring_enter": SYS_IO_URING_ENTER,
|
|
||||||
"io_uring_register": SYS_IO_URING_REGISTER,
|
|
||||||
"open_tree": SYS_OPEN_TREE,
|
|
||||||
"move_mount": SYS_MOVE_MOUNT,
|
|
||||||
"fsopen": SYS_FSOPEN,
|
|
||||||
"fsconfig": SYS_FSCONFIG,
|
|
||||||
"fsmount": SYS_FSMOUNT,
|
|
||||||
"fspick": SYS_FSPICK,
|
|
||||||
"pidfd_open": SYS_PIDFD_OPEN,
|
|
||||||
"clone3": SYS_CLONE3,
|
|
||||||
"close_range": SYS_CLOSE_RANGE,
|
|
||||||
"openat2": SYS_OPENAT2,
|
|
||||||
"pidfd_getfd": SYS_PIDFD_GETFD,
|
|
||||||
"faccessat2": SYS_FACCESSAT2,
|
|
||||||
"process_madvise": SYS_PROCESS_MADVISE,
|
|
||||||
"epoll_pwait2": SYS_EPOLL_PWAIT2,
|
|
||||||
"mount_setattr": SYS_MOUNT_SETATTR,
|
|
||||||
"quotactl_fd": SYS_QUOTACTL_FD,
|
|
||||||
"landlock_create_ruleset": SYS_LANDLOCK_CREATE_RULESET,
|
|
||||||
"landlock_add_rule": SYS_LANDLOCK_ADD_RULE,
|
|
||||||
"landlock_restrict_self": SYS_LANDLOCK_RESTRICT_SELF,
|
|
||||||
"memfd_secret": SYS_MEMFD_SECRET,
|
|
||||||
"process_mrelease": SYS_PROCESS_MRELEASE,
|
|
||||||
"futex_waitv": SYS_FUTEX_WAITV,
|
|
||||||
"set_mempolicy_home_node": SYS_SET_MEMPOLICY_HOME_NODE,
|
|
||||||
"cachestat": SYS_CACHESTAT,
|
|
||||||
"fchmodat2": SYS_FCHMODAT2,
|
|
||||||
"map_shadow_stack": SYS_MAP_SHADOW_STACK,
|
|
||||||
"futex_wake": SYS_FUTEX_WAKE,
|
|
||||||
"futex_wait": SYS_FUTEX_WAIT,
|
|
||||||
"futex_requeue": SYS_FUTEX_REQUEUE,
|
|
||||||
"statmount": SYS_STATMOUNT,
|
|
||||||
"listmount": SYS_LISTMOUNT,
|
|
||||||
"lsm_get_self_attr": SYS_LSM_GET_SELF_ATTR,
|
|
||||||
"lsm_set_self_attr": SYS_LSM_SET_SELF_ATTR,
|
|
||||||
"lsm_list_modules": SYS_LSM_LIST_MODULES,
|
|
||||||
"mseal": SYS_MSEAL,
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
SYS_NAME_TO_HANDLE_AT = 303
|
|
||||||
SYS_OPEN_BY_HANDLE_AT = 304
|
|
||||||
SYS_CLOCK_ADJTIME = 305
|
|
||||||
SYS_SYNCFS = 306
|
|
||||||
SYS_SENDMMSG = 307
|
|
||||||
SYS_SETNS = 308
|
|
||||||
SYS_GETCPU = 309
|
|
||||||
SYS_PROCESS_VM_READV = 310
|
|
||||||
SYS_PROCESS_VM_WRITEV = 311
|
|
||||||
SYS_KCMP = 312
|
|
||||||
SYS_FINIT_MODULE = 313
|
|
||||||
SYS_SCHED_SETATTR = 314
|
|
||||||
SYS_SCHED_GETATTR = 315
|
|
||||||
SYS_RENAMEAT2 = 316
|
|
||||||
SYS_SECCOMP = 317
|
|
||||||
SYS_GETRANDOM = 318
|
|
||||||
SYS_MEMFD_CREATE = 319
|
|
||||||
SYS_KEXEC_FILE_LOAD = 320
|
|
||||||
SYS_BPF = 321
|
|
||||||
SYS_EXECVEAT = 322
|
|
||||||
SYS_USERFAULTFD = 323
|
|
||||||
SYS_MEMBARRIER = 324
|
|
||||||
SYS_MLOCK2 = 325
|
|
||||||
SYS_COPY_FILE_RANGE = 326
|
|
||||||
SYS_PREADV2 = 327
|
|
||||||
SYS_PWRITEV2 = 328
|
|
||||||
SYS_PKEY_MPROTECT = 329
|
|
||||||
SYS_PKEY_ALLOC = 330
|
|
||||||
SYS_PKEY_FREE = 331
|
|
||||||
SYS_STATX = 332
|
|
||||||
SYS_IO_PGETEVENTS = 333
|
|
||||||
SYS_RSEQ = 334
|
|
||||||
SYS_URETPROBE = 335
|
|
||||||
SYS_PIDFD_SEND_SIGNAL = 424
|
|
||||||
SYS_IO_URING_SETUP = 425
|
|
||||||
SYS_IO_URING_ENTER = 426
|
|
||||||
SYS_IO_URING_REGISTER = 427
|
|
||||||
SYS_OPEN_TREE = 428
|
|
||||||
SYS_MOVE_MOUNT = 429
|
|
||||||
SYS_FSOPEN = 430
|
|
||||||
SYS_FSCONFIG = 431
|
|
||||||
SYS_FSMOUNT = 432
|
|
||||||
SYS_FSPICK = 433
|
|
||||||
SYS_PIDFD_OPEN = 434
|
|
||||||
SYS_CLONE3 = 435
|
|
||||||
SYS_CLOSE_RANGE = 436
|
|
||||||
SYS_OPENAT2 = 437
|
|
||||||
SYS_PIDFD_GETFD = 438
|
|
||||||
SYS_FACCESSAT2 = 439
|
|
||||||
SYS_PROCESS_MADVISE = 440
|
|
||||||
SYS_EPOLL_PWAIT2 = 441
|
|
||||||
SYS_MOUNT_SETATTR = 442
|
|
||||||
SYS_QUOTACTL_FD = 443
|
|
||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
|
||||||
SYS_MEMFD_SECRET = 447
|
|
||||||
SYS_PROCESS_MRELEASE = 448
|
|
||||||
SYS_FUTEX_WAITV = 449
|
|
||||||
SYS_SET_MEMPOLICY_HOME_NODE = 450
|
|
||||||
SYS_CACHESTAT = 451
|
|
||||||
SYS_FCHMODAT2 = 452
|
|
||||||
SYS_MAP_SHADOW_STACK = 453
|
|
||||||
SYS_FUTEX_WAKE = 454
|
|
||||||
SYS_FUTEX_WAIT = 455
|
|
||||||
SYS_FUTEX_REQUEUE = 456
|
|
||||||
SYS_STATMOUNT = 457
|
|
||||||
SYS_LISTMOUNT = 458
|
|
||||||
SYS_LSM_GET_SELF_ATTR = 459
|
|
||||||
SYS_LSM_SET_SELF_ATTR = 460
|
|
||||||
SYS_LSM_LIST_MODULES = 461
|
|
||||||
SYS_MSEAL = 462
|
|
||||||
)
|
|
||||||
@@ -1,382 +0,0 @@
|
|||||||
// mksysnum_linux.pl /usr/include/asm/unistd_64.h
|
|
||||||
// Code generated by the command above; DO NOT EDIT.
|
|
||||||
|
|
||||||
package seccomp
|
|
||||||
|
|
||||||
import . "syscall"
|
|
||||||
|
|
||||||
var syscallNum = map[string]int{
|
|
||||||
"io_setup": SYS_IO_SETUP,
|
|
||||||
"io_destroy": SYS_IO_DESTROY,
|
|
||||||
"io_submit": SYS_IO_SUBMIT,
|
|
||||||
"io_cancel": SYS_IO_CANCEL,
|
|
||||||
"io_getevents": SYS_IO_GETEVENTS,
|
|
||||||
"setxattr": SYS_SETXATTR,
|
|
||||||
"lsetxattr": SYS_LSETXATTR,
|
|
||||||
"fsetxattr": SYS_FSETXATTR,
|
|
||||||
"getxattr": SYS_GETXATTR,
|
|
||||||
"lgetxattr": SYS_LGETXATTR,
|
|
||||||
"fgetxattr": SYS_FGETXATTR,
|
|
||||||
"listxattr": SYS_LISTXATTR,
|
|
||||||
"llistxattr": SYS_LLISTXATTR,
|
|
||||||
"flistxattr": SYS_FLISTXATTR,
|
|
||||||
"removexattr": SYS_REMOVEXATTR,
|
|
||||||
"lremovexattr": SYS_LREMOVEXATTR,
|
|
||||||
"fremovexattr": SYS_FREMOVEXATTR,
|
|
||||||
"getcwd": SYS_GETCWD,
|
|
||||||
"lookup_dcookie": SYS_LOOKUP_DCOOKIE,
|
|
||||||
"eventfd2": SYS_EVENTFD2,
|
|
||||||
"epoll_create1": SYS_EPOLL_CREATE1,
|
|
||||||
"epoll_ctl": SYS_EPOLL_CTL,
|
|
||||||
"epoll_pwait": SYS_EPOLL_PWAIT,
|
|
||||||
"dup": SYS_DUP,
|
|
||||||
"dup3": SYS_DUP3,
|
|
||||||
"fcntl": SYS_FCNTL,
|
|
||||||
"inotify_init1": SYS_INOTIFY_INIT1,
|
|
||||||
"inotify_add_watch": SYS_INOTIFY_ADD_WATCH,
|
|
||||||
"inotify_rm_watch": SYS_INOTIFY_RM_WATCH,
|
|
||||||
"ioctl": SYS_IOCTL,
|
|
||||||
"ioprio_set": SYS_IOPRIO_SET,
|
|
||||||
"ioprio_get": SYS_IOPRIO_GET,
|
|
||||||
"flock": SYS_FLOCK,
|
|
||||||
"mknodat": SYS_MKNODAT,
|
|
||||||
"mkdirat": SYS_MKDIRAT,
|
|
||||||
"unlinkat": SYS_UNLINKAT,
|
|
||||||
"symlinkat": SYS_SYMLINKAT,
|
|
||||||
"linkat": SYS_LINKAT,
|
|
||||||
"renameat": SYS_RENAMEAT,
|
|
||||||
"umount2": SYS_UMOUNT2,
|
|
||||||
"mount": SYS_MOUNT,
|
|
||||||
"pivot_root": SYS_PIVOT_ROOT,
|
|
||||||
"nfsservctl": SYS_NFSSERVCTL,
|
|
||||||
"statfs": SYS_STATFS,
|
|
||||||
"fstatfs": SYS_FSTATFS,
|
|
||||||
"truncate": SYS_TRUNCATE,
|
|
||||||
"ftruncate": SYS_FTRUNCATE,
|
|
||||||
"fallocate": SYS_FALLOCATE,
|
|
||||||
"faccessat": SYS_FACCESSAT,
|
|
||||||
"chdir": SYS_CHDIR,
|
|
||||||
"fchdir": SYS_FCHDIR,
|
|
||||||
"chroot": SYS_CHROOT,
|
|
||||||
"fchmod": SYS_FCHMOD,
|
|
||||||
"fchmodat": SYS_FCHMODAT,
|
|
||||||
"fchownat": SYS_FCHOWNAT,
|
|
||||||
"fchown": SYS_FCHOWN,
|
|
||||||
"openat": SYS_OPENAT,
|
|
||||||
"close": SYS_CLOSE,
|
|
||||||
"vhangup": SYS_VHANGUP,
|
|
||||||
"pipe2": SYS_PIPE2,
|
|
||||||
"quotactl": SYS_QUOTACTL,
|
|
||||||
"getdents64": SYS_GETDENTS64,
|
|
||||||
"lseek": SYS_LSEEK,
|
|
||||||
"read": SYS_READ,
|
|
||||||
"write": SYS_WRITE,
|
|
||||||
"readv": SYS_READV,
|
|
||||||
"writev": SYS_WRITEV,
|
|
||||||
"pread64": SYS_PREAD64,
|
|
||||||
"pwrite64": SYS_PWRITE64,
|
|
||||||
"preadv": SYS_PREADV,
|
|
||||||
"pwritev": SYS_PWRITEV,
|
|
||||||
"sendfile": SYS_SENDFILE,
|
|
||||||
"pselect6": SYS_PSELECT6,
|
|
||||||
"ppoll": SYS_PPOLL,
|
|
||||||
"signalfd4": SYS_SIGNALFD4,
|
|
||||||
"vmsplice": SYS_VMSPLICE,
|
|
||||||
"splice": SYS_SPLICE,
|
|
||||||
"tee": SYS_TEE,
|
|
||||||
"readlinkat": SYS_READLINKAT,
|
|
||||||
"newfstatat": SYS_NEWFSTATAT,
|
|
||||||
"fstat": SYS_FSTAT,
|
|
||||||
"sync": SYS_SYNC,
|
|
||||||
"fsync": SYS_FSYNC,
|
|
||||||
"fdatasync": SYS_FDATASYNC,
|
|
||||||
"sync_file_range": SYS_SYNC_FILE_RANGE,
|
|
||||||
"timerfd_create": SYS_TIMERFD_CREATE,
|
|
||||||
"timerfd_settime": SYS_TIMERFD_SETTIME,
|
|
||||||
"timerfd_gettime": SYS_TIMERFD_GETTIME,
|
|
||||||
"utimensat": SYS_UTIMENSAT,
|
|
||||||
"acct": SYS_ACCT,
|
|
||||||
"capget": SYS_CAPGET,
|
|
||||||
"capset": SYS_CAPSET,
|
|
||||||
"personality": SYS_PERSONALITY,
|
|
||||||
"exit": SYS_EXIT,
|
|
||||||
"exit_group": SYS_EXIT_GROUP,
|
|
||||||
"waitid": SYS_WAITID,
|
|
||||||
"set_tid_address": SYS_SET_TID_ADDRESS,
|
|
||||||
"unshare": SYS_UNSHARE,
|
|
||||||
"futex": SYS_FUTEX,
|
|
||||||
"set_robust_list": SYS_SET_ROBUST_LIST,
|
|
||||||
"get_robust_list": SYS_GET_ROBUST_LIST,
|
|
||||||
"nanosleep": SYS_NANOSLEEP,
|
|
||||||
"getitimer": SYS_GETITIMER,
|
|
||||||
"setitimer": SYS_SETITIMER,
|
|
||||||
"kexec_load": SYS_KEXEC_LOAD,
|
|
||||||
"init_module": SYS_INIT_MODULE,
|
|
||||||
"delete_module": SYS_DELETE_MODULE,
|
|
||||||
"timer_create": SYS_TIMER_CREATE,
|
|
||||||
"timer_gettime": SYS_TIMER_GETTIME,
|
|
||||||
"timer_getoverrun": SYS_TIMER_GETOVERRUN,
|
|
||||||
"timer_settime": SYS_TIMER_SETTIME,
|
|
||||||
"timer_delete": SYS_TIMER_DELETE,
|
|
||||||
"clock_settime": SYS_CLOCK_SETTIME,
|
|
||||||
"clock_gettime": SYS_CLOCK_GETTIME,
|
|
||||||
"clock_getres": SYS_CLOCK_GETRES,
|
|
||||||
"clock_nanosleep": SYS_CLOCK_NANOSLEEP,
|
|
||||||
"syslog": SYS_SYSLOG,
|
|
||||||
"ptrace": SYS_PTRACE,
|
|
||||||
"sched_setparam": SYS_SCHED_SETPARAM,
|
|
||||||
"sched_setscheduler": SYS_SCHED_SETSCHEDULER,
|
|
||||||
"sched_getscheduler": SYS_SCHED_GETSCHEDULER,
|
|
||||||
"sched_getparam": SYS_SCHED_GETPARAM,
|
|
||||||
"sched_setaffinity": SYS_SCHED_SETAFFINITY,
|
|
||||||
"sched_getaffinity": SYS_SCHED_GETAFFINITY,
|
|
||||||
"sched_yield": SYS_SCHED_YIELD,
|
|
||||||
"sched_get_priority_max": SYS_SCHED_GET_PRIORITY_MAX,
|
|
||||||
"sched_get_priority_min": SYS_SCHED_GET_PRIORITY_MIN,
|
|
||||||
"sched_rr_get_interval": SYS_SCHED_RR_GET_INTERVAL,
|
|
||||||
"restart_syscall": SYS_RESTART_SYSCALL,
|
|
||||||
"kill": SYS_KILL,
|
|
||||||
"tkill": SYS_TKILL,
|
|
||||||
"tgkill": SYS_TGKILL,
|
|
||||||
"sigaltstack": SYS_SIGALTSTACK,
|
|
||||||
"rt_sigsuspend": SYS_RT_SIGSUSPEND,
|
|
||||||
"rt_sigaction": SYS_RT_SIGACTION,
|
|
||||||
"rt_sigprocmask": SYS_RT_SIGPROCMASK,
|
|
||||||
"rt_sigpending": SYS_RT_SIGPENDING,
|
|
||||||
"rt_sigtimedwait": SYS_RT_SIGTIMEDWAIT,
|
|
||||||
"rt_sigqueueinfo": SYS_RT_SIGQUEUEINFO,
|
|
||||||
"rt_sigreturn": SYS_RT_SIGRETURN,
|
|
||||||
"setpriority": SYS_SETPRIORITY,
|
|
||||||
"getpriority": SYS_GETPRIORITY,
|
|
||||||
"reboot": SYS_REBOOT,
|
|
||||||
"setregid": SYS_SETREGID,
|
|
||||||
"setgid": SYS_SETGID,
|
|
||||||
"setreuid": SYS_SETREUID,
|
|
||||||
"setuid": SYS_SETUID,
|
|
||||||
"setresuid": SYS_SETRESUID,
|
|
||||||
"getresuid": SYS_GETRESUID,
|
|
||||||
"setresgid": SYS_SETRESGID,
|
|
||||||
"getresgid": SYS_GETRESGID,
|
|
||||||
"setfsuid": SYS_SETFSUID,
|
|
||||||
"setfsgid": SYS_SETFSGID,
|
|
||||||
"times": SYS_TIMES,
|
|
||||||
"setpgid": SYS_SETPGID,
|
|
||||||
"getpgid": SYS_GETPGID,
|
|
||||||
"getsid": SYS_GETSID,
|
|
||||||
"setsid": SYS_SETSID,
|
|
||||||
"getgroups": SYS_GETGROUPS,
|
|
||||||
"setgroups": SYS_SETGROUPS,
|
|
||||||
"uname": SYS_UNAME,
|
|
||||||
"sethostname": SYS_SETHOSTNAME,
|
|
||||||
"setdomainname": SYS_SETDOMAINNAME,
|
|
||||||
"getrlimit": SYS_GETRLIMIT,
|
|
||||||
"setrlimit": SYS_SETRLIMIT,
|
|
||||||
"getrusage": SYS_GETRUSAGE,
|
|
||||||
"umask": SYS_UMASK,
|
|
||||||
"prctl": SYS_PRCTL,
|
|
||||||
"getcpu": SYS_GETCPU,
|
|
||||||
"gettimeofday": SYS_GETTIMEOFDAY,
|
|
||||||
"settimeofday": SYS_SETTIMEOFDAY,
|
|
||||||
"adjtimex": SYS_ADJTIMEX,
|
|
||||||
"getpid": SYS_GETPID,
|
|
||||||
"getppid": SYS_GETPPID,
|
|
||||||
"getuid": SYS_GETUID,
|
|
||||||
"geteuid": SYS_GETEUID,
|
|
||||||
"getgid": SYS_GETGID,
|
|
||||||
"getegid": SYS_GETEGID,
|
|
||||||
"gettid": SYS_GETTID,
|
|
||||||
"sysinfo": SYS_SYSINFO,
|
|
||||||
"mq_open": SYS_MQ_OPEN,
|
|
||||||
"mq_unlink": SYS_MQ_UNLINK,
|
|
||||||
"mq_timedsend": SYS_MQ_TIMEDSEND,
|
|
||||||
"mq_timedreceive": SYS_MQ_TIMEDRECEIVE,
|
|
||||||
"mq_notify": SYS_MQ_NOTIFY,
|
|
||||||
"mq_getsetattr": SYS_MQ_GETSETATTR,
|
|
||||||
"msgget": SYS_MSGGET,
|
|
||||||
"msgctl": SYS_MSGCTL,
|
|
||||||
"msgrcv": SYS_MSGRCV,
|
|
||||||
"msgsnd": SYS_MSGSND,
|
|
||||||
"semget": SYS_SEMGET,
|
|
||||||
"semctl": SYS_SEMCTL,
|
|
||||||
"semtimedop": SYS_SEMTIMEDOP,
|
|
||||||
"semop": SYS_SEMOP,
|
|
||||||
"shmget": SYS_SHMGET,
|
|
||||||
"shmctl": SYS_SHMCTL,
|
|
||||||
"shmat": SYS_SHMAT,
|
|
||||||
"shmdt": SYS_SHMDT,
|
|
||||||
"socket": SYS_SOCKET,
|
|
||||||
"socketpair": SYS_SOCKETPAIR,
|
|
||||||
"bind": SYS_BIND,
|
|
||||||
"listen": SYS_LISTEN,
|
|
||||||
"accept": SYS_ACCEPT,
|
|
||||||
"connect": SYS_CONNECT,
|
|
||||||
"getsockname": SYS_GETSOCKNAME,
|
|
||||||
"getpeername": SYS_GETPEERNAME,
|
|
||||||
"sendto": SYS_SENDTO,
|
|
||||||
"recvfrom": SYS_RECVFROM,
|
|
||||||
"setsockopt": SYS_SETSOCKOPT,
|
|
||||||
"getsockopt": SYS_GETSOCKOPT,
|
|
||||||
"shutdown": SYS_SHUTDOWN,
|
|
||||||
"sendmsg": SYS_SENDMSG,
|
|
||||||
"recvmsg": SYS_RECVMSG,
|
|
||||||
"readahead": SYS_READAHEAD,
|
|
||||||
"brk": SYS_BRK,
|
|
||||||
"munmap": SYS_MUNMAP,
|
|
||||||
"mremap": SYS_MREMAP,
|
|
||||||
"add_key": SYS_ADD_KEY,
|
|
||||||
"request_key": SYS_REQUEST_KEY,
|
|
||||||
"keyctl": SYS_KEYCTL,
|
|
||||||
"clone": SYS_CLONE,
|
|
||||||
"execve": SYS_EXECVE,
|
|
||||||
"mmap": SYS_MMAP,
|
|
||||||
"fadvise64": SYS_FADVISE64,
|
|
||||||
"swapon": SYS_SWAPON,
|
|
||||||
"swapoff": SYS_SWAPOFF,
|
|
||||||
"mprotect": SYS_MPROTECT,
|
|
||||||
"msync": SYS_MSYNC,
|
|
||||||
"mlock": SYS_MLOCK,
|
|
||||||
"munlock": SYS_MUNLOCK,
|
|
||||||
"mlockall": SYS_MLOCKALL,
|
|
||||||
"munlockall": SYS_MUNLOCKALL,
|
|
||||||
"mincore": SYS_MINCORE,
|
|
||||||
"madvise": SYS_MADVISE,
|
|
||||||
"remap_file_pages": SYS_REMAP_FILE_PAGES,
|
|
||||||
"mbind": SYS_MBIND,
|
|
||||||
"get_mempolicy": SYS_GET_MEMPOLICY,
|
|
||||||
"set_mempolicy": SYS_SET_MEMPOLICY,
|
|
||||||
"migrate_pages": SYS_MIGRATE_PAGES,
|
|
||||||
"move_pages": SYS_MOVE_PAGES,
|
|
||||||
"rt_tgsigqueueinfo": SYS_RT_TGSIGQUEUEINFO,
|
|
||||||
"perf_event_open": SYS_PERF_EVENT_OPEN,
|
|
||||||
"accept4": SYS_ACCEPT4,
|
|
||||||
"recvmmsg": SYS_RECVMMSG,
|
|
||||||
"wait4": SYS_WAIT4,
|
|
||||||
"prlimit64": SYS_PRLIMIT64,
|
|
||||||
"fanotify_init": SYS_FANOTIFY_INIT,
|
|
||||||
"fanotify_mark": SYS_FANOTIFY_MARK,
|
|
||||||
"name_to_handle_at": SYS_NAME_TO_HANDLE_AT,
|
|
||||||
"open_by_handle_at": SYS_OPEN_BY_HANDLE_AT,
|
|
||||||
"clock_adjtime": SYS_CLOCK_ADJTIME,
|
|
||||||
"syncfs": SYS_SYNCFS,
|
|
||||||
"setns": SYS_SETNS,
|
|
||||||
"sendmmsg": SYS_SENDMMSG,
|
|
||||||
"process_vm_readv": SYS_PROCESS_VM_READV,
|
|
||||||
"process_vm_writev": SYS_PROCESS_VM_WRITEV,
|
|
||||||
"kcmp": SYS_KCMP,
|
|
||||||
"finit_module": SYS_FINIT_MODULE,
|
|
||||||
"sched_setattr": SYS_SCHED_SETATTR,
|
|
||||||
"sched_getattr": SYS_SCHED_GETATTR,
|
|
||||||
"renameat2": SYS_RENAMEAT2,
|
|
||||||
"seccomp": SYS_SECCOMP,
|
|
||||||
"getrandom": SYS_GETRANDOM,
|
|
||||||
"memfd_create": SYS_MEMFD_CREATE,
|
|
||||||
"bpf": SYS_BPF,
|
|
||||||
"execveat": SYS_EXECVEAT,
|
|
||||||
"userfaultfd": SYS_USERFAULTFD,
|
|
||||||
"membarrier": SYS_MEMBARRIER,
|
|
||||||
"mlock2": SYS_MLOCK2,
|
|
||||||
"copy_file_range": SYS_COPY_FILE_RANGE,
|
|
||||||
"preadv2": SYS_PREADV2,
|
|
||||||
"pwritev2": SYS_PWRITEV2,
|
|
||||||
"pkey_mprotect": SYS_PKEY_MPROTECT,
|
|
||||||
"pkey_alloc": SYS_PKEY_ALLOC,
|
|
||||||
"pkey_free": SYS_PKEY_FREE,
|
|
||||||
"statx": SYS_STATX,
|
|
||||||
"io_pgetevents": SYS_IO_PGETEVENTS,
|
|
||||||
"rseq": SYS_RSEQ,
|
|
||||||
"kexec_file_load": SYS_KEXEC_FILE_LOAD,
|
|
||||||
"pidfd_send_signal": SYS_PIDFD_SEND_SIGNAL,
|
|
||||||
"io_uring_setup": SYS_IO_URING_SETUP,
|
|
||||||
"io_uring_enter": SYS_IO_URING_ENTER,
|
|
||||||
"io_uring_register": SYS_IO_URING_REGISTER,
|
|
||||||
"open_tree": SYS_OPEN_TREE,
|
|
||||||
"move_mount": SYS_MOVE_MOUNT,
|
|
||||||
"fsopen": SYS_FSOPEN,
|
|
||||||
"fsconfig": SYS_FSCONFIG,
|
|
||||||
"fsmount": SYS_FSMOUNT,
|
|
||||||
"fspick": SYS_FSPICK,
|
|
||||||
"pidfd_open": SYS_PIDFD_OPEN,
|
|
||||||
"clone3": SYS_CLONE3,
|
|
||||||
"close_range": SYS_CLOSE_RANGE,
|
|
||||||
"openat2": SYS_OPENAT2,
|
|
||||||
"pidfd_getfd": SYS_PIDFD_GETFD,
|
|
||||||
"faccessat2": SYS_FACCESSAT2,
|
|
||||||
"process_madvise": SYS_PROCESS_MADVISE,
|
|
||||||
"epoll_pwait2": SYS_EPOLL_PWAIT2,
|
|
||||||
"mount_setattr": SYS_MOUNT_SETATTR,
|
|
||||||
"quotactl_fd": SYS_QUOTACTL_FD,
|
|
||||||
"landlock_create_ruleset": SYS_LANDLOCK_CREATE_RULESET,
|
|
||||||
"landlock_add_rule": SYS_LANDLOCK_ADD_RULE,
|
|
||||||
"landlock_restrict_self": SYS_LANDLOCK_RESTRICT_SELF,
|
|
||||||
"memfd_secret": SYS_MEMFD_SECRET,
|
|
||||||
"process_mrelease": SYS_PROCESS_MRELEASE,
|
|
||||||
"futex_waitv": SYS_FUTEX_WAITV,
|
|
||||||
"set_mempolicy_home_node": SYS_SET_MEMPOLICY_HOME_NODE,
|
|
||||||
"cachestat": SYS_CACHESTAT,
|
|
||||||
"fchmodat2": SYS_FCHMODAT2,
|
|
||||||
"map_shadow_stack": SYS_MAP_SHADOW_STACK,
|
|
||||||
"futex_wake": SYS_FUTEX_WAKE,
|
|
||||||
"futex_wait": SYS_FUTEX_WAIT,
|
|
||||||
"futex_requeue": SYS_FUTEX_REQUEUE,
|
|
||||||
"statmount": SYS_STATMOUNT,
|
|
||||||
"listmount": SYS_LISTMOUNT,
|
|
||||||
"lsm_get_self_attr": SYS_LSM_GET_SELF_ATTR,
|
|
||||||
"lsm_set_self_attr": SYS_LSM_SET_SELF_ATTR,
|
|
||||||
"lsm_list_modules": SYS_LSM_LIST_MODULES,
|
|
||||||
"mseal": SYS_MSEAL,
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
SYS_USERFAULTFD = 282
|
|
||||||
SYS_MEMBARRIER = 283
|
|
||||||
SYS_MLOCK2 = 284
|
|
||||||
SYS_COPY_FILE_RANGE = 285
|
|
||||||
SYS_PREADV2 = 286
|
|
||||||
SYS_PWRITEV2 = 287
|
|
||||||
SYS_PKEY_MPROTECT = 288
|
|
||||||
SYS_PKEY_ALLOC = 289
|
|
||||||
SYS_PKEY_FREE = 290
|
|
||||||
SYS_STATX = 291
|
|
||||||
SYS_IO_PGETEVENTS = 292
|
|
||||||
SYS_RSEQ = 293
|
|
||||||
SYS_KEXEC_FILE_LOAD = 294
|
|
||||||
SYS_PIDFD_SEND_SIGNAL = 424
|
|
||||||
SYS_IO_URING_SETUP = 425
|
|
||||||
SYS_IO_URING_ENTER = 426
|
|
||||||
SYS_IO_URING_REGISTER = 427
|
|
||||||
SYS_OPEN_TREE = 428
|
|
||||||
SYS_MOVE_MOUNT = 429
|
|
||||||
SYS_FSOPEN = 430
|
|
||||||
SYS_FSCONFIG = 431
|
|
||||||
SYS_FSMOUNT = 432
|
|
||||||
SYS_FSPICK = 433
|
|
||||||
SYS_PIDFD_OPEN = 434
|
|
||||||
SYS_CLONE3 = 435
|
|
||||||
SYS_CLOSE_RANGE = 436
|
|
||||||
SYS_OPENAT2 = 437
|
|
||||||
SYS_PIDFD_GETFD = 438
|
|
||||||
SYS_FACCESSAT2 = 439
|
|
||||||
SYS_PROCESS_MADVISE = 440
|
|
||||||
SYS_EPOLL_PWAIT2 = 441
|
|
||||||
SYS_MOUNT_SETATTR = 442
|
|
||||||
SYS_QUOTACTL_FD = 443
|
|
||||||
SYS_LANDLOCK_CREATE_RULESET = 444
|
|
||||||
SYS_LANDLOCK_ADD_RULE = 445
|
|
||||||
SYS_LANDLOCK_RESTRICT_SELF = 446
|
|
||||||
SYS_MEMFD_SECRET = 447
|
|
||||||
SYS_PROCESS_MRELEASE = 448
|
|
||||||
SYS_FUTEX_WAITV = 449
|
|
||||||
SYS_SET_MEMPOLICY_HOME_NODE = 450
|
|
||||||
SYS_CACHESTAT = 451
|
|
||||||
SYS_FCHMODAT2 = 452
|
|
||||||
SYS_MAP_SHADOW_STACK = 453
|
|
||||||
SYS_FUTEX_WAKE = 454
|
|
||||||
SYS_FUTEX_WAIT = 455
|
|
||||||
SYS_FUTEX_REQUEUE = 456
|
|
||||||
SYS_STATMOUNT = 457
|
|
||||||
SYS_LISTMOUNT = 458
|
|
||||||
SYS_LSM_GET_SELF_ATTR = 459
|
|
||||||
SYS_LSM_SET_SELF_ATTR = 460
|
|
||||||
SYS_LSM_LIST_MODULES = 461
|
|
||||||
SYS_MSEAL = 462
|
|
||||||
)
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package seccomp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestSyscallResolveName(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
for name, want := range Syscalls() {
|
|
||||||
t.Run(name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
if got := syscallResolveName(name); got != want {
|
|
||||||
t.Errorf("syscallResolveName(%q) = %d, want %d", name, got, want)
|
|
||||||
}
|
|
||||||
if got, ok := SyscallResolveName(name); !ok || got != want {
|
|
||||||
t.Errorf("SyscallResolveName(%q) = %d, want %d", name, got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Package comp contains constants from container packages without depending on cgo.
|
// Package std contains constants from container packages without depending on cgo.
|
||||||
package comp
|
package std
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// BindOptional skips nonexistent host paths.
|
// BindOptional skips nonexistent host paths.
|
||||||
@@ -9,6 +9,7 @@ use POSIX ();
|
|||||||
my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
|
my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
|
||||||
my $uname_arch = (POSIX::uname)[4];
|
my $uname_arch = (POSIX::uname)[4];
|
||||||
my %syscall_cutoff_arch = (
|
my %syscall_cutoff_arch = (
|
||||||
|
"x86" => 340,
|
||||||
"x86_64" => 302,
|
"x86_64" => 302,
|
||||||
"aarch64" => 281,
|
"aarch64" => 281,
|
||||||
);
|
);
|
||||||
@@ -17,11 +18,11 @@ print <<EOF;
|
|||||||
// $command
|
// $command
|
||||||
// Code generated by the command above; DO NOT EDIT.
|
// Code generated by the command above; DO NOT EDIT.
|
||||||
|
|
||||||
package seccomp
|
package std
|
||||||
|
|
||||||
import . "syscall"
|
import . "syscall"
|
||||||
|
|
||||||
var syscallNum = map[string]int{
|
var syscallNum = map[string]ScmpSyscall{
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
my $offset = 0;
|
my $offset = 0;
|
||||||
@@ -36,16 +37,14 @@ sub fmt {
|
|||||||
}
|
}
|
||||||
(my $name_upper = $name) =~ y/a-z/A-Z/;
|
(my $name_upper = $name) =~ y/a-z/A-Z/;
|
||||||
$num = $num + $offset;
|
$num = $num + $offset;
|
||||||
if($num > $syscall_cutoff_arch{$uname_arch}){ # not wired in Go standard library
|
if($num > $syscall_cutoff_arch{$uname_arch} && $state == 0){ # not wired in Go standard library
|
||||||
if($state < 0){
|
print " SYS_$name_upper = $num\n";
|
||||||
print " \"$name\": SYS_$name_upper,\n";
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
print " SYS_$name_upper = $num;\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
elsif($state < 0){
|
elsif($state == -1){
|
||||||
print " \"$name\": SYS_$name_upper,\n";
|
print " \"$name\": SNR_$name_upper,\n";
|
||||||
|
}
|
||||||
|
elsif($state == 1){
|
||||||
|
print " SNR_$name_upper ScmpSyscall = SYS_$name_upper\n";
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return;
|
return;
|
||||||
@@ -80,10 +79,16 @@ while(<GCC>){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($state < 0){
|
if($state == -1){
|
||||||
$state = $state + 1;
|
|
||||||
print "}\n\nconst (\n";
|
print "}\n\nconst (\n";
|
||||||
goto GENERATE;
|
|
||||||
}
|
}
|
||||||
|
elsif($state == 0){
|
||||||
|
print ")\n\nconst (\n";
|
||||||
|
}
|
||||||
|
elsif($state == 1){
|
||||||
|
print ")";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
++$state;
|
||||||
|
goto GENERATE;
|
||||||
|
|
||||||
print ")";
|
|
||||||
267
container/std/pnr.go
Normal file
267
container/std/pnr.go
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
// Code generated from include/seccomp-syscalls.h; DO NOT EDIT.
|
||||||
|
|
||||||
|
package std
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pseudo syscall definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
const (
|
||||||
|
|
||||||
|
/* socket syscalls */
|
||||||
|
|
||||||
|
__PNR_socket = -101
|
||||||
|
__PNR_bind = -102
|
||||||
|
__PNR_connect = -103
|
||||||
|
__PNR_listen = -104
|
||||||
|
__PNR_accept = -105
|
||||||
|
__PNR_getsockname = -106
|
||||||
|
__PNR_getpeername = -107
|
||||||
|
__PNR_socketpair = -108
|
||||||
|
__PNR_send = -109
|
||||||
|
__PNR_recv = -110
|
||||||
|
__PNR_sendto = -111
|
||||||
|
__PNR_recvfrom = -112
|
||||||
|
__PNR_shutdown = -113
|
||||||
|
__PNR_setsockopt = -114
|
||||||
|
__PNR_getsockopt = -115
|
||||||
|
__PNR_sendmsg = -116
|
||||||
|
__PNR_recvmsg = -117
|
||||||
|
__PNR_accept4 = -118
|
||||||
|
__PNR_recvmmsg = -119
|
||||||
|
__PNR_sendmmsg = -120
|
||||||
|
|
||||||
|
/* ipc syscalls */
|
||||||
|
|
||||||
|
__PNR_semop = -201
|
||||||
|
__PNR_semget = -202
|
||||||
|
__PNR_semctl = -203
|
||||||
|
__PNR_semtimedop = -204
|
||||||
|
__PNR_msgsnd = -211
|
||||||
|
__PNR_msgrcv = -212
|
||||||
|
__PNR_msgget = -213
|
||||||
|
__PNR_msgctl = -214
|
||||||
|
__PNR_shmat = -221
|
||||||
|
__PNR_shmdt = -222
|
||||||
|
__PNR_shmget = -223
|
||||||
|
__PNR_shmctl = -224
|
||||||
|
|
||||||
|
/* single syscalls */
|
||||||
|
|
||||||
|
__PNR_arch_prctl = -10001
|
||||||
|
__PNR_bdflush = -10002
|
||||||
|
__PNR_break = -10003
|
||||||
|
__PNR_chown32 = -10004
|
||||||
|
__PNR_epoll_ctl_old = -10005
|
||||||
|
__PNR_epoll_wait_old = -10006
|
||||||
|
__PNR_fadvise64_64 = -10007
|
||||||
|
__PNR_fchown32 = -10008
|
||||||
|
__PNR_fcntl64 = -10009
|
||||||
|
__PNR_fstat64 = -10010
|
||||||
|
__PNR_fstatat64 = -10011
|
||||||
|
__PNR_fstatfs64 = -10012
|
||||||
|
__PNR_ftime = -10013
|
||||||
|
__PNR_ftruncate64 = -10014
|
||||||
|
__PNR_getegid32 = -10015
|
||||||
|
__PNR_geteuid32 = -10016
|
||||||
|
__PNR_getgid32 = -10017
|
||||||
|
__PNR_getgroups32 = -10018
|
||||||
|
__PNR_getresgid32 = -10019
|
||||||
|
__PNR_getresuid32 = -10020
|
||||||
|
__PNR_getuid32 = -10021
|
||||||
|
__PNR_gtty = -10022
|
||||||
|
__PNR_idle = -10023
|
||||||
|
__PNR_ipc = -10024
|
||||||
|
__PNR_lchown32 = -10025
|
||||||
|
__PNR__llseek = -10026
|
||||||
|
__PNR_lock = -10027
|
||||||
|
__PNR_lstat64 = -10028
|
||||||
|
__PNR_mmap2 = -10029
|
||||||
|
__PNR_mpx = -10030
|
||||||
|
__PNR_newfstatat = -10031
|
||||||
|
__PNR__newselect = -10032
|
||||||
|
__PNR_nice = -10033
|
||||||
|
__PNR_oldfstat = -10034
|
||||||
|
__PNR_oldlstat = -10035
|
||||||
|
__PNR_oldolduname = -10036
|
||||||
|
__PNR_oldstat = -10037
|
||||||
|
__PNR_olduname = -10038
|
||||||
|
__PNR_prof = -10039
|
||||||
|
__PNR_profil = -10040
|
||||||
|
__PNR_readdir = -10041
|
||||||
|
__PNR_security = -10042
|
||||||
|
__PNR_sendfile64 = -10043
|
||||||
|
__PNR_setfsgid32 = -10044
|
||||||
|
__PNR_setfsuid32 = -10045
|
||||||
|
__PNR_setgid32 = -10046
|
||||||
|
__PNR_setgroups32 = -10047
|
||||||
|
__PNR_setregid32 = -10048
|
||||||
|
__PNR_setresgid32 = -10049
|
||||||
|
__PNR_setresuid32 = -10050
|
||||||
|
__PNR_setreuid32 = -10051
|
||||||
|
__PNR_setuid32 = -10052
|
||||||
|
__PNR_sgetmask = -10053
|
||||||
|
__PNR_sigaction = -10054
|
||||||
|
__PNR_signal = -10055
|
||||||
|
__PNR_sigpending = -10056
|
||||||
|
__PNR_sigprocmask = -10057
|
||||||
|
__PNR_sigreturn = -10058
|
||||||
|
__PNR_sigsuspend = -10059
|
||||||
|
__PNR_socketcall = -10060
|
||||||
|
__PNR_ssetmask = -10061
|
||||||
|
__PNR_stat64 = -10062
|
||||||
|
__PNR_statfs64 = -10063
|
||||||
|
__PNR_stime = -10064
|
||||||
|
__PNR_stty = -10065
|
||||||
|
__PNR_truncate64 = -10066
|
||||||
|
__PNR_tuxcall = -10067
|
||||||
|
__PNR_ugetrlimit = -10068
|
||||||
|
__PNR_ulimit = -10069
|
||||||
|
__PNR_umount = -10070
|
||||||
|
__PNR_vm86 = -10071
|
||||||
|
__PNR_vm86old = -10072
|
||||||
|
__PNR_waitpid = -10073
|
||||||
|
__PNR_create_module = -10074
|
||||||
|
__PNR_get_kernel_syms = -10075
|
||||||
|
__PNR_get_thread_area = -10076
|
||||||
|
__PNR_nfsservctl = -10077
|
||||||
|
__PNR_query_module = -10078
|
||||||
|
__PNR_set_thread_area = -10079
|
||||||
|
__PNR__sysctl = -10080
|
||||||
|
__PNR_uselib = -10081
|
||||||
|
__PNR_vserver = -10082
|
||||||
|
__PNR_arm_fadvise64_64 = -10083
|
||||||
|
__PNR_arm_sync_file_range = -10084
|
||||||
|
__PNR_pciconfig_iobase = -10086
|
||||||
|
__PNR_pciconfig_read = -10087
|
||||||
|
__PNR_pciconfig_write = -10088
|
||||||
|
__PNR_sync_file_range2 = -10089
|
||||||
|
__PNR_syscall = -10090
|
||||||
|
__PNR_afs_syscall = -10091
|
||||||
|
__PNR_fadvise64 = -10092
|
||||||
|
__PNR_getpmsg = -10093
|
||||||
|
__PNR_ioperm = -10094
|
||||||
|
__PNR_iopl = -10095
|
||||||
|
__PNR_migrate_pages = -10097
|
||||||
|
__PNR_modify_ldt = -10098
|
||||||
|
__PNR_putpmsg = -10099
|
||||||
|
__PNR_sync_file_range = -10100
|
||||||
|
__PNR_select = -10101
|
||||||
|
__PNR_vfork = -10102
|
||||||
|
__PNR_cachectl = -10103
|
||||||
|
__PNR_cacheflush = -10104
|
||||||
|
__PNR_sysmips = -10106
|
||||||
|
__PNR_timerfd = -10107
|
||||||
|
__PNR_time = -10108
|
||||||
|
__PNR_getrandom = -10109
|
||||||
|
__PNR_memfd_create = -10110
|
||||||
|
__PNR_kexec_file_load = -10111
|
||||||
|
__PNR_sysfs = -10145
|
||||||
|
__PNR_oldwait4 = -10146
|
||||||
|
__PNR_access = -10147
|
||||||
|
__PNR_alarm = -10148
|
||||||
|
__PNR_chmod = -10149
|
||||||
|
__PNR_chown = -10150
|
||||||
|
__PNR_creat = -10151
|
||||||
|
__PNR_dup2 = -10152
|
||||||
|
__PNR_epoll_create = -10153
|
||||||
|
__PNR_epoll_wait = -10154
|
||||||
|
__PNR_eventfd = -10155
|
||||||
|
__PNR_fork = -10156
|
||||||
|
__PNR_futimesat = -10157
|
||||||
|
__PNR_getdents = -10158
|
||||||
|
__PNR_getpgrp = -10159
|
||||||
|
__PNR_inotify_init = -10160
|
||||||
|
__PNR_lchown = -10161
|
||||||
|
__PNR_link = -10162
|
||||||
|
__PNR_lstat = -10163
|
||||||
|
__PNR_mkdir = -10164
|
||||||
|
__PNR_mknod = -10165
|
||||||
|
__PNR_open = -10166
|
||||||
|
__PNR_pause = -10167
|
||||||
|
__PNR_pipe = -10168
|
||||||
|
__PNR_poll = -10169
|
||||||
|
__PNR_readlink = -10170
|
||||||
|
__PNR_rename = -10171
|
||||||
|
__PNR_rmdir = -10172
|
||||||
|
__PNR_signalfd = -10173
|
||||||
|
__PNR_stat = -10174
|
||||||
|
__PNR_symlink = -10175
|
||||||
|
__PNR_unlink = -10176
|
||||||
|
__PNR_ustat = -10177
|
||||||
|
__PNR_utime = -10178
|
||||||
|
__PNR_utimes = -10179
|
||||||
|
__PNR_getrlimit = -10180
|
||||||
|
__PNR_mmap = -10181
|
||||||
|
__PNR_breakpoint = -10182
|
||||||
|
__PNR_set_tls = -10183
|
||||||
|
__PNR_usr26 = -10184
|
||||||
|
__PNR_usr32 = -10185
|
||||||
|
__PNR_multiplexer = -10186
|
||||||
|
__PNR_rtas = -10187
|
||||||
|
__PNR_spu_create = -10188
|
||||||
|
__PNR_spu_run = -10189
|
||||||
|
__PNR_swapcontext = -10190
|
||||||
|
__PNR_sys_debug_setcontext = -10191
|
||||||
|
__PNR_switch_endian = -10191
|
||||||
|
__PNR_get_mempolicy = -10192
|
||||||
|
__PNR_move_pages = -10193
|
||||||
|
__PNR_mbind = -10194
|
||||||
|
__PNR_set_mempolicy = -10195
|
||||||
|
__PNR_s390_runtime_instr = -10196
|
||||||
|
__PNR_s390_pci_mmio_read = -10197
|
||||||
|
__PNR_s390_pci_mmio_write = -10198
|
||||||
|
__PNR_membarrier = -10199
|
||||||
|
__PNR_userfaultfd = -10200
|
||||||
|
__PNR_pkey_mprotect = -10201
|
||||||
|
__PNR_pkey_alloc = -10202
|
||||||
|
__PNR_pkey_free = -10203
|
||||||
|
__PNR_get_tls = -10204
|
||||||
|
__PNR_s390_guarded_storage = -10205
|
||||||
|
__PNR_s390_sthyi = -10206
|
||||||
|
__PNR_subpage_prot = -10207
|
||||||
|
__PNR_statx = -10208
|
||||||
|
__PNR_io_pgetevents = -10209
|
||||||
|
__PNR_rseq = -10210
|
||||||
|
__PNR_setrlimit = -10211
|
||||||
|
__PNR_clock_adjtime64 = -10212
|
||||||
|
__PNR_clock_getres_time64 = -10213
|
||||||
|
__PNR_clock_gettime64 = -10214
|
||||||
|
__PNR_clock_nanosleep_time64 = -10215
|
||||||
|
__PNR_clock_settime64 = -10216
|
||||||
|
__PNR_clone3 = -10217
|
||||||
|
__PNR_fsconfig = -10218
|
||||||
|
__PNR_fsmount = -10219
|
||||||
|
__PNR_fsopen = -10220
|
||||||
|
__PNR_fspick = -10221
|
||||||
|
__PNR_futex_time64 = -10222
|
||||||
|
__PNR_io_pgetevents_time64 = -10223
|
||||||
|
__PNR_move_mount = -10224
|
||||||
|
__PNR_mq_timedreceive_time64 = -10225
|
||||||
|
__PNR_mq_timedsend_time64 = -10226
|
||||||
|
__PNR_open_tree = -10227
|
||||||
|
__PNR_pidfd_open = -10228
|
||||||
|
__PNR_pidfd_send_signal = -10229
|
||||||
|
__PNR_ppoll_time64 = -10230
|
||||||
|
__PNR_pselect6_time64 = -10231
|
||||||
|
__PNR_recvmmsg_time64 = -10232
|
||||||
|
__PNR_rt_sigtimedwait_time64 = -10233
|
||||||
|
__PNR_sched_rr_get_interval_time64 = -10234
|
||||||
|
__PNR_semtimedop_time64 = -10235
|
||||||
|
__PNR_timer_gettime64 = -10236
|
||||||
|
__PNR_timer_settime64 = -10237
|
||||||
|
__PNR_timerfd_gettime64 = -10238
|
||||||
|
__PNR_timerfd_settime64 = -10239
|
||||||
|
__PNR_utimensat_time64 = -10240
|
||||||
|
__PNR_ppoll = -10241
|
||||||
|
__PNR_renameat = -10242
|
||||||
|
__PNR_riscv_flush_icache = -10243
|
||||||
|
__PNR_memfd_secret = -10244
|
||||||
|
__PNR_map_shadow_stack = -10245
|
||||||
|
__PNR_fstat = -10246
|
||||||
|
__PNR_atomic_barrier = -10247
|
||||||
|
__PNR_atomic_cmpxchg_32 = -10248
|
||||||
|
__PNR_getpagesize = -10249
|
||||||
|
__PNR_riscv_hwprobe = -10250
|
||||||
|
__PNR_uretprobe = -10251
|
||||||
|
)
|
||||||
76
container/std/seccomp.go
Normal file
76
container/std/seccomp.go
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
package std
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// ScmpUint is equivalent to C.uint.
|
||||||
|
ScmpUint uint32
|
||||||
|
// ScmpInt is equivalent to C.int.
|
||||||
|
ScmpInt int32
|
||||||
|
|
||||||
|
// ScmpSyscall represents a syscall number passed to libseccomp via [NativeRule.Syscall].
|
||||||
|
ScmpSyscall ScmpInt
|
||||||
|
// ScmpErrno represents an errno value passed to libseccomp via [NativeRule.Errno].
|
||||||
|
ScmpErrno ScmpInt
|
||||||
|
|
||||||
|
// ScmpCompare is equivalent to enum scmp_compare;
|
||||||
|
ScmpCompare ScmpUint
|
||||||
|
// ScmpDatum is equivalent to scmp_datum_t.
|
||||||
|
ScmpDatum uint64
|
||||||
|
|
||||||
|
// ScmpArgCmp is equivalent to struct scmp_arg_cmp.
|
||||||
|
ScmpArgCmp struct {
|
||||||
|
// argument number, starting at 0
|
||||||
|
Arg ScmpUint `json:"arg"`
|
||||||
|
// the comparison op, e.g. SCMP_CMP_*
|
||||||
|
Op ScmpCompare `json:"op"`
|
||||||
|
|
||||||
|
DatumA ScmpDatum `json:"a,omitempty"`
|
||||||
|
DatumB ScmpDatum `json:"b,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// A NativeRule specifies an arch-specific action taken by seccomp under certain conditions.
|
||||||
|
NativeRule struct {
|
||||||
|
// Syscall is the arch-dependent syscall number to act against.
|
||||||
|
Syscall ScmpSyscall `json:"syscall"`
|
||||||
|
// Errno is the errno value to return when the condition is satisfied.
|
||||||
|
Errno ScmpErrno `json:"errno"`
|
||||||
|
// Arg is the optional struct scmp_arg_cmp passed to libseccomp.
|
||||||
|
Arg *ScmpArgCmp `json:"arg,omitempty"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalJSON resolves the name of [ScmpSyscall] and encodes it as a [json] string.
|
||||||
|
// If such a name does not exist, the syscall number is encoded instead.
|
||||||
|
func (num *ScmpSyscall) MarshalJSON() ([]byte, error) {
|
||||||
|
n := *num
|
||||||
|
for name, cur := range Syscalls() {
|
||||||
|
if cur == n {
|
||||||
|
return json.Marshal(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return json.Marshal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyscallNameError is returned when trying to unmarshal an invalid syscall name into [ScmpSyscall].
|
||||||
|
type SyscallNameError string
|
||||||
|
|
||||||
|
func (e SyscallNameError) Error() string { return "invalid syscall name " + strconv.Quote(string(e)) }
|
||||||
|
|
||||||
|
// UnmarshalJSON looks up the syscall number corresponding to name encoded in data
|
||||||
|
// by calling [SyscallResolveName].
|
||||||
|
func (num *ScmpSyscall) UnmarshalJSON(data []byte) error {
|
||||||
|
var name string
|
||||||
|
if err := json.Unmarshal(data, &name); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n, ok := SyscallResolveName(name); !ok {
|
||||||
|
return SyscallNameError(name)
|
||||||
|
} else {
|
||||||
|
*num = n
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
62
container/std/seccomp_test.go
Normal file
62
container/std/seccomp_test.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package std_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container/std"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestScmpSyscall(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
data string
|
||||||
|
want std.ScmpSyscall
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"epoll_create1", `"epoll_create1"`, std.SNR_EPOLL_CREATE1, nil},
|
||||||
|
{"clone3", `"clone3"`, std.SNR_CLONE3, nil},
|
||||||
|
|
||||||
|
{"oob", `-2147483647`, -math.MaxInt32,
|
||||||
|
&json.UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 11}},
|
||||||
|
{"name", `"nonexistent_syscall"`, -math.MaxInt32,
|
||||||
|
std.SyscallNameError("nonexistent_syscall")},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
t.Run("decode", func(t *testing.T) {
|
||||||
|
var got std.ScmpSyscall
|
||||||
|
if err := json.Unmarshal([]byte(tc.data), &got); !reflect.DeepEqual(err, tc.err) {
|
||||||
|
t.Fatalf("Unmarshal: error = %#v, want %#v", err, tc.err)
|
||||||
|
} else if err == nil && got != tc.want {
|
||||||
|
t.Errorf("Unmarshal: %v, want %v", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if errors.As(tc.err, new(std.SyscallNameError)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("encode", func(t *testing.T) {
|
||||||
|
if got, err := json.Marshal(&tc.want); err != nil {
|
||||||
|
t.Fatalf("Marshal: error = %v", err)
|
||||||
|
} else if string(got) != tc.data {
|
||||||
|
t.Errorf("Marshal: %s, want %s", string(got), tc.data)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("error", func(t *testing.T) {
|
||||||
|
const want = `invalid syscall name "\x00"`
|
||||||
|
if got := std.SyscallNameError("\x00").Error(); got != want {
|
||||||
|
t.Fatalf("Error: %q, want %q", got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package seccomp
|
package std
|
||||||
|
|
||||||
import "iter"
|
import "iter"
|
||||||
|
|
||||||
// Syscalls returns an iterator over all wired syscalls.
|
// Syscalls returns an iterator over all wired syscalls.
|
||||||
func Syscalls() iter.Seq2[string, int] {
|
func Syscalls() iter.Seq2[string, ScmpSyscall] {
|
||||||
return func(yield func(string, int) bool) {
|
return func(yield func(string, ScmpSyscall) bool) {
|
||||||
for name, num := range syscallNum {
|
for name, num := range syscallNum {
|
||||||
if !yield(name, num) {
|
if !yield(name, num) {
|
||||||
return
|
return
|
||||||
@@ -19,7 +19,7 @@ func Syscalls() iter.Seq2[string, int] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SyscallResolveName resolves a syscall number from its string representation.
|
// SyscallResolveName resolves a syscall number from its string representation.
|
||||||
func SyscallResolveName(name string) (num int, ok bool) {
|
func SyscallResolveName(name string) (num ScmpSyscall, ok bool) {
|
||||||
if num, ok = syscallNum[name]; ok {
|
if num, ok = syscallNum[name]; ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
13
container/std/syscall_extra_linux_386.go
Normal file
13
container/std/syscall_extra_linux_386.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package std
|
||||||
|
|
||||||
|
var syscallNumExtra = map[string]ScmpSyscall{
|
||||||
|
"kexec_file_load": SNR_KEXEC_FILE_LOAD,
|
||||||
|
"subpage_prot": SNR_SUBPAGE_PROT,
|
||||||
|
"switch_endian": SNR_SWITCH_ENDIAN,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SNR_KEXEC_FILE_LOAD ScmpSyscall = __PNR_kexec_file_load
|
||||||
|
SNR_SUBPAGE_PROT ScmpSyscall = __PNR_subpage_prot
|
||||||
|
SNR_SWITCH_ENDIAN ScmpSyscall = __PNR_switch_endian
|
||||||
|
)
|
||||||
41
container/std/syscall_extra_linux_amd64.go
Normal file
41
container/std/syscall_extra_linux_amd64.go
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package std
|
||||||
|
|
||||||
|
var syscallNumExtra = map[string]ScmpSyscall{
|
||||||
|
"umount": SNR_UMOUNT,
|
||||||
|
"subpage_prot": SNR_SUBPAGE_PROT,
|
||||||
|
"switch_endian": SNR_SWITCH_ENDIAN,
|
||||||
|
"vm86": SNR_VM86,
|
||||||
|
"vm86old": SNR_VM86OLD,
|
||||||
|
"clock_adjtime64": SNR_CLOCK_ADJTIME64,
|
||||||
|
"clock_settime64": SNR_CLOCK_SETTIME64,
|
||||||
|
"chown32": SNR_CHOWN32,
|
||||||
|
"fchown32": SNR_FCHOWN32,
|
||||||
|
"lchown32": SNR_LCHOWN32,
|
||||||
|
"setgid32": SNR_SETGID32,
|
||||||
|
"setgroups32": SNR_SETGROUPS32,
|
||||||
|
"setregid32": SNR_SETREGID32,
|
||||||
|
"setresgid32": SNR_SETRESGID32,
|
||||||
|
"setresuid32": SNR_SETRESUID32,
|
||||||
|
"setreuid32": SNR_SETREUID32,
|
||||||
|
"setuid32": SNR_SETUID32,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SNR_UMOUNT ScmpSyscall = __PNR_umount
|
||||||
|
SNR_SUBPAGE_PROT ScmpSyscall = __PNR_subpage_prot
|
||||||
|
SNR_SWITCH_ENDIAN ScmpSyscall = __PNR_switch_endian
|
||||||
|
SNR_VM86 ScmpSyscall = __PNR_vm86
|
||||||
|
SNR_VM86OLD ScmpSyscall = __PNR_vm86old
|
||||||
|
SNR_CLOCK_ADJTIME64 ScmpSyscall = __PNR_clock_adjtime64
|
||||||
|
SNR_CLOCK_SETTIME64 ScmpSyscall = __PNR_clock_settime64
|
||||||
|
SNR_CHOWN32 ScmpSyscall = __PNR_chown32
|
||||||
|
SNR_FCHOWN32 ScmpSyscall = __PNR_fchown32
|
||||||
|
SNR_LCHOWN32 ScmpSyscall = __PNR_lchown32
|
||||||
|
SNR_SETGID32 ScmpSyscall = __PNR_setgid32
|
||||||
|
SNR_SETGROUPS32 ScmpSyscall = __PNR_setgroups32
|
||||||
|
SNR_SETREGID32 ScmpSyscall = __PNR_setregid32
|
||||||
|
SNR_SETRESGID32 ScmpSyscall = __PNR_setresgid32
|
||||||
|
SNR_SETRESUID32 ScmpSyscall = __PNR_setresuid32
|
||||||
|
SNR_SETREUID32 ScmpSyscall = __PNR_setreuid32
|
||||||
|
SNR_SETUID32 ScmpSyscall = __PNR_setuid32
|
||||||
|
)
|
||||||
55
container/std/syscall_extra_linux_arm64.go
Normal file
55
container/std/syscall_extra_linux_arm64.go
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
package std
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_NEWFSTATAT = syscall.SYS_FSTATAT
|
||||||
|
)
|
||||||
|
|
||||||
|
var syscallNumExtra = map[string]ScmpSyscall{
|
||||||
|
"uselib": SNR_USELIB,
|
||||||
|
"clock_adjtime64": SNR_CLOCK_ADJTIME64,
|
||||||
|
"clock_settime64": SNR_CLOCK_SETTIME64,
|
||||||
|
"umount": SNR_UMOUNT,
|
||||||
|
"chown": SNR_CHOWN,
|
||||||
|
"chown32": SNR_CHOWN32,
|
||||||
|
"fchown32": SNR_FCHOWN32,
|
||||||
|
"lchown": SNR_LCHOWN,
|
||||||
|
"lchown32": SNR_LCHOWN32,
|
||||||
|
"setgid32": SNR_SETGID32,
|
||||||
|
"setgroups32": SNR_SETGROUPS32,
|
||||||
|
"setregid32": SNR_SETREGID32,
|
||||||
|
"setresgid32": SNR_SETRESGID32,
|
||||||
|
"setresuid32": SNR_SETRESUID32,
|
||||||
|
"setreuid32": SNR_SETREUID32,
|
||||||
|
"setuid32": SNR_SETUID32,
|
||||||
|
"modify_ldt": SNR_MODIFY_LDT,
|
||||||
|
"subpage_prot": SNR_SUBPAGE_PROT,
|
||||||
|
"switch_endian": SNR_SWITCH_ENDIAN,
|
||||||
|
"vm86": SNR_VM86,
|
||||||
|
"vm86old": SNR_VM86OLD,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SNR_USELIB ScmpSyscall = __PNR_uselib
|
||||||
|
SNR_CLOCK_ADJTIME64 ScmpSyscall = __PNR_clock_adjtime64
|
||||||
|
SNR_CLOCK_SETTIME64 ScmpSyscall = __PNR_clock_settime64
|
||||||
|
SNR_UMOUNT ScmpSyscall = __PNR_umount
|
||||||
|
SNR_CHOWN ScmpSyscall = __PNR_chown
|
||||||
|
SNR_CHOWN32 ScmpSyscall = __PNR_chown32
|
||||||
|
SNR_FCHOWN32 ScmpSyscall = __PNR_fchown32
|
||||||
|
SNR_LCHOWN ScmpSyscall = __PNR_lchown
|
||||||
|
SNR_LCHOWN32 ScmpSyscall = __PNR_lchown32
|
||||||
|
SNR_SETGID32 ScmpSyscall = __PNR_setgid32
|
||||||
|
SNR_SETGROUPS32 ScmpSyscall = __PNR_setgroups32
|
||||||
|
SNR_SETREGID32 ScmpSyscall = __PNR_setregid32
|
||||||
|
SNR_SETRESGID32 ScmpSyscall = __PNR_setresgid32
|
||||||
|
SNR_SETRESUID32 ScmpSyscall = __PNR_setresuid32
|
||||||
|
SNR_SETREUID32 ScmpSyscall = __PNR_setreuid32
|
||||||
|
SNR_SETUID32 ScmpSyscall = __PNR_setuid32
|
||||||
|
SNR_MODIFY_LDT ScmpSyscall = __PNR_modify_ldt
|
||||||
|
SNR_SUBPAGE_PROT ScmpSyscall = __PNR_subpage_prot
|
||||||
|
SNR_SWITCH_ENDIAN ScmpSyscall = __PNR_switch_endian
|
||||||
|
SNR_VM86 ScmpSyscall = __PNR_vm86
|
||||||
|
SNR_VM86OLD ScmpSyscall = __PNR_vm86old
|
||||||
|
)
|
||||||
1034
container/std/syscall_linux_386.go
Normal file
1034
container/std/syscall_linux_386.go
Normal file
File diff suppressed because it is too large
Load Diff
837
container/std/syscall_linux_amd64.go
Normal file
837
container/std/syscall_linux_amd64.go
Normal file
@@ -0,0 +1,837 @@
|
|||||||
|
// mksysnum_linux.pl /usr/include/asm/unistd_64.h
|
||||||
|
// Code generated by the command above; DO NOT EDIT.
|
||||||
|
|
||||||
|
package std
|
||||||
|
|
||||||
|
import . "syscall"
|
||||||
|
|
||||||
|
var syscallNum = map[string]ScmpSyscall{
|
||||||
|
"read": SNR_READ,
|
||||||
|
"write": SNR_WRITE,
|
||||||
|
"open": SNR_OPEN,
|
||||||
|
"close": SNR_CLOSE,
|
||||||
|
"stat": SNR_STAT,
|
||||||
|
"fstat": SNR_FSTAT,
|
||||||
|
"lstat": SNR_LSTAT,
|
||||||
|
"poll": SNR_POLL,
|
||||||
|
"lseek": SNR_LSEEK,
|
||||||
|
"mmap": SNR_MMAP,
|
||||||
|
"mprotect": SNR_MPROTECT,
|
||||||
|
"munmap": SNR_MUNMAP,
|
||||||
|
"brk": SNR_BRK,
|
||||||
|
"rt_sigaction": SNR_RT_SIGACTION,
|
||||||
|
"rt_sigprocmask": SNR_RT_SIGPROCMASK,
|
||||||
|
"rt_sigreturn": SNR_RT_SIGRETURN,
|
||||||
|
"ioctl": SNR_IOCTL,
|
||||||
|
"pread64": SNR_PREAD64,
|
||||||
|
"pwrite64": SNR_PWRITE64,
|
||||||
|
"readv": SNR_READV,
|
||||||
|
"writev": SNR_WRITEV,
|
||||||
|
"access": SNR_ACCESS,
|
||||||
|
"pipe": SNR_PIPE,
|
||||||
|
"select": SNR_SELECT,
|
||||||
|
"sched_yield": SNR_SCHED_YIELD,
|
||||||
|
"mremap": SNR_MREMAP,
|
||||||
|
"msync": SNR_MSYNC,
|
||||||
|
"mincore": SNR_MINCORE,
|
||||||
|
"madvise": SNR_MADVISE,
|
||||||
|
"shmget": SNR_SHMGET,
|
||||||
|
"shmat": SNR_SHMAT,
|
||||||
|
"shmctl": SNR_SHMCTL,
|
||||||
|
"dup": SNR_DUP,
|
||||||
|
"dup2": SNR_DUP2,
|
||||||
|
"pause": SNR_PAUSE,
|
||||||
|
"nanosleep": SNR_NANOSLEEP,
|
||||||
|
"getitimer": SNR_GETITIMER,
|
||||||
|
"alarm": SNR_ALARM,
|
||||||
|
"setitimer": SNR_SETITIMER,
|
||||||
|
"getpid": SNR_GETPID,
|
||||||
|
"sendfile": SNR_SENDFILE,
|
||||||
|
"socket": SNR_SOCKET,
|
||||||
|
"connect": SNR_CONNECT,
|
||||||
|
"accept": SNR_ACCEPT,
|
||||||
|
"sendto": SNR_SENDTO,
|
||||||
|
"recvfrom": SNR_RECVFROM,
|
||||||
|
"sendmsg": SNR_SENDMSG,
|
||||||
|
"recvmsg": SNR_RECVMSG,
|
||||||
|
"shutdown": SNR_SHUTDOWN,
|
||||||
|
"bind": SNR_BIND,
|
||||||
|
"listen": SNR_LISTEN,
|
||||||
|
"getsockname": SNR_GETSOCKNAME,
|
||||||
|
"getpeername": SNR_GETPEERNAME,
|
||||||
|
"socketpair": SNR_SOCKETPAIR,
|
||||||
|
"setsockopt": SNR_SETSOCKOPT,
|
||||||
|
"getsockopt": SNR_GETSOCKOPT,
|
||||||
|
"clone": SNR_CLONE,
|
||||||
|
"fork": SNR_FORK,
|
||||||
|
"vfork": SNR_VFORK,
|
||||||
|
"execve": SNR_EXECVE,
|
||||||
|
"exit": SNR_EXIT,
|
||||||
|
"wait4": SNR_WAIT4,
|
||||||
|
"kill": SNR_KILL,
|
||||||
|
"uname": SNR_UNAME,
|
||||||
|
"semget": SNR_SEMGET,
|
||||||
|
"semop": SNR_SEMOP,
|
||||||
|
"semctl": SNR_SEMCTL,
|
||||||
|
"shmdt": SNR_SHMDT,
|
||||||
|
"msgget": SNR_MSGGET,
|
||||||
|
"msgsnd": SNR_MSGSND,
|
||||||
|
"msgrcv": SNR_MSGRCV,
|
||||||
|
"msgctl": SNR_MSGCTL,
|
||||||
|
"fcntl": SNR_FCNTL,
|
||||||
|
"flock": SNR_FLOCK,
|
||||||
|
"fsync": SNR_FSYNC,
|
||||||
|
"fdatasync": SNR_FDATASYNC,
|
||||||
|
"truncate": SNR_TRUNCATE,
|
||||||
|
"ftruncate": SNR_FTRUNCATE,
|
||||||
|
"getdents": SNR_GETDENTS,
|
||||||
|
"getcwd": SNR_GETCWD,
|
||||||
|
"chdir": SNR_CHDIR,
|
||||||
|
"fchdir": SNR_FCHDIR,
|
||||||
|
"rename": SNR_RENAME,
|
||||||
|
"mkdir": SNR_MKDIR,
|
||||||
|
"rmdir": SNR_RMDIR,
|
||||||
|
"creat": SNR_CREAT,
|
||||||
|
"link": SNR_LINK,
|
||||||
|
"unlink": SNR_UNLINK,
|
||||||
|
"symlink": SNR_SYMLINK,
|
||||||
|
"readlink": SNR_READLINK,
|
||||||
|
"chmod": SNR_CHMOD,
|
||||||
|
"fchmod": SNR_FCHMOD,
|
||||||
|
"chown": SNR_CHOWN,
|
||||||
|
"fchown": SNR_FCHOWN,
|
||||||
|
"lchown": SNR_LCHOWN,
|
||||||
|
"umask": SNR_UMASK,
|
||||||
|
"gettimeofday": SNR_GETTIMEOFDAY,
|
||||||
|
"getrlimit": SNR_GETRLIMIT,
|
||||||
|
"getrusage": SNR_GETRUSAGE,
|
||||||
|
"sysinfo": SNR_SYSINFO,
|
||||||
|
"times": SNR_TIMES,
|
||||||
|
"ptrace": SNR_PTRACE,
|
||||||
|
"getuid": SNR_GETUID,
|
||||||
|
"syslog": SNR_SYSLOG,
|
||||||
|
"getgid": SNR_GETGID,
|
||||||
|
"setuid": SNR_SETUID,
|
||||||
|
"setgid": SNR_SETGID,
|
||||||
|
"geteuid": SNR_GETEUID,
|
||||||
|
"getegid": SNR_GETEGID,
|
||||||
|
"setpgid": SNR_SETPGID,
|
||||||
|
"getppid": SNR_GETPPID,
|
||||||
|
"getpgrp": SNR_GETPGRP,
|
||||||
|
"setsid": SNR_SETSID,
|
||||||
|
"setreuid": SNR_SETREUID,
|
||||||
|
"setregid": SNR_SETREGID,
|
||||||
|
"getgroups": SNR_GETGROUPS,
|
||||||
|
"setgroups": SNR_SETGROUPS,
|
||||||
|
"setresuid": SNR_SETRESUID,
|
||||||
|
"getresuid": SNR_GETRESUID,
|
||||||
|
"setresgid": SNR_SETRESGID,
|
||||||
|
"getresgid": SNR_GETRESGID,
|
||||||
|
"getpgid": SNR_GETPGID,
|
||||||
|
"setfsuid": SNR_SETFSUID,
|
||||||
|
"setfsgid": SNR_SETFSGID,
|
||||||
|
"getsid": SNR_GETSID,
|
||||||
|
"capget": SNR_CAPGET,
|
||||||
|
"capset": SNR_CAPSET,
|
||||||
|
"rt_sigpending": SNR_RT_SIGPENDING,
|
||||||
|
"rt_sigtimedwait": SNR_RT_SIGTIMEDWAIT,
|
||||||
|
"rt_sigqueueinfo": SNR_RT_SIGQUEUEINFO,
|
||||||
|
"rt_sigsuspend": SNR_RT_SIGSUSPEND,
|
||||||
|
"sigaltstack": SNR_SIGALTSTACK,
|
||||||
|
"utime": SNR_UTIME,
|
||||||
|
"mknod": SNR_MKNOD,
|
||||||
|
"uselib": SNR_USELIB,
|
||||||
|
"personality": SNR_PERSONALITY,
|
||||||
|
"ustat": SNR_USTAT,
|
||||||
|
"statfs": SNR_STATFS,
|
||||||
|
"fstatfs": SNR_FSTATFS,
|
||||||
|
"sysfs": SNR_SYSFS,
|
||||||
|
"getpriority": SNR_GETPRIORITY,
|
||||||
|
"setpriority": SNR_SETPRIORITY,
|
||||||
|
"sched_setparam": SNR_SCHED_SETPARAM,
|
||||||
|
"sched_getparam": SNR_SCHED_GETPARAM,
|
||||||
|
"sched_setscheduler": SNR_SCHED_SETSCHEDULER,
|
||||||
|
"sched_getscheduler": SNR_SCHED_GETSCHEDULER,
|
||||||
|
"sched_get_priority_max": SNR_SCHED_GET_PRIORITY_MAX,
|
||||||
|
"sched_get_priority_min": SNR_SCHED_GET_PRIORITY_MIN,
|
||||||
|
"sched_rr_get_interval": SNR_SCHED_RR_GET_INTERVAL,
|
||||||
|
"mlock": SNR_MLOCK,
|
||||||
|
"munlock": SNR_MUNLOCK,
|
||||||
|
"mlockall": SNR_MLOCKALL,
|
||||||
|
"munlockall": SNR_MUNLOCKALL,
|
||||||
|
"vhangup": SNR_VHANGUP,
|
||||||
|
"modify_ldt": SNR_MODIFY_LDT,
|
||||||
|
"pivot_root": SNR_PIVOT_ROOT,
|
||||||
|
"_sysctl": SNR__SYSCTL,
|
||||||
|
"prctl": SNR_PRCTL,
|
||||||
|
"arch_prctl": SNR_ARCH_PRCTL,
|
||||||
|
"adjtimex": SNR_ADJTIMEX,
|
||||||
|
"setrlimit": SNR_SETRLIMIT,
|
||||||
|
"chroot": SNR_CHROOT,
|
||||||
|
"sync": SNR_SYNC,
|
||||||
|
"acct": SNR_ACCT,
|
||||||
|
"settimeofday": SNR_SETTIMEOFDAY,
|
||||||
|
"mount": SNR_MOUNT,
|
||||||
|
"umount2": SNR_UMOUNT2,
|
||||||
|
"swapon": SNR_SWAPON,
|
||||||
|
"swapoff": SNR_SWAPOFF,
|
||||||
|
"reboot": SNR_REBOOT,
|
||||||
|
"sethostname": SNR_SETHOSTNAME,
|
||||||
|
"setdomainname": SNR_SETDOMAINNAME,
|
||||||
|
"iopl": SNR_IOPL,
|
||||||
|
"ioperm": SNR_IOPERM,
|
||||||
|
"create_module": SNR_CREATE_MODULE,
|
||||||
|
"init_module": SNR_INIT_MODULE,
|
||||||
|
"delete_module": SNR_DELETE_MODULE,
|
||||||
|
"get_kernel_syms": SNR_GET_KERNEL_SYMS,
|
||||||
|
"query_module": SNR_QUERY_MODULE,
|
||||||
|
"quotactl": SNR_QUOTACTL,
|
||||||
|
"nfsservctl": SNR_NFSSERVCTL,
|
||||||
|
"getpmsg": SNR_GETPMSG,
|
||||||
|
"putpmsg": SNR_PUTPMSG,
|
||||||
|
"afs_syscall": SNR_AFS_SYSCALL,
|
||||||
|
"tuxcall": SNR_TUXCALL,
|
||||||
|
"security": SNR_SECURITY,
|
||||||
|
"gettid": SNR_GETTID,
|
||||||
|
"readahead": SNR_READAHEAD,
|
||||||
|
"setxattr": SNR_SETXATTR,
|
||||||
|
"lsetxattr": SNR_LSETXATTR,
|
||||||
|
"fsetxattr": SNR_FSETXATTR,
|
||||||
|
"getxattr": SNR_GETXATTR,
|
||||||
|
"lgetxattr": SNR_LGETXATTR,
|
||||||
|
"fgetxattr": SNR_FGETXATTR,
|
||||||
|
"listxattr": SNR_LISTXATTR,
|
||||||
|
"llistxattr": SNR_LLISTXATTR,
|
||||||
|
"flistxattr": SNR_FLISTXATTR,
|
||||||
|
"removexattr": SNR_REMOVEXATTR,
|
||||||
|
"lremovexattr": SNR_LREMOVEXATTR,
|
||||||
|
"fremovexattr": SNR_FREMOVEXATTR,
|
||||||
|
"tkill": SNR_TKILL,
|
||||||
|
"time": SNR_TIME,
|
||||||
|
"futex": SNR_FUTEX,
|
||||||
|
"sched_setaffinity": SNR_SCHED_SETAFFINITY,
|
||||||
|
"sched_getaffinity": SNR_SCHED_GETAFFINITY,
|
||||||
|
"set_thread_area": SNR_SET_THREAD_AREA,
|
||||||
|
"io_setup": SNR_IO_SETUP,
|
||||||
|
"io_destroy": SNR_IO_DESTROY,
|
||||||
|
"io_getevents": SNR_IO_GETEVENTS,
|
||||||
|
"io_submit": SNR_IO_SUBMIT,
|
||||||
|
"io_cancel": SNR_IO_CANCEL,
|
||||||
|
"get_thread_area": SNR_GET_THREAD_AREA,
|
||||||
|
"lookup_dcookie": SNR_LOOKUP_DCOOKIE,
|
||||||
|
"epoll_create": SNR_EPOLL_CREATE,
|
||||||
|
"epoll_ctl_old": SNR_EPOLL_CTL_OLD,
|
||||||
|
"epoll_wait_old": SNR_EPOLL_WAIT_OLD,
|
||||||
|
"remap_file_pages": SNR_REMAP_FILE_PAGES,
|
||||||
|
"getdents64": SNR_GETDENTS64,
|
||||||
|
"set_tid_address": SNR_SET_TID_ADDRESS,
|
||||||
|
"restart_syscall": SNR_RESTART_SYSCALL,
|
||||||
|
"semtimedop": SNR_SEMTIMEDOP,
|
||||||
|
"fadvise64": SNR_FADVISE64,
|
||||||
|
"timer_create": SNR_TIMER_CREATE,
|
||||||
|
"timer_settime": SNR_TIMER_SETTIME,
|
||||||
|
"timer_gettime": SNR_TIMER_GETTIME,
|
||||||
|
"timer_getoverrun": SNR_TIMER_GETOVERRUN,
|
||||||
|
"timer_delete": SNR_TIMER_DELETE,
|
||||||
|
"clock_settime": SNR_CLOCK_SETTIME,
|
||||||
|
"clock_gettime": SNR_CLOCK_GETTIME,
|
||||||
|
"clock_getres": SNR_CLOCK_GETRES,
|
||||||
|
"clock_nanosleep": SNR_CLOCK_NANOSLEEP,
|
||||||
|
"exit_group": SNR_EXIT_GROUP,
|
||||||
|
"epoll_wait": SNR_EPOLL_WAIT,
|
||||||
|
"epoll_ctl": SNR_EPOLL_CTL,
|
||||||
|
"tgkill": SNR_TGKILL,
|
||||||
|
"utimes": SNR_UTIMES,
|
||||||
|
"vserver": SNR_VSERVER,
|
||||||
|
"mbind": SNR_MBIND,
|
||||||
|
"set_mempolicy": SNR_SET_MEMPOLICY,
|
||||||
|
"get_mempolicy": SNR_GET_MEMPOLICY,
|
||||||
|
"mq_open": SNR_MQ_OPEN,
|
||||||
|
"mq_unlink": SNR_MQ_UNLINK,
|
||||||
|
"mq_timedsend": SNR_MQ_TIMEDSEND,
|
||||||
|
"mq_timedreceive": SNR_MQ_TIMEDRECEIVE,
|
||||||
|
"mq_notify": SNR_MQ_NOTIFY,
|
||||||
|
"mq_getsetattr": SNR_MQ_GETSETATTR,
|
||||||
|
"kexec_load": SNR_KEXEC_LOAD,
|
||||||
|
"waitid": SNR_WAITID,
|
||||||
|
"add_key": SNR_ADD_KEY,
|
||||||
|
"request_key": SNR_REQUEST_KEY,
|
||||||
|
"keyctl": SNR_KEYCTL,
|
||||||
|
"ioprio_set": SNR_IOPRIO_SET,
|
||||||
|
"ioprio_get": SNR_IOPRIO_GET,
|
||||||
|
"inotify_init": SNR_INOTIFY_INIT,
|
||||||
|
"inotify_add_watch": SNR_INOTIFY_ADD_WATCH,
|
||||||
|
"inotify_rm_watch": SNR_INOTIFY_RM_WATCH,
|
||||||
|
"migrate_pages": SNR_MIGRATE_PAGES,
|
||||||
|
"openat": SNR_OPENAT,
|
||||||
|
"mkdirat": SNR_MKDIRAT,
|
||||||
|
"mknodat": SNR_MKNODAT,
|
||||||
|
"fchownat": SNR_FCHOWNAT,
|
||||||
|
"futimesat": SNR_FUTIMESAT,
|
||||||
|
"newfstatat": SNR_NEWFSTATAT,
|
||||||
|
"unlinkat": SNR_UNLINKAT,
|
||||||
|
"renameat": SNR_RENAMEAT,
|
||||||
|
"linkat": SNR_LINKAT,
|
||||||
|
"symlinkat": SNR_SYMLINKAT,
|
||||||
|
"readlinkat": SNR_READLINKAT,
|
||||||
|
"fchmodat": SNR_FCHMODAT,
|
||||||
|
"faccessat": SNR_FACCESSAT,
|
||||||
|
"pselect6": SNR_PSELECT6,
|
||||||
|
"ppoll": SNR_PPOLL,
|
||||||
|
"unshare": SNR_UNSHARE,
|
||||||
|
"set_robust_list": SNR_SET_ROBUST_LIST,
|
||||||
|
"get_robust_list": SNR_GET_ROBUST_LIST,
|
||||||
|
"splice": SNR_SPLICE,
|
||||||
|
"tee": SNR_TEE,
|
||||||
|
"sync_file_range": SNR_SYNC_FILE_RANGE,
|
||||||
|
"vmsplice": SNR_VMSPLICE,
|
||||||
|
"move_pages": SNR_MOVE_PAGES,
|
||||||
|
"utimensat": SNR_UTIMENSAT,
|
||||||
|
"epoll_pwait": SNR_EPOLL_PWAIT,
|
||||||
|
"signalfd": SNR_SIGNALFD,
|
||||||
|
"timerfd_create": SNR_TIMERFD_CREATE,
|
||||||
|
"eventfd": SNR_EVENTFD,
|
||||||
|
"fallocate": SNR_FALLOCATE,
|
||||||
|
"timerfd_settime": SNR_TIMERFD_SETTIME,
|
||||||
|
"timerfd_gettime": SNR_TIMERFD_GETTIME,
|
||||||
|
"accept4": SNR_ACCEPT4,
|
||||||
|
"signalfd4": SNR_SIGNALFD4,
|
||||||
|
"eventfd2": SNR_EVENTFD2,
|
||||||
|
"epoll_create1": SNR_EPOLL_CREATE1,
|
||||||
|
"dup3": SNR_DUP3,
|
||||||
|
"pipe2": SNR_PIPE2,
|
||||||
|
"inotify_init1": SNR_INOTIFY_INIT1,
|
||||||
|
"preadv": SNR_PREADV,
|
||||||
|
"pwritev": SNR_PWRITEV,
|
||||||
|
"rt_tgsigqueueinfo": SNR_RT_TGSIGQUEUEINFO,
|
||||||
|
"perf_event_open": SNR_PERF_EVENT_OPEN,
|
||||||
|
"recvmmsg": SNR_RECVMMSG,
|
||||||
|
"fanotify_init": SNR_FANOTIFY_INIT,
|
||||||
|
"fanotify_mark": SNR_FANOTIFY_MARK,
|
||||||
|
"prlimit64": SNR_PRLIMIT64,
|
||||||
|
"name_to_handle_at": SNR_NAME_TO_HANDLE_AT,
|
||||||
|
"open_by_handle_at": SNR_OPEN_BY_HANDLE_AT,
|
||||||
|
"clock_adjtime": SNR_CLOCK_ADJTIME,
|
||||||
|
"syncfs": SNR_SYNCFS,
|
||||||
|
"sendmmsg": SNR_SENDMMSG,
|
||||||
|
"setns": SNR_SETNS,
|
||||||
|
"getcpu": SNR_GETCPU,
|
||||||
|
"process_vm_readv": SNR_PROCESS_VM_READV,
|
||||||
|
"process_vm_writev": SNR_PROCESS_VM_WRITEV,
|
||||||
|
"kcmp": SNR_KCMP,
|
||||||
|
"finit_module": SNR_FINIT_MODULE,
|
||||||
|
"sched_setattr": SNR_SCHED_SETATTR,
|
||||||
|
"sched_getattr": SNR_SCHED_GETATTR,
|
||||||
|
"renameat2": SNR_RENAMEAT2,
|
||||||
|
"seccomp": SNR_SECCOMP,
|
||||||
|
"getrandom": SNR_GETRANDOM,
|
||||||
|
"memfd_create": SNR_MEMFD_CREATE,
|
||||||
|
"kexec_file_load": SNR_KEXEC_FILE_LOAD,
|
||||||
|
"bpf": SNR_BPF,
|
||||||
|
"execveat": SNR_EXECVEAT,
|
||||||
|
"userfaultfd": SNR_USERFAULTFD,
|
||||||
|
"membarrier": SNR_MEMBARRIER,
|
||||||
|
"mlock2": SNR_MLOCK2,
|
||||||
|
"copy_file_range": SNR_COPY_FILE_RANGE,
|
||||||
|
"preadv2": SNR_PREADV2,
|
||||||
|
"pwritev2": SNR_PWRITEV2,
|
||||||
|
"pkey_mprotect": SNR_PKEY_MPROTECT,
|
||||||
|
"pkey_alloc": SNR_PKEY_ALLOC,
|
||||||
|
"pkey_free": SNR_PKEY_FREE,
|
||||||
|
"statx": SNR_STATX,
|
||||||
|
"io_pgetevents": SNR_IO_PGETEVENTS,
|
||||||
|
"rseq": SNR_RSEQ,
|
||||||
|
"uretprobe": SNR_URETPROBE,
|
||||||
|
"pidfd_send_signal": SNR_PIDFD_SEND_SIGNAL,
|
||||||
|
"io_uring_setup": SNR_IO_URING_SETUP,
|
||||||
|
"io_uring_enter": SNR_IO_URING_ENTER,
|
||||||
|
"io_uring_register": SNR_IO_URING_REGISTER,
|
||||||
|
"open_tree": SNR_OPEN_TREE,
|
||||||
|
"move_mount": SNR_MOVE_MOUNT,
|
||||||
|
"fsopen": SNR_FSOPEN,
|
||||||
|
"fsconfig": SNR_FSCONFIG,
|
||||||
|
"fsmount": SNR_FSMOUNT,
|
||||||
|
"fspick": SNR_FSPICK,
|
||||||
|
"pidfd_open": SNR_PIDFD_OPEN,
|
||||||
|
"clone3": SNR_CLONE3,
|
||||||
|
"close_range": SNR_CLOSE_RANGE,
|
||||||
|
"openat2": SNR_OPENAT2,
|
||||||
|
"pidfd_getfd": SNR_PIDFD_GETFD,
|
||||||
|
"faccessat2": SNR_FACCESSAT2,
|
||||||
|
"process_madvise": SNR_PROCESS_MADVISE,
|
||||||
|
"epoll_pwait2": SNR_EPOLL_PWAIT2,
|
||||||
|
"mount_setattr": SNR_MOUNT_SETATTR,
|
||||||
|
"quotactl_fd": SNR_QUOTACTL_FD,
|
||||||
|
"landlock_create_ruleset": SNR_LANDLOCK_CREATE_RULESET,
|
||||||
|
"landlock_add_rule": SNR_LANDLOCK_ADD_RULE,
|
||||||
|
"landlock_restrict_self": SNR_LANDLOCK_RESTRICT_SELF,
|
||||||
|
"memfd_secret": SNR_MEMFD_SECRET,
|
||||||
|
"process_mrelease": SNR_PROCESS_MRELEASE,
|
||||||
|
"futex_waitv": SNR_FUTEX_WAITV,
|
||||||
|
"set_mempolicy_home_node": SNR_SET_MEMPOLICY_HOME_NODE,
|
||||||
|
"cachestat": SNR_CACHESTAT,
|
||||||
|
"fchmodat2": SNR_FCHMODAT2,
|
||||||
|
"map_shadow_stack": SNR_MAP_SHADOW_STACK,
|
||||||
|
"futex_wake": SNR_FUTEX_WAKE,
|
||||||
|
"futex_wait": SNR_FUTEX_WAIT,
|
||||||
|
"futex_requeue": SNR_FUTEX_REQUEUE,
|
||||||
|
"statmount": SNR_STATMOUNT,
|
||||||
|
"listmount": SNR_LISTMOUNT,
|
||||||
|
"lsm_get_self_attr": SNR_LSM_GET_SELF_ATTR,
|
||||||
|
"lsm_set_self_attr": SNR_LSM_SET_SELF_ATTR,
|
||||||
|
"lsm_list_modules": SNR_LSM_LIST_MODULES,
|
||||||
|
"mseal": SNR_MSEAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_NAME_TO_HANDLE_AT = 303
|
||||||
|
SYS_OPEN_BY_HANDLE_AT = 304
|
||||||
|
SYS_CLOCK_ADJTIME = 305
|
||||||
|
SYS_SYNCFS = 306
|
||||||
|
SYS_SENDMMSG = 307
|
||||||
|
SYS_SETNS = 308
|
||||||
|
SYS_GETCPU = 309
|
||||||
|
SYS_PROCESS_VM_READV = 310
|
||||||
|
SYS_PROCESS_VM_WRITEV = 311
|
||||||
|
SYS_KCMP = 312
|
||||||
|
SYS_FINIT_MODULE = 313
|
||||||
|
SYS_SCHED_SETATTR = 314
|
||||||
|
SYS_SCHED_GETATTR = 315
|
||||||
|
SYS_RENAMEAT2 = 316
|
||||||
|
SYS_SECCOMP = 317
|
||||||
|
SYS_GETRANDOM = 318
|
||||||
|
SYS_MEMFD_CREATE = 319
|
||||||
|
SYS_KEXEC_FILE_LOAD = 320
|
||||||
|
SYS_BPF = 321
|
||||||
|
SYS_EXECVEAT = 322
|
||||||
|
SYS_USERFAULTFD = 323
|
||||||
|
SYS_MEMBARRIER = 324
|
||||||
|
SYS_MLOCK2 = 325
|
||||||
|
SYS_COPY_FILE_RANGE = 326
|
||||||
|
SYS_PREADV2 = 327
|
||||||
|
SYS_PWRITEV2 = 328
|
||||||
|
SYS_PKEY_MPROTECT = 329
|
||||||
|
SYS_PKEY_ALLOC = 330
|
||||||
|
SYS_PKEY_FREE = 331
|
||||||
|
SYS_STATX = 332
|
||||||
|
SYS_IO_PGETEVENTS = 333
|
||||||
|
SYS_RSEQ = 334
|
||||||
|
SYS_URETPROBE = 335
|
||||||
|
SYS_PIDFD_SEND_SIGNAL = 424
|
||||||
|
SYS_IO_URING_SETUP = 425
|
||||||
|
SYS_IO_URING_ENTER = 426
|
||||||
|
SYS_IO_URING_REGISTER = 427
|
||||||
|
SYS_OPEN_TREE = 428
|
||||||
|
SYS_MOVE_MOUNT = 429
|
||||||
|
SYS_FSOPEN = 430
|
||||||
|
SYS_FSCONFIG = 431
|
||||||
|
SYS_FSMOUNT = 432
|
||||||
|
SYS_FSPICK = 433
|
||||||
|
SYS_PIDFD_OPEN = 434
|
||||||
|
SYS_CLONE3 = 435
|
||||||
|
SYS_CLOSE_RANGE = 436
|
||||||
|
SYS_OPENAT2 = 437
|
||||||
|
SYS_PIDFD_GETFD = 438
|
||||||
|
SYS_FACCESSAT2 = 439
|
||||||
|
SYS_PROCESS_MADVISE = 440
|
||||||
|
SYS_EPOLL_PWAIT2 = 441
|
||||||
|
SYS_MOUNT_SETATTR = 442
|
||||||
|
SYS_QUOTACTL_FD = 443
|
||||||
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_MEMFD_SECRET = 447
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
|
SYS_FUTEX_WAITV = 449
|
||||||
|
SYS_SET_MEMPOLICY_HOME_NODE = 450
|
||||||
|
SYS_CACHESTAT = 451
|
||||||
|
SYS_FCHMODAT2 = 452
|
||||||
|
SYS_MAP_SHADOW_STACK = 453
|
||||||
|
SYS_FUTEX_WAKE = 454
|
||||||
|
SYS_FUTEX_WAIT = 455
|
||||||
|
SYS_FUTEX_REQUEUE = 456
|
||||||
|
SYS_STATMOUNT = 457
|
||||||
|
SYS_LISTMOUNT = 458
|
||||||
|
SYS_LSM_GET_SELF_ATTR = 459
|
||||||
|
SYS_LSM_SET_SELF_ATTR = 460
|
||||||
|
SYS_LSM_LIST_MODULES = 461
|
||||||
|
SYS_MSEAL = 462
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SNR_READ ScmpSyscall = SYS_READ
|
||||||
|
SNR_WRITE ScmpSyscall = SYS_WRITE
|
||||||
|
SNR_OPEN ScmpSyscall = SYS_OPEN
|
||||||
|
SNR_CLOSE ScmpSyscall = SYS_CLOSE
|
||||||
|
SNR_STAT ScmpSyscall = SYS_STAT
|
||||||
|
SNR_FSTAT ScmpSyscall = SYS_FSTAT
|
||||||
|
SNR_LSTAT ScmpSyscall = SYS_LSTAT
|
||||||
|
SNR_POLL ScmpSyscall = SYS_POLL
|
||||||
|
SNR_LSEEK ScmpSyscall = SYS_LSEEK
|
||||||
|
SNR_MMAP ScmpSyscall = SYS_MMAP
|
||||||
|
SNR_MPROTECT ScmpSyscall = SYS_MPROTECT
|
||||||
|
SNR_MUNMAP ScmpSyscall = SYS_MUNMAP
|
||||||
|
SNR_BRK ScmpSyscall = SYS_BRK
|
||||||
|
SNR_RT_SIGACTION ScmpSyscall = SYS_RT_SIGACTION
|
||||||
|
SNR_RT_SIGPROCMASK ScmpSyscall = SYS_RT_SIGPROCMASK
|
||||||
|
SNR_RT_SIGRETURN ScmpSyscall = SYS_RT_SIGRETURN
|
||||||
|
SNR_IOCTL ScmpSyscall = SYS_IOCTL
|
||||||
|
SNR_PREAD64 ScmpSyscall = SYS_PREAD64
|
||||||
|
SNR_PWRITE64 ScmpSyscall = SYS_PWRITE64
|
||||||
|
SNR_READV ScmpSyscall = SYS_READV
|
||||||
|
SNR_WRITEV ScmpSyscall = SYS_WRITEV
|
||||||
|
SNR_ACCESS ScmpSyscall = SYS_ACCESS
|
||||||
|
SNR_PIPE ScmpSyscall = SYS_PIPE
|
||||||
|
SNR_SELECT ScmpSyscall = SYS_SELECT
|
||||||
|
SNR_SCHED_YIELD ScmpSyscall = SYS_SCHED_YIELD
|
||||||
|
SNR_MREMAP ScmpSyscall = SYS_MREMAP
|
||||||
|
SNR_MSYNC ScmpSyscall = SYS_MSYNC
|
||||||
|
SNR_MINCORE ScmpSyscall = SYS_MINCORE
|
||||||
|
SNR_MADVISE ScmpSyscall = SYS_MADVISE
|
||||||
|
SNR_SHMGET ScmpSyscall = SYS_SHMGET
|
||||||
|
SNR_SHMAT ScmpSyscall = SYS_SHMAT
|
||||||
|
SNR_SHMCTL ScmpSyscall = SYS_SHMCTL
|
||||||
|
SNR_DUP ScmpSyscall = SYS_DUP
|
||||||
|
SNR_DUP2 ScmpSyscall = SYS_DUP2
|
||||||
|
SNR_PAUSE ScmpSyscall = SYS_PAUSE
|
||||||
|
SNR_NANOSLEEP ScmpSyscall = SYS_NANOSLEEP
|
||||||
|
SNR_GETITIMER ScmpSyscall = SYS_GETITIMER
|
||||||
|
SNR_ALARM ScmpSyscall = SYS_ALARM
|
||||||
|
SNR_SETITIMER ScmpSyscall = SYS_SETITIMER
|
||||||
|
SNR_GETPID ScmpSyscall = SYS_GETPID
|
||||||
|
SNR_SENDFILE ScmpSyscall = SYS_SENDFILE
|
||||||
|
SNR_SOCKET ScmpSyscall = SYS_SOCKET
|
||||||
|
SNR_CONNECT ScmpSyscall = SYS_CONNECT
|
||||||
|
SNR_ACCEPT ScmpSyscall = SYS_ACCEPT
|
||||||
|
SNR_SENDTO ScmpSyscall = SYS_SENDTO
|
||||||
|
SNR_RECVFROM ScmpSyscall = SYS_RECVFROM
|
||||||
|
SNR_SENDMSG ScmpSyscall = SYS_SENDMSG
|
||||||
|
SNR_RECVMSG ScmpSyscall = SYS_RECVMSG
|
||||||
|
SNR_SHUTDOWN ScmpSyscall = SYS_SHUTDOWN
|
||||||
|
SNR_BIND ScmpSyscall = SYS_BIND
|
||||||
|
SNR_LISTEN ScmpSyscall = SYS_LISTEN
|
||||||
|
SNR_GETSOCKNAME ScmpSyscall = SYS_GETSOCKNAME
|
||||||
|
SNR_GETPEERNAME ScmpSyscall = SYS_GETPEERNAME
|
||||||
|
SNR_SOCKETPAIR ScmpSyscall = SYS_SOCKETPAIR
|
||||||
|
SNR_SETSOCKOPT ScmpSyscall = SYS_SETSOCKOPT
|
||||||
|
SNR_GETSOCKOPT ScmpSyscall = SYS_GETSOCKOPT
|
||||||
|
SNR_CLONE ScmpSyscall = SYS_CLONE
|
||||||
|
SNR_FORK ScmpSyscall = SYS_FORK
|
||||||
|
SNR_VFORK ScmpSyscall = SYS_VFORK
|
||||||
|
SNR_EXECVE ScmpSyscall = SYS_EXECVE
|
||||||
|
SNR_EXIT ScmpSyscall = SYS_EXIT
|
||||||
|
SNR_WAIT4 ScmpSyscall = SYS_WAIT4
|
||||||
|
SNR_KILL ScmpSyscall = SYS_KILL
|
||||||
|
SNR_UNAME ScmpSyscall = SYS_UNAME
|
||||||
|
SNR_SEMGET ScmpSyscall = SYS_SEMGET
|
||||||
|
SNR_SEMOP ScmpSyscall = SYS_SEMOP
|
||||||
|
SNR_SEMCTL ScmpSyscall = SYS_SEMCTL
|
||||||
|
SNR_SHMDT ScmpSyscall = SYS_SHMDT
|
||||||
|
SNR_MSGGET ScmpSyscall = SYS_MSGGET
|
||||||
|
SNR_MSGSND ScmpSyscall = SYS_MSGSND
|
||||||
|
SNR_MSGRCV ScmpSyscall = SYS_MSGRCV
|
||||||
|
SNR_MSGCTL ScmpSyscall = SYS_MSGCTL
|
||||||
|
SNR_FCNTL ScmpSyscall = SYS_FCNTL
|
||||||
|
SNR_FLOCK ScmpSyscall = SYS_FLOCK
|
||||||
|
SNR_FSYNC ScmpSyscall = SYS_FSYNC
|
||||||
|
SNR_FDATASYNC ScmpSyscall = SYS_FDATASYNC
|
||||||
|
SNR_TRUNCATE ScmpSyscall = SYS_TRUNCATE
|
||||||
|
SNR_FTRUNCATE ScmpSyscall = SYS_FTRUNCATE
|
||||||
|
SNR_GETDENTS ScmpSyscall = SYS_GETDENTS
|
||||||
|
SNR_GETCWD ScmpSyscall = SYS_GETCWD
|
||||||
|
SNR_CHDIR ScmpSyscall = SYS_CHDIR
|
||||||
|
SNR_FCHDIR ScmpSyscall = SYS_FCHDIR
|
||||||
|
SNR_RENAME ScmpSyscall = SYS_RENAME
|
||||||
|
SNR_MKDIR ScmpSyscall = SYS_MKDIR
|
||||||
|
SNR_RMDIR ScmpSyscall = SYS_RMDIR
|
||||||
|
SNR_CREAT ScmpSyscall = SYS_CREAT
|
||||||
|
SNR_LINK ScmpSyscall = SYS_LINK
|
||||||
|
SNR_UNLINK ScmpSyscall = SYS_UNLINK
|
||||||
|
SNR_SYMLINK ScmpSyscall = SYS_SYMLINK
|
||||||
|
SNR_READLINK ScmpSyscall = SYS_READLINK
|
||||||
|
SNR_CHMOD ScmpSyscall = SYS_CHMOD
|
||||||
|
SNR_FCHMOD ScmpSyscall = SYS_FCHMOD
|
||||||
|
SNR_CHOWN ScmpSyscall = SYS_CHOWN
|
||||||
|
SNR_FCHOWN ScmpSyscall = SYS_FCHOWN
|
||||||
|
SNR_LCHOWN ScmpSyscall = SYS_LCHOWN
|
||||||
|
SNR_UMASK ScmpSyscall = SYS_UMASK
|
||||||
|
SNR_GETTIMEOFDAY ScmpSyscall = SYS_GETTIMEOFDAY
|
||||||
|
SNR_GETRLIMIT ScmpSyscall = SYS_GETRLIMIT
|
||||||
|
SNR_GETRUSAGE ScmpSyscall = SYS_GETRUSAGE
|
||||||
|
SNR_SYSINFO ScmpSyscall = SYS_SYSINFO
|
||||||
|
SNR_TIMES ScmpSyscall = SYS_TIMES
|
||||||
|
SNR_PTRACE ScmpSyscall = SYS_PTRACE
|
||||||
|
SNR_GETUID ScmpSyscall = SYS_GETUID
|
||||||
|
SNR_SYSLOG ScmpSyscall = SYS_SYSLOG
|
||||||
|
SNR_GETGID ScmpSyscall = SYS_GETGID
|
||||||
|
SNR_SETUID ScmpSyscall = SYS_SETUID
|
||||||
|
SNR_SETGID ScmpSyscall = SYS_SETGID
|
||||||
|
SNR_GETEUID ScmpSyscall = SYS_GETEUID
|
||||||
|
SNR_GETEGID ScmpSyscall = SYS_GETEGID
|
||||||
|
SNR_SETPGID ScmpSyscall = SYS_SETPGID
|
||||||
|
SNR_GETPPID ScmpSyscall = SYS_GETPPID
|
||||||
|
SNR_GETPGRP ScmpSyscall = SYS_GETPGRP
|
||||||
|
SNR_SETSID ScmpSyscall = SYS_SETSID
|
||||||
|
SNR_SETREUID ScmpSyscall = SYS_SETREUID
|
||||||
|
SNR_SETREGID ScmpSyscall = SYS_SETREGID
|
||||||
|
SNR_GETGROUPS ScmpSyscall = SYS_GETGROUPS
|
||||||
|
SNR_SETGROUPS ScmpSyscall = SYS_SETGROUPS
|
||||||
|
SNR_SETRESUID ScmpSyscall = SYS_SETRESUID
|
||||||
|
SNR_GETRESUID ScmpSyscall = SYS_GETRESUID
|
||||||
|
SNR_SETRESGID ScmpSyscall = SYS_SETRESGID
|
||||||
|
SNR_GETRESGID ScmpSyscall = SYS_GETRESGID
|
||||||
|
SNR_GETPGID ScmpSyscall = SYS_GETPGID
|
||||||
|
SNR_SETFSUID ScmpSyscall = SYS_SETFSUID
|
||||||
|
SNR_SETFSGID ScmpSyscall = SYS_SETFSGID
|
||||||
|
SNR_GETSID ScmpSyscall = SYS_GETSID
|
||||||
|
SNR_CAPGET ScmpSyscall = SYS_CAPGET
|
||||||
|
SNR_CAPSET ScmpSyscall = SYS_CAPSET
|
||||||
|
SNR_RT_SIGPENDING ScmpSyscall = SYS_RT_SIGPENDING
|
||||||
|
SNR_RT_SIGTIMEDWAIT ScmpSyscall = SYS_RT_SIGTIMEDWAIT
|
||||||
|
SNR_RT_SIGQUEUEINFO ScmpSyscall = SYS_RT_SIGQUEUEINFO
|
||||||
|
SNR_RT_SIGSUSPEND ScmpSyscall = SYS_RT_SIGSUSPEND
|
||||||
|
SNR_SIGALTSTACK ScmpSyscall = SYS_SIGALTSTACK
|
||||||
|
SNR_UTIME ScmpSyscall = SYS_UTIME
|
||||||
|
SNR_MKNOD ScmpSyscall = SYS_MKNOD
|
||||||
|
SNR_USELIB ScmpSyscall = SYS_USELIB
|
||||||
|
SNR_PERSONALITY ScmpSyscall = SYS_PERSONALITY
|
||||||
|
SNR_USTAT ScmpSyscall = SYS_USTAT
|
||||||
|
SNR_STATFS ScmpSyscall = SYS_STATFS
|
||||||
|
SNR_FSTATFS ScmpSyscall = SYS_FSTATFS
|
||||||
|
SNR_SYSFS ScmpSyscall = SYS_SYSFS
|
||||||
|
SNR_GETPRIORITY ScmpSyscall = SYS_GETPRIORITY
|
||||||
|
SNR_SETPRIORITY ScmpSyscall = SYS_SETPRIORITY
|
||||||
|
SNR_SCHED_SETPARAM ScmpSyscall = SYS_SCHED_SETPARAM
|
||||||
|
SNR_SCHED_GETPARAM ScmpSyscall = SYS_SCHED_GETPARAM
|
||||||
|
SNR_SCHED_SETSCHEDULER ScmpSyscall = SYS_SCHED_SETSCHEDULER
|
||||||
|
SNR_SCHED_GETSCHEDULER ScmpSyscall = SYS_SCHED_GETSCHEDULER
|
||||||
|
SNR_SCHED_GET_PRIORITY_MAX ScmpSyscall = SYS_SCHED_GET_PRIORITY_MAX
|
||||||
|
SNR_SCHED_GET_PRIORITY_MIN ScmpSyscall = SYS_SCHED_GET_PRIORITY_MIN
|
||||||
|
SNR_SCHED_RR_GET_INTERVAL ScmpSyscall = SYS_SCHED_RR_GET_INTERVAL
|
||||||
|
SNR_MLOCK ScmpSyscall = SYS_MLOCK
|
||||||
|
SNR_MUNLOCK ScmpSyscall = SYS_MUNLOCK
|
||||||
|
SNR_MLOCKALL ScmpSyscall = SYS_MLOCKALL
|
||||||
|
SNR_MUNLOCKALL ScmpSyscall = SYS_MUNLOCKALL
|
||||||
|
SNR_VHANGUP ScmpSyscall = SYS_VHANGUP
|
||||||
|
SNR_MODIFY_LDT ScmpSyscall = SYS_MODIFY_LDT
|
||||||
|
SNR_PIVOT_ROOT ScmpSyscall = SYS_PIVOT_ROOT
|
||||||
|
SNR__SYSCTL ScmpSyscall = SYS__SYSCTL
|
||||||
|
SNR_PRCTL ScmpSyscall = SYS_PRCTL
|
||||||
|
SNR_ARCH_PRCTL ScmpSyscall = SYS_ARCH_PRCTL
|
||||||
|
SNR_ADJTIMEX ScmpSyscall = SYS_ADJTIMEX
|
||||||
|
SNR_SETRLIMIT ScmpSyscall = SYS_SETRLIMIT
|
||||||
|
SNR_CHROOT ScmpSyscall = SYS_CHROOT
|
||||||
|
SNR_SYNC ScmpSyscall = SYS_SYNC
|
||||||
|
SNR_ACCT ScmpSyscall = SYS_ACCT
|
||||||
|
SNR_SETTIMEOFDAY ScmpSyscall = SYS_SETTIMEOFDAY
|
||||||
|
SNR_MOUNT ScmpSyscall = SYS_MOUNT
|
||||||
|
SNR_UMOUNT2 ScmpSyscall = SYS_UMOUNT2
|
||||||
|
SNR_SWAPON ScmpSyscall = SYS_SWAPON
|
||||||
|
SNR_SWAPOFF ScmpSyscall = SYS_SWAPOFF
|
||||||
|
SNR_REBOOT ScmpSyscall = SYS_REBOOT
|
||||||
|
SNR_SETHOSTNAME ScmpSyscall = SYS_SETHOSTNAME
|
||||||
|
SNR_SETDOMAINNAME ScmpSyscall = SYS_SETDOMAINNAME
|
||||||
|
SNR_IOPL ScmpSyscall = SYS_IOPL
|
||||||
|
SNR_IOPERM ScmpSyscall = SYS_IOPERM
|
||||||
|
SNR_CREATE_MODULE ScmpSyscall = SYS_CREATE_MODULE
|
||||||
|
SNR_INIT_MODULE ScmpSyscall = SYS_INIT_MODULE
|
||||||
|
SNR_DELETE_MODULE ScmpSyscall = SYS_DELETE_MODULE
|
||||||
|
SNR_GET_KERNEL_SYMS ScmpSyscall = SYS_GET_KERNEL_SYMS
|
||||||
|
SNR_QUERY_MODULE ScmpSyscall = SYS_QUERY_MODULE
|
||||||
|
SNR_QUOTACTL ScmpSyscall = SYS_QUOTACTL
|
||||||
|
SNR_NFSSERVCTL ScmpSyscall = SYS_NFSSERVCTL
|
||||||
|
SNR_GETPMSG ScmpSyscall = SYS_GETPMSG
|
||||||
|
SNR_PUTPMSG ScmpSyscall = SYS_PUTPMSG
|
||||||
|
SNR_AFS_SYSCALL ScmpSyscall = SYS_AFS_SYSCALL
|
||||||
|
SNR_TUXCALL ScmpSyscall = SYS_TUXCALL
|
||||||
|
SNR_SECURITY ScmpSyscall = SYS_SECURITY
|
||||||
|
SNR_GETTID ScmpSyscall = SYS_GETTID
|
||||||
|
SNR_READAHEAD ScmpSyscall = SYS_READAHEAD
|
||||||
|
SNR_SETXATTR ScmpSyscall = SYS_SETXATTR
|
||||||
|
SNR_LSETXATTR ScmpSyscall = SYS_LSETXATTR
|
||||||
|
SNR_FSETXATTR ScmpSyscall = SYS_FSETXATTR
|
||||||
|
SNR_GETXATTR ScmpSyscall = SYS_GETXATTR
|
||||||
|
SNR_LGETXATTR ScmpSyscall = SYS_LGETXATTR
|
||||||
|
SNR_FGETXATTR ScmpSyscall = SYS_FGETXATTR
|
||||||
|
SNR_LISTXATTR ScmpSyscall = SYS_LISTXATTR
|
||||||
|
SNR_LLISTXATTR ScmpSyscall = SYS_LLISTXATTR
|
||||||
|
SNR_FLISTXATTR ScmpSyscall = SYS_FLISTXATTR
|
||||||
|
SNR_REMOVEXATTR ScmpSyscall = SYS_REMOVEXATTR
|
||||||
|
SNR_LREMOVEXATTR ScmpSyscall = SYS_LREMOVEXATTR
|
||||||
|
SNR_FREMOVEXATTR ScmpSyscall = SYS_FREMOVEXATTR
|
||||||
|
SNR_TKILL ScmpSyscall = SYS_TKILL
|
||||||
|
SNR_TIME ScmpSyscall = SYS_TIME
|
||||||
|
SNR_FUTEX ScmpSyscall = SYS_FUTEX
|
||||||
|
SNR_SCHED_SETAFFINITY ScmpSyscall = SYS_SCHED_SETAFFINITY
|
||||||
|
SNR_SCHED_GETAFFINITY ScmpSyscall = SYS_SCHED_GETAFFINITY
|
||||||
|
SNR_SET_THREAD_AREA ScmpSyscall = SYS_SET_THREAD_AREA
|
||||||
|
SNR_IO_SETUP ScmpSyscall = SYS_IO_SETUP
|
||||||
|
SNR_IO_DESTROY ScmpSyscall = SYS_IO_DESTROY
|
||||||
|
SNR_IO_GETEVENTS ScmpSyscall = SYS_IO_GETEVENTS
|
||||||
|
SNR_IO_SUBMIT ScmpSyscall = SYS_IO_SUBMIT
|
||||||
|
SNR_IO_CANCEL ScmpSyscall = SYS_IO_CANCEL
|
||||||
|
SNR_GET_THREAD_AREA ScmpSyscall = SYS_GET_THREAD_AREA
|
||||||
|
SNR_LOOKUP_DCOOKIE ScmpSyscall = SYS_LOOKUP_DCOOKIE
|
||||||
|
SNR_EPOLL_CREATE ScmpSyscall = SYS_EPOLL_CREATE
|
||||||
|
SNR_EPOLL_CTL_OLD ScmpSyscall = SYS_EPOLL_CTL_OLD
|
||||||
|
SNR_EPOLL_WAIT_OLD ScmpSyscall = SYS_EPOLL_WAIT_OLD
|
||||||
|
SNR_REMAP_FILE_PAGES ScmpSyscall = SYS_REMAP_FILE_PAGES
|
||||||
|
SNR_GETDENTS64 ScmpSyscall = SYS_GETDENTS64
|
||||||
|
SNR_SET_TID_ADDRESS ScmpSyscall = SYS_SET_TID_ADDRESS
|
||||||
|
SNR_RESTART_SYSCALL ScmpSyscall = SYS_RESTART_SYSCALL
|
||||||
|
SNR_SEMTIMEDOP ScmpSyscall = SYS_SEMTIMEDOP
|
||||||
|
SNR_FADVISE64 ScmpSyscall = SYS_FADVISE64
|
||||||
|
SNR_TIMER_CREATE ScmpSyscall = SYS_TIMER_CREATE
|
||||||
|
SNR_TIMER_SETTIME ScmpSyscall = SYS_TIMER_SETTIME
|
||||||
|
SNR_TIMER_GETTIME ScmpSyscall = SYS_TIMER_GETTIME
|
||||||
|
SNR_TIMER_GETOVERRUN ScmpSyscall = SYS_TIMER_GETOVERRUN
|
||||||
|
SNR_TIMER_DELETE ScmpSyscall = SYS_TIMER_DELETE
|
||||||
|
SNR_CLOCK_SETTIME ScmpSyscall = SYS_CLOCK_SETTIME
|
||||||
|
SNR_CLOCK_GETTIME ScmpSyscall = SYS_CLOCK_GETTIME
|
||||||
|
SNR_CLOCK_GETRES ScmpSyscall = SYS_CLOCK_GETRES
|
||||||
|
SNR_CLOCK_NANOSLEEP ScmpSyscall = SYS_CLOCK_NANOSLEEP
|
||||||
|
SNR_EXIT_GROUP ScmpSyscall = SYS_EXIT_GROUP
|
||||||
|
SNR_EPOLL_WAIT ScmpSyscall = SYS_EPOLL_WAIT
|
||||||
|
SNR_EPOLL_CTL ScmpSyscall = SYS_EPOLL_CTL
|
||||||
|
SNR_TGKILL ScmpSyscall = SYS_TGKILL
|
||||||
|
SNR_UTIMES ScmpSyscall = SYS_UTIMES
|
||||||
|
SNR_VSERVER ScmpSyscall = SYS_VSERVER
|
||||||
|
SNR_MBIND ScmpSyscall = SYS_MBIND
|
||||||
|
SNR_SET_MEMPOLICY ScmpSyscall = SYS_SET_MEMPOLICY
|
||||||
|
SNR_GET_MEMPOLICY ScmpSyscall = SYS_GET_MEMPOLICY
|
||||||
|
SNR_MQ_OPEN ScmpSyscall = SYS_MQ_OPEN
|
||||||
|
SNR_MQ_UNLINK ScmpSyscall = SYS_MQ_UNLINK
|
||||||
|
SNR_MQ_TIMEDSEND ScmpSyscall = SYS_MQ_TIMEDSEND
|
||||||
|
SNR_MQ_TIMEDRECEIVE ScmpSyscall = SYS_MQ_TIMEDRECEIVE
|
||||||
|
SNR_MQ_NOTIFY ScmpSyscall = SYS_MQ_NOTIFY
|
||||||
|
SNR_MQ_GETSETATTR ScmpSyscall = SYS_MQ_GETSETATTR
|
||||||
|
SNR_KEXEC_LOAD ScmpSyscall = SYS_KEXEC_LOAD
|
||||||
|
SNR_WAITID ScmpSyscall = SYS_WAITID
|
||||||
|
SNR_ADD_KEY ScmpSyscall = SYS_ADD_KEY
|
||||||
|
SNR_REQUEST_KEY ScmpSyscall = SYS_REQUEST_KEY
|
||||||
|
SNR_KEYCTL ScmpSyscall = SYS_KEYCTL
|
||||||
|
SNR_IOPRIO_SET ScmpSyscall = SYS_IOPRIO_SET
|
||||||
|
SNR_IOPRIO_GET ScmpSyscall = SYS_IOPRIO_GET
|
||||||
|
SNR_INOTIFY_INIT ScmpSyscall = SYS_INOTIFY_INIT
|
||||||
|
SNR_INOTIFY_ADD_WATCH ScmpSyscall = SYS_INOTIFY_ADD_WATCH
|
||||||
|
SNR_INOTIFY_RM_WATCH ScmpSyscall = SYS_INOTIFY_RM_WATCH
|
||||||
|
SNR_MIGRATE_PAGES ScmpSyscall = SYS_MIGRATE_PAGES
|
||||||
|
SNR_OPENAT ScmpSyscall = SYS_OPENAT
|
||||||
|
SNR_MKDIRAT ScmpSyscall = SYS_MKDIRAT
|
||||||
|
SNR_MKNODAT ScmpSyscall = SYS_MKNODAT
|
||||||
|
SNR_FCHOWNAT ScmpSyscall = SYS_FCHOWNAT
|
||||||
|
SNR_FUTIMESAT ScmpSyscall = SYS_FUTIMESAT
|
||||||
|
SNR_NEWFSTATAT ScmpSyscall = SYS_NEWFSTATAT
|
||||||
|
SNR_UNLINKAT ScmpSyscall = SYS_UNLINKAT
|
||||||
|
SNR_RENAMEAT ScmpSyscall = SYS_RENAMEAT
|
||||||
|
SNR_LINKAT ScmpSyscall = SYS_LINKAT
|
||||||
|
SNR_SYMLINKAT ScmpSyscall = SYS_SYMLINKAT
|
||||||
|
SNR_READLINKAT ScmpSyscall = SYS_READLINKAT
|
||||||
|
SNR_FCHMODAT ScmpSyscall = SYS_FCHMODAT
|
||||||
|
SNR_FACCESSAT ScmpSyscall = SYS_FACCESSAT
|
||||||
|
SNR_PSELECT6 ScmpSyscall = SYS_PSELECT6
|
||||||
|
SNR_PPOLL ScmpSyscall = SYS_PPOLL
|
||||||
|
SNR_UNSHARE ScmpSyscall = SYS_UNSHARE
|
||||||
|
SNR_SET_ROBUST_LIST ScmpSyscall = SYS_SET_ROBUST_LIST
|
||||||
|
SNR_GET_ROBUST_LIST ScmpSyscall = SYS_GET_ROBUST_LIST
|
||||||
|
SNR_SPLICE ScmpSyscall = SYS_SPLICE
|
||||||
|
SNR_TEE ScmpSyscall = SYS_TEE
|
||||||
|
SNR_SYNC_FILE_RANGE ScmpSyscall = SYS_SYNC_FILE_RANGE
|
||||||
|
SNR_VMSPLICE ScmpSyscall = SYS_VMSPLICE
|
||||||
|
SNR_MOVE_PAGES ScmpSyscall = SYS_MOVE_PAGES
|
||||||
|
SNR_UTIMENSAT ScmpSyscall = SYS_UTIMENSAT
|
||||||
|
SNR_EPOLL_PWAIT ScmpSyscall = SYS_EPOLL_PWAIT
|
||||||
|
SNR_SIGNALFD ScmpSyscall = SYS_SIGNALFD
|
||||||
|
SNR_TIMERFD_CREATE ScmpSyscall = SYS_TIMERFD_CREATE
|
||||||
|
SNR_EVENTFD ScmpSyscall = SYS_EVENTFD
|
||||||
|
SNR_FALLOCATE ScmpSyscall = SYS_FALLOCATE
|
||||||
|
SNR_TIMERFD_SETTIME ScmpSyscall = SYS_TIMERFD_SETTIME
|
||||||
|
SNR_TIMERFD_GETTIME ScmpSyscall = SYS_TIMERFD_GETTIME
|
||||||
|
SNR_ACCEPT4 ScmpSyscall = SYS_ACCEPT4
|
||||||
|
SNR_SIGNALFD4 ScmpSyscall = SYS_SIGNALFD4
|
||||||
|
SNR_EVENTFD2 ScmpSyscall = SYS_EVENTFD2
|
||||||
|
SNR_EPOLL_CREATE1 ScmpSyscall = SYS_EPOLL_CREATE1
|
||||||
|
SNR_DUP3 ScmpSyscall = SYS_DUP3
|
||||||
|
SNR_PIPE2 ScmpSyscall = SYS_PIPE2
|
||||||
|
SNR_INOTIFY_INIT1 ScmpSyscall = SYS_INOTIFY_INIT1
|
||||||
|
SNR_PREADV ScmpSyscall = SYS_PREADV
|
||||||
|
SNR_PWRITEV ScmpSyscall = SYS_PWRITEV
|
||||||
|
SNR_RT_TGSIGQUEUEINFO ScmpSyscall = SYS_RT_TGSIGQUEUEINFO
|
||||||
|
SNR_PERF_EVENT_OPEN ScmpSyscall = SYS_PERF_EVENT_OPEN
|
||||||
|
SNR_RECVMMSG ScmpSyscall = SYS_RECVMMSG
|
||||||
|
SNR_FANOTIFY_INIT ScmpSyscall = SYS_FANOTIFY_INIT
|
||||||
|
SNR_FANOTIFY_MARK ScmpSyscall = SYS_FANOTIFY_MARK
|
||||||
|
SNR_PRLIMIT64 ScmpSyscall = SYS_PRLIMIT64
|
||||||
|
SNR_NAME_TO_HANDLE_AT ScmpSyscall = SYS_NAME_TO_HANDLE_AT
|
||||||
|
SNR_OPEN_BY_HANDLE_AT ScmpSyscall = SYS_OPEN_BY_HANDLE_AT
|
||||||
|
SNR_CLOCK_ADJTIME ScmpSyscall = SYS_CLOCK_ADJTIME
|
||||||
|
SNR_SYNCFS ScmpSyscall = SYS_SYNCFS
|
||||||
|
SNR_SENDMMSG ScmpSyscall = SYS_SENDMMSG
|
||||||
|
SNR_SETNS ScmpSyscall = SYS_SETNS
|
||||||
|
SNR_GETCPU ScmpSyscall = SYS_GETCPU
|
||||||
|
SNR_PROCESS_VM_READV ScmpSyscall = SYS_PROCESS_VM_READV
|
||||||
|
SNR_PROCESS_VM_WRITEV ScmpSyscall = SYS_PROCESS_VM_WRITEV
|
||||||
|
SNR_KCMP ScmpSyscall = SYS_KCMP
|
||||||
|
SNR_FINIT_MODULE ScmpSyscall = SYS_FINIT_MODULE
|
||||||
|
SNR_SCHED_SETATTR ScmpSyscall = SYS_SCHED_SETATTR
|
||||||
|
SNR_SCHED_GETATTR ScmpSyscall = SYS_SCHED_GETATTR
|
||||||
|
SNR_RENAMEAT2 ScmpSyscall = SYS_RENAMEAT2
|
||||||
|
SNR_SECCOMP ScmpSyscall = SYS_SECCOMP
|
||||||
|
SNR_GETRANDOM ScmpSyscall = SYS_GETRANDOM
|
||||||
|
SNR_MEMFD_CREATE ScmpSyscall = SYS_MEMFD_CREATE
|
||||||
|
SNR_KEXEC_FILE_LOAD ScmpSyscall = SYS_KEXEC_FILE_LOAD
|
||||||
|
SNR_BPF ScmpSyscall = SYS_BPF
|
||||||
|
SNR_EXECVEAT ScmpSyscall = SYS_EXECVEAT
|
||||||
|
SNR_USERFAULTFD ScmpSyscall = SYS_USERFAULTFD
|
||||||
|
SNR_MEMBARRIER ScmpSyscall = SYS_MEMBARRIER
|
||||||
|
SNR_MLOCK2 ScmpSyscall = SYS_MLOCK2
|
||||||
|
SNR_COPY_FILE_RANGE ScmpSyscall = SYS_COPY_FILE_RANGE
|
||||||
|
SNR_PREADV2 ScmpSyscall = SYS_PREADV2
|
||||||
|
SNR_PWRITEV2 ScmpSyscall = SYS_PWRITEV2
|
||||||
|
SNR_PKEY_MPROTECT ScmpSyscall = SYS_PKEY_MPROTECT
|
||||||
|
SNR_PKEY_ALLOC ScmpSyscall = SYS_PKEY_ALLOC
|
||||||
|
SNR_PKEY_FREE ScmpSyscall = SYS_PKEY_FREE
|
||||||
|
SNR_STATX ScmpSyscall = SYS_STATX
|
||||||
|
SNR_IO_PGETEVENTS ScmpSyscall = SYS_IO_PGETEVENTS
|
||||||
|
SNR_RSEQ ScmpSyscall = SYS_RSEQ
|
||||||
|
SNR_URETPROBE ScmpSyscall = SYS_URETPROBE
|
||||||
|
SNR_PIDFD_SEND_SIGNAL ScmpSyscall = SYS_PIDFD_SEND_SIGNAL
|
||||||
|
SNR_IO_URING_SETUP ScmpSyscall = SYS_IO_URING_SETUP
|
||||||
|
SNR_IO_URING_ENTER ScmpSyscall = SYS_IO_URING_ENTER
|
||||||
|
SNR_IO_URING_REGISTER ScmpSyscall = SYS_IO_URING_REGISTER
|
||||||
|
SNR_OPEN_TREE ScmpSyscall = SYS_OPEN_TREE
|
||||||
|
SNR_MOVE_MOUNT ScmpSyscall = SYS_MOVE_MOUNT
|
||||||
|
SNR_FSOPEN ScmpSyscall = SYS_FSOPEN
|
||||||
|
SNR_FSCONFIG ScmpSyscall = SYS_FSCONFIG
|
||||||
|
SNR_FSMOUNT ScmpSyscall = SYS_FSMOUNT
|
||||||
|
SNR_FSPICK ScmpSyscall = SYS_FSPICK
|
||||||
|
SNR_PIDFD_OPEN ScmpSyscall = SYS_PIDFD_OPEN
|
||||||
|
SNR_CLONE3 ScmpSyscall = SYS_CLONE3
|
||||||
|
SNR_CLOSE_RANGE ScmpSyscall = SYS_CLOSE_RANGE
|
||||||
|
SNR_OPENAT2 ScmpSyscall = SYS_OPENAT2
|
||||||
|
SNR_PIDFD_GETFD ScmpSyscall = SYS_PIDFD_GETFD
|
||||||
|
SNR_FACCESSAT2 ScmpSyscall = SYS_FACCESSAT2
|
||||||
|
SNR_PROCESS_MADVISE ScmpSyscall = SYS_PROCESS_MADVISE
|
||||||
|
SNR_EPOLL_PWAIT2 ScmpSyscall = SYS_EPOLL_PWAIT2
|
||||||
|
SNR_MOUNT_SETATTR ScmpSyscall = SYS_MOUNT_SETATTR
|
||||||
|
SNR_QUOTACTL_FD ScmpSyscall = SYS_QUOTACTL_FD
|
||||||
|
SNR_LANDLOCK_CREATE_RULESET ScmpSyscall = SYS_LANDLOCK_CREATE_RULESET
|
||||||
|
SNR_LANDLOCK_ADD_RULE ScmpSyscall = SYS_LANDLOCK_ADD_RULE
|
||||||
|
SNR_LANDLOCK_RESTRICT_SELF ScmpSyscall = SYS_LANDLOCK_RESTRICT_SELF
|
||||||
|
SNR_MEMFD_SECRET ScmpSyscall = SYS_MEMFD_SECRET
|
||||||
|
SNR_PROCESS_MRELEASE ScmpSyscall = SYS_PROCESS_MRELEASE
|
||||||
|
SNR_FUTEX_WAITV ScmpSyscall = SYS_FUTEX_WAITV
|
||||||
|
SNR_SET_MEMPOLICY_HOME_NODE ScmpSyscall = SYS_SET_MEMPOLICY_HOME_NODE
|
||||||
|
SNR_CACHESTAT ScmpSyscall = SYS_CACHESTAT
|
||||||
|
SNR_FCHMODAT2 ScmpSyscall = SYS_FCHMODAT2
|
||||||
|
SNR_MAP_SHADOW_STACK ScmpSyscall = SYS_MAP_SHADOW_STACK
|
||||||
|
SNR_FUTEX_WAKE ScmpSyscall = SYS_FUTEX_WAKE
|
||||||
|
SNR_FUTEX_WAIT ScmpSyscall = SYS_FUTEX_WAIT
|
||||||
|
SNR_FUTEX_REQUEUE ScmpSyscall = SYS_FUTEX_REQUEUE
|
||||||
|
SNR_STATMOUNT ScmpSyscall = SYS_STATMOUNT
|
||||||
|
SNR_LISTMOUNT ScmpSyscall = SYS_LISTMOUNT
|
||||||
|
SNR_LSM_GET_SELF_ATTR ScmpSyscall = SYS_LSM_GET_SELF_ATTR
|
||||||
|
SNR_LSM_SET_SELF_ATTR ScmpSyscall = SYS_LSM_SET_SELF_ATTR
|
||||||
|
SNR_LSM_LIST_MODULES ScmpSyscall = SYS_LSM_LIST_MODULES
|
||||||
|
SNR_MSEAL ScmpSyscall = SYS_MSEAL
|
||||||
|
)
|
||||||
703
container/std/syscall_linux_arm64.go
Normal file
703
container/std/syscall_linux_arm64.go
Normal file
@@ -0,0 +1,703 @@
|
|||||||
|
// mksysnum_linux.pl /usr/include/asm/unistd_64.h
|
||||||
|
// Code generated by the command above; DO NOT EDIT.
|
||||||
|
|
||||||
|
package std
|
||||||
|
|
||||||
|
import . "syscall"
|
||||||
|
|
||||||
|
var syscallNum = map[string]ScmpSyscall{
|
||||||
|
"io_setup": SNR_IO_SETUP,
|
||||||
|
"io_destroy": SNR_IO_DESTROY,
|
||||||
|
"io_submit": SNR_IO_SUBMIT,
|
||||||
|
"io_cancel": SNR_IO_CANCEL,
|
||||||
|
"io_getevents": SNR_IO_GETEVENTS,
|
||||||
|
"setxattr": SNR_SETXATTR,
|
||||||
|
"lsetxattr": SNR_LSETXATTR,
|
||||||
|
"fsetxattr": SNR_FSETXATTR,
|
||||||
|
"getxattr": SNR_GETXATTR,
|
||||||
|
"lgetxattr": SNR_LGETXATTR,
|
||||||
|
"fgetxattr": SNR_FGETXATTR,
|
||||||
|
"listxattr": SNR_LISTXATTR,
|
||||||
|
"llistxattr": SNR_LLISTXATTR,
|
||||||
|
"flistxattr": SNR_FLISTXATTR,
|
||||||
|
"removexattr": SNR_REMOVEXATTR,
|
||||||
|
"lremovexattr": SNR_LREMOVEXATTR,
|
||||||
|
"fremovexattr": SNR_FREMOVEXATTR,
|
||||||
|
"getcwd": SNR_GETCWD,
|
||||||
|
"lookup_dcookie": SNR_LOOKUP_DCOOKIE,
|
||||||
|
"eventfd2": SNR_EVENTFD2,
|
||||||
|
"epoll_create1": SNR_EPOLL_CREATE1,
|
||||||
|
"epoll_ctl": SNR_EPOLL_CTL,
|
||||||
|
"epoll_pwait": SNR_EPOLL_PWAIT,
|
||||||
|
"dup": SNR_DUP,
|
||||||
|
"dup3": SNR_DUP3,
|
||||||
|
"fcntl": SNR_FCNTL,
|
||||||
|
"inotify_init1": SNR_INOTIFY_INIT1,
|
||||||
|
"inotify_add_watch": SNR_INOTIFY_ADD_WATCH,
|
||||||
|
"inotify_rm_watch": SNR_INOTIFY_RM_WATCH,
|
||||||
|
"ioctl": SNR_IOCTL,
|
||||||
|
"ioprio_set": SNR_IOPRIO_SET,
|
||||||
|
"ioprio_get": SNR_IOPRIO_GET,
|
||||||
|
"flock": SNR_FLOCK,
|
||||||
|
"mknodat": SNR_MKNODAT,
|
||||||
|
"mkdirat": SNR_MKDIRAT,
|
||||||
|
"unlinkat": SNR_UNLINKAT,
|
||||||
|
"symlinkat": SNR_SYMLINKAT,
|
||||||
|
"linkat": SNR_LINKAT,
|
||||||
|
"renameat": SNR_RENAMEAT,
|
||||||
|
"umount2": SNR_UMOUNT2,
|
||||||
|
"mount": SNR_MOUNT,
|
||||||
|
"pivot_root": SNR_PIVOT_ROOT,
|
||||||
|
"nfsservctl": SNR_NFSSERVCTL,
|
||||||
|
"statfs": SNR_STATFS,
|
||||||
|
"fstatfs": SNR_FSTATFS,
|
||||||
|
"truncate": SNR_TRUNCATE,
|
||||||
|
"ftruncate": SNR_FTRUNCATE,
|
||||||
|
"fallocate": SNR_FALLOCATE,
|
||||||
|
"faccessat": SNR_FACCESSAT,
|
||||||
|
"chdir": SNR_CHDIR,
|
||||||
|
"fchdir": SNR_FCHDIR,
|
||||||
|
"chroot": SNR_CHROOT,
|
||||||
|
"fchmod": SNR_FCHMOD,
|
||||||
|
"fchmodat": SNR_FCHMODAT,
|
||||||
|
"fchownat": SNR_FCHOWNAT,
|
||||||
|
"fchown": SNR_FCHOWN,
|
||||||
|
"openat": SNR_OPENAT,
|
||||||
|
"close": SNR_CLOSE,
|
||||||
|
"vhangup": SNR_VHANGUP,
|
||||||
|
"pipe2": SNR_PIPE2,
|
||||||
|
"quotactl": SNR_QUOTACTL,
|
||||||
|
"getdents64": SNR_GETDENTS64,
|
||||||
|
"lseek": SNR_LSEEK,
|
||||||
|
"read": SNR_READ,
|
||||||
|
"write": SNR_WRITE,
|
||||||
|
"readv": SNR_READV,
|
||||||
|
"writev": SNR_WRITEV,
|
||||||
|
"pread64": SNR_PREAD64,
|
||||||
|
"pwrite64": SNR_PWRITE64,
|
||||||
|
"preadv": SNR_PREADV,
|
||||||
|
"pwritev": SNR_PWRITEV,
|
||||||
|
"sendfile": SNR_SENDFILE,
|
||||||
|
"pselect6": SNR_PSELECT6,
|
||||||
|
"ppoll": SNR_PPOLL,
|
||||||
|
"signalfd4": SNR_SIGNALFD4,
|
||||||
|
"vmsplice": SNR_VMSPLICE,
|
||||||
|
"splice": SNR_SPLICE,
|
||||||
|
"tee": SNR_TEE,
|
||||||
|
"readlinkat": SNR_READLINKAT,
|
||||||
|
"newfstatat": SNR_NEWFSTATAT,
|
||||||
|
"fstat": SNR_FSTAT,
|
||||||
|
"sync": SNR_SYNC,
|
||||||
|
"fsync": SNR_FSYNC,
|
||||||
|
"fdatasync": SNR_FDATASYNC,
|
||||||
|
"sync_file_range": SNR_SYNC_FILE_RANGE,
|
||||||
|
"timerfd_create": SNR_TIMERFD_CREATE,
|
||||||
|
"timerfd_settime": SNR_TIMERFD_SETTIME,
|
||||||
|
"timerfd_gettime": SNR_TIMERFD_GETTIME,
|
||||||
|
"utimensat": SNR_UTIMENSAT,
|
||||||
|
"acct": SNR_ACCT,
|
||||||
|
"capget": SNR_CAPGET,
|
||||||
|
"capset": SNR_CAPSET,
|
||||||
|
"personality": SNR_PERSONALITY,
|
||||||
|
"exit": SNR_EXIT,
|
||||||
|
"exit_group": SNR_EXIT_GROUP,
|
||||||
|
"waitid": SNR_WAITID,
|
||||||
|
"set_tid_address": SNR_SET_TID_ADDRESS,
|
||||||
|
"unshare": SNR_UNSHARE,
|
||||||
|
"futex": SNR_FUTEX,
|
||||||
|
"set_robust_list": SNR_SET_ROBUST_LIST,
|
||||||
|
"get_robust_list": SNR_GET_ROBUST_LIST,
|
||||||
|
"nanosleep": SNR_NANOSLEEP,
|
||||||
|
"getitimer": SNR_GETITIMER,
|
||||||
|
"setitimer": SNR_SETITIMER,
|
||||||
|
"kexec_load": SNR_KEXEC_LOAD,
|
||||||
|
"init_module": SNR_INIT_MODULE,
|
||||||
|
"delete_module": SNR_DELETE_MODULE,
|
||||||
|
"timer_create": SNR_TIMER_CREATE,
|
||||||
|
"timer_gettime": SNR_TIMER_GETTIME,
|
||||||
|
"timer_getoverrun": SNR_TIMER_GETOVERRUN,
|
||||||
|
"timer_settime": SNR_TIMER_SETTIME,
|
||||||
|
"timer_delete": SNR_TIMER_DELETE,
|
||||||
|
"clock_settime": SNR_CLOCK_SETTIME,
|
||||||
|
"clock_gettime": SNR_CLOCK_GETTIME,
|
||||||
|
"clock_getres": SNR_CLOCK_GETRES,
|
||||||
|
"clock_nanosleep": SNR_CLOCK_NANOSLEEP,
|
||||||
|
"syslog": SNR_SYSLOG,
|
||||||
|
"ptrace": SNR_PTRACE,
|
||||||
|
"sched_setparam": SNR_SCHED_SETPARAM,
|
||||||
|
"sched_setscheduler": SNR_SCHED_SETSCHEDULER,
|
||||||
|
"sched_getscheduler": SNR_SCHED_GETSCHEDULER,
|
||||||
|
"sched_getparam": SNR_SCHED_GETPARAM,
|
||||||
|
"sched_setaffinity": SNR_SCHED_SETAFFINITY,
|
||||||
|
"sched_getaffinity": SNR_SCHED_GETAFFINITY,
|
||||||
|
"sched_yield": SNR_SCHED_YIELD,
|
||||||
|
"sched_get_priority_max": SNR_SCHED_GET_PRIORITY_MAX,
|
||||||
|
"sched_get_priority_min": SNR_SCHED_GET_PRIORITY_MIN,
|
||||||
|
"sched_rr_get_interval": SNR_SCHED_RR_GET_INTERVAL,
|
||||||
|
"restart_syscall": SNR_RESTART_SYSCALL,
|
||||||
|
"kill": SNR_KILL,
|
||||||
|
"tkill": SNR_TKILL,
|
||||||
|
"tgkill": SNR_TGKILL,
|
||||||
|
"sigaltstack": SNR_SIGALTSTACK,
|
||||||
|
"rt_sigsuspend": SNR_RT_SIGSUSPEND,
|
||||||
|
"rt_sigaction": SNR_RT_SIGACTION,
|
||||||
|
"rt_sigprocmask": SNR_RT_SIGPROCMASK,
|
||||||
|
"rt_sigpending": SNR_RT_SIGPENDING,
|
||||||
|
"rt_sigtimedwait": SNR_RT_SIGTIMEDWAIT,
|
||||||
|
"rt_sigqueueinfo": SNR_RT_SIGQUEUEINFO,
|
||||||
|
"rt_sigreturn": SNR_RT_SIGRETURN,
|
||||||
|
"setpriority": SNR_SETPRIORITY,
|
||||||
|
"getpriority": SNR_GETPRIORITY,
|
||||||
|
"reboot": SNR_REBOOT,
|
||||||
|
"setregid": SNR_SETREGID,
|
||||||
|
"setgid": SNR_SETGID,
|
||||||
|
"setreuid": SNR_SETREUID,
|
||||||
|
"setuid": SNR_SETUID,
|
||||||
|
"setresuid": SNR_SETRESUID,
|
||||||
|
"getresuid": SNR_GETRESUID,
|
||||||
|
"setresgid": SNR_SETRESGID,
|
||||||
|
"getresgid": SNR_GETRESGID,
|
||||||
|
"setfsuid": SNR_SETFSUID,
|
||||||
|
"setfsgid": SNR_SETFSGID,
|
||||||
|
"times": SNR_TIMES,
|
||||||
|
"setpgid": SNR_SETPGID,
|
||||||
|
"getpgid": SNR_GETPGID,
|
||||||
|
"getsid": SNR_GETSID,
|
||||||
|
"setsid": SNR_SETSID,
|
||||||
|
"getgroups": SNR_GETGROUPS,
|
||||||
|
"setgroups": SNR_SETGROUPS,
|
||||||
|
"uname": SNR_UNAME,
|
||||||
|
"sethostname": SNR_SETHOSTNAME,
|
||||||
|
"setdomainname": SNR_SETDOMAINNAME,
|
||||||
|
"getrlimit": SNR_GETRLIMIT,
|
||||||
|
"setrlimit": SNR_SETRLIMIT,
|
||||||
|
"getrusage": SNR_GETRUSAGE,
|
||||||
|
"umask": SNR_UMASK,
|
||||||
|
"prctl": SNR_PRCTL,
|
||||||
|
"getcpu": SNR_GETCPU,
|
||||||
|
"gettimeofday": SNR_GETTIMEOFDAY,
|
||||||
|
"settimeofday": SNR_SETTIMEOFDAY,
|
||||||
|
"adjtimex": SNR_ADJTIMEX,
|
||||||
|
"getpid": SNR_GETPID,
|
||||||
|
"getppid": SNR_GETPPID,
|
||||||
|
"getuid": SNR_GETUID,
|
||||||
|
"geteuid": SNR_GETEUID,
|
||||||
|
"getgid": SNR_GETGID,
|
||||||
|
"getegid": SNR_GETEGID,
|
||||||
|
"gettid": SNR_GETTID,
|
||||||
|
"sysinfo": SNR_SYSINFO,
|
||||||
|
"mq_open": SNR_MQ_OPEN,
|
||||||
|
"mq_unlink": SNR_MQ_UNLINK,
|
||||||
|
"mq_timedsend": SNR_MQ_TIMEDSEND,
|
||||||
|
"mq_timedreceive": SNR_MQ_TIMEDRECEIVE,
|
||||||
|
"mq_notify": SNR_MQ_NOTIFY,
|
||||||
|
"mq_getsetattr": SNR_MQ_GETSETATTR,
|
||||||
|
"msgget": SNR_MSGGET,
|
||||||
|
"msgctl": SNR_MSGCTL,
|
||||||
|
"msgrcv": SNR_MSGRCV,
|
||||||
|
"msgsnd": SNR_MSGSND,
|
||||||
|
"semget": SNR_SEMGET,
|
||||||
|
"semctl": SNR_SEMCTL,
|
||||||
|
"semtimedop": SNR_SEMTIMEDOP,
|
||||||
|
"semop": SNR_SEMOP,
|
||||||
|
"shmget": SNR_SHMGET,
|
||||||
|
"shmctl": SNR_SHMCTL,
|
||||||
|
"shmat": SNR_SHMAT,
|
||||||
|
"shmdt": SNR_SHMDT,
|
||||||
|
"socket": SNR_SOCKET,
|
||||||
|
"socketpair": SNR_SOCKETPAIR,
|
||||||
|
"bind": SNR_BIND,
|
||||||
|
"listen": SNR_LISTEN,
|
||||||
|
"accept": SNR_ACCEPT,
|
||||||
|
"connect": SNR_CONNECT,
|
||||||
|
"getsockname": SNR_GETSOCKNAME,
|
||||||
|
"getpeername": SNR_GETPEERNAME,
|
||||||
|
"sendto": SNR_SENDTO,
|
||||||
|
"recvfrom": SNR_RECVFROM,
|
||||||
|
"setsockopt": SNR_SETSOCKOPT,
|
||||||
|
"getsockopt": SNR_GETSOCKOPT,
|
||||||
|
"shutdown": SNR_SHUTDOWN,
|
||||||
|
"sendmsg": SNR_SENDMSG,
|
||||||
|
"recvmsg": SNR_RECVMSG,
|
||||||
|
"readahead": SNR_READAHEAD,
|
||||||
|
"brk": SNR_BRK,
|
||||||
|
"munmap": SNR_MUNMAP,
|
||||||
|
"mremap": SNR_MREMAP,
|
||||||
|
"add_key": SNR_ADD_KEY,
|
||||||
|
"request_key": SNR_REQUEST_KEY,
|
||||||
|
"keyctl": SNR_KEYCTL,
|
||||||
|
"clone": SNR_CLONE,
|
||||||
|
"execve": SNR_EXECVE,
|
||||||
|
"mmap": SNR_MMAP,
|
||||||
|
"fadvise64": SNR_FADVISE64,
|
||||||
|
"swapon": SNR_SWAPON,
|
||||||
|
"swapoff": SNR_SWAPOFF,
|
||||||
|
"mprotect": SNR_MPROTECT,
|
||||||
|
"msync": SNR_MSYNC,
|
||||||
|
"mlock": SNR_MLOCK,
|
||||||
|
"munlock": SNR_MUNLOCK,
|
||||||
|
"mlockall": SNR_MLOCKALL,
|
||||||
|
"munlockall": SNR_MUNLOCKALL,
|
||||||
|
"mincore": SNR_MINCORE,
|
||||||
|
"madvise": SNR_MADVISE,
|
||||||
|
"remap_file_pages": SNR_REMAP_FILE_PAGES,
|
||||||
|
"mbind": SNR_MBIND,
|
||||||
|
"get_mempolicy": SNR_GET_MEMPOLICY,
|
||||||
|
"set_mempolicy": SNR_SET_MEMPOLICY,
|
||||||
|
"migrate_pages": SNR_MIGRATE_PAGES,
|
||||||
|
"move_pages": SNR_MOVE_PAGES,
|
||||||
|
"rt_tgsigqueueinfo": SNR_RT_TGSIGQUEUEINFO,
|
||||||
|
"perf_event_open": SNR_PERF_EVENT_OPEN,
|
||||||
|
"accept4": SNR_ACCEPT4,
|
||||||
|
"recvmmsg": SNR_RECVMMSG,
|
||||||
|
"wait4": SNR_WAIT4,
|
||||||
|
"prlimit64": SNR_PRLIMIT64,
|
||||||
|
"fanotify_init": SNR_FANOTIFY_INIT,
|
||||||
|
"fanotify_mark": SNR_FANOTIFY_MARK,
|
||||||
|
"name_to_handle_at": SNR_NAME_TO_HANDLE_AT,
|
||||||
|
"open_by_handle_at": SNR_OPEN_BY_HANDLE_AT,
|
||||||
|
"clock_adjtime": SNR_CLOCK_ADJTIME,
|
||||||
|
"syncfs": SNR_SYNCFS,
|
||||||
|
"setns": SNR_SETNS,
|
||||||
|
"sendmmsg": SNR_SENDMMSG,
|
||||||
|
"process_vm_readv": SNR_PROCESS_VM_READV,
|
||||||
|
"process_vm_writev": SNR_PROCESS_VM_WRITEV,
|
||||||
|
"kcmp": SNR_KCMP,
|
||||||
|
"finit_module": SNR_FINIT_MODULE,
|
||||||
|
"sched_setattr": SNR_SCHED_SETATTR,
|
||||||
|
"sched_getattr": SNR_SCHED_GETATTR,
|
||||||
|
"renameat2": SNR_RENAMEAT2,
|
||||||
|
"seccomp": SNR_SECCOMP,
|
||||||
|
"getrandom": SNR_GETRANDOM,
|
||||||
|
"memfd_create": SNR_MEMFD_CREATE,
|
||||||
|
"bpf": SNR_BPF,
|
||||||
|
"execveat": SNR_EXECVEAT,
|
||||||
|
"userfaultfd": SNR_USERFAULTFD,
|
||||||
|
"membarrier": SNR_MEMBARRIER,
|
||||||
|
"mlock2": SNR_MLOCK2,
|
||||||
|
"copy_file_range": SNR_COPY_FILE_RANGE,
|
||||||
|
"preadv2": SNR_PREADV2,
|
||||||
|
"pwritev2": SNR_PWRITEV2,
|
||||||
|
"pkey_mprotect": SNR_PKEY_MPROTECT,
|
||||||
|
"pkey_alloc": SNR_PKEY_ALLOC,
|
||||||
|
"pkey_free": SNR_PKEY_FREE,
|
||||||
|
"statx": SNR_STATX,
|
||||||
|
"io_pgetevents": SNR_IO_PGETEVENTS,
|
||||||
|
"rseq": SNR_RSEQ,
|
||||||
|
"kexec_file_load": SNR_KEXEC_FILE_LOAD,
|
||||||
|
"pidfd_send_signal": SNR_PIDFD_SEND_SIGNAL,
|
||||||
|
"io_uring_setup": SNR_IO_URING_SETUP,
|
||||||
|
"io_uring_enter": SNR_IO_URING_ENTER,
|
||||||
|
"io_uring_register": SNR_IO_URING_REGISTER,
|
||||||
|
"open_tree": SNR_OPEN_TREE,
|
||||||
|
"move_mount": SNR_MOVE_MOUNT,
|
||||||
|
"fsopen": SNR_FSOPEN,
|
||||||
|
"fsconfig": SNR_FSCONFIG,
|
||||||
|
"fsmount": SNR_FSMOUNT,
|
||||||
|
"fspick": SNR_FSPICK,
|
||||||
|
"pidfd_open": SNR_PIDFD_OPEN,
|
||||||
|
"clone3": SNR_CLONE3,
|
||||||
|
"close_range": SNR_CLOSE_RANGE,
|
||||||
|
"openat2": SNR_OPENAT2,
|
||||||
|
"pidfd_getfd": SNR_PIDFD_GETFD,
|
||||||
|
"faccessat2": SNR_FACCESSAT2,
|
||||||
|
"process_madvise": SNR_PROCESS_MADVISE,
|
||||||
|
"epoll_pwait2": SNR_EPOLL_PWAIT2,
|
||||||
|
"mount_setattr": SNR_MOUNT_SETATTR,
|
||||||
|
"quotactl_fd": SNR_QUOTACTL_FD,
|
||||||
|
"landlock_create_ruleset": SNR_LANDLOCK_CREATE_RULESET,
|
||||||
|
"landlock_add_rule": SNR_LANDLOCK_ADD_RULE,
|
||||||
|
"landlock_restrict_self": SNR_LANDLOCK_RESTRICT_SELF,
|
||||||
|
"memfd_secret": SNR_MEMFD_SECRET,
|
||||||
|
"process_mrelease": SNR_PROCESS_MRELEASE,
|
||||||
|
"futex_waitv": SNR_FUTEX_WAITV,
|
||||||
|
"set_mempolicy_home_node": SNR_SET_MEMPOLICY_HOME_NODE,
|
||||||
|
"cachestat": SNR_CACHESTAT,
|
||||||
|
"fchmodat2": SNR_FCHMODAT2,
|
||||||
|
"map_shadow_stack": SNR_MAP_SHADOW_STACK,
|
||||||
|
"futex_wake": SNR_FUTEX_WAKE,
|
||||||
|
"futex_wait": SNR_FUTEX_WAIT,
|
||||||
|
"futex_requeue": SNR_FUTEX_REQUEUE,
|
||||||
|
"statmount": SNR_STATMOUNT,
|
||||||
|
"listmount": SNR_LISTMOUNT,
|
||||||
|
"lsm_get_self_attr": SNR_LSM_GET_SELF_ATTR,
|
||||||
|
"lsm_set_self_attr": SNR_LSM_SET_SELF_ATTR,
|
||||||
|
"lsm_list_modules": SNR_LSM_LIST_MODULES,
|
||||||
|
"mseal": SNR_MSEAL,
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
SYS_USERFAULTFD = 282
|
||||||
|
SYS_MEMBARRIER = 283
|
||||||
|
SYS_MLOCK2 = 284
|
||||||
|
SYS_COPY_FILE_RANGE = 285
|
||||||
|
SYS_PREADV2 = 286
|
||||||
|
SYS_PWRITEV2 = 287
|
||||||
|
SYS_PKEY_MPROTECT = 288
|
||||||
|
SYS_PKEY_ALLOC = 289
|
||||||
|
SYS_PKEY_FREE = 290
|
||||||
|
SYS_STATX = 291
|
||||||
|
SYS_IO_PGETEVENTS = 292
|
||||||
|
SYS_RSEQ = 293
|
||||||
|
SYS_KEXEC_FILE_LOAD = 294
|
||||||
|
SYS_PIDFD_SEND_SIGNAL = 424
|
||||||
|
SYS_IO_URING_SETUP = 425
|
||||||
|
SYS_IO_URING_ENTER = 426
|
||||||
|
SYS_IO_URING_REGISTER = 427
|
||||||
|
SYS_OPEN_TREE = 428
|
||||||
|
SYS_MOVE_MOUNT = 429
|
||||||
|
SYS_FSOPEN = 430
|
||||||
|
SYS_FSCONFIG = 431
|
||||||
|
SYS_FSMOUNT = 432
|
||||||
|
SYS_FSPICK = 433
|
||||||
|
SYS_PIDFD_OPEN = 434
|
||||||
|
SYS_CLONE3 = 435
|
||||||
|
SYS_CLOSE_RANGE = 436
|
||||||
|
SYS_OPENAT2 = 437
|
||||||
|
SYS_PIDFD_GETFD = 438
|
||||||
|
SYS_FACCESSAT2 = 439
|
||||||
|
SYS_PROCESS_MADVISE = 440
|
||||||
|
SYS_EPOLL_PWAIT2 = 441
|
||||||
|
SYS_MOUNT_SETATTR = 442
|
||||||
|
SYS_QUOTACTL_FD = 443
|
||||||
|
SYS_LANDLOCK_CREATE_RULESET = 444
|
||||||
|
SYS_LANDLOCK_ADD_RULE = 445
|
||||||
|
SYS_LANDLOCK_RESTRICT_SELF = 446
|
||||||
|
SYS_MEMFD_SECRET = 447
|
||||||
|
SYS_PROCESS_MRELEASE = 448
|
||||||
|
SYS_FUTEX_WAITV = 449
|
||||||
|
SYS_SET_MEMPOLICY_HOME_NODE = 450
|
||||||
|
SYS_CACHESTAT = 451
|
||||||
|
SYS_FCHMODAT2 = 452
|
||||||
|
SYS_MAP_SHADOW_STACK = 453
|
||||||
|
SYS_FUTEX_WAKE = 454
|
||||||
|
SYS_FUTEX_WAIT = 455
|
||||||
|
SYS_FUTEX_REQUEUE = 456
|
||||||
|
SYS_STATMOUNT = 457
|
||||||
|
SYS_LISTMOUNT = 458
|
||||||
|
SYS_LSM_GET_SELF_ATTR = 459
|
||||||
|
SYS_LSM_SET_SELF_ATTR = 460
|
||||||
|
SYS_LSM_LIST_MODULES = 461
|
||||||
|
SYS_MSEAL = 462
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
SNR_IO_SETUP ScmpSyscall = SYS_IO_SETUP
|
||||||
|
SNR_IO_DESTROY ScmpSyscall = SYS_IO_DESTROY
|
||||||
|
SNR_IO_SUBMIT ScmpSyscall = SYS_IO_SUBMIT
|
||||||
|
SNR_IO_CANCEL ScmpSyscall = SYS_IO_CANCEL
|
||||||
|
SNR_IO_GETEVENTS ScmpSyscall = SYS_IO_GETEVENTS
|
||||||
|
SNR_SETXATTR ScmpSyscall = SYS_SETXATTR
|
||||||
|
SNR_LSETXATTR ScmpSyscall = SYS_LSETXATTR
|
||||||
|
SNR_FSETXATTR ScmpSyscall = SYS_FSETXATTR
|
||||||
|
SNR_GETXATTR ScmpSyscall = SYS_GETXATTR
|
||||||
|
SNR_LGETXATTR ScmpSyscall = SYS_LGETXATTR
|
||||||
|
SNR_FGETXATTR ScmpSyscall = SYS_FGETXATTR
|
||||||
|
SNR_LISTXATTR ScmpSyscall = SYS_LISTXATTR
|
||||||
|
SNR_LLISTXATTR ScmpSyscall = SYS_LLISTXATTR
|
||||||
|
SNR_FLISTXATTR ScmpSyscall = SYS_FLISTXATTR
|
||||||
|
SNR_REMOVEXATTR ScmpSyscall = SYS_REMOVEXATTR
|
||||||
|
SNR_LREMOVEXATTR ScmpSyscall = SYS_LREMOVEXATTR
|
||||||
|
SNR_FREMOVEXATTR ScmpSyscall = SYS_FREMOVEXATTR
|
||||||
|
SNR_GETCWD ScmpSyscall = SYS_GETCWD
|
||||||
|
SNR_LOOKUP_DCOOKIE ScmpSyscall = SYS_LOOKUP_DCOOKIE
|
||||||
|
SNR_EVENTFD2 ScmpSyscall = SYS_EVENTFD2
|
||||||
|
SNR_EPOLL_CREATE1 ScmpSyscall = SYS_EPOLL_CREATE1
|
||||||
|
SNR_EPOLL_CTL ScmpSyscall = SYS_EPOLL_CTL
|
||||||
|
SNR_EPOLL_PWAIT ScmpSyscall = SYS_EPOLL_PWAIT
|
||||||
|
SNR_DUP ScmpSyscall = SYS_DUP
|
||||||
|
SNR_DUP3 ScmpSyscall = SYS_DUP3
|
||||||
|
SNR_FCNTL ScmpSyscall = SYS_FCNTL
|
||||||
|
SNR_INOTIFY_INIT1 ScmpSyscall = SYS_INOTIFY_INIT1
|
||||||
|
SNR_INOTIFY_ADD_WATCH ScmpSyscall = SYS_INOTIFY_ADD_WATCH
|
||||||
|
SNR_INOTIFY_RM_WATCH ScmpSyscall = SYS_INOTIFY_RM_WATCH
|
||||||
|
SNR_IOCTL ScmpSyscall = SYS_IOCTL
|
||||||
|
SNR_IOPRIO_SET ScmpSyscall = SYS_IOPRIO_SET
|
||||||
|
SNR_IOPRIO_GET ScmpSyscall = SYS_IOPRIO_GET
|
||||||
|
SNR_FLOCK ScmpSyscall = SYS_FLOCK
|
||||||
|
SNR_MKNODAT ScmpSyscall = SYS_MKNODAT
|
||||||
|
SNR_MKDIRAT ScmpSyscall = SYS_MKDIRAT
|
||||||
|
SNR_UNLINKAT ScmpSyscall = SYS_UNLINKAT
|
||||||
|
SNR_SYMLINKAT ScmpSyscall = SYS_SYMLINKAT
|
||||||
|
SNR_LINKAT ScmpSyscall = SYS_LINKAT
|
||||||
|
SNR_RENAMEAT ScmpSyscall = SYS_RENAMEAT
|
||||||
|
SNR_UMOUNT2 ScmpSyscall = SYS_UMOUNT2
|
||||||
|
SNR_MOUNT ScmpSyscall = SYS_MOUNT
|
||||||
|
SNR_PIVOT_ROOT ScmpSyscall = SYS_PIVOT_ROOT
|
||||||
|
SNR_NFSSERVCTL ScmpSyscall = SYS_NFSSERVCTL
|
||||||
|
SNR_STATFS ScmpSyscall = SYS_STATFS
|
||||||
|
SNR_FSTATFS ScmpSyscall = SYS_FSTATFS
|
||||||
|
SNR_TRUNCATE ScmpSyscall = SYS_TRUNCATE
|
||||||
|
SNR_FTRUNCATE ScmpSyscall = SYS_FTRUNCATE
|
||||||
|
SNR_FALLOCATE ScmpSyscall = SYS_FALLOCATE
|
||||||
|
SNR_FACCESSAT ScmpSyscall = SYS_FACCESSAT
|
||||||
|
SNR_CHDIR ScmpSyscall = SYS_CHDIR
|
||||||
|
SNR_FCHDIR ScmpSyscall = SYS_FCHDIR
|
||||||
|
SNR_CHROOT ScmpSyscall = SYS_CHROOT
|
||||||
|
SNR_FCHMOD ScmpSyscall = SYS_FCHMOD
|
||||||
|
SNR_FCHMODAT ScmpSyscall = SYS_FCHMODAT
|
||||||
|
SNR_FCHOWNAT ScmpSyscall = SYS_FCHOWNAT
|
||||||
|
SNR_FCHOWN ScmpSyscall = SYS_FCHOWN
|
||||||
|
SNR_OPENAT ScmpSyscall = SYS_OPENAT
|
||||||
|
SNR_CLOSE ScmpSyscall = SYS_CLOSE
|
||||||
|
SNR_VHANGUP ScmpSyscall = SYS_VHANGUP
|
||||||
|
SNR_PIPE2 ScmpSyscall = SYS_PIPE2
|
||||||
|
SNR_QUOTACTL ScmpSyscall = SYS_QUOTACTL
|
||||||
|
SNR_GETDENTS64 ScmpSyscall = SYS_GETDENTS64
|
||||||
|
SNR_LSEEK ScmpSyscall = SYS_LSEEK
|
||||||
|
SNR_READ ScmpSyscall = SYS_READ
|
||||||
|
SNR_WRITE ScmpSyscall = SYS_WRITE
|
||||||
|
SNR_READV ScmpSyscall = SYS_READV
|
||||||
|
SNR_WRITEV ScmpSyscall = SYS_WRITEV
|
||||||
|
SNR_PREAD64 ScmpSyscall = SYS_PREAD64
|
||||||
|
SNR_PWRITE64 ScmpSyscall = SYS_PWRITE64
|
||||||
|
SNR_PREADV ScmpSyscall = SYS_PREADV
|
||||||
|
SNR_PWRITEV ScmpSyscall = SYS_PWRITEV
|
||||||
|
SNR_SENDFILE ScmpSyscall = SYS_SENDFILE
|
||||||
|
SNR_PSELECT6 ScmpSyscall = SYS_PSELECT6
|
||||||
|
SNR_PPOLL ScmpSyscall = SYS_PPOLL
|
||||||
|
SNR_SIGNALFD4 ScmpSyscall = SYS_SIGNALFD4
|
||||||
|
SNR_VMSPLICE ScmpSyscall = SYS_VMSPLICE
|
||||||
|
SNR_SPLICE ScmpSyscall = SYS_SPLICE
|
||||||
|
SNR_TEE ScmpSyscall = SYS_TEE
|
||||||
|
SNR_READLINKAT ScmpSyscall = SYS_READLINKAT
|
||||||
|
SNR_NEWFSTATAT ScmpSyscall = SYS_NEWFSTATAT
|
||||||
|
SNR_FSTAT ScmpSyscall = SYS_FSTAT
|
||||||
|
SNR_SYNC ScmpSyscall = SYS_SYNC
|
||||||
|
SNR_FSYNC ScmpSyscall = SYS_FSYNC
|
||||||
|
SNR_FDATASYNC ScmpSyscall = SYS_FDATASYNC
|
||||||
|
SNR_SYNC_FILE_RANGE ScmpSyscall = SYS_SYNC_FILE_RANGE
|
||||||
|
SNR_TIMERFD_CREATE ScmpSyscall = SYS_TIMERFD_CREATE
|
||||||
|
SNR_TIMERFD_SETTIME ScmpSyscall = SYS_TIMERFD_SETTIME
|
||||||
|
SNR_TIMERFD_GETTIME ScmpSyscall = SYS_TIMERFD_GETTIME
|
||||||
|
SNR_UTIMENSAT ScmpSyscall = SYS_UTIMENSAT
|
||||||
|
SNR_ACCT ScmpSyscall = SYS_ACCT
|
||||||
|
SNR_CAPGET ScmpSyscall = SYS_CAPGET
|
||||||
|
SNR_CAPSET ScmpSyscall = SYS_CAPSET
|
||||||
|
SNR_PERSONALITY ScmpSyscall = SYS_PERSONALITY
|
||||||
|
SNR_EXIT ScmpSyscall = SYS_EXIT
|
||||||
|
SNR_EXIT_GROUP ScmpSyscall = SYS_EXIT_GROUP
|
||||||
|
SNR_WAITID ScmpSyscall = SYS_WAITID
|
||||||
|
SNR_SET_TID_ADDRESS ScmpSyscall = SYS_SET_TID_ADDRESS
|
||||||
|
SNR_UNSHARE ScmpSyscall = SYS_UNSHARE
|
||||||
|
SNR_FUTEX ScmpSyscall = SYS_FUTEX
|
||||||
|
SNR_SET_ROBUST_LIST ScmpSyscall = SYS_SET_ROBUST_LIST
|
||||||
|
SNR_GET_ROBUST_LIST ScmpSyscall = SYS_GET_ROBUST_LIST
|
||||||
|
SNR_NANOSLEEP ScmpSyscall = SYS_NANOSLEEP
|
||||||
|
SNR_GETITIMER ScmpSyscall = SYS_GETITIMER
|
||||||
|
SNR_SETITIMER ScmpSyscall = SYS_SETITIMER
|
||||||
|
SNR_KEXEC_LOAD ScmpSyscall = SYS_KEXEC_LOAD
|
||||||
|
SNR_INIT_MODULE ScmpSyscall = SYS_INIT_MODULE
|
||||||
|
SNR_DELETE_MODULE ScmpSyscall = SYS_DELETE_MODULE
|
||||||
|
SNR_TIMER_CREATE ScmpSyscall = SYS_TIMER_CREATE
|
||||||
|
SNR_TIMER_GETTIME ScmpSyscall = SYS_TIMER_GETTIME
|
||||||
|
SNR_TIMER_GETOVERRUN ScmpSyscall = SYS_TIMER_GETOVERRUN
|
||||||
|
SNR_TIMER_SETTIME ScmpSyscall = SYS_TIMER_SETTIME
|
||||||
|
SNR_TIMER_DELETE ScmpSyscall = SYS_TIMER_DELETE
|
||||||
|
SNR_CLOCK_SETTIME ScmpSyscall = SYS_CLOCK_SETTIME
|
||||||
|
SNR_CLOCK_GETTIME ScmpSyscall = SYS_CLOCK_GETTIME
|
||||||
|
SNR_CLOCK_GETRES ScmpSyscall = SYS_CLOCK_GETRES
|
||||||
|
SNR_CLOCK_NANOSLEEP ScmpSyscall = SYS_CLOCK_NANOSLEEP
|
||||||
|
SNR_SYSLOG ScmpSyscall = SYS_SYSLOG
|
||||||
|
SNR_PTRACE ScmpSyscall = SYS_PTRACE
|
||||||
|
SNR_SCHED_SETPARAM ScmpSyscall = SYS_SCHED_SETPARAM
|
||||||
|
SNR_SCHED_SETSCHEDULER ScmpSyscall = SYS_SCHED_SETSCHEDULER
|
||||||
|
SNR_SCHED_GETSCHEDULER ScmpSyscall = SYS_SCHED_GETSCHEDULER
|
||||||
|
SNR_SCHED_GETPARAM ScmpSyscall = SYS_SCHED_GETPARAM
|
||||||
|
SNR_SCHED_SETAFFINITY ScmpSyscall = SYS_SCHED_SETAFFINITY
|
||||||
|
SNR_SCHED_GETAFFINITY ScmpSyscall = SYS_SCHED_GETAFFINITY
|
||||||
|
SNR_SCHED_YIELD ScmpSyscall = SYS_SCHED_YIELD
|
||||||
|
SNR_SCHED_GET_PRIORITY_MAX ScmpSyscall = SYS_SCHED_GET_PRIORITY_MAX
|
||||||
|
SNR_SCHED_GET_PRIORITY_MIN ScmpSyscall = SYS_SCHED_GET_PRIORITY_MIN
|
||||||
|
SNR_SCHED_RR_GET_INTERVAL ScmpSyscall = SYS_SCHED_RR_GET_INTERVAL
|
||||||
|
SNR_RESTART_SYSCALL ScmpSyscall = SYS_RESTART_SYSCALL
|
||||||
|
SNR_KILL ScmpSyscall = SYS_KILL
|
||||||
|
SNR_TKILL ScmpSyscall = SYS_TKILL
|
||||||
|
SNR_TGKILL ScmpSyscall = SYS_TGKILL
|
||||||
|
SNR_SIGALTSTACK ScmpSyscall = SYS_SIGALTSTACK
|
||||||
|
SNR_RT_SIGSUSPEND ScmpSyscall = SYS_RT_SIGSUSPEND
|
||||||
|
SNR_RT_SIGACTION ScmpSyscall = SYS_RT_SIGACTION
|
||||||
|
SNR_RT_SIGPROCMASK ScmpSyscall = SYS_RT_SIGPROCMASK
|
||||||
|
SNR_RT_SIGPENDING ScmpSyscall = SYS_RT_SIGPENDING
|
||||||
|
SNR_RT_SIGTIMEDWAIT ScmpSyscall = SYS_RT_SIGTIMEDWAIT
|
||||||
|
SNR_RT_SIGQUEUEINFO ScmpSyscall = SYS_RT_SIGQUEUEINFO
|
||||||
|
SNR_RT_SIGRETURN ScmpSyscall = SYS_RT_SIGRETURN
|
||||||
|
SNR_SETPRIORITY ScmpSyscall = SYS_SETPRIORITY
|
||||||
|
SNR_GETPRIORITY ScmpSyscall = SYS_GETPRIORITY
|
||||||
|
SNR_REBOOT ScmpSyscall = SYS_REBOOT
|
||||||
|
SNR_SETREGID ScmpSyscall = SYS_SETREGID
|
||||||
|
SNR_SETGID ScmpSyscall = SYS_SETGID
|
||||||
|
SNR_SETREUID ScmpSyscall = SYS_SETREUID
|
||||||
|
SNR_SETUID ScmpSyscall = SYS_SETUID
|
||||||
|
SNR_SETRESUID ScmpSyscall = SYS_SETRESUID
|
||||||
|
SNR_GETRESUID ScmpSyscall = SYS_GETRESUID
|
||||||
|
SNR_SETRESGID ScmpSyscall = SYS_SETRESGID
|
||||||
|
SNR_GETRESGID ScmpSyscall = SYS_GETRESGID
|
||||||
|
SNR_SETFSUID ScmpSyscall = SYS_SETFSUID
|
||||||
|
SNR_SETFSGID ScmpSyscall = SYS_SETFSGID
|
||||||
|
SNR_TIMES ScmpSyscall = SYS_TIMES
|
||||||
|
SNR_SETPGID ScmpSyscall = SYS_SETPGID
|
||||||
|
SNR_GETPGID ScmpSyscall = SYS_GETPGID
|
||||||
|
SNR_GETSID ScmpSyscall = SYS_GETSID
|
||||||
|
SNR_SETSID ScmpSyscall = SYS_SETSID
|
||||||
|
SNR_GETGROUPS ScmpSyscall = SYS_GETGROUPS
|
||||||
|
SNR_SETGROUPS ScmpSyscall = SYS_SETGROUPS
|
||||||
|
SNR_UNAME ScmpSyscall = SYS_UNAME
|
||||||
|
SNR_SETHOSTNAME ScmpSyscall = SYS_SETHOSTNAME
|
||||||
|
SNR_SETDOMAINNAME ScmpSyscall = SYS_SETDOMAINNAME
|
||||||
|
SNR_GETRLIMIT ScmpSyscall = SYS_GETRLIMIT
|
||||||
|
SNR_SETRLIMIT ScmpSyscall = SYS_SETRLIMIT
|
||||||
|
SNR_GETRUSAGE ScmpSyscall = SYS_GETRUSAGE
|
||||||
|
SNR_UMASK ScmpSyscall = SYS_UMASK
|
||||||
|
SNR_PRCTL ScmpSyscall = SYS_PRCTL
|
||||||
|
SNR_GETCPU ScmpSyscall = SYS_GETCPU
|
||||||
|
SNR_GETTIMEOFDAY ScmpSyscall = SYS_GETTIMEOFDAY
|
||||||
|
SNR_SETTIMEOFDAY ScmpSyscall = SYS_SETTIMEOFDAY
|
||||||
|
SNR_ADJTIMEX ScmpSyscall = SYS_ADJTIMEX
|
||||||
|
SNR_GETPID ScmpSyscall = SYS_GETPID
|
||||||
|
SNR_GETPPID ScmpSyscall = SYS_GETPPID
|
||||||
|
SNR_GETUID ScmpSyscall = SYS_GETUID
|
||||||
|
SNR_GETEUID ScmpSyscall = SYS_GETEUID
|
||||||
|
SNR_GETGID ScmpSyscall = SYS_GETGID
|
||||||
|
SNR_GETEGID ScmpSyscall = SYS_GETEGID
|
||||||
|
SNR_GETTID ScmpSyscall = SYS_GETTID
|
||||||
|
SNR_SYSINFO ScmpSyscall = SYS_SYSINFO
|
||||||
|
SNR_MQ_OPEN ScmpSyscall = SYS_MQ_OPEN
|
||||||
|
SNR_MQ_UNLINK ScmpSyscall = SYS_MQ_UNLINK
|
||||||
|
SNR_MQ_TIMEDSEND ScmpSyscall = SYS_MQ_TIMEDSEND
|
||||||
|
SNR_MQ_TIMEDRECEIVE ScmpSyscall = SYS_MQ_TIMEDRECEIVE
|
||||||
|
SNR_MQ_NOTIFY ScmpSyscall = SYS_MQ_NOTIFY
|
||||||
|
SNR_MQ_GETSETATTR ScmpSyscall = SYS_MQ_GETSETATTR
|
||||||
|
SNR_MSGGET ScmpSyscall = SYS_MSGGET
|
||||||
|
SNR_MSGCTL ScmpSyscall = SYS_MSGCTL
|
||||||
|
SNR_MSGRCV ScmpSyscall = SYS_MSGRCV
|
||||||
|
SNR_MSGSND ScmpSyscall = SYS_MSGSND
|
||||||
|
SNR_SEMGET ScmpSyscall = SYS_SEMGET
|
||||||
|
SNR_SEMCTL ScmpSyscall = SYS_SEMCTL
|
||||||
|
SNR_SEMTIMEDOP ScmpSyscall = SYS_SEMTIMEDOP
|
||||||
|
SNR_SEMOP ScmpSyscall = SYS_SEMOP
|
||||||
|
SNR_SHMGET ScmpSyscall = SYS_SHMGET
|
||||||
|
SNR_SHMCTL ScmpSyscall = SYS_SHMCTL
|
||||||
|
SNR_SHMAT ScmpSyscall = SYS_SHMAT
|
||||||
|
SNR_SHMDT ScmpSyscall = SYS_SHMDT
|
||||||
|
SNR_SOCKET ScmpSyscall = SYS_SOCKET
|
||||||
|
SNR_SOCKETPAIR ScmpSyscall = SYS_SOCKETPAIR
|
||||||
|
SNR_BIND ScmpSyscall = SYS_BIND
|
||||||
|
SNR_LISTEN ScmpSyscall = SYS_LISTEN
|
||||||
|
SNR_ACCEPT ScmpSyscall = SYS_ACCEPT
|
||||||
|
SNR_CONNECT ScmpSyscall = SYS_CONNECT
|
||||||
|
SNR_GETSOCKNAME ScmpSyscall = SYS_GETSOCKNAME
|
||||||
|
SNR_GETPEERNAME ScmpSyscall = SYS_GETPEERNAME
|
||||||
|
SNR_SENDTO ScmpSyscall = SYS_SENDTO
|
||||||
|
SNR_RECVFROM ScmpSyscall = SYS_RECVFROM
|
||||||
|
SNR_SETSOCKOPT ScmpSyscall = SYS_SETSOCKOPT
|
||||||
|
SNR_GETSOCKOPT ScmpSyscall = SYS_GETSOCKOPT
|
||||||
|
SNR_SHUTDOWN ScmpSyscall = SYS_SHUTDOWN
|
||||||
|
SNR_SENDMSG ScmpSyscall = SYS_SENDMSG
|
||||||
|
SNR_RECVMSG ScmpSyscall = SYS_RECVMSG
|
||||||
|
SNR_READAHEAD ScmpSyscall = SYS_READAHEAD
|
||||||
|
SNR_BRK ScmpSyscall = SYS_BRK
|
||||||
|
SNR_MUNMAP ScmpSyscall = SYS_MUNMAP
|
||||||
|
SNR_MREMAP ScmpSyscall = SYS_MREMAP
|
||||||
|
SNR_ADD_KEY ScmpSyscall = SYS_ADD_KEY
|
||||||
|
SNR_REQUEST_KEY ScmpSyscall = SYS_REQUEST_KEY
|
||||||
|
SNR_KEYCTL ScmpSyscall = SYS_KEYCTL
|
||||||
|
SNR_CLONE ScmpSyscall = SYS_CLONE
|
||||||
|
SNR_EXECVE ScmpSyscall = SYS_EXECVE
|
||||||
|
SNR_MMAP ScmpSyscall = SYS_MMAP
|
||||||
|
SNR_FADVISE64 ScmpSyscall = SYS_FADVISE64
|
||||||
|
SNR_SWAPON ScmpSyscall = SYS_SWAPON
|
||||||
|
SNR_SWAPOFF ScmpSyscall = SYS_SWAPOFF
|
||||||
|
SNR_MPROTECT ScmpSyscall = SYS_MPROTECT
|
||||||
|
SNR_MSYNC ScmpSyscall = SYS_MSYNC
|
||||||
|
SNR_MLOCK ScmpSyscall = SYS_MLOCK
|
||||||
|
SNR_MUNLOCK ScmpSyscall = SYS_MUNLOCK
|
||||||
|
SNR_MLOCKALL ScmpSyscall = SYS_MLOCKALL
|
||||||
|
SNR_MUNLOCKALL ScmpSyscall = SYS_MUNLOCKALL
|
||||||
|
SNR_MINCORE ScmpSyscall = SYS_MINCORE
|
||||||
|
SNR_MADVISE ScmpSyscall = SYS_MADVISE
|
||||||
|
SNR_REMAP_FILE_PAGES ScmpSyscall = SYS_REMAP_FILE_PAGES
|
||||||
|
SNR_MBIND ScmpSyscall = SYS_MBIND
|
||||||
|
SNR_GET_MEMPOLICY ScmpSyscall = SYS_GET_MEMPOLICY
|
||||||
|
SNR_SET_MEMPOLICY ScmpSyscall = SYS_SET_MEMPOLICY
|
||||||
|
SNR_MIGRATE_PAGES ScmpSyscall = SYS_MIGRATE_PAGES
|
||||||
|
SNR_MOVE_PAGES ScmpSyscall = SYS_MOVE_PAGES
|
||||||
|
SNR_RT_TGSIGQUEUEINFO ScmpSyscall = SYS_RT_TGSIGQUEUEINFO
|
||||||
|
SNR_PERF_EVENT_OPEN ScmpSyscall = SYS_PERF_EVENT_OPEN
|
||||||
|
SNR_ACCEPT4 ScmpSyscall = SYS_ACCEPT4
|
||||||
|
SNR_RECVMMSG ScmpSyscall = SYS_RECVMMSG
|
||||||
|
SNR_WAIT4 ScmpSyscall = SYS_WAIT4
|
||||||
|
SNR_PRLIMIT64 ScmpSyscall = SYS_PRLIMIT64
|
||||||
|
SNR_FANOTIFY_INIT ScmpSyscall = SYS_FANOTIFY_INIT
|
||||||
|
SNR_FANOTIFY_MARK ScmpSyscall = SYS_FANOTIFY_MARK
|
||||||
|
SNR_NAME_TO_HANDLE_AT ScmpSyscall = SYS_NAME_TO_HANDLE_AT
|
||||||
|
SNR_OPEN_BY_HANDLE_AT ScmpSyscall = SYS_OPEN_BY_HANDLE_AT
|
||||||
|
SNR_CLOCK_ADJTIME ScmpSyscall = SYS_CLOCK_ADJTIME
|
||||||
|
SNR_SYNCFS ScmpSyscall = SYS_SYNCFS
|
||||||
|
SNR_SETNS ScmpSyscall = SYS_SETNS
|
||||||
|
SNR_SENDMMSG ScmpSyscall = SYS_SENDMMSG
|
||||||
|
SNR_PROCESS_VM_READV ScmpSyscall = SYS_PROCESS_VM_READV
|
||||||
|
SNR_PROCESS_VM_WRITEV ScmpSyscall = SYS_PROCESS_VM_WRITEV
|
||||||
|
SNR_KCMP ScmpSyscall = SYS_KCMP
|
||||||
|
SNR_FINIT_MODULE ScmpSyscall = SYS_FINIT_MODULE
|
||||||
|
SNR_SCHED_SETATTR ScmpSyscall = SYS_SCHED_SETATTR
|
||||||
|
SNR_SCHED_GETATTR ScmpSyscall = SYS_SCHED_GETATTR
|
||||||
|
SNR_RENAMEAT2 ScmpSyscall = SYS_RENAMEAT2
|
||||||
|
SNR_SECCOMP ScmpSyscall = SYS_SECCOMP
|
||||||
|
SNR_GETRANDOM ScmpSyscall = SYS_GETRANDOM
|
||||||
|
SNR_MEMFD_CREATE ScmpSyscall = SYS_MEMFD_CREATE
|
||||||
|
SNR_BPF ScmpSyscall = SYS_BPF
|
||||||
|
SNR_EXECVEAT ScmpSyscall = SYS_EXECVEAT
|
||||||
|
SNR_USERFAULTFD ScmpSyscall = SYS_USERFAULTFD
|
||||||
|
SNR_MEMBARRIER ScmpSyscall = SYS_MEMBARRIER
|
||||||
|
SNR_MLOCK2 ScmpSyscall = SYS_MLOCK2
|
||||||
|
SNR_COPY_FILE_RANGE ScmpSyscall = SYS_COPY_FILE_RANGE
|
||||||
|
SNR_PREADV2 ScmpSyscall = SYS_PREADV2
|
||||||
|
SNR_PWRITEV2 ScmpSyscall = SYS_PWRITEV2
|
||||||
|
SNR_PKEY_MPROTECT ScmpSyscall = SYS_PKEY_MPROTECT
|
||||||
|
SNR_PKEY_ALLOC ScmpSyscall = SYS_PKEY_ALLOC
|
||||||
|
SNR_PKEY_FREE ScmpSyscall = SYS_PKEY_FREE
|
||||||
|
SNR_STATX ScmpSyscall = SYS_STATX
|
||||||
|
SNR_IO_PGETEVENTS ScmpSyscall = SYS_IO_PGETEVENTS
|
||||||
|
SNR_RSEQ ScmpSyscall = SYS_RSEQ
|
||||||
|
SNR_KEXEC_FILE_LOAD ScmpSyscall = SYS_KEXEC_FILE_LOAD
|
||||||
|
SNR_PIDFD_SEND_SIGNAL ScmpSyscall = SYS_PIDFD_SEND_SIGNAL
|
||||||
|
SNR_IO_URING_SETUP ScmpSyscall = SYS_IO_URING_SETUP
|
||||||
|
SNR_IO_URING_ENTER ScmpSyscall = SYS_IO_URING_ENTER
|
||||||
|
SNR_IO_URING_REGISTER ScmpSyscall = SYS_IO_URING_REGISTER
|
||||||
|
SNR_OPEN_TREE ScmpSyscall = SYS_OPEN_TREE
|
||||||
|
SNR_MOVE_MOUNT ScmpSyscall = SYS_MOVE_MOUNT
|
||||||
|
SNR_FSOPEN ScmpSyscall = SYS_FSOPEN
|
||||||
|
SNR_FSCONFIG ScmpSyscall = SYS_FSCONFIG
|
||||||
|
SNR_FSMOUNT ScmpSyscall = SYS_FSMOUNT
|
||||||
|
SNR_FSPICK ScmpSyscall = SYS_FSPICK
|
||||||
|
SNR_PIDFD_OPEN ScmpSyscall = SYS_PIDFD_OPEN
|
||||||
|
SNR_CLONE3 ScmpSyscall = SYS_CLONE3
|
||||||
|
SNR_CLOSE_RANGE ScmpSyscall = SYS_CLOSE_RANGE
|
||||||
|
SNR_OPENAT2 ScmpSyscall = SYS_OPENAT2
|
||||||
|
SNR_PIDFD_GETFD ScmpSyscall = SYS_PIDFD_GETFD
|
||||||
|
SNR_FACCESSAT2 ScmpSyscall = SYS_FACCESSAT2
|
||||||
|
SNR_PROCESS_MADVISE ScmpSyscall = SYS_PROCESS_MADVISE
|
||||||
|
SNR_EPOLL_PWAIT2 ScmpSyscall = SYS_EPOLL_PWAIT2
|
||||||
|
SNR_MOUNT_SETATTR ScmpSyscall = SYS_MOUNT_SETATTR
|
||||||
|
SNR_QUOTACTL_FD ScmpSyscall = SYS_QUOTACTL_FD
|
||||||
|
SNR_LANDLOCK_CREATE_RULESET ScmpSyscall = SYS_LANDLOCK_CREATE_RULESET
|
||||||
|
SNR_LANDLOCK_ADD_RULE ScmpSyscall = SYS_LANDLOCK_ADD_RULE
|
||||||
|
SNR_LANDLOCK_RESTRICT_SELF ScmpSyscall = SYS_LANDLOCK_RESTRICT_SELF
|
||||||
|
SNR_MEMFD_SECRET ScmpSyscall = SYS_MEMFD_SECRET
|
||||||
|
SNR_PROCESS_MRELEASE ScmpSyscall = SYS_PROCESS_MRELEASE
|
||||||
|
SNR_FUTEX_WAITV ScmpSyscall = SYS_FUTEX_WAITV
|
||||||
|
SNR_SET_MEMPOLICY_HOME_NODE ScmpSyscall = SYS_SET_MEMPOLICY_HOME_NODE
|
||||||
|
SNR_CACHESTAT ScmpSyscall = SYS_CACHESTAT
|
||||||
|
SNR_FCHMODAT2 ScmpSyscall = SYS_FCHMODAT2
|
||||||
|
SNR_MAP_SHADOW_STACK ScmpSyscall = SYS_MAP_SHADOW_STACK
|
||||||
|
SNR_FUTEX_WAKE ScmpSyscall = SYS_FUTEX_WAKE
|
||||||
|
SNR_FUTEX_WAIT ScmpSyscall = SYS_FUTEX_WAIT
|
||||||
|
SNR_FUTEX_REQUEUE ScmpSyscall = SYS_FUTEX_REQUEUE
|
||||||
|
SNR_STATMOUNT ScmpSyscall = SYS_STATMOUNT
|
||||||
|
SNR_LISTMOUNT ScmpSyscall = SYS_LISTMOUNT
|
||||||
|
SNR_LSM_GET_SELF_ATTR ScmpSyscall = SYS_LSM_GET_SELF_ATTR
|
||||||
|
SNR_LSM_SET_SELF_ATTR ScmpSyscall = SYS_LSM_SET_SELF_ATTR
|
||||||
|
SNR_LSM_LIST_MODULES ScmpSyscall = SYS_LSM_LIST_MODULES
|
||||||
|
SNR_MSEAL ScmpSyscall = SYS_MSEAL
|
||||||
|
)
|
||||||
21
container/std/syscall_test.go
Normal file
21
container/std/syscall_test.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package std_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container/std"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSyscallResolveName(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for name, want := range std.Syscalls() {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got, ok := std.SyscallResolveName(name); !ok || got != want {
|
||||||
|
t.Errorf("SyscallResolveName(%q) = %d, want %d", name, got, want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ var (
|
|||||||
type UniqueError uintptr
|
type UniqueError uintptr
|
||||||
|
|
||||||
func (e UniqueError) Error() string {
|
func (e UniqueError) Error() string {
|
||||||
return "unique error " + strconv.Itoa(int(e)) + " injected by the test suite"
|
return "unique error " + strconv.FormatUint(uint64(e), 10) + " injected by the test suite"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e UniqueError) Is(target error) bool {
|
func (e UniqueError) Is(target error) bool {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package stub
|
|||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
// PanicExit is a magic panic value treated as a simulated exit.
|
// PanicExit is a magic panic value treated as a simulated exit.
|
||||||
const PanicExit = 0xdeadbeef
|
const PanicExit = 0xdead
|
||||||
|
|
||||||
const (
|
const (
|
||||||
panicFailNow = 0xcafe0000 + iota
|
panicFailNow = 0xcafe0 + iota
|
||||||
panicFatal
|
panicFatal
|
||||||
panicFatalf
|
panicFatalf
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package stub_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
_ "unsafe"
|
_ "unsafe" // for go:linkname
|
||||||
|
|
||||||
"hakurei.app/container/stub"
|
"hakurei.app/container/stub"
|
||||||
)
|
)
|
||||||
@@ -53,7 +53,7 @@ func TestHandleExit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
defer stub.HandleExit(ot)
|
defer stub.HandleExit(ot)
|
||||||
panic(0xcafe0000)
|
panic(0xcafe0)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Fail", func(t *testing.T) {
|
t.Run("Fail", func(t *testing.T) {
|
||||||
@@ -66,7 +66,7 @@ func TestHandleExit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
defer handleExitNew(ot)
|
defer handleExitNew(ot)
|
||||||
panic(0xcafe0000)
|
panic(0xcafe0)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -82,14 +82,14 @@ func TestHandleExit(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
want := 0xcafebabe
|
want := 0xcafe
|
||||||
if r := recover(); r != want {
|
if r := recover(); r != want {
|
||||||
t.Errorf("recover: %v, want %v", r, want)
|
t.Errorf("recover: %v, want %v", r, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
}()
|
}()
|
||||||
defer stub.HandleExit(t)
|
defer stub.HandleExit(t)
|
||||||
panic(0xcafebabe)
|
panic(0xcafe)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("new", func(t *testing.T) {
|
t.Run("new", func(t *testing.T) {
|
||||||
|
|||||||
7
container/syscall_386.go
Normal file
7
container/syscall_386.go
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
const (
|
||||||
|
O_PATH = 0x200000
|
||||||
|
|
||||||
|
PR_SET_NO_NEW_PRIVS = 0x26
|
||||||
|
)
|
||||||
@@ -26,11 +26,11 @@ func TestDecoderError(t *testing.T) {
|
|||||||
target error
|
target error
|
||||||
targetF error
|
targetF error
|
||||||
}{
|
}{
|
||||||
{"errno", &vfs.DecoderError{Op: "parse", Line: 0xdeadbeef, Err: syscall.ENOTRECOVERABLE},
|
{"errno", &vfs.DecoderError{Op: "parse", Line: 0xdead, Err: syscall.ENOTRECOVERABLE},
|
||||||
"parse mountinfo at line 3735928559: state not recoverable", syscall.ENOTRECOVERABLE, syscall.EROFS},
|
"parse mountinfo at line 57005: state not recoverable", syscall.ENOTRECOVERABLE, syscall.EROFS},
|
||||||
|
|
||||||
{"strconv", &vfs.DecoderError{Op: "parse", Line: 0xdeadbeef, Err: &strconv.NumError{Func: "Atoi", Num: "meow", Err: strconv.ErrSyntax}},
|
{"strconv", &vfs.DecoderError{Op: "parse", Line: 0xdead, Err: &strconv.NumError{Func: "Atoi", Num: "meow", Err: strconv.ErrSyntax}},
|
||||||
`parse mountinfo at line 3735928559: numeric field "meow" invalid syntax`, strconv.ErrSyntax, os.ErrInvalid},
|
`parse mountinfo at line 57005: numeric field "meow" invalid syntax`, strconv.ErrSyntax, os.ErrInvalid},
|
||||||
|
|
||||||
{"unfold", &vfs.DecoderError{Op: "unfold", Line: -1, Err: vfs.UnfoldTargetError("/proc/nonexistent")},
|
{"unfold", &vfs.DecoderError{Op: "unfold", Line: -1, Err: vfs.UnfoldTargetError("/proc/nonexistent")},
|
||||||
"unfold mountinfo: mount point /proc/nonexistent never appeared in mountinfo", vfs.UnfoldTargetError("/proc/nonexistent"), os.ErrNotExist},
|
"unfold mountinfo: mount point /proc/nonexistent never appeared in mountinfo", vfs.UnfoldTargetError("/proc/nonexistent"), os.ErrNotExist},
|
||||||
|
|||||||
@@ -244,10 +244,10 @@
|
|||||||
shellHook = "exec ${pkgs.writeShellScript "generate-syscall-table" ''
|
shellHook = "exec ${pkgs.writeShellScript "generate-syscall-table" ''
|
||||||
set -e
|
set -e
|
||||||
${pkgs.perl}/bin/perl \
|
${pkgs.perl}/bin/perl \
|
||||||
container/seccomp/mksysnum_linux.pl \
|
container/std/mksysnum_linux.pl \
|
||||||
${pkgs.linuxHeaders}/include/asm/unistd_64.h | \
|
${pkgs.linuxHeaders}/include/asm/unistd_64.h | \
|
||||||
${pkgs.go}/bin/gofmt > \
|
${pkgs.go}/bin/gofmt > \
|
||||||
container/seccomp/syscall_linux_${GOARCH.${system}}.go
|
container/std/syscall_linux_${GOARCH.${system}}.go
|
||||||
''}";
|
''}";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
// Reverse-DNS style configured arbitrary identifier string.
|
// Reverse-DNS style configured arbitrary identifier string.
|
||||||
// Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
|
// Passed to wayland security-context-v1 and used as part of defaults in dbus session proxy.
|
||||||
ID string `json:"id"`
|
ID string `json:"id,omitempty"`
|
||||||
|
|
||||||
// System services to make available in the container.
|
// System services to make available in the container.
|
||||||
Enablements *Enablements `json:"enablements,omitempty"`
|
Enablements *Enablements `json:"enablements,omitempty"`
|
||||||
@@ -59,7 +59,7 @@ func (config *Config) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this is checked again in hsu
|
// this is checked again in hsu
|
||||||
if config.Identity < IdentityMin || config.Identity > IdentityMax {
|
if config.Identity < IdentityStart || config.Identity > IdentityEnd {
|
||||||
return &AppError{Step: "validate configuration", Err: ErrIdentityBounds,
|
return &AppError{Step: "validate configuration", Err: ErrIdentityBounds,
|
||||||
Msg: "identity " + strconv.Itoa(config.Identity) + " out of range"}
|
Msg: "identity " + strconv.Itoa(config.Identity) + " out of range"}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,6 @@ const (
|
|||||||
WaitDelayDefault = 5 * time.Second
|
WaitDelayDefault = 5 * time.Second
|
||||||
// WaitDelayMax is used if WaitDelay exceeds its value.
|
// WaitDelayMax is used if WaitDelay exceeds its value.
|
||||||
WaitDelayMax = 30 * time.Second
|
WaitDelayMax = 30 * time.Second
|
||||||
|
|
||||||
// IdentityMin is the minimum value of [Config.Identity]. This is enforced by cmd/hsu.
|
|
||||||
IdentityMin = 0
|
|
||||||
// IdentityMax is the maximum value of [Config.Identity]. This is enforced by cmd/hsu.
|
|
||||||
IdentityMax = 9999
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ func TestEnablements(t *testing.T) {
|
|||||||
|
|
||||||
if got, err := json.Marshal(struct {
|
if got, err := json.Marshal(struct {
|
||||||
Value *hst.Enablements `json:"value"`
|
Value *hst.Enablements `json:"value"`
|
||||||
Magic int `json:"magic"`
|
Magic uint64 `json:"magic"`
|
||||||
}{tc.e, syscall.MS_MGC_VAL}); err != nil {
|
}{tc.e, syscall.MS_MGC_VAL}); err != nil {
|
||||||
t.Fatalf("Marshal: error = %v", err)
|
t.Fatalf("Marshal: error = %v", err)
|
||||||
} else if string(got) != tc.sData {
|
} else if string(got) != tc.sData {
|
||||||
@@ -108,7 +108,7 @@ func TestEnablements(t *testing.T) {
|
|||||||
{
|
{
|
||||||
got := *(new(struct {
|
got := *(new(struct {
|
||||||
Value *hst.Enablements `json:"value"`
|
Value *hst.Enablements `json:"value"`
|
||||||
Magic int `json:"magic"`
|
Magic uint64 `json:"magic"`
|
||||||
}))
|
}))
|
||||||
if err := json.Unmarshal([]byte(tc.sData), &got); err != nil {
|
if err := json.Unmarshal([]byte(tc.sData), &got); err != nil {
|
||||||
t.Fatalf("Unmarshal: error = %v", err)
|
t.Fatalf("Unmarshal: error = %v", err)
|
||||||
|
|||||||
@@ -241,7 +241,7 @@ func (s stubFS) String() string { return "<invalid " + s.typeName + ">"
|
|||||||
|
|
||||||
type sCheck struct {
|
type sCheck struct {
|
||||||
FS hst.FilesystemConfigJSON `json:"fs"`
|
FS hst.FilesystemConfigJSON `json:"fs"`
|
||||||
Magic int `json:"magic"`
|
Magic uint64 `json:"magic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type fsTestCase struct {
|
type fsTestCase struct {
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
"hakurei.app/container/check"
|
||||||
"hakurei.app/container/comp"
|
|
||||||
"hakurei.app/container/fhs"
|
"hakurei.app/container/fhs"
|
||||||
|
"hakurei.app/container/std"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() { gob.Register(new(FSBind)) }
|
func init() { gob.Register(new(FSBind)) }
|
||||||
@@ -97,16 +97,16 @@ func (b *FSBind) Apply(z *ApplyState) {
|
|||||||
}
|
}
|
||||||
var flags int
|
var flags int
|
||||||
if b.Write {
|
if b.Write {
|
||||||
flags |= comp.BindWritable
|
flags |= std.BindWritable
|
||||||
}
|
}
|
||||||
if b.Device {
|
if b.Device {
|
||||||
flags |= comp.BindDevice | comp.BindWritable
|
flags |= std.BindDevice | std.BindWritable
|
||||||
}
|
}
|
||||||
if b.Ensure {
|
if b.Ensure {
|
||||||
flags |= comp.BindEnsure
|
flags |= std.BindEnsure
|
||||||
}
|
}
|
||||||
if b.Optional {
|
if b.Optional {
|
||||||
flags |= comp.BindOptional
|
flags |= std.BindOptional
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
"hakurei.app/container/comp"
|
"hakurei.app/container/std"
|
||||||
"hakurei.app/hst"
|
"hakurei.app/hst"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ func TestFSBind(t *testing.T) {
|
|||||||
}, true, container.Ops{&container.BindMountOp{
|
}, true, container.Ops{&container.BindMountOp{
|
||||||
Source: m("/mnt/dev"),
|
Source: m("/mnt/dev"),
|
||||||
Target: m("/dev"),
|
Target: m("/dev"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice | comp.BindOptional,
|
Flags: std.BindWritable | std.BindDevice | std.BindOptional,
|
||||||
}}, m("/dev"), ms("/mnt/dev"),
|
}}, m("/dev"), ms("/mnt/dev"),
|
||||||
"d+/mnt/dev:/dev"},
|
"d+/mnt/dev:/dev"},
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ func TestFSBind(t *testing.T) {
|
|||||||
}, true, container.Ops{&container.BindMountOp{
|
}, true, container.Ops{&container.BindMountOp{
|
||||||
Source: m("/mnt/dev"),
|
Source: m("/mnt/dev"),
|
||||||
Target: m("/dev"),
|
Target: m("/dev"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice | comp.BindEnsure,
|
Flags: std.BindWritable | std.BindDevice | std.BindEnsure,
|
||||||
}}, m("/dev"), ms("/mnt/dev"),
|
}}, m("/dev"), ms("/mnt/dev"),
|
||||||
"d-/mnt/dev:/dev"},
|
"d-/mnt/dev:/dev"},
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ func TestFSBind(t *testing.T) {
|
|||||||
}, true, container.Ops{&container.BindMountOp{
|
}, true, container.Ops{&container.BindMountOp{
|
||||||
Source: m("/mnt/dev"),
|
Source: m("/mnt/dev"),
|
||||||
Target: m("/dev"),
|
Target: m("/dev"),
|
||||||
Flags: comp.BindWritable | comp.BindDevice,
|
Flags: std.BindWritable | std.BindDevice,
|
||||||
}}, m("/dev"), ms("/mnt/dev"),
|
}}, m("/dev"), ms("/mnt/dev"),
|
||||||
"d*/mnt/dev:/dev"},
|
"d*/mnt/dev:/dev"},
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ func TestFSBind(t *testing.T) {
|
|||||||
}, true, container.Ops{&container.BindMountOp{
|
}, true, container.Ops{&container.BindMountOp{
|
||||||
Source: m("/mnt/tmp"),
|
Source: m("/mnt/tmp"),
|
||||||
Target: m("/tmp"),
|
Target: m("/tmp"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}}, m("/tmp"), ms("/mnt/tmp"),
|
}}, m("/tmp"), ms("/mnt/tmp"),
|
||||||
"w*/mnt/tmp:/tmp"},
|
"w*/mnt/tmp:/tmp"},
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ func TestFSBind(t *testing.T) {
|
|||||||
Special: true,
|
Special: true,
|
||||||
}, true, container.Ops{&container.AutoRootOp{
|
}, true, container.Ops{&container.AutoRootOp{
|
||||||
Host: m("/"),
|
Host: m("/"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}}, m("/"), ms("/"), "autoroot:w"},
|
}}, m("/"), ms("/"), "autoroot:w"},
|
||||||
|
|
||||||
{"autoroot silly", &hst.FSBind{
|
{"autoroot silly", &hst.FSBind{
|
||||||
@@ -108,7 +108,7 @@ func TestFSBind(t *testing.T) {
|
|||||||
Special: true,
|
Special: true,
|
||||||
}, true, container.Ops{&container.AutoRootOp{
|
}, true, container.Ops{&container.AutoRootOp{
|
||||||
Host: m("/etc"),
|
Host: m("/etc"),
|
||||||
Flags: comp.BindWritable,
|
Flags: std.BindWritable,
|
||||||
}}, m("/"), ms("/etc"), "autoroot:w:/etc"},
|
}}, m("/"), ms("/etc"), "autoroot:w:/etc"},
|
||||||
|
|
||||||
{"autoetc", &hst.FSBind{
|
{"autoetc", &hst.FSBind{
|
||||||
|
|||||||
61
hst/grp_pwd.go
Normal file
61
hst/grp_pwd.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package hst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// UserOffset is the offset for UID and GID ranges for each user.
|
||||||
|
UserOffset = 100000
|
||||||
|
// RangeSize is the size of each UID and GID range.
|
||||||
|
RangeSize = UserOffset / 10
|
||||||
|
|
||||||
|
// IdentityStart is the first [Config.Identity] value. This is enforced in cmd/hsu.
|
||||||
|
IdentityStart = 0
|
||||||
|
// IdentityEnd is the last [Config.Identity] value. This is enforced in cmd/hsu.
|
||||||
|
IdentityEnd = AppEnd - AppStart
|
||||||
|
|
||||||
|
// AppStart is the first app user UID and GID.
|
||||||
|
AppStart = RangeSize * 1
|
||||||
|
// AppEnd is the last app user UID and GID.
|
||||||
|
AppEnd = AppStart + RangeSize - 1
|
||||||
|
|
||||||
|
/* these are for Rosa OS: use the ranges below to determine whether a process is isolated */
|
||||||
|
|
||||||
|
// IsolatedStart is the start of UID and GID for fully isolated sandboxed processes.
|
||||||
|
IsolatedStart = RangeSize * 9
|
||||||
|
// IsolatedEnd is the end of UID and GID for fully isolated sandboxed processes.
|
||||||
|
IsolatedEnd = IsolatedStart + RangeSize - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
// A UID represents a kernel uid in the init namespace.
|
||||||
|
type UID uint32
|
||||||
|
|
||||||
|
// String returns the username corresponding to this uid.
|
||||||
|
//
|
||||||
|
// Not safe against untrusted input.
|
||||||
|
func (uid UID) String() string {
|
||||||
|
appid := uid % UserOffset
|
||||||
|
userid := uid / UserOffset
|
||||||
|
if appid >= IsolatedStart && appid <= IsolatedEnd {
|
||||||
|
return fmt.Sprintf("u%d_i%d", userid, appid-IsolatedStart)
|
||||||
|
} else if appid >= AppStart && appid <= AppEnd {
|
||||||
|
return fmt.Sprintf("u%d_a%d", userid, appid-AppStart)
|
||||||
|
} else {
|
||||||
|
return strconv.Itoa(int(uid))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A GID represents a kernel gid in the init namespace.
|
||||||
|
type GID uint32
|
||||||
|
|
||||||
|
// String returns the group name corresponding to this gid.
|
||||||
|
//
|
||||||
|
// Not safe against untrusted input.
|
||||||
|
func (gid GID) String() string { return UID(gid).String() }
|
||||||
|
|
||||||
|
// ToUser returns a [hst.UID] value from userid and appid.
|
||||||
|
//
|
||||||
|
// Not safe against untrusted input.
|
||||||
|
func ToUser[U int | uint32](userid, appid U) U { return userid*UserOffset + AppStart + appid }
|
||||||
40
hst/grp_pwd_test.go
Normal file
40
hst/grp_pwd_test.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package hst_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUIDString(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
val uint32
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{hst.AppStart + hst.IdentityStart, "u0_a0"}, // uidStart
|
||||||
|
{hst.ToUser[uint32](hst.RangeSize-1, hst.IdentityEnd), "u9999_a9999"}, // uidEnd
|
||||||
|
|
||||||
|
{hst.IsolatedStart + hst.IdentityStart, "u0_i0"}, // isolatedStart
|
||||||
|
{(hst.RangeSize-1)*hst.UserOffset + hst.IsolatedEnd, "u9999_i9999"}, // isolatedEnd
|
||||||
|
|
||||||
|
{hst.ToUser[uint32](10, 127), "u10_a127"},
|
||||||
|
{hst.ToUser[uint32](11, 127), "u11_a127"},
|
||||||
|
|
||||||
|
{0, "0"}, // out of bounds
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(strconv.Itoa(int(tc.val)), func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got := hst.UID(tc.val).String(); got != tc.want {
|
||||||
|
t.Fatalf("UID.String: %q, want %q", got, tc.want)
|
||||||
|
}
|
||||||
|
if got := hst.GID(tc.val).String(); got != tc.want {
|
||||||
|
t.Fatalf("GID.String: %q, want %q", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ type AppError struct {
|
|||||||
// A user-facing description of where the error occurred.
|
// A user-facing description of where the error occurred.
|
||||||
Step string `json:"step"`
|
Step string `json:"step"`
|
||||||
// The underlying error value.
|
// The underlying error value.
|
||||||
Err error
|
Err error `json:"err"`
|
||||||
// An arbitrary error message, overriding the return value of Message if not empty.
|
// An arbitrary error message, overriding the return value of Message if not empty.
|
||||||
Msg string `json:"message,omitempty"`
|
Msg string `json:"message,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
87
hst/instance.go
Normal file
87
hst/instance.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package hst
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// An ID is a unique identifier held by a running hakurei container.
|
||||||
|
type ID [16]byte
|
||||||
|
|
||||||
|
// ErrIdentifierLength is returned when encountering a [hex] representation of [ID] with unexpected length.
|
||||||
|
var ErrIdentifierLength = errors.New("identifier string has unexpected length")
|
||||||
|
|
||||||
|
// IdentifierDecodeError is returned by [ID.UnmarshalText] to provide relevant error descriptions.
|
||||||
|
type IdentifierDecodeError struct{ Err error }
|
||||||
|
|
||||||
|
func (e IdentifierDecodeError) Unwrap() error { return e.Err }
|
||||||
|
func (e IdentifierDecodeError) Error() string {
|
||||||
|
var invalidByteError hex.InvalidByteError
|
||||||
|
switch {
|
||||||
|
case errors.As(e.Err, &invalidByteError):
|
||||||
|
return fmt.Sprintf("got invalid byte %#U in identifier", rune(invalidByteError))
|
||||||
|
case errors.Is(e.Err, hex.ErrLength):
|
||||||
|
return "odd length identifier hex string"
|
||||||
|
|
||||||
|
default:
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the [hex] string representation of [ID].
|
||||||
|
func (a *ID) String() string { return hex.EncodeToString(a[:]) }
|
||||||
|
|
||||||
|
// CreationTime returns the point in time [ID] was created.
|
||||||
|
func (a *ID) CreationTime() time.Time {
|
||||||
|
return time.Unix(0, int64(binary.BigEndian.Uint64(a[:8]))).UTC()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewInstanceID creates a new unique [ID].
|
||||||
|
func NewInstanceID(id *ID) error { return newInstanceID(id, uint64(time.Now().UnixNano())) }
|
||||||
|
|
||||||
|
// newInstanceID creates a new unique [ID] with the specified timestamp.
|
||||||
|
func newInstanceID(id *ID, p uint64) error {
|
||||||
|
binary.BigEndian.PutUint64(id[:8], p)
|
||||||
|
_, err := rand.Read(id[8:])
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the [hex] representation of [ID].
|
||||||
|
func (a *ID) MarshalText() (text []byte, err error) {
|
||||||
|
text = make([]byte, hex.EncodedLen(len(a)))
|
||||||
|
hex.Encode(text, a[:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText decodes a [hex] representation of [ID].
|
||||||
|
func (a *ID) UnmarshalText(text []byte) error {
|
||||||
|
dl := hex.DecodedLen(len(text))
|
||||||
|
if dl != len(a) {
|
||||||
|
return IdentifierDecodeError{ErrIdentifierLength}
|
||||||
|
}
|
||||||
|
_, err := hex.Decode(a[:], text)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return IdentifierDecodeError{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A State describes a running hakurei container.
|
||||||
|
type State struct {
|
||||||
|
// Unique instance id, created by [NewInstanceID].
|
||||||
|
ID ID `json:"instance"`
|
||||||
|
// Monitoring process pid. Runs as the priv user.
|
||||||
|
PID int `json:"pid"`
|
||||||
|
// Shim process pid. Runs as the target user.
|
||||||
|
ShimPID int `json:"shim_pid"`
|
||||||
|
|
||||||
|
// Configuration used to start the container.
|
||||||
|
*Config
|
||||||
|
|
||||||
|
// Point in time the shim process was created.
|
||||||
|
Time time.Time `json:"time"`
|
||||||
|
}
|
||||||
113
hst/instance_test.go
Normal file
113
hst/instance_test.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package hst_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"hakurei.app/hst"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname newInstanceID hakurei.app/hst.newInstanceID
|
||||||
|
func newInstanceID(id *hst.ID, p uint64) error
|
||||||
|
|
||||||
|
func TestIdentifierDecodeError(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{"invalid byte", hst.IdentifierDecodeError{Err: hex.InvalidByteError(0)},
|
||||||
|
"got invalid byte U+0000 in identifier"},
|
||||||
|
{"odd length", hst.IdentifierDecodeError{Err: hex.ErrLength},
|
||||||
|
"odd length identifier hex string"},
|
||||||
|
{"passthrough", hst.IdentifierDecodeError{Err: hst.ErrIdentifierLength},
|
||||||
|
hst.ErrIdentifierLength.Error()},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if got := tc.err.Error(); got != tc.want {
|
||||||
|
t.Errorf("Error: %q, want %q", got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("unwrap", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
err := hst.IdentifierDecodeError{Err: hst.ErrIdentifierLength}
|
||||||
|
if !errors.Is(err, hst.ErrIdentifierLength) {
|
||||||
|
t.Errorf("Is unexpected false")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestID(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var randomID hst.ID
|
||||||
|
if err := hst.NewInstanceID(&randomID); err != nil {
|
||||||
|
t.Fatalf("NewInstanceID: error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
data string
|
||||||
|
want hst.ID
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"bad length", "meow", hst.ID{},
|
||||||
|
hst.IdentifierDecodeError{Err: hst.ErrIdentifierLength}},
|
||||||
|
{"invalid byte", "02bc7f8936b2af6\x00\x00e2535cd71ef0bb7", hst.ID{},
|
||||||
|
hst.IdentifierDecodeError{Err: hex.InvalidByteError(0)}},
|
||||||
|
|
||||||
|
{"zero", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", hst.ID{}, nil},
|
||||||
|
{"random", randomID.String(), randomID, nil},
|
||||||
|
{"sample", "ba21c9bd33d9d37917288281a2a0d239", hst.ID{
|
||||||
|
0xba, 0x21, 0xc9, 0xbd,
|
||||||
|
0x33, 0xd9, 0xd3, 0x79,
|
||||||
|
0x17, 0x28, 0x82, 0x81,
|
||||||
|
0xa2, 0xa0, 0xd2, 0x39}, nil},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
var got hst.ID
|
||||||
|
if err := got.UnmarshalText([]byte(tc.data)); !reflect.DeepEqual(err, tc.err) {
|
||||||
|
t.Errorf("UnmarshalText: error = %#v, want %#v", err, tc.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tc.err == nil {
|
||||||
|
if gotString := got.String(); gotString != tc.data {
|
||||||
|
t.Errorf("String: %q, want %q", gotString, tc.data)
|
||||||
|
}
|
||||||
|
if gotData, _ := got.MarshalText(); string(gotData) != tc.data {
|
||||||
|
t.Errorf("MarshalText: %q, want %q", string(gotData), tc.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("time", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
var id hst.ID
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
if err := newInstanceID(&id, uint64(now.UnixNano())); err != nil {
|
||||||
|
t.Fatalf("newInstanceID: error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := id.CreationTime()
|
||||||
|
if !got.Equal(now) {
|
||||||
|
t.Fatalf("CreationTime(%q): %s, want %s", id.String(), got, now)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// Package app implements high-level hakurei container behaviour.
|
|
||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"hakurei.app/hst"
|
|
||||||
"hakurei.app/internal/app/state"
|
|
||||||
"hakurei.app/message"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Main runs an app according to [hst.Config] and terminates. Main does not return.
|
|
||||||
func Main(ctx context.Context, msg message.Msg, config *hst.Config) {
|
|
||||||
var id state.ID
|
|
||||||
if err := state.NewAppID(&id); err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
seal := outcome{syscallDispatcher: direct{msg}}
|
|
||||||
if err := seal.finalise(ctx, msg, &id, config); err != nil {
|
|
||||||
printMessageError("cannot seal app:", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
seal.main(msg)
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"hakurei.app/container/check"
|
|
||||||
"hakurei.app/hst"
|
|
||||||
)
|
|
||||||
|
|
||||||
// EnvPaths holds paths copied from the environment and is used to create [hst.Paths].
|
|
||||||
type EnvPaths struct {
|
|
||||||
// TempDir is returned by [os.TempDir].
|
|
||||||
TempDir *check.Absolute
|
|
||||||
// RuntimePath is copied from $XDG_RUNTIME_DIR.
|
|
||||||
RuntimePath *check.Absolute
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy expands [EnvPaths] into [hst.Paths].
|
|
||||||
func (env *EnvPaths) Copy(v *hst.Paths, userid int) {
|
|
||||||
if env == nil || env.TempDir == nil || v == nil {
|
|
||||||
panic("attempting to use an invalid EnvPaths")
|
|
||||||
}
|
|
||||||
|
|
||||||
v.TempDir = env.TempDir
|
|
||||||
v.SharePath = env.TempDir.Append("hakurei." + strconv.Itoa(userid))
|
|
||||||
|
|
||||||
if env.RuntimePath == nil {
|
|
||||||
// fall back to path in share since hakurei has no hard XDG dependency
|
|
||||||
v.RunDirPath = v.SharePath.Append("run")
|
|
||||||
v.RuntimePath = v.RunDirPath.Append("compat")
|
|
||||||
} else {
|
|
||||||
v.RuntimePath = env.RuntimePath
|
|
||||||
v.RunDirPath = env.RuntimePath.Append("hakurei")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyPaths returns a populated [EnvPaths].
|
|
||||||
func CopyPaths() *EnvPaths { return copyPaths(direct{}) }
|
|
||||||
|
|
||||||
// copyPaths returns a populated [EnvPaths].
|
|
||||||
func copyPaths(k syscallDispatcher) *EnvPaths {
|
|
||||||
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
|
|
||||||
|
|
||||||
var env EnvPaths
|
|
||||||
|
|
||||||
if tempDir, err := check.NewAbs(k.tempdir()); err != nil {
|
|
||||||
k.fatalf("invalid TMPDIR: %v", err)
|
|
||||||
panic("unreachable")
|
|
||||||
} else {
|
|
||||||
env.TempDir = tempDir
|
|
||||||
}
|
|
||||||
|
|
||||||
r, _ := k.lookupEnv(xdgRuntimeDir)
|
|
||||||
if a, err := check.NewAbs(r); err == nil {
|
|
||||||
env.RuntimePath = a
|
|
||||||
}
|
|
||||||
|
|
||||||
return &env
|
|
||||||
}
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/container"
|
|
||||||
"hakurei.app/container/check"
|
|
||||||
"hakurei.app/container/fhs"
|
|
||||||
"hakurei.app/container/stub"
|
|
||||||
"hakurei.app/hst"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEnvPaths(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
env *EnvPaths
|
|
||||||
want hst.Paths
|
|
||||||
|
|
||||||
wantPanic string
|
|
||||||
}{
|
|
||||||
{"nil", nil, hst.Paths{}, "attempting to use an invalid EnvPaths"},
|
|
||||||
{"zero", new(EnvPaths), hst.Paths{}, "attempting to use an invalid EnvPaths"},
|
|
||||||
|
|
||||||
{"nil tempdir", &EnvPaths{
|
|
||||||
RuntimePath: fhs.AbsTmp,
|
|
||||||
}, hst.Paths{}, "attempting to use an invalid EnvPaths"},
|
|
||||||
|
|
||||||
{"nil runtime", &EnvPaths{
|
|
||||||
TempDir: fhs.AbsTmp,
|
|
||||||
}, hst.Paths{
|
|
||||||
TempDir: fhs.AbsTmp,
|
|
||||||
SharePath: fhs.AbsTmp.Append("hakurei.3735928559"),
|
|
||||||
RuntimePath: fhs.AbsTmp.Append("hakurei.3735928559/run/compat"),
|
|
||||||
RunDirPath: fhs.AbsTmp.Append("hakurei.3735928559/run"),
|
|
||||||
}, ""},
|
|
||||||
|
|
||||||
{"full", &EnvPaths{
|
|
||||||
TempDir: fhs.AbsTmp,
|
|
||||||
RuntimePath: fhs.AbsRunUser.Append("1000"),
|
|
||||||
}, hst.Paths{
|
|
||||||
TempDir: fhs.AbsTmp,
|
|
||||||
SharePath: fhs.AbsTmp.Append("hakurei.3735928559"),
|
|
||||||
RuntimePath: fhs.AbsRunUser.Append("1000"),
|
|
||||||
RunDirPath: fhs.AbsRunUser.Append("1000/hakurei"),
|
|
||||||
}, ""},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
if tc.wantPanic != "" {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != tc.wantPanic {
|
|
||||||
t.Errorf("Copy: panic = %#v, want %q", r, tc.wantPanic)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
var sc hst.Paths
|
|
||||||
tc.env.Copy(&sc, 0xdeadbeef)
|
|
||||||
if !reflect.DeepEqual(&sc, &tc.want) {
|
|
||||||
t.Errorf("Copy: %#v, want %#v", sc, tc.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyPaths(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
env map[string]string
|
|
||||||
tmp string
|
|
||||||
fatal string
|
|
||||||
want EnvPaths
|
|
||||||
}{
|
|
||||||
{"invalid tempdir", nil, "\x00",
|
|
||||||
"invalid TMPDIR: path \"\\x00\" is not absolute", EnvPaths{}},
|
|
||||||
{"empty environment", make(map[string]string), container.Nonexistent,
|
|
||||||
"", EnvPaths{TempDir: check.MustAbs(container.Nonexistent)}},
|
|
||||||
{"invalid XDG_RUNTIME_DIR", map[string]string{"XDG_RUNTIME_DIR": "\x00"}, container.Nonexistent,
|
|
||||||
"", EnvPaths{TempDir: check.MustAbs(container.Nonexistent)}},
|
|
||||||
{"full", map[string]string{"XDG_RUNTIME_DIR": "/\x00"}, container.Nonexistent,
|
|
||||||
"", EnvPaths{TempDir: check.MustAbs(container.Nonexistent), RuntimePath: check.MustAbs("/\x00")}},
|
|
||||||
}
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
if tc.fatal != "" {
|
|
||||||
defer stub.HandleExit(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
k := copyPathsDispatcher{t: t, env: tc.env, tmp: tc.tmp, expectsFatal: tc.fatal}
|
|
||||||
got := copyPaths(k)
|
|
||||||
|
|
||||||
if tc.fatal != "" {
|
|
||||||
t.Fatalf("copyPaths: expected fatal %q", tc.fatal)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, &tc.want) {
|
|
||||||
t.Errorf("copyPaths: %#v, want %#v", got, &tc.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// copyPathsDispatcher implements enough of syscallDispatcher for all copyPaths code paths.
|
|
||||||
type copyPathsDispatcher struct {
|
|
||||||
env map[string]string
|
|
||||||
tmp string
|
|
||||||
|
|
||||||
// must be checked at the conclusion of the test
|
|
||||||
expectsFatal string
|
|
||||||
|
|
||||||
t *testing.T
|
|
||||||
panicDispatcher
|
|
||||||
}
|
|
||||||
|
|
||||||
func (k copyPathsDispatcher) tempdir() string { return k.tmp }
|
|
||||||
func (k copyPathsDispatcher) lookupEnv(key string) (value string, ok bool) {
|
|
||||||
value, ok = k.env[key]
|
|
||||||
return
|
|
||||||
}
|
|
||||||
func (k copyPathsDispatcher) fatalf(format string, v ...any) {
|
|
||||||
if k.expectsFatal == "" {
|
|
||||||
k.t.Fatalf("unexpected call to fatalf: format = %q, v = %#v", format, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := fmt.Sprintf(format, v...); got != k.expectsFatal {
|
|
||||||
k.t.Fatalf("fatalf: %q, want %q", got, k.expectsFatal)
|
|
||||||
}
|
|
||||||
panic(stub.PanicExit)
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func deepContainsH(basepath, targpath string) (bool, error) {
|
|
||||||
const upper = ".." + string(filepath.Separator)
|
|
||||||
|
|
||||||
rel, err := filepath.Rel(basepath, targpath)
|
|
||||||
return err == nil &&
|
|
||||||
rel != ".." &&
|
|
||||||
!strings.HasPrefix(rel, upper), err
|
|
||||||
}
|
|
||||||
@@ -1,326 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/gob"
|
|
||||||
"errors"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"hakurei.app/container"
|
|
||||||
"hakurei.app/container/fhs"
|
|
||||||
"hakurei.app/hst"
|
|
||||||
"hakurei.app/internal"
|
|
||||||
"hakurei.app/internal/app/state"
|
|
||||||
"hakurei.app/message"
|
|
||||||
"hakurei.app/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Duration to wait for shim to exit on top of container WaitDelay.
|
|
||||||
const shimWaitTimeout = 5 * time.Second
|
|
||||||
|
|
||||||
// mainState holds persistent state bound to outcome.main.
|
|
||||||
type mainState struct {
|
|
||||||
// done is whether beforeExit has been called already.
|
|
||||||
done bool
|
|
||||||
|
|
||||||
// Time is the exact point in time where the process was created.
|
|
||||||
// Location must be set to UTC.
|
|
||||||
//
|
|
||||||
// Time is nil if no process was ever created.
|
|
||||||
Time *time.Time
|
|
||||||
|
|
||||||
store state.Store
|
|
||||||
cancel context.CancelFunc
|
|
||||||
cmd *exec.Cmd
|
|
||||||
cmdWait chan error
|
|
||||||
|
|
||||||
k *outcome
|
|
||||||
message.Msg
|
|
||||||
uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
// mainNeedsRevert indicates the call to Commit has succeeded.
|
|
||||||
mainNeedsRevert uintptr = 1 << iota
|
|
||||||
// mainNeedsDestroy indicates the instance state entry is present in the store.
|
|
||||||
mainNeedsDestroy
|
|
||||||
)
|
|
||||||
|
|
||||||
// beforeExit must be called immediately before a call to [os.Exit].
|
|
||||||
func (ms mainState) beforeExit(isFault bool) {
|
|
||||||
if ms.done {
|
|
||||||
panic("attempting to call beforeExit twice")
|
|
||||||
}
|
|
||||||
ms.done = true
|
|
||||||
defer ms.BeforeExit()
|
|
||||||
|
|
||||||
if isFault && ms.cancel != nil {
|
|
||||||
ms.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasErr bool
|
|
||||||
// updates hasErr but does not terminate
|
|
||||||
perror := func(err error, message string) {
|
|
||||||
hasErr = true
|
|
||||||
printMessageError("cannot "+message+":", err)
|
|
||||||
}
|
|
||||||
exitCode := 1
|
|
||||||
defer func() {
|
|
||||||
if hasErr {
|
|
||||||
os.Exit(exitCode)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// this also handles wait for a non-fault termination
|
|
||||||
if ms.cmd != nil && ms.cmdWait != nil {
|
|
||||||
waitDone := make(chan struct{})
|
|
||||||
|
|
||||||
// this ties waitDone to ctx with the additional compensated timeout duration
|
|
||||||
go func() { <-ms.k.ctx.Done(); time.Sleep(ms.k.state.Shim.WaitDelay + shimWaitTimeout); close(waitDone) }()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case err := <-ms.cmdWait:
|
|
||||||
wstatus, ok := ms.cmd.ProcessState.Sys().(syscall.WaitStatus)
|
|
||||||
if ok {
|
|
||||||
if v := wstatus.ExitStatus(); v != 0 {
|
|
||||||
hasErr = true
|
|
||||||
exitCode = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ms.IsVerbose() {
|
|
||||||
if !ok {
|
|
||||||
if err != nil {
|
|
||||||
ms.Verbosef("wait: %v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch {
|
|
||||||
case wstatus.Exited():
|
|
||||||
ms.Verbosef("process %d exited with code %d", ms.cmd.Process.Pid, wstatus.ExitStatus())
|
|
||||||
|
|
||||||
case wstatus.CoreDump():
|
|
||||||
ms.Verbosef("process %d dumped core", ms.cmd.Process.Pid)
|
|
||||||
|
|
||||||
case wstatus.Signaled():
|
|
||||||
ms.Verbosef("process %d got %s", ms.cmd.Process.Pid, wstatus.Signal())
|
|
||||||
|
|
||||||
default:
|
|
||||||
ms.Verbosef("process %d exited with status %#x", ms.cmd.Process.Pid, wstatus)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
case <-waitDone:
|
|
||||||
ms.Resume()
|
|
||||||
// this is only reachable when shim did not exit within shimWaitTimeout, after its WaitDelay has elapsed.
|
|
||||||
// This is different from the container failing to terminate within its timeout period, as that is enforced
|
|
||||||
// by the shim. This path is instead reached when there is a lockup in shim preventing it from completing.
|
|
||||||
log.Printf("process %d did not terminate", ms.cmd.Process.Pid)
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.Resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
if ms.uintptr&mainNeedsRevert != 0 {
|
|
||||||
if ok, err := ms.store.Do(ms.k.state.identity.unwrap(), func(c state.Cursor) {
|
|
||||||
if ms.uintptr&mainNeedsDestroy != 0 {
|
|
||||||
if err := c.Destroy(ms.k.state.id.unwrap()); err != nil {
|
|
||||||
perror(err, "destroy state entry")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var rt hst.Enablement
|
|
||||||
if states, err := c.Load(); err != nil {
|
|
||||||
// it is impossible to continue from this point;
|
|
||||||
// revert per-process state here to limit damage
|
|
||||||
ec := system.Process
|
|
||||||
if revertErr := ms.k.sys.Revert((*system.Criteria)(&ec)); revertErr != nil {
|
|
||||||
var joinError interface {
|
|
||||||
Unwrap() []error
|
|
||||||
error
|
|
||||||
}
|
|
||||||
if !errors.As(revertErr, &joinError) || joinError == nil {
|
|
||||||
perror(revertErr, "revert system setup")
|
|
||||||
} else {
|
|
||||||
for _, v := range joinError.Unwrap() {
|
|
||||||
perror(v, "revert system setup step")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
perror(err, "load instance states")
|
|
||||||
} else {
|
|
||||||
ec := system.Process
|
|
||||||
if l := len(states); l == 0 {
|
|
||||||
ec |= system.User
|
|
||||||
} else {
|
|
||||||
ms.Verbosef("found %d instances, cleaning up without user-scoped operations", l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// accumulate enablements of remaining launchers
|
|
||||||
for i, s := range states {
|
|
||||||
if s.Config != nil {
|
|
||||||
rt |= s.Config.Enablements.Unwrap()
|
|
||||||
} else {
|
|
||||||
log.Printf("state entry %d does not contain config", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ec |= rt ^ (hst.EWayland | hst.EX11 | hst.EDBus | hst.EPulse)
|
|
||||||
if ms.IsVerbose() {
|
|
||||||
if ec > 0 {
|
|
||||||
ms.Verbose("reverting operations scope", system.TypeString(ec))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = ms.k.sys.Revert((*system.Criteria)(&ec)); err != nil {
|
|
||||||
perror(err, "revert system setup")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}); err != nil {
|
|
||||||
if ok {
|
|
||||||
perror(err, "unlock state store")
|
|
||||||
} else {
|
|
||||||
perror(err, "open state store")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ms.uintptr&mainNeedsDestroy != 0 {
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
|
|
||||||
if ms.store != nil {
|
|
||||||
if err := ms.store.Close(); err != nil {
|
|
||||||
perror(err, "close state store")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fatal calls printMessageError, performs necessary cleanup, followed by a call to [os.Exit](1).
|
|
||||||
func (ms mainState) fatal(fallback string, ferr error) {
|
|
||||||
printMessageError(fallback, ferr)
|
|
||||||
ms.beforeExit(true)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// main carries out outcome and terminates. main does not return.
|
|
||||||
func (k *outcome) main(msg message.Msg) {
|
|
||||||
if !k.active.CompareAndSwap(false, true) {
|
|
||||||
panic("outcome: attempted to run twice")
|
|
||||||
}
|
|
||||||
|
|
||||||
if k.ctx == nil || k.sys == nil || k.state == nil {
|
|
||||||
panic("outcome: did not finalise")
|
|
||||||
}
|
|
||||||
|
|
||||||
// read comp value early for early failure
|
|
||||||
hsuPath := internal.MustHsuPath()
|
|
||||||
|
|
||||||
// ms.beforeExit required beyond this point
|
|
||||||
ms := &mainState{Msg: msg, k: k}
|
|
||||||
|
|
||||||
if err := k.sys.Commit(); err != nil {
|
|
||||||
ms.fatal("cannot commit system setup:", err)
|
|
||||||
}
|
|
||||||
ms.uintptr |= mainNeedsRevert
|
|
||||||
ms.store = state.NewMulti(msg, k.state.sc.RunDirPath.String())
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(k.ctx)
|
|
||||||
defer cancel()
|
|
||||||
ms.cancel = cancel
|
|
||||||
|
|
||||||
ms.cmd = exec.CommandContext(ctx, hsuPath.String())
|
|
||||||
ms.cmd.Stdin, ms.cmd.Stdout, ms.cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
|
|
||||||
ms.cmd.Dir = fhs.Root // container init enters final working directory
|
|
||||||
// shim runs in the same session as monitor; see shim.go for behaviour
|
|
||||||
ms.cmd.Cancel = func() error { return ms.cmd.Process.Signal(syscall.SIGCONT) }
|
|
||||||
|
|
||||||
var e *gob.Encoder
|
|
||||||
if fd, encoder, err := container.Setup(&ms.cmd.ExtraFiles); err != nil {
|
|
||||||
ms.fatal("cannot create shim setup pipe:", err)
|
|
||||||
} else {
|
|
||||||
e = encoder
|
|
||||||
ms.cmd.Env = []string{
|
|
||||||
// passed through to shim by hsu
|
|
||||||
shimEnv + "=" + strconv.Itoa(fd),
|
|
||||||
// interpreted by hsu
|
|
||||||
"HAKUREI_IDENTITY=" + k.state.identity.String(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(k.supp) > 0 {
|
|
||||||
msg.Verbosef("attaching supplementary group ids %s", k.supp)
|
|
||||||
// interpreted by hsu
|
|
||||||
ms.cmd.Env = append(ms.cmd.Env, "HAKUREI_GROUPS="+strings.Join(k.supp, " "))
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Verbosef("setuid helper at %s", hsuPath)
|
|
||||||
msg.Suspend()
|
|
||||||
if err := ms.cmd.Start(); err != nil {
|
|
||||||
ms.fatal("cannot start setuid wrapper:", err)
|
|
||||||
}
|
|
||||||
startTime := time.Now().UTC()
|
|
||||||
ms.cmdWait = make(chan error, 1)
|
|
||||||
// this ties context back to the life of the process
|
|
||||||
go func() { ms.cmdWait <- ms.cmd.Wait(); cancel() }()
|
|
||||||
ms.Time = &startTime
|
|
||||||
|
|
||||||
// unfortunately the I/O here cannot be directly canceled;
|
|
||||||
// the cancellation path leads to fatal in this case so that is fine
|
|
||||||
select {
|
|
||||||
case err := <-func() (setupErr chan error) {
|
|
||||||
setupErr = make(chan error, 1)
|
|
||||||
go func() { setupErr <- e.Encode(k.state) }()
|
|
||||||
return
|
|
||||||
}():
|
|
||||||
if err != nil {
|
|
||||||
msg.Resume()
|
|
||||||
ms.fatal("cannot transmit shim config:", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case <-ctx.Done():
|
|
||||||
msg.Resume()
|
|
||||||
ms.fatal("shim context canceled:", newWithMessageError("shim setup canceled", ctx.Err()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// shim accepted setup payload, create process state
|
|
||||||
if ok, err := ms.store.Do(k.state.identity.unwrap(), func(c state.Cursor) {
|
|
||||||
if err := c.Save(&state.State{
|
|
||||||
ID: k.state.id.unwrap(),
|
|
||||||
PID: ms.cmd.Process.Pid,
|
|
||||||
Config: k.config,
|
|
||||||
Time: *ms.Time,
|
|
||||||
}); err != nil {
|
|
||||||
ms.fatal("cannot save state entry:", err)
|
|
||||||
}
|
|
||||||
}); err != nil {
|
|
||||||
if ok {
|
|
||||||
ms.uintptr |= mainNeedsDestroy
|
|
||||||
ms.fatal("cannot unlock state store:", err)
|
|
||||||
} else {
|
|
||||||
ms.fatal("cannot open state store:", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// state in store at this point, destroy defunct state entry on termination
|
|
||||||
ms.uintptr |= mainNeedsDestroy
|
|
||||||
|
|
||||||
// beforeExit ties shim process to context
|
|
||||||
ms.beforeExit(false)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// printMessageError prints the error message according to [message.GetMessage],
|
|
||||||
// or fallback prepended to err if an error message is not available.
|
|
||||||
func printMessageError(fallback string, err error) {
|
|
||||||
m, ok := message.GetMessage(err)
|
|
||||||
if !ok {
|
|
||||||
log.Println(fallback, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Print(m)
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
#include <signal.h>
|
|
||||||
|
|
||||||
void hakurei_shim_setup_cont_signal(pid_t ppid, int fd);
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"syscall"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/container"
|
|
||||||
"hakurei.app/container/comp"
|
|
||||||
"hakurei.app/container/fhs"
|
|
||||||
"hakurei.app/container/seccomp"
|
|
||||||
"hakurei.app/container/stub"
|
|
||||||
"hakurei.app/hst"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestShimEntrypoint(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
shimPreset := seccomp.Preset(comp.PresetStrict, seccomp.AllowMultiarch)
|
|
||||||
templateParams := &container.Params{
|
|
||||||
Dir: m("/data/data/org.chromium.Chromium"),
|
|
||||||
Env: []string{
|
|
||||||
"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus",
|
|
||||||
"DBUS_SYSTEM_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket",
|
|
||||||
"GOOGLE_API_KEY=AIzaSyBHDrl33hwRp4rMQY0ziRbj8K9LPA6vUCY",
|
|
||||||
"GOOGLE_DEFAULT_CLIENT_ID=77185425430.apps.googleusercontent.com",
|
|
||||||
"GOOGLE_DEFAULT_CLIENT_SECRET=OTJgUOQcT7lO7GsGZq2G4IlT",
|
|
||||||
"HOME=/data/data/org.chromium.Chromium",
|
|
||||||
"PULSE_COOKIE=/.hakurei/pulse-cookie",
|
|
||||||
"PULSE_SERVER=unix:/run/user/1000/pulse/native",
|
|
||||||
"SHELL=/run/current-system/sw/bin/zsh",
|
|
||||||
"TERM=xterm-256color",
|
|
||||||
"USER=chronos",
|
|
||||||
"WAYLAND_DISPLAY=wayland-0",
|
|
||||||
"XDG_RUNTIME_DIR=/run/user/1000",
|
|
||||||
"XDG_SESSION_CLASS=user",
|
|
||||||
"XDG_SESSION_TYPE=wayland",
|
|
||||||
},
|
|
||||||
|
|
||||||
// spParamsOp
|
|
||||||
Hostname: "localhost",
|
|
||||||
RetainSession: true,
|
|
||||||
HostNet: true,
|
|
||||||
HostAbstract: true,
|
|
||||||
ForwardCancel: true,
|
|
||||||
Path: m("/run/current-system/sw/bin/chromium"),
|
|
||||||
Args: []string{
|
|
||||||
"chromium",
|
|
||||||
"--ignore-gpu-blocklist",
|
|
||||||
"--disable-smooth-scrolling",
|
|
||||||
"--enable-features=UseOzonePlatform",
|
|
||||||
"--ozone-platform=wayland",
|
|
||||||
},
|
|
||||||
SeccompFlags: seccomp.AllowMultiarch,
|
|
||||||
Uid: 1000,
|
|
||||||
Gid: 100,
|
|
||||||
|
|
||||||
Ops: new(container.Ops).
|
|
||||||
// resolveRoot
|
|
||||||
Root(m("/var/lib/hakurei/base/org.debian"), comp.BindWritable).
|
|
||||||
// spParamsOp
|
|
||||||
Proc(fhs.AbsProc).
|
|
||||||
Tmpfs(hst.AbsPrivateTmp, 1<<12, 0755).
|
|
||||||
Bind(fhs.AbsDev, fhs.AbsDev, comp.BindWritable|comp.BindDevice).
|
|
||||||
Tmpfs(fhs.AbsDev.Append("shm"), 0, 01777).
|
|
||||||
|
|
||||||
// spRuntimeOp
|
|
||||||
Tmpfs(fhs.AbsRunUser, 1<<12, 0755).
|
|
||||||
Bind(m("/tmp/hakurei.10/runtime/9999"), m("/run/user/1000"), comp.BindWritable).
|
|
||||||
|
|
||||||
// spTmpdirOp
|
|
||||||
Bind(m("/tmp/hakurei.10/tmpdir/9999"), fhs.AbsTmp, comp.BindWritable).
|
|
||||||
|
|
||||||
// spAccountOp
|
|
||||||
Place(m("/etc/passwd"), []byte("chronos:x:1000:100:Hakurei:/data/data/org.chromium.Chromium:/run/current-system/sw/bin/zsh\n")).
|
|
||||||
Place(m("/etc/group"), []byte("hakurei:x:100:\n")).
|
|
||||||
|
|
||||||
// spWaylandOp
|
|
||||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/wayland"), m("/run/user/1000/wayland-0"), 0).
|
|
||||||
|
|
||||||
// spPulseOp
|
|
||||||
Bind(m("/run/user/1000/hakurei/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/pulse"), m("/run/user/1000/pulse/native"), 0).
|
|
||||||
Place(m("/.hakurei/pulse-cookie"), bytes.Repeat([]byte{0}, pulseCookieSizeMax)).
|
|
||||||
|
|
||||||
// spDBusOp
|
|
||||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bus"), m("/run/user/1000/bus"), 0).
|
|
||||||
Bind(m("/tmp/hakurei.10/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/system_bus_socket"), m("/var/run/dbus/system_bus_socket"), 0).
|
|
||||||
|
|
||||||
// spFilesystemOp
|
|
||||||
Etc(fhs.AbsEtc, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").
|
|
||||||
Tmpfs(fhs.AbsTmp, 0, 0755).
|
|
||||||
Overlay(m("/nix/store"),
|
|
||||||
fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/upper"),
|
|
||||||
fhs.AbsVarLib.Append("hakurei/nix/u0/org.chromium.Chromium/rw-store/work"),
|
|
||||||
fhs.AbsVarLib.Append("hakurei/base/org.nixos/ro-store")).
|
|
||||||
Link(m("/run/current-system"), "/run/current-system", true).
|
|
||||||
Link(m("/run/opengl-driver"), "/run/opengl-driver", true).
|
|
||||||
Bind(fhs.AbsVarLib.Append("hakurei/u0/org.chromium.Chromium"),
|
|
||||||
m("/data/data/org.chromium.Chromium"),
|
|
||||||
comp.BindWritable|comp.BindEnsure).
|
|
||||||
Bind(fhs.AbsDev.Append("dri"), fhs.AbsDev.Append("dri"),
|
|
||||||
comp.BindOptional|comp.BindWritable|comp.BindDevice).
|
|
||||||
Remount(fhs.AbsRoot, syscall.MS_RDONLY),
|
|
||||||
}
|
|
||||||
|
|
||||||
checkSimple(t, "shimEntrypoint", []simpleTestCase{
|
|
||||||
{"success", func(k *kstub) error { shimEntrypoint(k); return nil }, stub.Expect{Calls: []stub.Call{
|
|
||||||
call("getMsg", stub.ExpectArgs{}, nil, nil),
|
|
||||||
call("getLogger", stub.ExpectArgs{}, (*log.Logger)(nil), nil),
|
|
||||||
call("setDumpable", stub.ExpectArgs{uintptr(container.SUID_DUMP_DISABLE)}, nil, nil),
|
|
||||||
call("receive", stub.ExpectArgs{"HAKUREI_SHIM", outcomeState{
|
|
||||||
Shim: &shimParams{PrivPID: 0xbad, WaitDelay: 0xf, Verbose: true, Ops: []outcomeOp{
|
|
||||||
&spParamsOp{"xterm-256color", true},
|
|
||||||
&spRuntimeOp{sessionTypeWayland},
|
|
||||||
spTmpdirOp{},
|
|
||||||
spAccountOp{},
|
|
||||||
&spWaylandOp{},
|
|
||||||
&spPulseOp{(*[256]byte)(bytes.Repeat([]byte{0}, pulseCookieSizeMax)), pulseCookieSizeMax},
|
|
||||||
&spDBusOp{true},
|
|
||||||
&spFilesystemOp{},
|
|
||||||
}},
|
|
||||||
|
|
||||||
ID: &checkExpectInstanceId,
|
|
||||||
Identity: hst.IdentityMax,
|
|
||||||
UserID: 10,
|
|
||||||
Container: hst.Template().Container,
|
|
||||||
Mapuid: 1000,
|
|
||||||
Mapgid: 100,
|
|
||||||
EnvPaths: &EnvPaths{TempDir: fhs.AbsTmp, RuntimePath: fhs.AbsRunUser.Append("1000")},
|
|
||||||
}, nil}, nil, nil),
|
|
||||||
call("swapVerbose", stub.ExpectArgs{true}, false, nil),
|
|
||||||
call("verbosef", stub.ExpectArgs{"process share directory at %q, runtime directory at %q", []any{m("/tmp/hakurei.10"), m("/run/user/1000/hakurei")}}, nil, nil),
|
|
||||||
call("setupContSignal", stub.ExpectArgs{0xbad}, 0, nil),
|
|
||||||
call("prctl", stub.ExpectArgs{uintptr(syscall.PR_SET_PDEATHSIG), uintptr(syscall.SIGCONT), uintptr(0)}, nil, nil),
|
|
||||||
call("New", stub.ExpectArgs{}, nil, nil),
|
|
||||||
call("closeReceive", stub.ExpectArgs{}, nil, nil),
|
|
||||||
call("notifyContext", stub.ExpectArgs{context.Background(), []os.Signal{os.Interrupt, syscall.SIGTERM}}, nil, nil),
|
|
||||||
call("containerStart", stub.ExpectArgs{templateParams}, nil, nil),
|
|
||||||
call("containerServe", stub.ExpectArgs{templateParams}, nil, nil),
|
|
||||||
call("seccompLoad", stub.ExpectArgs{shimPreset, seccomp.AllowMultiarch}, nil, nil),
|
|
||||||
call("containerWait", stub.ExpectArgs{templateParams}, nil, nil),
|
|
||||||
|
|
||||||
// deferred
|
|
||||||
call("wKeepAlive", stub.ExpectArgs{}, nil, nil),
|
|
||||||
}, Tracks: []stub.Expect{{Calls: []stub.Call{
|
|
||||||
call("rcRead", stub.ExpectArgs{}, []byte{2}, nil),
|
|
||||||
call("verbose", stub.ExpectArgs{[]any{"sa_sigaction got invalid siginfo"}}, nil, nil),
|
|
||||||
call("rcRead", stub.ExpectArgs{}, []byte{3}, nil),
|
|
||||||
call("verbose", stub.ExpectArgs{[]any{"got SIGCONT from unexpected process"}}, nil, nil),
|
|
||||||
call("rcRead", stub.ExpectArgs{}, nil, nil), // stub terminates this goroutine
|
|
||||||
}}}}, nil},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/hex"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ID [16]byte
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrInvalidLength = errors.New("string representation must have a length of 32")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (a *ID) String() string {
|
|
||||||
return hex.EncodeToString(a[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAppID(id *ID) error {
|
|
||||||
_, err := rand.Read(id[:])
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func ParseAppID(id *ID, s string) error {
|
|
||||||
if len(s) != 32 {
|
|
||||||
return ErrInvalidLength
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, b := range s {
|
|
||||||
if b < '0' || b > 'f' {
|
|
||||||
return fmt.Errorf("invalid char %q at byte %d", b, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
v := uint8(b)
|
|
||||||
if v > '9' {
|
|
||||||
v = 10 + v - 'a'
|
|
||||||
} else {
|
|
||||||
v -= '0'
|
|
||||||
}
|
|
||||||
if i%2 == 0 {
|
|
||||||
v <<= 4
|
|
||||||
}
|
|
||||||
id[i/2] += v
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
package state_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/internal/app/state"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestParseAppID(t *testing.T) {
|
|
||||||
t.Run("bad length", func(t *testing.T) {
|
|
||||||
if err := state.ParseAppID(new(state.ID), "meow"); !errors.Is(err, state.ErrInvalidLength) {
|
|
||||||
t.Errorf("ParseAppID: error = %v, wantErr = %v", err, state.ErrInvalidLength)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("bad byte", func(t *testing.T) {
|
|
||||||
wantErr := "invalid char '\\n' at byte 15"
|
|
||||||
if err := state.ParseAppID(new(state.ID), "02bc7f8936b2af6\n\ne2535cd71ef0bb7"); err == nil || err.Error() != wantErr {
|
|
||||||
t.Errorf("ParseAppID: error = %v, wantErr = %v", err, wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("fuzz 16 iterations", func(t *testing.T) {
|
|
||||||
for i := 0; i < 16; i++ {
|
|
||||||
testParseAppIDWithRandom(t)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func FuzzParseAppID(f *testing.F) {
|
|
||||||
for i := 0; i < 16; i++ {
|
|
||||||
id := new(state.ID)
|
|
||||||
if err := state.NewAppID(id); err != nil {
|
|
||||||
panic(err.Error())
|
|
||||||
}
|
|
||||||
f.Add(id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15])
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Fuzz(func(t *testing.T, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15 byte) {
|
|
||||||
testParseAppID(t, &state.ID{b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func testParseAppIDWithRandom(t *testing.T) {
|
|
||||||
id := new(state.ID)
|
|
||||||
if err := state.NewAppID(id); err != nil {
|
|
||||||
t.Fatalf("cannot generate app ID: %v", err)
|
|
||||||
}
|
|
||||||
testParseAppID(t, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testParseAppID(t *testing.T, id *state.ID) {
|
|
||||||
s := id.String()
|
|
||||||
got := new(state.ID)
|
|
||||||
if err := state.ParseAppID(got, s); err != nil {
|
|
||||||
t.Fatalf("cannot parse app ID: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *got != *id {
|
|
||||||
t.Fatalf("ParseAppID(%#v) = \n%#v, want \n%#v", s, got, id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"maps"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrDuplicate = errors.New("store contains duplicates")
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Joiner is the interface that wraps the Join method.
|
|
||||||
|
|
||||||
The Join function uses Joiner if available.
|
|
||||||
*/
|
|
||||||
type Joiner interface{ Join() (Entries, error) }
|
|
||||||
|
|
||||||
// Join returns joined state entries of all active aids.
|
|
||||||
func Join(s Store) (Entries, error) {
|
|
||||||
if j, ok := s.(Joiner); ok {
|
|
||||||
return j.Join()
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
aids []int
|
|
||||||
entries = make(Entries)
|
|
||||||
|
|
||||||
el int
|
|
||||||
res Entries
|
|
||||||
loadErr error
|
|
||||||
)
|
|
||||||
|
|
||||||
if ln, err := s.List(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else {
|
|
||||||
aids = ln
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, aid := range aids {
|
|
||||||
if _, err := s.Do(aid, func(c Cursor) {
|
|
||||||
res, loadErr = c.Load()
|
|
||||||
}); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if loadErr != nil {
|
|
||||||
return nil, loadErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// save expected length
|
|
||||||
el = len(entries) + len(res)
|
|
||||||
maps.Copy(entries, res)
|
|
||||||
if len(entries) != el {
|
|
||||||
return nil, ErrDuplicate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return entries, nil
|
|
||||||
}
|
|
||||||
@@ -1,289 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/gob"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"hakurei.app/hst"
|
|
||||||
"hakurei.app/message"
|
|
||||||
)
|
|
||||||
|
|
||||||
// fine-grained locking and access
|
|
||||||
type multiStore struct {
|
|
||||||
base string
|
|
||||||
|
|
||||||
// initialised backends
|
|
||||||
backends *sync.Map
|
|
||||||
|
|
||||||
msg message.Msg
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *multiStore) Do(identity int, f func(c Cursor)) (bool, error) {
|
|
||||||
s.mu.RLock()
|
|
||||||
defer s.mu.RUnlock()
|
|
||||||
|
|
||||||
// load or initialise new backend
|
|
||||||
b := new(multiBackend)
|
|
||||||
b.mu.Lock()
|
|
||||||
if v, ok := s.backends.LoadOrStore(identity, b); ok {
|
|
||||||
b = v.(*multiBackend)
|
|
||||||
} else {
|
|
||||||
b.path = path.Join(s.base, strconv.Itoa(identity))
|
|
||||||
|
|
||||||
// ensure directory
|
|
||||||
if err := os.MkdirAll(b.path, 0700); err != nil && !errors.Is(err, fs.ErrExist) {
|
|
||||||
s.backends.CompareAndDelete(identity, b)
|
|
||||||
return false, &hst.AppError{Step: "create store segment directory", Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// open locker file
|
|
||||||
if l, err := os.OpenFile(b.path+".lock", os.O_RDWR|os.O_CREATE, 0600); err != nil {
|
|
||||||
s.backends.CompareAndDelete(identity, b)
|
|
||||||
return false, &hst.AppError{Step: "open store segment lock file", Err: err}
|
|
||||||
} else {
|
|
||||||
b.lockfile = l
|
|
||||||
}
|
|
||||||
b.mu.Unlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock backend
|
|
||||||
if err := b.lockFile(); err != nil {
|
|
||||||
return false, &hst.AppError{Step: "lock store segment", Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// expose backend methods without exporting the pointer
|
|
||||||
c := new(struct{ *multiBackend })
|
|
||||||
c.multiBackend = b
|
|
||||||
f(b)
|
|
||||||
// disable access to the backend on a best-effort basis
|
|
||||||
c.multiBackend = nil
|
|
||||||
|
|
||||||
// unlock backend
|
|
||||||
if err := b.unlockFile(); err != nil {
|
|
||||||
return true, &hst.AppError{Step: "unlock store segment", Err: err}
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *multiStore) List() ([]int, error) {
|
|
||||||
var entries []os.DirEntry
|
|
||||||
|
|
||||||
// read base directory to get all identities
|
|
||||||
if v, err := os.ReadDir(s.base); err != nil && !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return nil, &hst.AppError{Step: "read store directory", Err: err}
|
|
||||||
} else {
|
|
||||||
entries = v
|
|
||||||
}
|
|
||||||
|
|
||||||
aidsBuf := make([]int, 0, len(entries))
|
|
||||||
for _, e := range entries {
|
|
||||||
// skip non-directories
|
|
||||||
if !e.IsDir() {
|
|
||||||
s.msg.Verbosef("skipped non-directory entry %q", e.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip non-numerical names
|
|
||||||
if v, err := strconv.Atoi(e.Name()); err != nil {
|
|
||||||
s.msg.Verbosef("skipped non-aid entry %q", e.Name())
|
|
||||||
continue
|
|
||||||
} else {
|
|
||||||
if v < hst.IdentityMin || v > hst.IdentityMax {
|
|
||||||
s.msg.Verbosef("skipped out of bounds entry %q", e.Name())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
aidsBuf = append(aidsBuf, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return append([]int(nil), aidsBuf...), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *multiStore) Close() error {
|
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
s.backends.Range(func(_, value any) bool {
|
|
||||||
b := value.(*multiBackend)
|
|
||||||
errs = append(errs, b.close())
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
return errors.Join(errs...)
|
|
||||||
}
|
|
||||||
|
|
||||||
type multiBackend struct {
|
|
||||||
path string
|
|
||||||
|
|
||||||
// created/opened by prepare
|
|
||||||
lockfile *os.File
|
|
||||||
|
|
||||||
mu sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *multiBackend) filename(id *ID) string { return path.Join(b.path, id.String()) }
|
|
||||||
|
|
||||||
func (b *multiBackend) lockFileAct(lt int) (err error) {
|
|
||||||
op := "LockAct"
|
|
||||||
switch lt {
|
|
||||||
case syscall.LOCK_EX:
|
|
||||||
op = "Lock"
|
|
||||||
case syscall.LOCK_UN:
|
|
||||||
op = "Unlock"
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
err = syscall.Flock(int(b.lockfile.Fd()), lt)
|
|
||||||
if !errors.Is(err, syscall.EINTR) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return &fs.PathError{
|
|
||||||
Op: op,
|
|
||||||
Path: b.lockfile.Name(),
|
|
||||||
Err: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *multiBackend) lockFile() error { return b.lockFileAct(syscall.LOCK_EX) }
|
|
||||||
func (b *multiBackend) unlockFile() error { return b.lockFileAct(syscall.LOCK_UN) }
|
|
||||||
|
|
||||||
// reads all launchers in simpleBackend
|
|
||||||
// file contents are ignored if decode is false
|
|
||||||
func (b *multiBackend) load(decode bool) (Entries, error) {
|
|
||||||
b.mu.RLock()
|
|
||||||
defer b.mu.RUnlock()
|
|
||||||
|
|
||||||
// read directory contents, should only contain files named after ids
|
|
||||||
var entries []os.DirEntry
|
|
||||||
if pl, err := os.ReadDir(b.path); err != nil {
|
|
||||||
return nil, &hst.AppError{Step: "read store segment directory", Err: err}
|
|
||||||
} else {
|
|
||||||
entries = pl
|
|
||||||
}
|
|
||||||
|
|
||||||
// allocate as if every entry is valid
|
|
||||||
// since that should be the case assuming no external interference happens
|
|
||||||
r := make(Entries, len(entries))
|
|
||||||
|
|
||||||
for _, e := range entries {
|
|
||||||
if e.IsDir() {
|
|
||||||
return nil, fmt.Errorf("unexpected directory %q in store", e.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
var id ID
|
|
||||||
if err := ParseAppID(&id, e.Name()); err != nil {
|
|
||||||
return nil, &hst.AppError{Step: "parse state key", Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// run in a function to better handle file closing
|
|
||||||
if err := func() error {
|
|
||||||
// open state file for reading
|
|
||||||
if f, err := os.Open(path.Join(b.path, e.Name())); err != nil {
|
|
||||||
return &hst.AppError{Step: "open state file", Err: err}
|
|
||||||
} else {
|
|
||||||
var s State
|
|
||||||
r[id] = &s
|
|
||||||
|
|
||||||
// append regardless, but only parse if required, implements Len
|
|
||||||
if decode {
|
|
||||||
if err = gob.NewDecoder(f).Decode(&s); err != nil {
|
|
||||||
_ = f.Close()
|
|
||||||
return &hst.AppError{Step: "decode state data", Err: err}
|
|
||||||
} else if s.ID != id {
|
|
||||||
_ = f.Close()
|
|
||||||
return fmt.Errorf("state entry %s has unexpected id %s", id, &s.ID)
|
|
||||||
} else if err = f.Close(); err != nil {
|
|
||||||
return &hst.AppError{Step: "close state file", Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
if s.Config == nil {
|
|
||||||
return ErrNoConfig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save writes process state to filesystem
|
|
||||||
func (b *multiBackend) Save(state *State) error {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if state.Config == nil {
|
|
||||||
return ErrNoConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
statePath := b.filename(&state.ID)
|
|
||||||
|
|
||||||
if f, err := os.OpenFile(statePath, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600); err != nil {
|
|
||||||
return &hst.AppError{Step: "create state file", Err: err}
|
|
||||||
} else if err = gob.NewEncoder(f).Encode(state); err != nil {
|
|
||||||
_ = f.Close()
|
|
||||||
return &hst.AppError{Step: "encode state data", Err: err}
|
|
||||||
} else if err = f.Close(); err != nil {
|
|
||||||
return &hst.AppError{Step: "close state file", Err: err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *multiBackend) Destroy(id ID) error {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
if err := os.Remove(b.filename(&id)); err != nil {
|
|
||||||
return &hst.AppError{Step: "destroy state entry", Err: err}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *multiBackend) Load() (Entries, error) { return b.load(true) }
|
|
||||||
|
|
||||||
func (b *multiBackend) Len() (int, error) {
|
|
||||||
// rn consists of only nil entries but has the correct length
|
|
||||||
rn, err := b.load(false)
|
|
||||||
if err != nil {
|
|
||||||
return -1, &hst.AppError{Step: "count state entries", Err: err}
|
|
||||||
}
|
|
||||||
return len(rn), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *multiBackend) close() error {
|
|
||||||
b.mu.Lock()
|
|
||||||
defer b.mu.Unlock()
|
|
||||||
|
|
||||||
err := b.lockfile.Close()
|
|
||||||
if err == nil || errors.Is(err, os.ErrInvalid) || errors.Is(err, os.ErrClosed) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &hst.AppError{Step: "close lock file", Err: err}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMulti returns an instance of the multi-file store.
|
|
||||||
func NewMulti(msg message.Msg, runDir string) Store {
|
|
||||||
return &multiStore{
|
|
||||||
msg: msg,
|
|
||||||
base: path.Join(runDir, "state"),
|
|
||||||
backends: new(sync.Map),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package state_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"hakurei.app/internal/app/state"
|
|
||||||
"hakurei.app/message"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMulti(t *testing.T) {
|
|
||||||
testStore(t, state.NewMulti(message.NewMsg(log.New(log.Writer(), "multi: ", 0)), t.TempDir()))
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
// Package state provides cross-process state tracking for hakurei container instances.
|
|
||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"hakurei.app/hst"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ErrNoConfig is returned by [Cursor] when used with a nil [hst.Config].
|
|
||||||
var ErrNoConfig = errors.New("state does not contain config")
|
|
||||||
|
|
||||||
type Entries map[ID]*State
|
|
||||||
|
|
||||||
type Store interface {
|
|
||||||
// Do calls f exactly once and ensures store exclusivity until f returns.
|
|
||||||
// Returns whether f is called and any errors during the locking process.
|
|
||||||
// Cursor provided to f becomes invalid as soon as f returns.
|
|
||||||
Do(identity int, f func(c Cursor)) (ok bool, err error)
|
|
||||||
|
|
||||||
// List queries the store and returns a list of identities known to the store.
|
|
||||||
// Note that some or all returned identities might not have any active apps.
|
|
||||||
List() (identities []int, err error)
|
|
||||||
|
|
||||||
// Close releases any resources held by Store.
|
|
||||||
Close() error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cursor provides access to the store of an identity.
|
|
||||||
type Cursor interface {
|
|
||||||
Save(state *State) error
|
|
||||||
Destroy(id ID) error
|
|
||||||
Load() (Entries, error)
|
|
||||||
Len() (int, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// State is the on-disk state of a container instance.
|
|
||||||
type State struct {
|
|
||||||
// Unique instance id, generated by internal/app.
|
|
||||||
ID ID `json:"instance"`
|
|
||||||
// Shim process pid. This runs as the target user.
|
|
||||||
PID int `json:"pid"`
|
|
||||||
// Configuration value used to start the container.
|
|
||||||
Config *hst.Config `json:"config"`
|
|
||||||
|
|
||||||
// Exact point in time that the shim process was created.
|
|
||||||
Time time.Time `json:"time"`
|
|
||||||
}
|
|
||||||
@@ -1,132 +0,0 @@
|
|||||||
package state_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math/rand/v2"
|
|
||||||
"reflect"
|
|
||||||
"slices"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"hakurei.app/hst"
|
|
||||||
"hakurei.app/internal/app/state"
|
|
||||||
)
|
|
||||||
|
|
||||||
func testStore(t *testing.T, s state.Store) {
|
|
||||||
t.Run("list empty store", func(t *testing.T) {
|
|
||||||
if identities, err := s.List(); err != nil {
|
|
||||||
t.Fatalf("List: error = %v", err)
|
|
||||||
} else if len(identities) != 0 {
|
|
||||||
t.Fatalf("List: identities = %#v", identities)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const (
|
|
||||||
insertEntryChecked = iota
|
|
||||||
insertEntryNoCheck
|
|
||||||
insertEntryOtherApp
|
|
||||||
|
|
||||||
tl
|
|
||||||
)
|
|
||||||
|
|
||||||
var tc [tl]state.State
|
|
||||||
for i := 0; i < tl; i++ {
|
|
||||||
makeState(t, &tc[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
do := func(identity int, f func(c state.Cursor)) {
|
|
||||||
if ok, err := s.Do(identity, f); err != nil {
|
|
||||||
t.Fatalf("Do: ok = %v, error = %v", ok, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
insert := func(i, identity int) {
|
|
||||||
do(identity, func(c state.Cursor) {
|
|
||||||
if err := c.Save(&tc[i]); err != nil {
|
|
||||||
t.Fatalf("Save: error = %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
check := func(i, identity int) {
|
|
||||||
do(identity, func(c state.Cursor) {
|
|
||||||
if entries, err := c.Load(); err != nil {
|
|
||||||
t.Fatalf("Load: error = %v", err)
|
|
||||||
} else if got, ok := entries[tc[i].ID]; !ok {
|
|
||||||
t.Fatalf("Load: entry %s missing", &tc[i].ID)
|
|
||||||
} else {
|
|
||||||
got.Time = tc[i].Time
|
|
||||||
if !reflect.DeepEqual(got, &tc[i]) {
|
|
||||||
t.Fatalf("Load: entry %s got %#v, want %#v", &tc[i].ID, got, &tc[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("insert entry checked", func(t *testing.T) {
|
|
||||||
insert(insertEntryChecked, 0)
|
|
||||||
check(insertEntryChecked, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("insert entry unchecked", func(t *testing.T) {
|
|
||||||
insert(insertEntryNoCheck, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("insert entry different identity", func(t *testing.T) {
|
|
||||||
insert(insertEntryOtherApp, 1)
|
|
||||||
check(insertEntryOtherApp, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("check previous insertion", func(t *testing.T) {
|
|
||||||
check(insertEntryNoCheck, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("list identities", func(t *testing.T) {
|
|
||||||
if identities, err := s.List(); err != nil {
|
|
||||||
t.Fatalf("List: error = %v", err)
|
|
||||||
} else {
|
|
||||||
slices.Sort(identities)
|
|
||||||
want := []int{0, 1}
|
|
||||||
if !slices.Equal(identities, want) {
|
|
||||||
t.Fatalf("List() = %#v, want %#v", identities, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("join store", func(t *testing.T) {
|
|
||||||
if entries, err := state.Join(s); err != nil {
|
|
||||||
t.Fatalf("Join: error = %v", err)
|
|
||||||
} else if len(entries) != 3 {
|
|
||||||
t.Fatalf("Join(s) = %#v", entries)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("clear identity 1", func(t *testing.T) {
|
|
||||||
do(1, func(c state.Cursor) {
|
|
||||||
if err := c.Destroy(tc[insertEntryOtherApp].ID); err != nil {
|
|
||||||
t.Fatalf("Destroy: error = %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
do(1, func(c state.Cursor) {
|
|
||||||
if l, err := c.Len(); err != nil {
|
|
||||||
t.Fatalf("Len: error = %v", err)
|
|
||||||
} else if l != 0 {
|
|
||||||
t.Fatalf("Len: %d, want 0", l)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("close store", func(t *testing.T) {
|
|
||||||
if err := s.Close(); err != nil {
|
|
||||||
t.Fatalf("Close: error = %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeState(t *testing.T, s *state.State) {
|
|
||||||
if err := state.NewAppID(&s.ID); err != nil {
|
|
||||||
t.Fatalf("cannot create dummy state: %v", err)
|
|
||||||
}
|
|
||||||
s.PID = rand.Int()
|
|
||||||
s.Config = hst.Template()
|
|
||||||
s.Time = time.Now()
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
//#include <unistd.h>
|
|
||||||
import "C"
|
|
||||||
|
|
||||||
const _SC_LOGIN_NAME_MAX = C._SC_LOGIN_NAME_MAX
|
|
||||||
|
|
||||||
func sysconf(name C.int) int { return int(C.sysconf(name)) }
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestIsValidUsername(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
t.Run("long", func(t *testing.T) {
|
|
||||||
if isValidUsername(strings.Repeat("a", sysconf(_SC_LOGIN_NAME_MAX))) {
|
|
||||||
t.Errorf("isValidUsername unexpected true")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("regexp", func(t *testing.T) {
|
|
||||||
if isValidUsername("0") {
|
|
||||||
t.Errorf("isValidUsername unexpected true")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("valid", func(t *testing.T) {
|
|
||||||
if !isValidUsername("alice") {
|
|
||||||
t.Errorf("isValidUsername unexpected false")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
65
internal/env/env.go
vendored
Normal file
65
internal/env/env.go
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Package env provides the [Paths] struct for efficiently building paths from the environment.
|
||||||
|
package env
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"hakurei.app/container/check"
|
||||||
|
"hakurei.app/hst"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Paths holds paths copied from the environment and is used to create [hst.Paths].
|
||||||
|
type Paths struct {
|
||||||
|
// TempDir is returned by [os.TempDir].
|
||||||
|
TempDir *check.Absolute
|
||||||
|
// RuntimePath is copied from $XDG_RUNTIME_DIR.
|
||||||
|
RuntimePath *check.Absolute
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy expands [Paths] into [hst.Paths].
|
||||||
|
func (env *Paths) Copy(v *hst.Paths, userid int) {
|
||||||
|
if env == nil || env.TempDir == nil || v == nil {
|
||||||
|
panic("attempting to use an invalid Paths")
|
||||||
|
}
|
||||||
|
|
||||||
|
v.TempDir = env.TempDir
|
||||||
|
v.SharePath = env.TempDir.Append("hakurei." + strconv.Itoa(userid))
|
||||||
|
|
||||||
|
if env.RuntimePath == nil {
|
||||||
|
// fall back to path in share since hakurei has no hard XDG dependency
|
||||||
|
v.RuntimePath = v.SharePath.Append("compat")
|
||||||
|
} else {
|
||||||
|
v.RuntimePath = env.RuntimePath
|
||||||
|
}
|
||||||
|
v.RunDirPath = v.RuntimePath.Append("hakurei")
|
||||||
|
}
|
||||||
|
|
||||||
|
// CopyPaths returns a populated [Paths].
|
||||||
|
func CopyPaths() *Paths { return CopyPathsFunc(log.Fatalf, os.TempDir, os.Getenv) }
|
||||||
|
|
||||||
|
// CopyPathsFunc returns a populated [Paths],
|
||||||
|
// using the provided [log.Fatalf], [os.TempDir], [os.Getenv] functions.
|
||||||
|
func CopyPathsFunc(
|
||||||
|
fatalf func(format string, v ...any),
|
||||||
|
tempdir func() string,
|
||||||
|
getenv func(key string) string,
|
||||||
|
) *Paths {
|
||||||
|
const xdgRuntimeDir = "XDG_RUNTIME_DIR"
|
||||||
|
|
||||||
|
var env Paths
|
||||||
|
|
||||||
|
if tempDir, err := check.NewAbs(tempdir()); err != nil {
|
||||||
|
fatalf("invalid TMPDIR: %v", err)
|
||||||
|
panic("unreachable")
|
||||||
|
} else {
|
||||||
|
env.TempDir = tempDir
|
||||||
|
}
|
||||||
|
|
||||||
|
if a, err := check.NewAbs(getenv(xdgRuntimeDir)); err == nil {
|
||||||
|
env.RuntimePath = a
|
||||||
|
}
|
||||||
|
|
||||||
|
return &env
|
||||||
|
}
|
||||||
118
internal/env/env_test.go
vendored
Normal file
118
internal/env/env_test.go
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package env_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/container/check"
|
||||||
|
"hakurei.app/container/fhs"
|
||||||
|
"hakurei.app/container/stub"
|
||||||
|
"hakurei.app/hst"
|
||||||
|
"hakurei.app/internal/env"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPaths(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
env *env.Paths
|
||||||
|
want hst.Paths
|
||||||
|
|
||||||
|
wantPanic string
|
||||||
|
}{
|
||||||
|
{"nil", nil, hst.Paths{}, "attempting to use an invalid Paths"},
|
||||||
|
{"zero", new(env.Paths), hst.Paths{}, "attempting to use an invalid Paths"},
|
||||||
|
|
||||||
|
{"nil tempdir", &env.Paths{
|
||||||
|
RuntimePath: fhs.AbsTmp,
|
||||||
|
}, hst.Paths{}, "attempting to use an invalid Paths"},
|
||||||
|
|
||||||
|
{"nil runtime", &env.Paths{
|
||||||
|
TempDir: fhs.AbsTmp,
|
||||||
|
}, hst.Paths{
|
||||||
|
TempDir: fhs.AbsTmp,
|
||||||
|
SharePath: fhs.AbsTmp.Append("hakurei.57005"),
|
||||||
|
RuntimePath: fhs.AbsTmp.Append("hakurei.57005/compat"),
|
||||||
|
RunDirPath: fhs.AbsTmp.Append("hakurei.57005/compat/hakurei"),
|
||||||
|
}, ""},
|
||||||
|
|
||||||
|
{"full", &env.Paths{
|
||||||
|
TempDir: fhs.AbsTmp,
|
||||||
|
RuntimePath: fhs.AbsRunUser.Append("1000"),
|
||||||
|
}, hst.Paths{
|
||||||
|
TempDir: fhs.AbsTmp,
|
||||||
|
SharePath: fhs.AbsTmp.Append("hakurei.57005"),
|
||||||
|
RuntimePath: fhs.AbsRunUser.Append("1000"),
|
||||||
|
RunDirPath: fhs.AbsRunUser.Append("1000/hakurei"),
|
||||||
|
}, ""},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if tc.wantPanic != "" {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != tc.wantPanic {
|
||||||
|
t.Errorf("Copy: panic = %#v, want %q", r, tc.wantPanic)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
var sc hst.Paths
|
||||||
|
tc.env.Copy(&sc, 0xdead)
|
||||||
|
if !reflect.DeepEqual(&sc, &tc.want) {
|
||||||
|
t.Errorf("Copy: %#v, want %#v", sc, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCopyPaths(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
env map[string]string
|
||||||
|
tmp string
|
||||||
|
fatal string
|
||||||
|
want env.Paths
|
||||||
|
}{
|
||||||
|
{"invalid tempdir", nil, "\x00",
|
||||||
|
"invalid TMPDIR: path \"\\x00\" is not absolute", env.Paths{}},
|
||||||
|
{"empty environment", make(map[string]string), container.Nonexistent,
|
||||||
|
"", env.Paths{TempDir: check.MustAbs(container.Nonexistent)}},
|
||||||
|
{"invalid XDG_RUNTIME_DIR", map[string]string{"XDG_RUNTIME_DIR": "\x00"}, container.Nonexistent,
|
||||||
|
"", env.Paths{TempDir: check.MustAbs(container.Nonexistent)}},
|
||||||
|
{"full", map[string]string{"XDG_RUNTIME_DIR": "/\x00"}, container.Nonexistent,
|
||||||
|
"", env.Paths{TempDir: check.MustAbs(container.Nonexistent), RuntimePath: check.MustAbs("/\x00")}},
|
||||||
|
}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
if tc.fatal != "" {
|
||||||
|
defer stub.HandleExit(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := env.CopyPathsFunc(func(format string, v ...any) {
|
||||||
|
if tc.fatal == "" {
|
||||||
|
t.Fatalf("unexpected call to fatalf: format = %q, v = %#v", format, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := fmt.Sprintf(format, v...); got != tc.fatal {
|
||||||
|
t.Fatalf("fatalf: %q, want %q", got, tc.fatal)
|
||||||
|
}
|
||||||
|
panic(stub.PanicExit)
|
||||||
|
}, func() string { return tc.tmp }, func(key string) string { return tc.env[key] })
|
||||||
|
|
||||||
|
if tc.fatal != "" {
|
||||||
|
t.Fatalf("copyPaths: expected fatal %q", tc.fatal)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(got, &tc.want) {
|
||||||
|
t.Errorf("copyPaths: %#v, want %#v", got, &tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
83
internal/lockedfile/internal/filelock/filelock.go
Normal file
83
internal/lockedfile/internal/filelock/filelock.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package filelock provides a platform-independent API for advisory file
|
||||||
|
// locking. Calls to functions in this package on platforms that do not support
|
||||||
|
// advisory locks will return errors for which IsNotSupported returns true.
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A File provides the minimal set of methods required to lock an open file.
|
||||||
|
// File implementations must be usable as map keys.
|
||||||
|
// The usual implementation is *os.File.
|
||||||
|
type File interface {
|
||||||
|
// Name returns the name of the file.
|
||||||
|
Name() string
|
||||||
|
|
||||||
|
// Fd returns a valid file descriptor.
|
||||||
|
// (If the File is an *os.File, it must not be closed.)
|
||||||
|
Fd() uintptr
|
||||||
|
|
||||||
|
// Stat returns the FileInfo structure describing file.
|
||||||
|
Stat() (fs.FileInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock places an advisory write lock on the file, blocking until it can be
|
||||||
|
// locked.
|
||||||
|
//
|
||||||
|
// If Lock returns nil, no other process will be able to place a read or write
|
||||||
|
// lock on the file until this process exits, closes f, or calls Unlock on it.
|
||||||
|
//
|
||||||
|
// If f's descriptor is already read- or write-locked, the behavior of Lock is
|
||||||
|
// unspecified.
|
||||||
|
//
|
||||||
|
// Closing the file may or may not release the lock promptly. Callers should
|
||||||
|
// ensure that Unlock is always called when Lock succeeds.
|
||||||
|
func Lock(f File) error {
|
||||||
|
return lock(f, writeLock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RLock places an advisory read lock on the file, blocking until it can be locked.
|
||||||
|
//
|
||||||
|
// If RLock returns nil, no other process will be able to place a write lock on
|
||||||
|
// the file until this process exits, closes f, or calls Unlock on it.
|
||||||
|
//
|
||||||
|
// If f is already read- or write-locked, the behavior of RLock is unspecified.
|
||||||
|
//
|
||||||
|
// Closing the file may or may not release the lock promptly. Callers should
|
||||||
|
// ensure that Unlock is always called if RLock succeeds.
|
||||||
|
func RLock(f File) error {
|
||||||
|
return lock(f, readLock)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock removes an advisory lock placed on f by this process.
|
||||||
|
//
|
||||||
|
// The caller must not attempt to unlock a file that is not locked.
|
||||||
|
func Unlock(f File) error {
|
||||||
|
return unlock(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the name of the function corresponding to lt
|
||||||
|
// (Lock, RLock, or Unlock).
|
||||||
|
func (lt lockType) String() string {
|
||||||
|
switch lt {
|
||||||
|
case readLock:
|
||||||
|
return "RLock"
|
||||||
|
case writeLock:
|
||||||
|
return "Lock"
|
||||||
|
default:
|
||||||
|
return "Unlock"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotSupported returns a boolean indicating whether the error is known to
|
||||||
|
// report that a function is not supported (possibly for a specific input).
|
||||||
|
// It is satisfied by errors.ErrUnsupported as well as some syscall errors.
|
||||||
|
func IsNotSupported(err error) bool {
|
||||||
|
return errors.Is(err, errors.ErrUnsupported)
|
||||||
|
}
|
||||||
210
internal/lockedfile/internal/filelock/filelock_fcntl.go
Normal file
210
internal/lockedfile/internal/filelock/filelock_fcntl.go
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build aix || (solaris && !illumos)
|
||||||
|
|
||||||
|
// This code implements the filelock API using POSIX 'fcntl' locks, which attach
|
||||||
|
// to an (inode, process) pair rather than a file descriptor. To avoid unlocking
|
||||||
|
// files prematurely when the same file is opened through different descriptors,
|
||||||
|
// we allow only one read-lock at a time.
|
||||||
|
//
|
||||||
|
// Most platforms provide some alternative API, such as an 'flock' system call
|
||||||
|
// or an F_OFD_SETLK command for 'fcntl', that allows for better concurrency and
|
||||||
|
// does not require per-inode bookkeeping in the application.
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"math/rand"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType int16
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock lockType = syscall.F_RDLCK
|
||||||
|
writeLock lockType = syscall.F_WRLCK
|
||||||
|
)
|
||||||
|
|
||||||
|
type inode = uint64 // type of syscall.Stat_t.Ino
|
||||||
|
|
||||||
|
type inodeLock struct {
|
||||||
|
owner File
|
||||||
|
queue []<-chan File
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
mu sync.Mutex
|
||||||
|
inodes = map[File]inode{}
|
||||||
|
locks = map[inode]inodeLock{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) (err error) {
|
||||||
|
// POSIX locks apply per inode and process, and the lock for an inode is
|
||||||
|
// released when *any* descriptor for that inode is closed. So we need to
|
||||||
|
// synchronize access to each inode internally, and must serialize lock and
|
||||||
|
// unlock calls that refer to the same inode through different descriptors.
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
ino := fi.Sys().(*syscall.Stat_t).Ino
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
if i, dup := inodes[f]; dup && i != ino {
|
||||||
|
mu.Unlock()
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: errors.New("inode for file changed since last Lock or RLock"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inodes[f] = ino
|
||||||
|
|
||||||
|
var wait chan File
|
||||||
|
l := locks[ino]
|
||||||
|
if l.owner == f {
|
||||||
|
// This file already owns the lock, but the call may change its lock type.
|
||||||
|
} else if l.owner == nil {
|
||||||
|
// No owner: it's ours now.
|
||||||
|
l.owner = f
|
||||||
|
} else {
|
||||||
|
// Already owned: add a channel to wait on.
|
||||||
|
wait = make(chan File)
|
||||||
|
l.queue = append(l.queue, wait)
|
||||||
|
}
|
||||||
|
locks[ino] = l
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
if wait != nil {
|
||||||
|
wait <- f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spurious EDEADLK errors arise on platforms that compute deadlock graphs at
|
||||||
|
// the process, rather than thread, level. Consider processes P and Q, with
|
||||||
|
// threads P.1, P.2, and Q.3. The following trace is NOT a deadlock, but will be
|
||||||
|
// reported as a deadlock on systems that consider only process granularity:
|
||||||
|
//
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 blocks on file B. (This is erroneously reported as a deadlock.)
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 unblocks and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
//
|
||||||
|
// These spurious errors were observed in practice on AIX and Solaris in
|
||||||
|
// cmd/go: see https://golang.org/issue/32817.
|
||||||
|
//
|
||||||
|
// We work around this bug by treating EDEADLK as always spurious. If there
|
||||||
|
// really is a lock-ordering bug between the interacting processes, it will
|
||||||
|
// become a livelock instead, but that's not appreciably worse than if we had
|
||||||
|
// a proper flock implementation (which generally does not even attempt to
|
||||||
|
// diagnose deadlocks).
|
||||||
|
//
|
||||||
|
// In the above example, that changes the trace to:
|
||||||
|
//
|
||||||
|
// P.1 locks file A.
|
||||||
|
// Q.3 locks file B.
|
||||||
|
// Q.3 blocks on file A.
|
||||||
|
// P.2 spuriously fails to lock file B and goes to sleep.
|
||||||
|
// P.1 unlocks file A.
|
||||||
|
// Q.3 unblocks and locks file A.
|
||||||
|
// Q.3 unlocks files A and B.
|
||||||
|
// P.2 wakes up and locks file B.
|
||||||
|
// P.2 unlocks file B.
|
||||||
|
//
|
||||||
|
// We know that the retry loop will not introduce a *spurious* livelock
|
||||||
|
// because, according to the POSIX specification, EDEADLK is only to be
|
||||||
|
// returned when “the lock is blocked by a lock from another process”.
|
||||||
|
// If that process is blocked on some lock that we are holding, then the
|
||||||
|
// resulting livelock is due to a real deadlock (and would manifest as such
|
||||||
|
// when using, for example, the flock implementation of this package).
|
||||||
|
// If the other process is *not* blocked on some other lock that we are
|
||||||
|
// holding, then it will eventually release the requested lock.
|
||||||
|
|
||||||
|
nextSleep := 1 * time.Millisecond
|
||||||
|
const maxSleep = 500 * time.Millisecond
|
||||||
|
for {
|
||||||
|
err = setlkw(f.Fd(), lt)
|
||||||
|
if err != syscall.EDEADLK {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
time.Sleep(nextSleep)
|
||||||
|
|
||||||
|
nextSleep += nextSleep
|
||||||
|
if nextSleep > maxSleep {
|
||||||
|
nextSleep = maxSleep
|
||||||
|
}
|
||||||
|
// Apply 10% jitter to avoid synchronizing collisions when we finally unblock.
|
||||||
|
nextSleep += time.Duration((0.1*rand.Float64() - 0.05) * float64(nextSleep))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
unlock(f)
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
var owner File
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
ino, ok := inodes[f]
|
||||||
|
if ok {
|
||||||
|
owner = locks[ino].owner
|
||||||
|
}
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
if owner != f {
|
||||||
|
panic("unlock called on a file that is not locked")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := setlkw(f.Fd(), syscall.F_UNLCK)
|
||||||
|
|
||||||
|
mu.Lock()
|
||||||
|
l := locks[ino]
|
||||||
|
if len(l.queue) == 0 {
|
||||||
|
// No waiters: remove the map entry.
|
||||||
|
delete(locks, ino)
|
||||||
|
} else {
|
||||||
|
// The first waiter is sending us their file now.
|
||||||
|
// Receive it and update the queue.
|
||||||
|
l.owner = <-l.queue[0]
|
||||||
|
l.queue = l.queue[1:]
|
||||||
|
locks[ino] = l
|
||||||
|
}
|
||||||
|
delete(inodes, f)
|
||||||
|
mu.Unlock()
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// setlkw calls FcntlFlock with F_SETLKW for the entire file indicated by fd.
|
||||||
|
func setlkw(fd uintptr, lt lockType) error {
|
||||||
|
for {
|
||||||
|
err := syscall.FcntlFlock(fd, syscall.F_SETLKW, &syscall.Flock_t{
|
||||||
|
Type: int16(lt),
|
||||||
|
Whence: io.SeekStart,
|
||||||
|
Start: 0,
|
||||||
|
Len: 0, // All bytes.
|
||||||
|
})
|
||||||
|
if err != syscall.EINTR {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
internal/lockedfile/internal/filelock/filelock_other.go
Normal file
35
internal/lockedfile/internal/filelock/filelock_other.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !unix && !windows
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock = iota + 1
|
||||||
|
writeLock
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) error {
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: errors.ErrUnsupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: "Unlock",
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: errors.ErrUnsupported,
|
||||||
|
}
|
||||||
|
}
|
||||||
209
internal/lockedfile/internal/filelock/filelock_test.go
Normal file
209
internal/lockedfile/internal/filelock/filelock_test.go
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build !js && !plan9 && !wasip1
|
||||||
|
|
||||||
|
package filelock_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"hakurei.app/container"
|
||||||
|
"hakurei.app/internal/lockedfile/internal/filelock"
|
||||||
|
"hakurei.app/internal/lockedfile/internal/testexec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(t *testing.T, f *os.File) {
|
||||||
|
t.Helper()
|
||||||
|
err := filelock.Lock(f)
|
||||||
|
t.Logf("Lock(fd %d) = %v", f.Fd(), err)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rLock(t *testing.T, f *os.File) {
|
||||||
|
t.Helper()
|
||||||
|
err := filelock.RLock(f)
|
||||||
|
t.Logf("RLock(fd %d) = %v", f.Fd(), err)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(t *testing.T, f *os.File) {
|
||||||
|
t.Helper()
|
||||||
|
err := filelock.Unlock(f)
|
||||||
|
t.Logf("Unlock(fd %d) = %v", f.Fd(), err)
|
||||||
|
if err != nil {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustTempFile(t *testing.T) (f *os.File, remove func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
base := filepath.Base(t.Name())
|
||||||
|
f, err := os.CreateTemp("", base)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf(`os.CreateTemp("", %q) = %v`, base, err)
|
||||||
|
}
|
||||||
|
t.Logf("fd %d = %s", f.Fd(), f.Name())
|
||||||
|
|
||||||
|
return f, func() {
|
||||||
|
f.Close()
|
||||||
|
os.Remove(f.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustOpen(t *testing.T, name string) *os.File {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
f, err := os.OpenFile(name, os.O_RDWR, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("os.OpenFile(%q) = %v", name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("fd %d = os.OpenFile(%q)", f.Fd(), name)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
quiescent = 10 * time.Millisecond
|
||||||
|
probablyStillBlocked = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
func mustBlock(t *testing.T, op string, f *os.File) (wait func(*testing.T)) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
desc := fmt.Sprintf("%s(fd %d)", op, f.Fd())
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
t.Helper()
|
||||||
|
switch op {
|
||||||
|
case "Lock":
|
||||||
|
lock(t, f)
|
||||||
|
case "RLock":
|
||||||
|
rLock(t, f)
|
||||||
|
default:
|
||||||
|
panic("invalid op: " + op)
|
||||||
|
}
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
t.Fatalf("%s unexpectedly did not block", desc)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case <-time.After(quiescent):
|
||||||
|
t.Logf("%s is blocked (as expected)", desc)
|
||||||
|
return func(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
select {
|
||||||
|
case <-time.After(probablyStillBlocked):
|
||||||
|
t.Fatalf("%s is unexpectedly still blocked", desc)
|
||||||
|
case <-done:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLockExcludesLock(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
f, remove := mustTempFile(t)
|
||||||
|
defer remove()
|
||||||
|
|
||||||
|
other := mustOpen(t, f.Name())
|
||||||
|
defer other.Close()
|
||||||
|
|
||||||
|
lock(t, f)
|
||||||
|
lockOther := mustBlock(t, "Lock", other)
|
||||||
|
unlock(t, f)
|
||||||
|
lockOther(t)
|
||||||
|
unlock(t, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLockExcludesRLock(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
f, remove := mustTempFile(t)
|
||||||
|
defer remove()
|
||||||
|
|
||||||
|
other := mustOpen(t, f.Name())
|
||||||
|
defer other.Close()
|
||||||
|
|
||||||
|
lock(t, f)
|
||||||
|
rLockOther := mustBlock(t, "RLock", other)
|
||||||
|
unlock(t, f)
|
||||||
|
rLockOther(t)
|
||||||
|
unlock(t, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRLockExcludesOnlyLock(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
f, remove := mustTempFile(t)
|
||||||
|
defer remove()
|
||||||
|
rLock(t, f)
|
||||||
|
|
||||||
|
f2 := mustOpen(t, f.Name())
|
||||||
|
defer f2.Close()
|
||||||
|
|
||||||
|
doUnlockTF := false
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "aix", "solaris":
|
||||||
|
// When using POSIX locks (as on Solaris), we can't safely read-lock the
|
||||||
|
// same inode through two different descriptors at the same time: when the
|
||||||
|
// first descriptor is closed, the second descriptor would still be open but
|
||||||
|
// silently unlocked. So a second RLock must block instead of proceeding.
|
||||||
|
lockF2 := mustBlock(t, "RLock", f2)
|
||||||
|
unlock(t, f)
|
||||||
|
lockF2(t)
|
||||||
|
default:
|
||||||
|
rLock(t, f2)
|
||||||
|
doUnlockTF = true
|
||||||
|
}
|
||||||
|
|
||||||
|
other := mustOpen(t, f.Name())
|
||||||
|
defer other.Close()
|
||||||
|
lockOther := mustBlock(t, "Lock", other)
|
||||||
|
|
||||||
|
unlock(t, f2)
|
||||||
|
if doUnlockTF {
|
||||||
|
unlock(t, f)
|
||||||
|
}
|
||||||
|
lockOther(t)
|
||||||
|
unlock(t, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLockNotDroppedByExecCommand(t *testing.T) {
|
||||||
|
f, remove := mustTempFile(t)
|
||||||
|
defer remove()
|
||||||
|
|
||||||
|
lock(t, f)
|
||||||
|
|
||||||
|
other := mustOpen(t, f.Name())
|
||||||
|
defer other.Close()
|
||||||
|
|
||||||
|
// Some kinds of file locks are dropped when a duplicated or forked file
|
||||||
|
// descriptor is unlocked. Double-check that the approach used by os/exec does
|
||||||
|
// not accidentally drop locks.
|
||||||
|
cmd := testexec.CommandContext(t, t.Context(), container.MustExecutable(nil), "-test.run=^$")
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
t.Fatalf("exec failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lockOther := mustBlock(t, "Lock", other)
|
||||||
|
unlock(t, f)
|
||||||
|
lockOther(t)
|
||||||
|
unlock(t, other)
|
||||||
|
}
|
||||||
40
internal/lockedfile/internal/filelock/filelock_unix.go
Normal file
40
internal/lockedfile/internal/filelock/filelock_unix.go
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build darwin || dragonfly || freebsd || illumos || linux || netbsd || openbsd
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType int16
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock lockType = syscall.LOCK_SH
|
||||||
|
writeLock lockType = syscall.LOCK_EX
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) (err error) {
|
||||||
|
for {
|
||||||
|
err = syscall.Flock(int(f.Fd()), int(lt))
|
||||||
|
if err != syscall.EINTR {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
return lock(f, syscall.LOCK_UN)
|
||||||
|
}
|
||||||
57
internal/lockedfile/internal/filelock/filelock_windows.go
Normal file
57
internal/lockedfile/internal/filelock/filelock_windows.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// Copyright 2018 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package filelock
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/syscall/windows"
|
||||||
|
"io/fs"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
type lockType uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
readLock lockType = 0
|
||||||
|
writeLock lockType = windows.LOCKFILE_EXCLUSIVE_LOCK
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
reserved = 0
|
||||||
|
allBytes = ^uint32(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
func lock(f File, lt lockType) error {
|
||||||
|
// Per https://golang.org/issue/19098, “Programs currently expect the Fd
|
||||||
|
// method to return a handle that uses ordinary synchronous I/O.”
|
||||||
|
// However, LockFileEx still requires an OVERLAPPED structure,
|
||||||
|
// which contains the file offset of the beginning of the lock range.
|
||||||
|
// We want to lock the entire file, so we leave the offset as zero.
|
||||||
|
ol := new(syscall.Overlapped)
|
||||||
|
|
||||||
|
err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol)
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: lt.String(),
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unlock(f File) error {
|
||||||
|
ol := new(syscall.Overlapped)
|
||||||
|
err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol)
|
||||||
|
if err != nil {
|
||||||
|
return &fs.PathError{
|
||||||
|
Op: "Unlock",
|
||||||
|
Path: f.Name(),
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
43
internal/lockedfile/internal/testexec/exec.go
Normal file
43
internal/lockedfile/internal/testexec/exec.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package testexec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CommandContext is like exec.CommandContext, but:
|
||||||
|
// - sends SIGQUIT instead of SIGKILL in its Cancel function
|
||||||
|
// - fails the test if the command does not complete before the context is canceled, and
|
||||||
|
// - sets a Cleanup function that verifies that the test did not leak a subprocess.
|
||||||
|
func CommandContext(t testing.TB, ctx context.Context, name string, args ...string) *exec.Cmd {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cmd := exec.CommandContext(ctx, name, args...)
|
||||||
|
cmd.Cancel = func() error {
|
||||||
|
if ctx.Err() == context.DeadlineExceeded {
|
||||||
|
// The command timed out due to running too close to the test's deadline.
|
||||||
|
// There is no way the test did that intentionally — it's too close to the
|
||||||
|
// wire! — so mark it as a test failure. That way, if the test expects the
|
||||||
|
// command to fail for some other reason, it doesn't have to distinguish
|
||||||
|
// between that reason and a timeout.
|
||||||
|
t.Errorf("test timed out while running command: %v", cmd)
|
||||||
|
} else {
|
||||||
|
// The command is being terminated due to ctx being canceled, but
|
||||||
|
// apparently not due to an explicit test deadline that we added.
|
||||||
|
// Log that information in case it is useful for diagnosing a failure,
|
||||||
|
// but don't actually fail the test because of it.
|
||||||
|
t.Logf("%v: terminating command: %v", ctx.Err(), cmd)
|
||||||
|
}
|
||||||
|
return cmd.Process.Signal(syscall.SIGQUIT)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if cmd.Process != nil && cmd.ProcessState == nil {
|
||||||
|
t.Errorf("command was started, but test did not wait for it to complete: %v", cmd)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user