Skip to content

Commit

Permalink
refactor: tidy things up a bit more
Browse files Browse the repository at this point in the history
  • Loading branch information
nixpig committed Dec 14, 2024
1 parent 4f15a32 commit 3dc403c
Show file tree
Hide file tree
Showing 18 changed files with 140 additions and 199 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ This is a personal project for me to explore and better understand the OCI Runti

- [ ] Use execve instead of fork/exec
- [ ] Major refactor and tidy-up
- internal/logging
- container/*
- internal/ipc
- [ ] Implement seccomp
- [ ] Implement AppArmor
- [ ] Implement cgroups v2
Expand Down
4 changes: 0 additions & 4 deletions capabilities/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ var Capabilities = map[string]capability.Cap{
}

func SetCapabilities(caps *specs.LinuxCapabilities) error {
if caps == nil {
return nil
}

c, err := capability.NewPid2(0)
if err != nil {
return fmt.Errorf("initialise capabilities object: %w", err)
Expand Down
34 changes: 22 additions & 12 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"syscall"

Expand Down Expand Up @@ -178,28 +179,37 @@ func (c *Container) RefreshState(log *zerolog.Logger) error {
return nil
}

func (c *Container) save(configPath string) error {
func (c *Container) Save() error {
b, err := json.Marshal(c.State)
if err != nil {
return err
}

if err := os.WriteFile(configPath, b, 0644); err != nil {
if err := os.WriteFile(
filepath.Join(
containerRootDir,
c.ID(),
"state.json"),
b,
0644,
); err != nil {
return fmt.Errorf("(save: %s) write state file: %w", c.State.Status, err)
}

return nil
}
if c.Opts != nil && c.Opts.PIDFile != "" {
if err := os.WriteFile(
c.Opts.PIDFile,
[]byte(strconv.Itoa(c.PID())),
0666,
); err != nil {
return fmt.Errorf("write pid to file (%s): %w", c.Opts.PIDFile, err)
}
}

func (c *Container) Save() error {
return c.save(filepath.Join(
containerRootDir,
c.ID(),
"state.json"),
)
return nil
}

func (c *Container) ExecHooks(lifecycleHook string, log *zerolog.Logger) error {
func (c *Container) ExecHooks(lifecycleHook string) error {
if c.Spec.Hooks == nil {
return nil
}
Expand All @@ -226,7 +236,7 @@ func (c *Container) ExecHooks(lifecycleHook string, log *zerolog.Logger) error {
return fmt.Errorf("marshal state: %w", err)
}

return lifecycle.ExecHooks(specHooks, string(s), log)
return lifecycle.ExecHooks(specHooks, string(s))
}

func (c *Container) CanBeStarted() bool {
Expand Down
2 changes: 1 addition & 1 deletion container/container_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func (c *Container) Delete(force bool, log *zerolog.Logger) error {
}

// TODO: actually do the 'deleting'; rewind all the creation steps
if err := c.ExecHooks("poststop", log); err != nil {
if err := c.ExecHooks("poststop"); err != nil {
log.Warn().Err(err).Msg("failed to execute poststop hooks")
fmt.Println("WARNING: failed to execute poststop hooks")
}
Expand Down
71 changes: 7 additions & 64 deletions container/container_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import (
"github.com/nixpig/brownie/terminal"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/rs/zerolog"
"golang.org/x/sys/unix"
)

func (c *Container) Init(reexec string, arg string, log *zerolog.Logger) error {
if err := c.ExecHooks("createRuntime", log); err != nil {
if err := c.ExecHooks("createRuntime"); err != nil {
return fmt.Errorf("execute createruntime hooks: %w", err)
}

if err := c.ExecHooks("createContainer", log); err != nil {
if err := c.ExecHooks("createContainer"); err != nil {
return fmt.Errorf("execute createcontainer hooks: %w", err)
}

Expand All @@ -41,40 +40,8 @@ func (c *Container) Init(reexec string, arg string, log *zerolog.Logger) error {
c.Opts.ConsoleSocket != ""

if useTerminal {
prev, err := os.Getwd()
if err != nil {
log.Error().Err(err).Msg("failed to get current working directory")
return fmt.Errorf("get cwd: %w", err)
}

if err := os.Chdir(c.Rootfs()); err != nil {
log.Error().Err(err).Msg("failed to change to container root dir")
return fmt.Errorf("change to container root dir: %w", err)
}

cwd, err := os.Getwd()
if err != nil {
log.Error().Err(err).Msg("failed to get cwd")
return fmt.Errorf("get cwd: %w", err)
}
log.Info().Str("cwd", cwd).Msg("INIT current working directory")

if err := os.Symlink(c.Opts.ConsoleSocket, "./console-socket"); err != nil {
log.Error().Err(err).Msg("failed to symlink console socket")
return fmt.Errorf("symlink console socket: %w", err)
}

consoleSocket, err := terminal.NewPtySocket(
"./console-socket",
)
if err != nil {
return fmt.Errorf("create terminal socket: %w", err)
}
c.State.ConsoleSocket = &consoleSocket.SocketFd

if err := os.Chdir(prev); err != nil {
log.Error().Err(err).Msg("failed to change back to previous directory")
return fmt.Errorf("change back to prev dir: %w", err)
if c.State.ConsoleSocket, err = terminal.Setup(c.Rootfs(), c.Opts.ConsoleSocket); err != nil {
return err
}
}

Expand Down Expand Up @@ -163,15 +130,10 @@ func (c *Container) Init(reexec string, arg string, log *zerolog.Logger) error {
}

ns := namespace.LinuxNamespace(ns)
flag, err := ns.ToFlag()
if err != nil {
return fmt.Errorf("convert namespace to flag: %w", err)
}

if ns.Path == "" {
cloneFlags |= flag
cloneFlags |= ns.ToFlag()
} else {

if !strings.HasSuffix(ns.Path, fmt.Sprintf("/%s", ns.ToEnv())) &&
ns.Type != specs.PIDNamespace {
return fmt.Errorf("namespace type (%s) and path (%s) do not match", ns.Type, ns.Path)
Expand All @@ -181,17 +143,8 @@ func (c *Container) Init(reexec string, arg string, log *zerolog.Logger) error {
if ns.Type == specs.MountNamespace {
reexecCmd.Env = append(reexecCmd.Env, fmt.Sprintf("gons_%s=%s", ns.ToEnv(), ns.Path))
} else {
fd, err := syscall.Open(ns.Path, syscall.O_RDONLY, 0666)
if err != nil {
log.Error().Err(err).Str("path", ns.Path).Str("type", string(ns.Type)).Msg("failed to open namespace path")
return fmt.Errorf("open ns path: %w", err)
}
defer syscall.Close(fd)

_, _, errno := syscall.RawSyscall(unix.SYS_SETNS, uintptr(fd), 0, 0)
if errno != 0 {
log.Error().Str("path", ns.Path).Int("errno", int(errno)).Msg("FAIELD THE RAWSYSCALL")
return fmt.Errorf("errno: %w", err)
if err := ns.Enter(); err != nil {
return fmt.Errorf("enter namespace: %w", err)
}
}
}
Expand Down Expand Up @@ -222,16 +175,6 @@ func (c *Container) Init(reexec string, arg string, log *zerolog.Logger) error {
return fmt.Errorf("save pid for reexec: %w", err)
}

if c.Opts.PIDFile != "" {
if err := os.WriteFile(
c.Opts.PIDFile,
[]byte(strconv.Itoa(pid)),
0666,
); err != nil {
return fmt.Errorf("write pid to file (%s): %w", c.Opts.PIDFile, err)
}
}

if err := reexecCmd.Process.Release(); err != nil {
return fmt.Errorf("detach reexec container: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion container/container_kill.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func (c *Container) Kill(sig syscall.Signal, log *zerolog.Logger) error {
}

// TODO: delete everything then
if err := c.ExecHooks("poststop", log); err != nil {
if err := c.ExecHooks("poststop"); err != nil {
log.Warn().Err(err).Msg("failed to execute poststop hooks")
fmt.Println("WARNING: failed to execute poststop hooks")
// TODO: log a warning???
Expand Down
58 changes: 18 additions & 40 deletions container/container_reexec.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package container

import (
"errors"
"fmt"
"os"
"os/exec"
Expand Down Expand Up @@ -44,38 +45,35 @@ func (c *Container) Reexec(log *zerolog.Logger) error {

c.initIPC.ch <- []byte("ready")

log.Info().Msg("waiting for start")
if err := ipc.WaitForMsg(listCh, "start", func() error {
log.Info().Msg("received start")
if c.Spec.Process == nil {
return errors.New("process is required")
}

if err := filesystem.PivotRoot(c.Rootfs()); err != nil {
log.Error().Err(err).Msg("pivot root")
return err
}

if err := filesystem.MountMaskedPaths(
c.Spec.Linux.MaskedPaths,
); err != nil {
log.Error().Err(err).Msg("mount masked paths")
return err
}

if err := filesystem.MountReadonlyPaths(
c.Spec.Linux.ReadonlyPaths,
); err != nil {
log.Error().Err(err).Msg("mount readonly paths")
return err
}

if c.Spec.Linux.RootfsPropagation != "" {
if err := syscall.Mount("", "/", "", filesystem.MountOptions[c.Spec.Linux.RootfsPropagation].Flag, ""); err != nil {
log.Error().Err(err).Msg("mount rootfs RootfsPropagation paths")
return err
}
}

if c.Spec.Root.Readonly {
if err := syscall.Mount("", "/", "", syscall.MS_BIND|syscall.MS_REMOUNT|syscall.MS_RDONLY, ""); err != nil {
log.Error().Err(err).Msg("mount rootfs readonly paths")
return err
}
}
Expand All @@ -86,36 +84,26 @@ func (c *Container) Reexec(log *zerolog.Logger) error {
return n.Type == specs.UTSNamespace
},
) {
if err := syscall.Sethostname(
[]byte(c.Spec.Hostname),
); err != nil {
log.Error().Err(err).Msg("set hostname")
if err := syscall.Sethostname([]byte(c.Spec.Hostname)); err != nil {
return err
}

if err := syscall.Setdomainname(
[]byte(c.Spec.Domainname),
); err != nil {
log.Error().Err(err).Msg("set domainname")
if err := syscall.Setdomainname([]byte(c.Spec.Domainname)); err != nil {
return err
}
}

if c.Spec.Process != nil {
if c.Spec.Process.Rlimits != nil {
if err := cgroups.SetRlimits(c.Spec.Process.Rlimits); err != nil {
log.Error().Err(err).Msg("set rlimits")
return err
}
if c.Spec.Process.Rlimits != nil {
if err := cgroups.SetRlimits(c.Spec.Process.Rlimits); err != nil {
return err
}
}

if c.Spec.Process.Capabilities != nil {
if err := capabilities.SetCapabilities(
c.Spec.Process.Capabilities,
); err != nil {
log.Error().Err(err).Msg("set caps")
return err
}
if c.Spec.Process.Capabilities != nil {
if err := capabilities.SetCapabilities(
c.Spec.Process.Capabilities,
); err != nil {
return err
}
}

Expand All @@ -127,8 +115,7 @@ func (c *Container) Reexec(log *zerolog.Logger) error {
cmd.Dir = c.Spec.Process.Cwd

var ambientCapsFlags []uintptr
if c.Spec.Process != nil &&
c.Spec.Process.Capabilities != nil {
if c.Spec.Process.Capabilities != nil {
for _, cap := range c.Spec.Process.Capabilities.Ambient {
ambientCapsFlags = append(
ambientCapsFlags,
Expand All @@ -148,9 +135,6 @@ func (c *Container) Reexec(log *zerolog.Logger) error {
},
}

// syscall.Setuid(int(c.Spec.Process.User.UID))
// syscall.Setgid(int(c.Spec.Process.User.GID))

if c.Spec.Linux.UIDMappings != nil {
cmd.SysProcAttr.UidMappings = user.BuildUIDMappings(c.Spec.Linux.UIDMappings)
}
Expand All @@ -163,23 +147,17 @@ func (c *Container) Reexec(log *zerolog.Logger) error {
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

if err := c.ExecHooks("startContainer", log); err != nil {
if err := c.ExecHooks("startContainer"); err != nil {
return fmt.Errorf("execute startContainer hooks: %w", err)
}

// we can't get logs or anything past this point
// syscall.Seteuid(int(c.Spec.Process.User.UID))
// syscall.Setegid(int(c.Spec.Process.User.GID))
log.Info().Str("cmd", cmd.Args[0]).Any("args", cmd.Args[1:]).Msg("process")
if err := cmd.Run(); err != nil {
log.Error().Err(err).Msg("(run) error executing in reexec2")
return err
}

return nil

}); err != nil {
log.Error().Err(err).Msg("error in waitformsg")
return err
}

Expand Down
6 changes: 3 additions & 3 deletions container/container_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ func (c *Container) Start(log *zerolog.Logger) error {
}

// FIXME: 'prestart' hook is deprecated and appears to break 'docker run'??
if err := c.ExecHooks("prestart", log); err != nil {
if err := c.ExecHooks("prestart"); err != nil {
// TODO: run DELETE tasks here, then...
if err := c.ExecHooks("poststop", log); err != nil {
if err := c.ExecHooks("poststop"); err != nil {
log.Warn().Err(err).Msg("failed to execute poststop hooks")
fmt.Println("WARNING: failed to execute poststop hooks")
}
Expand All @@ -51,7 +51,7 @@ func (c *Container) Start(log *zerolog.Logger) error {
return fmt.Errorf("save host container state: %w", err)
}
// FIXME: do these need to move up before the cmd.Wait call??
if err := c.ExecHooks("poststart", log); err != nil {
if err := c.ExecHooks("poststart"); err != nil {
// TODO: how to handle this (log a warning) from start command??
// FIXME: needs to 'log a warning'
log.Warn().Err(err).Msg("failed to execute poststart hook")
Expand Down
1 change: 0 additions & 1 deletion filesystem/devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ func mountDefaultDevices(rootfs string) error {

func mountSpecDevices(devices []specs.LinuxDevice, rootfs string) error {
for _, dev := range devices {

absPath := filepath.Join(rootfs, strings.TrimPrefix(dev.Path, "/"))

dt := map[string]uint32{
Expand Down
Loading

0 comments on commit 3dc403c

Please sign in to comment.