mirror of
https://github.com/criyle/go-sandbox.git
synced 2025-11-04 14:49:53 +08:00
add lock for daemon socket
This commit is contained in:
parent
f2a28034f3
commit
c244811c19
@ -3,6 +3,7 @@ package daemon
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/forkexec"
|
"github.com/criyle/go-sandbox/pkg/forkexec"
|
||||||
"github.com/criyle/go-sandbox/pkg/memfd"
|
"github.com/criyle/go-sandbox/pkg/memfd"
|
||||||
@ -32,7 +33,8 @@ type Builder struct {
|
|||||||
type Master struct {
|
type Master struct {
|
||||||
pid int // underlying container init pid
|
pid int // underlying container init pid
|
||||||
socket *unixsocket.Socket // master - container communication
|
socket *unixsocket.Socket // master - container communication
|
||||||
buff *pipe.Buffer
|
buff *pipe.Buffer // collect stderr output from container
|
||||||
|
mu sync.Mutex // lock to avoid race condition
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build creates new master with underlying container
|
// Build creates new master with underlying container
|
||||||
@ -55,14 +57,14 @@ func (b *Builder) Build() (*Master, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// prepare stdin / stdout / stderr
|
// prepare stdin / stdout / stderr
|
||||||
fnull, err := os.OpenFile(os.DevNull, os.O_RDWR, os.ModePerm)
|
devNull, err := os.OpenFile(os.DevNull, os.O_RDWR, os.ModePerm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("daemon: failed to open devNull(%v)", err)
|
return nil, fmt.Errorf("daemon: failed to open devNull(%v)", err)
|
||||||
}
|
}
|
||||||
defer fnull.Close()
|
defer devNull.Close()
|
||||||
|
|
||||||
files := make([]uintptr, 0, 4)
|
files := make([]uintptr, 0, 4)
|
||||||
files = append(files, []uintptr{fnull.Fd(), fnull.Fd()}...)
|
files = append(files, devNull.Fd(), devNull.Fd())
|
||||||
if b.Stderr {
|
if b.Stderr {
|
||||||
buff, err = pipe.NewBuffer(bufferSize)
|
buff, err = pipe.NewBuffer(bufferSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -71,7 +73,7 @@ func (b *Builder) Build() (*Master, error) {
|
|||||||
defer buff.W.Close()
|
defer buff.W.Close()
|
||||||
files = append(files, buff.W.Fd())
|
files = append(files, buff.W.Fd())
|
||||||
} else {
|
} else {
|
||||||
files = append(files, fnull.Fd())
|
files = append(files, devNull.Fd())
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare self memfd
|
// prepare self memfd
|
||||||
@ -113,7 +115,11 @@ func (b *Builder) Build() (*Master, error) {
|
|||||||
ins.Close()
|
ins.Close()
|
||||||
return nil, fmt.Errorf("daemon: failed to execve(%v)", err)
|
return nil, fmt.Errorf("daemon: failed to execve(%v)", err)
|
||||||
}
|
}
|
||||||
return &Master{pid, ins, buff}, nil
|
return &Master{
|
||||||
|
pid: pid,
|
||||||
|
socket: ins,
|
||||||
|
buff: buff,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroy kill the daemon process (with container)
|
// Destroy kill the daemon process (with container)
|
||||||
|
|||||||
@ -3,12 +3,21 @@ package daemon
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
"github.com/criyle/go-sandbox/pkg/unixsocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ping send ping message to container
|
// Ping send ping message to container
|
||||||
func (m *Master) Ping() error {
|
func (m *Master) Ping() error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
|
// avoid infinite wait (max 3s)
|
||||||
|
const pingWait = 3 * time.Second
|
||||||
|
m.socket.SetDeadline(time.Now().Add(pingWait))
|
||||||
|
defer m.socket.SetDeadline(time.Time{})
|
||||||
|
|
||||||
// send ping
|
// send ping
|
||||||
cmd := Cmd{
|
cmd := Cmd{
|
||||||
Cmd: cmdPing,
|
Cmd: cmdPing,
|
||||||
@ -22,6 +31,9 @@ func (m *Master) Ping() error {
|
|||||||
|
|
||||||
// CopyIn copies file to container
|
// CopyIn copies file to container
|
||||||
func (m *Master) CopyIn(f *os.File, p string) error {
|
func (m *Master) CopyIn(f *os.File, p string) error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
// send copyin
|
// send copyin
|
||||||
cmd := Cmd{
|
cmd := Cmd{
|
||||||
Cmd: cmdCopyIn,
|
Cmd: cmdCopyIn,
|
||||||
@ -38,6 +50,9 @@ func (m *Master) CopyIn(f *os.File, p string) error {
|
|||||||
|
|
||||||
// Open open file in container
|
// Open open file in container
|
||||||
func (m *Master) Open(p string) (*os.File, error) {
|
func (m *Master) Open(p string) (*os.File, error) {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
// send copyin
|
// send copyin
|
||||||
cmd := Cmd{
|
cmd := Cmd{
|
||||||
Cmd: cmdOpen,
|
Cmd: cmdOpen,
|
||||||
@ -67,6 +82,9 @@ func (m *Master) Open(p string) (*os.File, error) {
|
|||||||
|
|
||||||
// Delete remove file from container
|
// Delete remove file from container
|
||||||
func (m *Master) Delete(p string) error {
|
func (m *Master) Delete(p string) error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
cmd := Cmd{
|
cmd := Cmd{
|
||||||
Cmd: cmdDelete,
|
Cmd: cmdDelete,
|
||||||
Path: p,
|
Path: p,
|
||||||
@ -79,6 +97,9 @@ func (m *Master) Delete(p string) error {
|
|||||||
|
|
||||||
// Reset remove all from /tmp and /w
|
// Reset remove all from /tmp and /w
|
||||||
func (m *Master) Reset() error {
|
func (m *Master) Reset() error {
|
||||||
|
m.mu.Lock()
|
||||||
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
cmd := Cmd{
|
cmd := Cmd{
|
||||||
Cmd: cmdReset,
|
Cmd: cmdReset,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,20 +14,26 @@ type ExecveParam struct {
|
|||||||
Args []string
|
Args []string
|
||||||
Env []string
|
Env []string
|
||||||
Fds []uintptr
|
Fds []uintptr
|
||||||
|
|
||||||
// fexecve fd
|
// fexecve fd
|
||||||
ExecFile uintptr
|
ExecFile uintptr
|
||||||
|
|
||||||
// POSIX Resource limit set by set rlimit
|
// POSIX Resource limit set by set rlimit
|
||||||
RLimits []rlimit.RLimit
|
RLimits []rlimit.RLimit
|
||||||
// SyncFunc called with pid before execve
|
|
||||||
|
// SyncFunc called with pid before execve (e.g. add to cgroup)
|
||||||
SyncFunc func(pid int) error
|
SyncFunc func(pid int) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execve runs process inside container
|
// Execve runs process inside container
|
||||||
// accepts done for cancelation
|
// accepts done for cancelation
|
||||||
func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.Result, error) {
|
func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.Result, error) {
|
||||||
var files []int
|
m.mu.Lock()
|
||||||
|
|
||||||
sTime := time.Now()
|
sTime := time.Now()
|
||||||
|
|
||||||
|
// if execve with fd, put fd at the first parameter
|
||||||
|
var files []int
|
||||||
if param.ExecFile > 0 {
|
if param.ExecFile > 0 {
|
||||||
files = append(files, int(param.ExecFile))
|
files = append(files, int(param.ExecFile))
|
||||||
}
|
}
|
||||||
@ -43,36 +49,46 @@ func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.
|
|||||||
FdExec: param.ExecFile > 0,
|
FdExec: param.ExecFile > 0,
|
||||||
}
|
}
|
||||||
if err := m.sendCmd(&cmd, msg); err != nil {
|
if err := m.sendCmd(&cmd, msg); err != nil {
|
||||||
|
m.mu.Unlock()
|
||||||
return nil, fmt.Errorf("execve: sendCmd %v", err)
|
return nil, fmt.Errorf("execve: sendCmd %v", err)
|
||||||
}
|
}
|
||||||
reply, msg, err := m.recvReply()
|
reply, msg, err := m.recvReply()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
m.mu.Unlock()
|
||||||
return nil, fmt.Errorf("execve: recvReply %v", err)
|
return nil, fmt.Errorf("execve: recvReply %v", err)
|
||||||
}
|
}
|
||||||
if reply.Error != "" || msg == nil || msg.Cred == nil {
|
if reply.Error != "" || msg == nil || msg.Cred == nil {
|
||||||
m.execveSyncKill()
|
m.execveSyncKill()
|
||||||
|
m.mu.Unlock()
|
||||||
return nil, fmt.Errorf("execve: no pid recved or error(%v)", reply.Error)
|
return nil, fmt.Errorf("execve: no pid recved or error(%v)", reply.Error)
|
||||||
}
|
}
|
||||||
if param.SyncFunc != nil {
|
if param.SyncFunc != nil {
|
||||||
if err := param.SyncFunc(int(msg.Cred.Pid)); err != nil {
|
if err := param.SyncFunc(int(msg.Cred.Pid)); err != nil {
|
||||||
m.execveSyncKill()
|
m.execveSyncKill()
|
||||||
|
m.mu.Unlock()
|
||||||
return nil, fmt.Errorf("execve: syncfunc failed(%v)", err)
|
return nil, fmt.Errorf("execve: syncfunc failed(%v)", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// send to syncFunc ack ok
|
// send to syncFunc ack ok
|
||||||
if err := m.sendCmd(&Cmd{Cmd: cmdOk}, nil); err != nil {
|
if err := m.sendCmd(&Cmd{Cmd: cmdOk}, nil); err != nil {
|
||||||
|
m.mu.Unlock()
|
||||||
return nil, fmt.Errorf("execve: ok failed(%v)", err)
|
return nil, fmt.Errorf("execve: ok failed(%v)", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mTime := time.Now()
|
mTime := time.Now()
|
||||||
|
|
||||||
// make sure goroutine not leaked (blocked) even if result is not consumed
|
// make sure goroutine not leaked (blocked) even if result is not consumed
|
||||||
result := make(chan types.Result, 1)
|
result := make(chan types.Result, 1)
|
||||||
waitDone := make(chan struct{})
|
waitDone := make(chan struct{})
|
||||||
|
|
||||||
// Wait
|
// Wait
|
||||||
go func() {
|
go func() {
|
||||||
reply2, _, _ := m.recvReply()
|
reply2, _, _ := m.recvReply()
|
||||||
close(waitDone)
|
close(waitDone)
|
||||||
// done signal (should recv after kill)
|
// done signal (should recv after kill)
|
||||||
m.recvReply()
|
m.recvReply()
|
||||||
|
// unlock after last read / write
|
||||||
|
m.mu.Unlock()
|
||||||
// emit result after all communication finish
|
// emit result after all communication finish
|
||||||
status := reply2.Status
|
status := reply2.Status
|
||||||
if reply2.Error != "" {
|
if reply2.Error != "" {
|
||||||
@ -88,6 +104,7 @@ func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.
|
|||||||
RunningTime: time.Since(mTime),
|
RunningTime: time.Since(mTime),
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Kill (if wait is done, a kill message need to be send to collect zombies)
|
// Kill (if wait is done, a kill message need to be send to collect zombies)
|
||||||
go func() {
|
go func() {
|
||||||
select {
|
select {
|
||||||
@ -96,6 +113,7 @@ func (m *Master) Execve(done <-chan struct{}, param *ExecveParam) (<-chan types.
|
|||||||
}
|
}
|
||||||
m.sendCmd(&Cmd{Cmd: cmdKill}, nil)
|
m.sendCmd(&Cmd{Cmd: cmdKill}, nil)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -4,5 +4,5 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1
|
github.com/seccomp/libseccomp-golang v0.9.1
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47
|
golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2
|
||||||
)
|
)
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -1,4 +1,4 @@
|
|||||||
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo=
|
||||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2 h1:nq114VpM8lsSlP+lyUbANecYHYiFcSNFtqcBlxRV+gA=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191020212454-3e7259c5e7c2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user