Implement sysv shm.

PiperOrigin-RevId: 197058289
Change-Id: I3946c25028b7e032be4894d61acb48ac0c24d574
This commit is contained in:
Rahat Mahmood
2018-05-17 15:06:19 -07:00
committed by Shentubot
parent a8d7cee3e8
commit 8878a66a56
18 changed files with 1072 additions and 42 deletions
+1
View File
@@ -51,6 +51,7 @@ go_library(
"sched.go",
"seccomp.go",
"sem.go",
"shm.go",
"signal.go",
"socket.go",
"time.go",
+75
View File
@@ -0,0 +1,75 @@
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package linux
// shmat(2) flags. Source: include/uapi/linux/shm.h
const (
SHM_RDONLY = 010000 // Read-only access.
SHM_RND = 020000 // Round attach address to SHMLBA boundary.
SHM_REMAP = 040000 // Take-over region on attach.
SHM_EXEC = 0100000 // Execution access.
)
// IPCPerm.Mode upper byte flags. Source: include/linux/shm.h
const (
SHM_DEST = 01000 // Segment will be destroyed on last detach.
SHM_LOCKED = 02000 // Segment will not be swapped.
SHM_HUGETLB = 04000 // Segment will use huge TLB pages.
SHM_NORESERVE = 010000 // Don't check for reservations.
)
// Additional Linux-only flags for shmctl(2). Source: include/uapi/linux/shm.h
const (
SHM_LOCK = 11
SHM_UNLOCK = 12
SHM_STAT = 13
SHM_INFO = 14
)
// ShmidDS is equivalent to struct shmid64_ds. Source:
// include/uapi/asm-generic/shmbuf.h
type ShmidDS struct {
ShmPerm IPCPerm
ShmSegsz uint64
ShmAtime TimeT
ShmDtime TimeT
ShmCtime TimeT
ShmCpid int32
ShmLpid int32
ShmNattach uint64
Unused4 uint64
Unused5 uint64
}
// ShmParams is equivalent to struct shminfo. Source: include/uapi/linux/shm.h
type ShmParams struct {
ShmMax uint64
ShmMin uint64
ShmMni uint64
ShmSeg uint64
ShmAll uint64
}
// ShmInfo is equivalent to struct shm_info. Source: include/uapi/linux/shm.h
type ShmInfo struct {
UsedIDs int32 // Number of currently existing segments.
_ [4]byte
ShmTot uint64 // Total number of shared memory pages.
ShmRss uint64 // Number of resident shared memory pages.
ShmSwp uint64 // Number of swapped shared memory pages.
SwapAttempts uint64 // Unused since Linux 2.4.
SwapSuccesses uint64 // Unused since Linux 2.4.
}
+5 -3
View File
@@ -194,9 +194,11 @@ type AtomicRefCount struct {
weakRefs ilist.List `state:"nosave"`
}
// TestReadRefs returns the current reference count of r. Use only for tests.
func (r *AtomicRefCount) TestReadRefs() int64 {
return atomic.LoadInt64(&r.refCount)
// ReadRefs returns the current number of references. The returned count is
// inherently racy and is unsafe to use without external synchronization.
func (r *AtomicRefCount) ReadRefs() int64 {
// Account for the internal -1 offset on refcounts.
return atomic.LoadInt64(&r.refCount) + 1
}
// IncRef increments this object's reference count. While the count is kept
+20
View File
@@ -20,6 +20,26 @@ import (
"gvisor.googlesource.com/gvisor/pkg/log"
)
type contextID int
// Globally accessible values from a context. These keys are defined in the
// context package to resolve dependency cycles by not requiring the caller to
// import packages usually required to get these information.
const (
// CtxThreadGroupID is the current thread group ID when a context represents
// a task context. The value is represented as an int32.
CtxThreadGroupID contextID = iota
)
// ThreadGroupIDFromContext returns the current thread group ID when ctx
// represents a task context.
func ThreadGroupIDFromContext(ctx Context) (tgid int32, ok bool) {
if tgid := ctx.Value(CtxThreadGroupID); tgid != nil {
return tgid.(int32), true
}
return 0, false
}
// A Context represents a thread of execution (hereafter "goroutine" to reflect
// Go idiosyncrasy). It carries state associated with the goroutine across API
// boundaries.
+31 -31
View File
@@ -33,8 +33,8 @@ func TestWalkPositive(t *testing.T) {
ctx := contexttest.Context(t)
root := NewDirent(newMockDirInode(ctx, nil), "root")
if got := root.TestReadRefs(); got != 0 {
t.Fatalf("root has a ref count of %d, want %d", got, 0)
if got := root.ReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
}
name := "d"
@@ -43,22 +43,22 @@ func TestWalkPositive(t *testing.T) {
t.Fatalf("root.walk(root, %q) got %v, want nil", name, err)
}
if got := root.TestReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
if got := root.ReadRefs(); got != 2 {
t.Fatalf("root has a ref count of %d, want %d", got, 2)
}
if got := d.TestReadRefs(); got != 0 {
t.Fatalf("child name = %q has a ref count of %d, want %d", d.name, got, 0)
if got := d.ReadRefs(); got != 1 {
t.Fatalf("child name = %q has a ref count of %d, want %d", d.name, got, 1)
}
d.DecRef()
if got := root.TestReadRefs(); got != 0 {
t.Fatalf("root has a ref count of %d, want %d", got, 0)
if got := root.ReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
}
if got := d.TestReadRefs(); got != -1 {
t.Fatalf("child name = %q has a ref count of %d, want %d", d.name, got, -1)
if got := d.ReadRefs(); got != 0 {
t.Fatalf("child name = %q has a ref count of %d, want %d", d.name, got, 0)
}
root.flush()
@@ -76,8 +76,8 @@ func TestWalkNegative(t *testing.T) {
root := NewDirent(NewEmptyDir(ctx, nil), "root")
mn := root.Inode.InodeOperations.(*mockInodeOperationsLookupNegative)
if got := root.TestReadRefs(); got != 0 {
t.Fatalf("root has a ref count of %d, want %d", got, 0)
if got := root.ReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
}
name := "d"
@@ -88,7 +88,7 @@ func TestWalkNegative(t *testing.T) {
}
}
if got := root.TestReadRefs(); got != 0 {
if got := root.ReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
}
@@ -110,14 +110,14 @@ func TestWalkNegative(t *testing.T) {
t.Fatalf("root found positive child at %q, want negative", name)
}
if got := child.(*Dirent).TestReadRefs(); got != 1 {
t.Fatalf("child has a ref count of %d, want %d", got, 1)
if got := child.(*Dirent).ReadRefs(); got != 2 {
t.Fatalf("child has a ref count of %d, want %d", got, 2)
}
child.DecRef()
if got := child.(*Dirent).TestReadRefs(); got != 0 {
t.Fatalf("child has a ref count of %d, want %d", got, 0)
if got := child.(*Dirent).ReadRefs(); got != 1 {
t.Fatalf("child has a ref count of %d, want %d", got, 1)
}
if got := len(root.children); got != 1 {
@@ -126,7 +126,7 @@ func TestWalkNegative(t *testing.T) {
root.DecRef()
if got := root.TestReadRefs(); got != -1 {
if got := root.ReadRefs(); got != 0 {
t.Fatalf("root has a ref count of %d, want %d", got, 0)
}
@@ -184,12 +184,12 @@ func TestHashNegativeToPositive(t *testing.T) {
t.Fatalf("got negative Dirent, want positive")
}
if got := d.TestReadRefs(); got != 0 {
t.Fatalf("child %q has a ref count of %d, want %d", name, got, 0)
if got := d.ReadRefs(); got != 1 {
t.Fatalf("child %q has a ref count of %d, want %d", name, got, 1)
}
if got := root.TestReadRefs(); got != 1 {
t.Fatalf("root has a ref count of %d, want %d", got, 1)
if got := root.ReadRefs(); got != 2 {
t.Fatalf("root has a ref count of %d, want %d", got, 2)
}
if got := len(root.children); got != 1 {
@@ -291,12 +291,12 @@ func TestCreateExtraRefs(t *testing.T) {
{
desc: "Create caching",
root: NewDirent(NewEmptyDir(ctx, NewDirentCache(1)), "root"),
refs: 1,
refs: 2,
},
{
desc: "Create not caching",
root: NewDirent(NewEmptyDir(ctx, nil), "root"),
refs: 0,
refs: 1,
},
} {
t.Run(test.desc, func(t *testing.T) {
@@ -307,7 +307,7 @@ func TestCreateExtraRefs(t *testing.T) {
}
d := f.Dirent
if got := d.TestReadRefs(); got != test.refs {
if got := d.ReadRefs(); got != test.refs {
t.Errorf("dirent has a ref count of %d, want %d", got, test.refs)
}
})
@@ -347,8 +347,8 @@ func TestRemoveExtraRefs(t *testing.T) {
t.Fatalf("root.Remove(root, %q) failed: %v", name, err)
}
if got := d.TestReadRefs(); got != 0 {
t.Fatalf("dirent has a ref count of %d, want %d", got, 0)
if got := d.ReadRefs(); got != 1 {
t.Fatalf("dirent has a ref count of %d, want %d", got, 1)
}
d.DecRef()
@@ -406,11 +406,11 @@ func TestRenameExtraRefs(t *testing.T) {
newParent.flush()
// Expect to have only active references.
if got := renamed.TestReadRefs(); got != 0 {
t.Errorf("renamed has ref count %d, want only active references %d", got, 0)
if got := renamed.ReadRefs(); got != 1 {
t.Errorf("renamed has ref count %d, want only active references %d", got, 1)
}
if got := replaced.TestReadRefs(); got != 0 {
t.Errorf("replaced has ref count %d, want only active references %d", got, 0)
if got := replaced.ReadRefs(); got != 1 {
t.Errorf("replaced has ref count %d, want only active references %d", got, 1)
}
})
}
+1
View File
@@ -184,6 +184,7 @@ go_library(
"//pkg/sentry/kernel/kdefs",
"//pkg/sentry/kernel/sched",
"//pkg/sentry/kernel/semaphore",
"//pkg/sentry/kernel/shm",
"//pkg/sentry/kernel/time",
"//pkg/sentry/limits",
"//pkg/sentry/loader",
+14 -1
View File
@@ -15,18 +15,26 @@
package kernel
import (
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/semaphore"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/shm"
)
// IPCNamespace represents an IPC namespace.
type IPCNamespace struct {
// User namespace which owns this IPC namespace. Immutable.
userNS *auth.UserNamespace
semaphores *semaphore.Registry
shms *shm.Registry
}
// NewIPCNamespace creates a new IPC namespace.
func NewIPCNamespace() *IPCNamespace {
func NewIPCNamespace(userNS *auth.UserNamespace) *IPCNamespace {
return &IPCNamespace{
userNS: userNS,
semaphores: semaphore.NewRegistry(),
shms: shm.NewRegistry(userNS),
}
}
@@ -35,6 +43,11 @@ func (i *IPCNamespace) SemaphoreRegistry() *semaphore.Registry {
return i.semaphores
}
// ShmRegistry returns the shm segment registry for this namespace.
func (i *IPCNamespace) ShmRegistry() *shm.Registry {
return i.shms
}
// IPCNamespace returns the task's IPC namespace.
func (t *Task) IPCNamespace() *IPCNamespace {
t.mu.Lock()
+40
View File
@@ -0,0 +1,40 @@
package(licenses = ["notice"]) # Apache 2.0
load("@io_bazel_rules_go//go:def.bzl", "go_library")
load("//tools/go_stateify:defs.bzl", "go_stateify")
go_stateify(
name = "shm_state",
srcs = [
"shm.go",
],
out = "shm_autogen_state.go",
package = "shm",
)
go_library(
name = "shm",
srcs = [
"device.go",
"shm.go",
"shm_autogen_state.go",
],
importpath = "gvisor.googlesource.com/gvisor/pkg/sentry/kernel/shm",
visibility = ["//pkg/sentry:internal"],
deps = [
"//pkg/abi/linux",
"//pkg/log",
"//pkg/refs",
"//pkg/sentry/context",
"//pkg/sentry/device",
"//pkg/sentry/fs",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/kernel/time",
"//pkg/sentry/memmap",
"//pkg/sentry/platform",
"//pkg/sentry/usage",
"//pkg/sentry/usermem",
"//pkg/state",
"//pkg/syserror",
],
)
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shm
import "gvisor.googlesource.com/gvisor/pkg/sentry/device"
// shmDevice is the kernel shm device.
var shmDevice = device.NewAnonDevice()
File diff suppressed because it is too large Load Diff
+3
View File
@@ -21,6 +21,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/bpf"
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/fs"
"gvisor.googlesource.com/gvisor/pkg/sentry/inet"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/auth"
@@ -559,6 +560,8 @@ func (t *Task) Value(key interface{}) interface{} {
return t
case auth.CtxCredentials:
return t.creds
case context.CtxThreadGroupID:
return int32(t.ThreadGroup().ID())
case fs.CtxRoot:
return t.FSContext().RootDirectory()
case inet.CtxStack:
+2 -2
View File
@@ -197,7 +197,7 @@ func (t *Task) Clone(opts *CloneOptions) (ThreadID, *SyscallControl, error) {
if opts.NewIPCNamespace {
// Note that "If CLONE_NEWIPC is set, then create the process in a new IPC
// namespace"
ipcns = NewIPCNamespace()
ipcns = NewIPCNamespace(userns)
}
tc, err := t.tc.Fork(t, !opts.NewAddressSpace)
@@ -449,7 +449,7 @@ func (t *Task) Unshare(opts *SharingOptions) error {
}
// Note that "If CLONE_NEWIPC is set, then create the process in a new IPC
// namespace"
t.ipcns = NewIPCNamespace()
t.ipcns = NewIPCNamespace(t.creds.UserNamespace)
}
if opts.NewFiles {
oldFDMap := t.tr.FDMap
+2
View File
@@ -107,6 +107,7 @@ go_library(
"pma_set.go",
"proc_pid_maps.go",
"save_restore.go",
"shm.go",
"special_mappable.go",
"syscalls.go",
"vma.go",
@@ -123,6 +124,7 @@ go_library(
"//pkg/sentry/context",
"//pkg/sentry/fs",
"//pkg/sentry/fs/proc/seqfile",
"//pkg/sentry/kernel/shm",
"//pkg/sentry/limits",
"//pkg/sentry/memmap",
"//pkg/sentry/platform",
+66
View File
@@ -0,0 +1,66 @@
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mm
import (
"gvisor.googlesource.com/gvisor/pkg/sentry/context"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/shm"
"gvisor.googlesource.com/gvisor/pkg/sentry/usermem"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
// DetachShm unmaps a sysv shared memory segment.
func (mm *MemoryManager) DetachShm(ctx context.Context, addr usermem.Addr) error {
if addr != addr.RoundDown() {
// "... shmaddr is not aligned on a page boundary." - man shmdt(2)
return syserror.EINVAL
}
var detached *shm.Shm
mm.mappingMu.Lock()
defer mm.mappingMu.Unlock()
// Find and remove the first vma containing an address >= addr that maps a
// segment originally attached at addr.
vseg := mm.vmas.LowerBoundSegment(addr)
for vseg.Ok() {
vma := vseg.ValuePtr()
if shm, ok := vma.mappable.(*shm.Shm); ok && vseg.Start() >= addr && uint64(vseg.Start()-addr) == vma.off {
detached = shm
vseg = mm.unmapLocked(ctx, vseg.Range()).NextSegment()
break
} else {
vseg = vseg.NextSegment()
}
}
if detached == nil {
// There is no shared memory segment attached at addr.
return syserror.EINVAL
}
// Remove all vmas that could have been created by the same attach.
end := addr + usermem.Addr(detached.EffectiveSize())
for vseg.Ok() && vseg.End() <= end {
vma := vseg.ValuePtr()
if vma.mappable == detached && uint64(vseg.Start()-addr) == vma.off {
vseg = mm.unmapLocked(ctx, vseg.Range()).NextSegment()
} else {
vseg = vseg.NextSegment()
}
}
return nil
}
+2
View File
@@ -44,6 +44,7 @@ go_library(
"sys_rusage.go",
"sys_sched.go",
"sys_sem.go",
"sys_shm.go",
"sys_signal.go",
"sys_socket.go",
"sys_stat.go",
@@ -84,6 +85,7 @@ go_library(
"//pkg/sentry/kernel/pipe",
"//pkg/sentry/kernel/sched",
"//pkg/sentry/kernel/semaphore",
"//pkg/sentry/kernel/shm",
"//pkg/sentry/kernel/time",
"//pkg/sentry/limits",
"//pkg/sentry/memmap",
+4 -4
View File
@@ -75,9 +75,9 @@ var AMD64 = &kernel.SyscallTable{
26: Msync,
27: Mincore,
28: Madvise,
// 29: Shmget, TODO
// 30: Shmat, TODO
// 31: Shmctl, TODO
29: Shmget,
30: Shmat,
31: Shmctl,
32: Dup,
33: Dup2,
34: Pause,
@@ -113,7 +113,7 @@ var AMD64 = &kernel.SyscallTable{
64: Semget,
65: Semop,
66: Semctl,
// 67: Shmdt, TODO
67: Shmdt,
// 68: Msgget, TODO
// 69: Msgsnd, TODO
// 70: Msgrcv, TODO
+155
View File
@@ -0,0 +1,155 @@
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package linux
import (
"gvisor.googlesource.com/gvisor/pkg/abi/linux"
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel"
"gvisor.googlesource.com/gvisor/pkg/sentry/kernel/shm"
"gvisor.googlesource.com/gvisor/pkg/syserror"
)
// Shmget implements shmget(2).
func Shmget(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
key := args[0].Int()
size := uint64(args[1].SizeT())
flag := args[2].Int()
private := key == linux.IPC_PRIVATE
create := flag&linux.IPC_CREAT == linux.IPC_CREAT
exclusive := flag&linux.IPC_EXCL == linux.IPC_EXCL
mode := linux.FileMode(flag & 0777)
pid := int32(t.ThreadGroup().ID())
r := t.IPCNamespace().ShmRegistry()
segment, err := r.FindOrCreate(t, pid, key, size, mode, private, create, exclusive)
if err != nil {
return 0, nil, err
}
return uintptr(segment.ID), nil, nil
}
// findSegment retrives a shm segment by the given id.
func findSegment(t *kernel.Task, id int32) (*shm.Shm, error) {
r := t.IPCNamespace().ShmRegistry()
segment := r.FindByID(id)
if segment == nil {
// No segment with provided id.
return nil, syserror.EINVAL
}
return segment, nil
}
// Shmat implements shmat(2).
func Shmat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
id := args[0].Int()
addr := args[1].Pointer()
flag := args[2].Int()
segment, err := findSegment(t, id)
if err != nil {
return 0, nil, syserror.EINVAL
}
opts, err := segment.ConfigureAttach(t, addr, shm.AttachOpts{
Execute: flag&linux.SHM_EXEC == linux.SHM_EXEC,
Readonly: flag&linux.SHM_RDONLY == linux.SHM_RDONLY,
Remap: flag&linux.SHM_REMAP == linux.SHM_REMAP,
})
if err != nil {
return 0, nil, err
}
defer segment.DecRef()
addr, err = t.MemoryManager().MMap(t, opts)
return uintptr(addr), nil, err
}
// Shmdt implements shmdt(2).
func Shmdt(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
addr := args[0].Pointer()
err := t.MemoryManager().DetachShm(t, addr)
return 0, nil, err
}
// Shmctl implements shmctl(2).
func Shmctl(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
id := args[0].Int()
cmd := args[1].Int()
buf := args[2].Pointer()
r := t.IPCNamespace().ShmRegistry()
switch cmd {
case linux.SHM_STAT:
// Technically, we should be treating id as "an index into the kernel's
// internal array that maintains information about all shared memory
// segments on the system". Since we don't track segments in an array,
// we'll just pretend the shmid is the index and do the same thing as
// IPC_STAT. Linux also uses the index as the shmid.
fallthrough
case linux.IPC_STAT:
segment, err := findSegment(t, id)
if err != nil {
return 0, nil, syserror.EINVAL
}
stat, err := segment.IPCStat(t)
if err == nil {
_, err = t.CopyOut(buf, stat)
}
return 0, nil, err
case linux.IPC_INFO:
params := r.IPCInfo()
_, err := t.CopyOut(buf, params)
return 0, nil, err
case linux.SHM_INFO:
info := r.ShmInfo()
_, err := t.CopyOut(buf, info)
return 0, nil, err
}
// Remaining commands refer to a specific segment.
segment, err := findSegment(t, id)
if err != nil {
return 0, nil, syserror.EINVAL
}
switch cmd {
case linux.IPC_SET:
var ds linux.ShmidDS
_, err = t.CopyIn(buf, &ds)
if err != nil {
return 0, nil, err
}
err = segment.Set(t, &ds)
return 0, nil, err
case linux.IPC_RMID:
segment.MarkDestroyed()
return 0, nil, nil
case linux.SHM_LOCK, linux.SHM_UNLOCK:
// We currently do not support memmory locking anywhere.
// mlock(2)/munlock(2) are currently stubbed out as no-ops so do the
// same here.
return 0, nil, nil
default:
return 0, nil, syserror.EINVAL
}
}
+1 -1
View File
@@ -146,7 +146,7 @@ func New(spec *specs.Spec, conf *Config, controllerFD int, ioFDs []int, console
// not configurable from runtime spec.
utsns := kernel.NewUTSNamespace(spec.Hostname, "", creds.UserNamespace)
ipcns := kernel.NewIPCNamespace()
ipcns := kernel.NewIPCNamespace(creds.UserNamespace)
if err := enableStrace(conf); err != nil {
return nil, fmt.Errorf("failed to enable strace: %v", err)