summaryrefslogtreecommitdiffhomepage
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/abi/linux/sem.go5
-rw-r--r--pkg/sentry/kernel/semaphore/semaphore.go34
-rw-r--r--pkg/sentry/kernel/semaphore/semaphore_test.go6
-rw-r--r--pkg/sentry/syscalls/linux/sys_sem.go43
4 files changed, 74 insertions, 14 deletions
diff --git a/pkg/abi/linux/sem.go b/pkg/abi/linux/sem.go
index d1a0bdb32..b80c93daf 100644
--- a/pkg/abi/linux/sem.go
+++ b/pkg/abi/linux/sem.go
@@ -27,8 +27,9 @@ const (
// ipcs ctl cmds. Source: include/uapi/linux/sem.h
const (
- SEM_STAT = 18
- SEM_INFO = 19
+ SEM_STAT = 18
+ SEM_INFO = 19
+ SEM_STAT_ANY = 20
)
const SEM_UNDO = 0x1000
diff --git a/pkg/sentry/kernel/semaphore/semaphore.go b/pkg/sentry/kernel/semaphore/semaphore.go
index c134931cd..29a2eb804 100644
--- a/pkg/sentry/kernel/semaphore/semaphore.go
+++ b/pkg/sentry/kernel/semaphore/semaphore.go
@@ -92,6 +92,7 @@ type Set struct {
type sem struct {
value int16
waiters waiterList `state:"zerovalue"`
+ pid int32
}
// waiter represents a caller that is waiting for the semaphore value to
@@ -283,7 +284,7 @@ func (s *Set) Change(ctx context.Context, creds *auth.Credentials, owner fs.File
}
// SetVal overrides a semaphore value, waking up waiters as needed.
-func (s *Set) SetVal(ctx context.Context, num int32, val int16, creds *auth.Credentials) error {
+func (s *Set) SetVal(ctx context.Context, num int32, val int16, creds *auth.Credentials, pid int32) error {
if val < 0 || val > valueMax {
return syserror.ERANGE
}
@@ -303,15 +304,17 @@ func (s *Set) SetVal(ctx context.Context, num int32, val int16, creds *auth.Cred
// TODO: Clear undo entries in all processes
sem.value = val
+ sem.pid = pid
s.changeTime = ktime.NowFromContext(ctx)
sem.wakeWaiters()
return nil
}
-// SetValAll overrides all semaphores values, waking up waiters as needed.
+// SetValAll overrides all semaphores values, waking up waiters as needed. It also
+// sets semaphore's PID which was fixed in Linux 4.6.
//
// 'len(vals)' must be equal to 's.Size()'.
-func (s *Set) SetValAll(ctx context.Context, vals []uint16, creds *auth.Credentials) error {
+func (s *Set) SetValAll(ctx context.Context, vals []uint16, creds *auth.Credentials, pid int32) error {
if len(vals) != s.Size() {
panic(fmt.Sprintf("vals length (%d) different that Set.Size() (%d)", len(vals), s.Size()))
}
@@ -335,6 +338,7 @@ func (s *Set) SetValAll(ctx context.Context, vals []uint16, creds *auth.Credenti
// TODO: Clear undo entries in all processes
sem.value = int16(val)
+ sem.pid = pid
sem.wakeWaiters()
}
s.changeTime = ktime.NowFromContext(ctx)
@@ -375,12 +379,29 @@ func (s *Set) GetValAll(creds *auth.Credentials) ([]uint16, error) {
return vals, nil
}
+// GetPID returns the PID set when performing operations in the semaphore.
+func (s *Set) GetPID(num int32, creds *auth.Credentials) (int32, error) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+
+ // "The calling process must have read permission on the semaphore set."
+ if !s.checkPerms(creds, fs.PermMask{Read: true}) {
+ return 0, syserror.EACCES
+ }
+
+ sem := s.findSem(num)
+ if sem == nil {
+ return 0, syserror.ERANGE
+ }
+ return sem.pid, nil
+}
+
// ExecuteOps attempts to execute a list of operations to the set. It only
// succeeds when all operations can be applied. No changes are made if it fails.
//
// On failure, it may return an error (retries are hopeless) or it may return
// a channel that can be waited on before attempting again.
-func (s *Set) ExecuteOps(ctx context.Context, ops []linux.Sembuf, creds *auth.Credentials) (chan struct{}, int32, error) {
+func (s *Set) ExecuteOps(ctx context.Context, ops []linux.Sembuf, creds *auth.Credentials, pid int32) (chan struct{}, int32, error) {
s.mu.Lock()
defer s.mu.Unlock()
@@ -404,14 +425,14 @@ func (s *Set) ExecuteOps(ctx context.Context, ops []linux.Sembuf, creds *auth.Cr
return nil, 0, syserror.EACCES
}
- ch, num, err := s.executeOps(ctx, ops)
+ ch, num, err := s.executeOps(ctx, ops, pid)
if err != nil {
return nil, 0, err
}
return ch, num, nil
}
-func (s *Set) executeOps(ctx context.Context, ops []linux.Sembuf) (chan struct{}, int32, error) {
+func (s *Set) executeOps(ctx context.Context, ops []linux.Sembuf, pid int32) (chan struct{}, int32, error) {
// Changes to semaphores go to this slice temporarily until they all succeed.
tmpVals := make([]int16, len(s.sems))
for i := range s.sems {
@@ -464,6 +485,7 @@ func (s *Set) executeOps(ctx context.Context, ops []linux.Sembuf) (chan struct{}
for i, v := range tmpVals {
s.sems[i].value = v
s.sems[i].wakeWaiters()
+ s.sems[i].pid = pid
}
s.opTime = ktime.NowFromContext(ctx)
return nil, 0, nil
diff --git a/pkg/sentry/kernel/semaphore/semaphore_test.go b/pkg/sentry/kernel/semaphore/semaphore_test.go
index 5f886bf31..2e51e6ee5 100644
--- a/pkg/sentry/kernel/semaphore/semaphore_test.go
+++ b/pkg/sentry/kernel/semaphore/semaphore_test.go
@@ -25,7 +25,7 @@ import (
)
func executeOps(ctx context.Context, t *testing.T, set *Set, ops []linux.Sembuf, block bool) chan struct{} {
- ch, _, err := set.executeOps(ctx, ops)
+ ch, _, err := set.executeOps(ctx, ops, 123)
if err != nil {
t.Fatalf("ExecuteOps(ops) failed, err: %v, ops: %+v", err, ops)
}
@@ -123,13 +123,13 @@ func TestNoWait(t *testing.T) {
ops[0].SemOp = -2
ops[0].SemFlg = linux.IPC_NOWAIT
- if _, _, err := set.executeOps(ctx, ops); err != syserror.ErrWouldBlock {
+ if _, _, err := set.executeOps(ctx, ops, 123); err != syserror.ErrWouldBlock {
t.Fatalf("ExecuteOps(ops) wrong result, got: %v, expected: %v", err, syserror.ErrWouldBlock)
}
ops[0].SemOp = 0
ops[0].SemFlg = linux.IPC_NOWAIT
- if _, _, err := set.executeOps(ctx, ops); err != syserror.ErrWouldBlock {
+ if _, _, err := set.executeOps(ctx, ops, 123); err != syserror.ErrWouldBlock {
t.Fatalf("ExecuteOps(ops) wrong result, got: %v, expected: %v", err, syserror.ErrWouldBlock)
}
}
diff --git a/pkg/sentry/syscalls/linux/sys_sem.go b/pkg/sentry/syscalls/linux/sys_sem.go
index 6775725ca..86f850ef1 100644
--- a/pkg/sentry/syscalls/linux/sys_sem.go
+++ b/pkg/sentry/syscalls/linux/sys_sem.go
@@ -71,8 +71,9 @@ func Semop(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscall
}
creds := auth.CredentialsFromContext(t)
+ pid := t.Kernel().GlobalInit().PIDNamespace().IDOfThreadGroup(t.ThreadGroup())
for {
- ch, num, err := set.ExecuteOps(t, ops, creds)
+ ch, num, err := set.ExecuteOps(t, ops, creds, int32(pid))
if ch == nil || err != nil {
// We're done (either on success or a failure).
return 0, nil, err
@@ -123,6 +124,21 @@ func Semctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Syscal
perms := fs.FilePermsFromMode(linux.FileMode(s.SemPerm.Mode & 0777))
return 0, nil, ipcSet(t, id, auth.UID(s.SemPerm.UID), auth.GID(s.SemPerm.GID), perms)
+ case linux.GETPID:
+ v, err := getPID(t, id, num)
+ return uintptr(v), nil, err
+
+ case linux.IPC_INFO,
+ linux.SEM_INFO,
+ linux.IPC_STAT,
+ linux.SEM_STAT,
+ linux.SEM_STAT_ANY,
+ linux.GETNCNT,
+ linux.GETZCNT:
+
+ t.Kernel().EmitUnimplementedEvent(t)
+ fallthrough
+
default:
return 0, nil, syserror.EINVAL
}
@@ -161,7 +177,8 @@ func setVal(t *kernel.Task, id int32, num int32, val int16) error {
return syserror.EINVAL
}
creds := auth.CredentialsFromContext(t)
- return set.SetVal(t, num, val, creds)
+ pid := t.Kernel().GlobalInit().PIDNamespace().IDOfThreadGroup(t.ThreadGroup())
+ return set.SetVal(t, num, val, creds, int32(pid))
}
func setValAll(t *kernel.Task, id int32, array usermem.Addr) error {
@@ -175,7 +192,8 @@ func setValAll(t *kernel.Task, id int32, array usermem.Addr) error {
return err
}
creds := auth.CredentialsFromContext(t)
- return set.SetValAll(t, vals, creds)
+ pid := t.Kernel().GlobalInit().PIDNamespace().IDOfThreadGroup(t.ThreadGroup())
+ return set.SetValAll(t, vals, creds, int32(pid))
}
func getVal(t *kernel.Task, id int32, num int32) (int16, error) {
@@ -202,3 +220,22 @@ func getValAll(t *kernel.Task, id int32, array usermem.Addr) error {
_, err = t.CopyOut(array, vals)
return err
}
+
+func getPID(t *kernel.Task, id int32, num int32) (int32, error) {
+ r := t.IPCNamespace().SemaphoreRegistry()
+ set := r.FindByID(id)
+ if set == nil {
+ return 0, syserror.EINVAL
+ }
+ creds := auth.CredentialsFromContext(t)
+ gpid, err := set.GetPID(num, creds)
+ if err != nil {
+ return 0, err
+ }
+ // Convert pid from init namespace to the caller's namespace.
+ tg := t.PIDNamespace().ThreadGroupWithID(kernel.ThreadID(gpid))
+ if tg == nil {
+ return 0, nil
+ }
+ return int32(tg.ID()), nil
+}