diff --git a/README.md b/README.md
index 2d6a987..4cb57e6 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,7 @@ Packages:
- forkexec: fork-exec provides mount, unshare, ptrace, seccomp, capset before exec
- memfd: read regular file and creates a seaed memfd for its contents
- unixsocket: send / recv oob msg from a unix socket
-- cgroup: creates cgroup directories and collects resource usage / limits
+- cgroup: creates cgroup directories and collects resource usage / limits
- tracer: ptrace tracer and provides syscall trap filter context
- runprogram: wrapper to call forkexec and trecer
- rununshared: wrapper to call forkexec and unshared namespaces
@@ -71,3 +71,4 @@ It seems unshare net or ipc takes time, maybe limits action by seccomp instead.
TODO:
1. Add ability to pre-fork container deamons
+2. Add fork-exec with execve memfd (execveat), sethostname, setdomainname, prepare devices (mknod)
diff --git a/deamon/deamon.go b/deamon/deamon.go
new file mode 100644
index 0000000..64e65a0
--- /dev/null
+++ b/deamon/deamon.go
@@ -0,0 +1,52 @@
+// Package deamon provides pre-forked container to reduce the container
+// create / destroy costs (about 160ms). It creates deamon within unshared
+// container and communicate with original process using unix socket with
+// oob for fd / pid and structs are encoded in gob format.
+package deamon
+
+/*
+Protocol between client and deamon (not thread safe):
+- copyin (copy file into container):
+ send: path, perm,
+ reply: "finished" (after copy finished) / "error"
+- open (open file inside container):
+ send: path, flags, perm
+ reply: "success", / "error"
+- delete (unlik file / rmdir dir inside container):
+ send: path
+ reply: "finished" / "error"
+- reset (clean up container for later use (clear workdir / tmp)):
+ send:
+ reply: "success"
+- execve: (execute file inside container):
+ send: argv, envv, fd map, rlimits,
+ reply:
+ - success: "success",
+ - failed: "failed"
+ send (success): "init_finished" (as cmd)
+ - reply: "finished" / send: "kill" (as cmd)
+ - send: "kill" (as cmd) / reply: "finished"
+
+Any socket related error will cause the deamon exit (with all process inside container)
+*/
+
+import (
+ "github.com/criyle/go-judger/types/rlimit"
+)
+
+// Cmd is the control message send into deamon
+type Cmd struct {
+ Cmd string // type of the cmd
+ Path string // path
+ Perm int // write perm / open perm
+ Flags int // open flags
+ Argv []string // execve argv
+ Envv []string // execve envv
+ FdMap []int // execvc fd map
+ RLmits []rlimit.RLimit // execve posix rlimit
+}
+
+// Reply is the reply message send back to controller
+type Reply struct {
+ Error string // empty if no error
+}
diff --git a/unixsocket/socket.go b/unixsocket/socket.go
index ac8796a..8138dde 100644
--- a/unixsocket/socket.go
+++ b/unixsocket/socket.go
@@ -30,7 +30,7 @@ type Msg struct {
}
// NewSocket creates Socket conn struct using existing unix socket fd
-// creates by socketpair or net.DialUnix
+// creates by socketpair or net.DialUnix and mark it as close_on_exec (avoid fd leak)
// it need SOCK_SEQPACKET socket for reliable transfer
// it will need SO_PASSCRED to pass unix credential, Notice: in the documentation,
// if cred is not specified, self information will be sent
@@ -40,6 +40,7 @@ func NewSocket(fd int) (*Socket, error) {
return nil, fmt.Errorf("NewSocket: fd(%d) is not a valid fd", fd)
}
defer file.Close()
+ syscall.CloseOnExec(int(file.Fd()))
conn, err := net.FileConn(file)
if err != nil {
return nil, err