inet: allow to create abstract unix sockets in non-root namespaces

PiperOrigin-RevId: 573253619
This commit is contained in:
Andrei Vagin
2023-10-13 10:20:56 -07:00
committed by gVisor bot
parent c134ec9283
commit f3b0a527c2
16 changed files with 221 additions and 199 deletions
+10 -11
View File
@@ -225,17 +225,16 @@ func (l *Lifecycle) StartContainer(args *StartContainerArgs, _ *uint32) error {
Filename: args.Filename,
Argv: args.Argv,
// Order Envv before SecretEnvv.
Envv: append(args.Envv, args.SecretEnvv...),
WorkingDirectory: args.WorkingDirectory,
Credentials: creds,
Umask: 0022,
Limits: ls,
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
UTSNamespace: l.Kernel.RootUTSNamespace(),
IPCNamespace: l.Kernel.RootIPCNamespace(),
AbstractSocketNamespace: l.Kernel.RootAbstractSocketNamespace(),
ContainerID: args.ContainerID,
PIDNamespace: pidNs,
Envv: append(args.Envv, args.SecretEnvv...),
WorkingDirectory: args.WorkingDirectory,
Credentials: creds,
Umask: 0022,
Limits: ls,
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
UTSNamespace: l.Kernel.RootUTSNamespace(),
IPCNamespace: l.Kernel.RootIPCNamespace(),
ContainerID: args.ContainerID,
PIDNamespace: pidNs,
}
ctx := initArgs.NewContext(l.Kernel)
+14 -15
View File
@@ -198,21 +198,20 @@ func (proc *Proc) execAsync(args *ExecArgs) (*kernel.ThreadGroup, kernel.ThreadI
limitSet = limits.NewLimitSet()
}
initArgs := kernel.CreateProcessArgs{
Filename: args.Filename,
Argv: args.Argv,
Envv: args.Envv,
WorkingDirectory: args.WorkingDirectory,
MountNamespace: args.MountNamespace,
Credentials: creds,
FDTable: fdTable,
Umask: 0022,
Limits: limitSet,
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
UTSNamespace: proc.Kernel.RootUTSNamespace(),
IPCNamespace: proc.Kernel.RootIPCNamespace(),
AbstractSocketNamespace: proc.Kernel.RootAbstractSocketNamespace(),
ContainerID: args.ContainerID,
PIDNamespace: pidns,
Filename: args.Filename,
Argv: args.Argv,
Envv: args.Envv,
WorkingDirectory: args.WorkingDirectory,
MountNamespace: args.MountNamespace,
Credentials: creds,
FDTable: fdTable,
Umask: 0022,
Limits: limitSet,
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
UTSNamespace: proc.Kernel.RootUTSNamespace(),
IPCNamespace: proc.Kernel.RootIPCNamespace(),
ContainerID: args.ContainerID,
PIDNamespace: pidns,
}
if initArgs.MountNamespace != nil {
// initArgs must hold a reference on MountNamespace, which will
+1 -1
View File
@@ -656,7 +656,7 @@ func (i *inode) open(ctx context.Context, d *kernfs.Dentry, mnt *vfs.Mount, file
return nil, err
}
// Currently, we only allow Unix sockets to be imported.
return unixsocket.NewFileDescription(ep, ep.Type(), flags, mnt, d.VFSDentry(), &i.locks)
return unixsocket.NewFileDescription(ep, ep.Type(), flags, nil, mnt, d.VFSDentry(), &i.locks)
case unix.S_IFREG, unix.S_IFIFO, unix.S_IFCHR:
if i.isTTY {
+20 -22
View File
@@ -91,15 +91,14 @@ func Boot() (*kernel.Kernel, error) {
// Initiate the Kernel object, which is required by the Context passed
// to createVFS in order to mount (among other things) procfs.
if err = k.Init(kernel.InitKernelArgs{
ApplicationCores: uint(runtime.GOMAXPROCS(-1)),
FeatureSet: cpuid.HostFeatureSet(),
Timekeeper: tk,
RootUserNamespace: creds.UserNamespace,
Vdso: vdso,
RootUTSNamespace: kernel.NewUTSNamespace("hostname", "domain", creds.UserNamespace),
RootIPCNamespace: kernel.NewIPCNamespace(creds.UserNamespace),
RootAbstractSocketNamespace: kernel.NewAbstractSocketNamespace(),
PIDNamespace: kernel.NewRootPIDNamespace(creds.UserNamespace),
ApplicationCores: uint(runtime.GOMAXPROCS(-1)),
FeatureSet: cpuid.HostFeatureSet(),
Timekeeper: tk,
RootUserNamespace: creds.UserNamespace,
Vdso: vdso,
RootUTSNamespace: kernel.NewUTSNamespace("hostname", "domain", creds.UserNamespace),
RootIPCNamespace: kernel.NewIPCNamespace(creds.UserNamespace),
PIDNamespace: kernel.NewRootPIDNamespace(creds.UserNamespace),
}); err != nil {
return nil, fmt.Errorf("initializing kernel: %v", err)
}
@@ -135,19 +134,18 @@ func CreateTask(ctx context.Context, name string, tc *kernel.ThreadGroup, mntns
creds := auth.CredentialsFromContext(ctx)
config := &kernel.TaskConfig{
Kernel: k,
ThreadGroup: tc,
TaskImage: &kernel.TaskImage{Name: name, MemoryManager: m},
Credentials: auth.CredentialsFromContext(ctx),
NetworkNamespace: k.RootNetworkNamespace(),
AllowedCPUMask: sched.NewFullCPUSet(k.ApplicationCores()),
UTSNamespace: kernel.UTSNamespaceFromContext(ctx),
IPCNamespace: kernel.IPCNamespaceFromContext(ctx),
AbstractSocketNamespace: kernel.NewAbstractSocketNamespace(),
MountNamespace: mntns,
FSContext: kernel.NewFSContext(root, cwd, 0022),
FDTable: k.NewFDTable(),
UserCounters: k.GetUserCounters(creds.RealKUID),
Kernel: k,
ThreadGroup: tc,
TaskImage: &kernel.TaskImage{Name: name, MemoryManager: m},
Credentials: auth.CredentialsFromContext(ctx),
NetworkNamespace: k.RootNetworkNamespace(),
AllowedCPUMask: sched.NewFullCPUSet(k.ApplicationCores()),
UTSNamespace: kernel.UTSNamespaceFromContext(ctx),
IPCNamespace: kernel.IPCNamespaceFromContext(ctx),
MountNamespace: mntns,
FSContext: kernel.NewFSContext(root, cwd, 0022),
FDTable: k.NewFDTable(),
UserCounters: k.GetUserCounters(creds.RealKUID),
}
config.NetworkNamespace.IncRef()
t, err := k.TaskSet().NewTask(ctx, config)
+4
View File
@@ -21,6 +21,7 @@ go_template_instance(
go_library(
name = "inet",
srcs = [
"abstract_socket_namespace.go",
"context.go",
"inet.go",
"namespace.go",
@@ -34,6 +35,9 @@ go_library(
"//pkg/refs",
"//pkg/sentry/fsimpl/nsfs",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/socket/unix/transport",
"//pkg/sync",
"//pkg/syserr",
"//pkg/tcpip",
"//pkg/tcpip/stack",
],
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package kernel
package inet
import (
"fmt"
@@ -47,13 +47,6 @@ type AbstractSocketNamespace struct {
endpoints map[string]abstractEndpoint
}
// NewAbstractSocketNamespace returns a new AbstractSocketNamespace.
func NewAbstractSocketNamespace() *AbstractSocketNamespace {
return &AbstractSocketNamespace{
endpoints: make(map[string]abstractEndpoint),
}
}
// A boundEndpoint wraps a transport.BoundEndpoint to maintain a reference on
// its backing socket.
type boundEndpoint struct {
@@ -67,6 +60,10 @@ func (e *boundEndpoint) Release(ctx context.Context) {
e.BoundEndpoint.Release(ctx)
}
func (a *AbstractSocketNamespace) init() {
a.endpoints = make(map[string]abstractEndpoint)
}
// BoundEndpoint retrieves the endpoint bound to the given name. The return
// value is nil if no endpoint was bound.
func (a *AbstractSocketNamespace) BoundEndpoint(name string) transport.BoundEndpoint {
+10
View File
@@ -40,6 +40,9 @@ type Namespace struct {
isRoot bool
userNS *auth.UserNamespace
// abstractSockets tracks abstract sockets that are in use.
abstractSockets AbstractSocketNamespace
}
// NewRootNamespace creates the root network namespace, with creator
@@ -52,6 +55,7 @@ func NewRootNamespace(stack Stack, creator NetworkStackCreator, userNS *auth.Use
isRoot: true,
userNS: userNS,
}
n.abstractSockets.init()
return n
}
@@ -137,6 +141,7 @@ func (n *Namespace) init() {
panic(err)
}
}
n.abstractSockets.init()
}
// afterLoad is invoked by stateify.
@@ -144,6 +149,11 @@ func (n *Namespace) afterLoad() {
n.init()
}
// AbstractSockets returns AbstractSocketNamespace.
func (n *Namespace) AbstractSockets() *AbstractSocketNamespace {
return &n.abstractSockets
}
// NetworkStackCreator allows new instances of a network stack to be created. It
// is used by the kernel to create new network namespaces when requested.
type NetworkStackCreator interface {
+1 -2
View File
@@ -1,6 +1,6 @@
load("//pkg/sync/locking:locking.bzl", "declare_mutex", "declare_rwmutex")
load("//tools:defs.bzl", "go_library", "go_test", "proto_library")
load("//tools/go_generics:defs.bzl", "go_template_instance")
load("//pkg/sync/locking:locking.bzl", "declare_mutex", "declare_rwmutex")
package(
default_applicable_licenses = ["//:license"],
@@ -225,7 +225,6 @@ proto_library(
go_library(
name = "kernel",
srcs = [
"abstract_socket_namespace.go",
"aio.go",
"atomicptr_bucket_slice_unsafe.go",
"atomicptr_bucket_unsafe.go",
+25 -39
View File
@@ -139,18 +139,17 @@ type Kernel struct {
mf *pgalloc.MemoryFile `state:"nosave"`
// See InitKernelArgs for the meaning of these fields.
featureSet cpuid.FeatureSet
timekeeper *Timekeeper
tasks *TaskSet
rootUserNamespace *auth.UserNamespace
rootNetworkNamespace *inet.Namespace
applicationCores uint
useHostCores bool
extraAuxv []arch.AuxEntry
vdso *loader.VDSO
rootUTSNamespace *UTSNamespace
rootIPCNamespace *IPCNamespace
rootAbstractSocketNamespace *AbstractSocketNamespace
featureSet cpuid.FeatureSet
timekeeper *Timekeeper
tasks *TaskSet
rootUserNamespace *auth.UserNamespace
rootNetworkNamespace *inet.Namespace
applicationCores uint
useHostCores bool
extraAuxv []arch.AuxEntry
vdso *loader.VDSO
rootUTSNamespace *UTSNamespace
rootIPCNamespace *IPCNamespace
// futexes is the "root" futex.Manager, from which all others are forked.
// This is necessary to ensure that shared futexes are coherent across all
@@ -366,9 +365,6 @@ type InitKernelArgs struct {
// RootIPCNamespace is the root IPC namespace.
RootIPCNamespace *IPCNamespace
// RootAbstractSocketNamespace is the root Abstract Socket namespace.
RootAbstractSocketNamespace *AbstractSocketNamespace
// PIDNamespace is the root PID namespace.
PIDNamespace *PIDNamespace
}
@@ -397,7 +393,6 @@ func (k *Kernel) Init(args InitKernelArgs) error {
k.rootUserNamespace = args.RootUserNamespace
k.rootUTSNamespace = args.RootUTSNamespace
k.rootIPCNamespace = args.RootIPCNamespace
k.rootAbstractSocketNamespace = args.RootAbstractSocketNamespace
k.rootNetworkNamespace = args.RootNetworkNamespace
if k.rootNetworkNamespace == nil {
k.rootNetworkNamespace = inet.NewRootNamespace(nil, nil, args.RootUserNamespace)
@@ -727,9 +722,6 @@ type CreateProcessArgs struct {
// PIDNamespace is the initial PID Namespace.
PIDNamespace *PIDNamespace
// AbstractSocketNamespace is the initial Abstract Socket namespace.
AbstractSocketNamespace *AbstractSocketNamespace
// MountNamespace optionally contains the mount namespace for this
// process. If nil, the init process's mount namespace is used.
//
@@ -937,21 +929,20 @@ func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID,
// Create the task.
config := &TaskConfig{
Kernel: k,
ThreadGroup: tg,
TaskImage: image,
FSContext: fsContext,
FDTable: args.FDTable,
Credentials: args.Credentials,
NetworkNamespace: k.RootNetworkNamespace(),
AllowedCPUMask: sched.NewFullCPUSet(k.applicationCores),
UTSNamespace: args.UTSNamespace,
IPCNamespace: args.IPCNamespace,
AbstractSocketNamespace: args.AbstractSocketNamespace,
MountNamespace: mntns,
ContainerID: args.ContainerID,
InitialCgroups: args.InitialCgroups,
UserCounters: k.GetUserCounters(args.Credentials.RealKUID),
Kernel: k,
ThreadGroup: tg,
TaskImage: image,
FSContext: fsContext,
FDTable: args.FDTable,
Credentials: args.Credentials,
NetworkNamespace: k.RootNetworkNamespace(),
AllowedCPUMask: sched.NewFullCPUSet(k.applicationCores),
UTSNamespace: args.UTSNamespace,
IPCNamespace: args.IPCNamespace,
MountNamespace: mntns,
ContainerID: args.ContainerID,
InitialCgroups: args.InitialCgroups,
UserCounters: k.GetUserCounters(args.Credentials.RealKUID),
// A task with no parent starts out with no session keyring.
SessionKeyring: nil,
}
@@ -1324,11 +1315,6 @@ func (k *Kernel) RootPIDNamespace() *PIDNamespace {
return k.tasks.Root
}
// RootAbstractSocketNamespace returns the root AbstractSocketNamespace.
func (k *Kernel) RootAbstractSocketNamespace() *AbstractSocketNamespace {
return k.rootAbstractSocketNamespace
}
// RootNetworkNamespace returns the root network namespace, always non-nil.
func (k *Kernel) RootNetworkNamespace() *inet.Namespace {
return k.rootNetworkNamespace
-10
View File
@@ -441,11 +441,6 @@ type Task struct {
// ipcns is protected by mu. ipcns is owned by the task goroutine.
ipcns *IPCNamespace
// abstractSockets tracks abstract sockets that are in use.
//
// abstractSockets is protected by mu.
abstractSockets *AbstractSocketNamespace
// mountNamespace is the task's mount namespace.
//
// It is protected by mu. It is owned by the task goroutine.
@@ -809,11 +804,6 @@ func (t *Task) GetMountNamespace() *vfs.MountNamespace {
return mntns
}
// AbstractSockets returns t's AbstractSocketNamespace.
func (t *Task) AbstractSockets() *AbstractSocketNamespace {
return t.abstractSockets
}
// ContainerID returns t's container ID.
func (t *Task) ContainerID() string {
return t.containerID
+18 -19
View File
@@ -248,25 +248,24 @@ func (t *Task) Clone(args *linux.CloneArgs) (ThreadID, *SyscallControl, error) {
}
cfg := &TaskConfig{
Kernel: t.k,
ThreadGroup: tg,
SignalMask: t.SignalMask(),
TaskImage: image,
FSContext: fsContext,
FDTable: fdTable,
Credentials: creds,
Niceness: t.Niceness(),
NetworkNamespace: netns,
AllowedCPUMask: t.CPUMask(),
UTSNamespace: utsns,
IPCNamespace: ipcns,
AbstractSocketNamespace: t.abstractSockets,
MountNamespace: mntns,
RSeqAddr: rseqAddr,
RSeqSignature: rseqSignature,
ContainerID: t.ContainerID(),
UserCounters: uc,
SessionKeyring: sessionKeyring,
Kernel: t.k,
ThreadGroup: tg,
SignalMask: t.SignalMask(),
TaskImage: image,
FSContext: fsContext,
FDTable: fdTable,
Credentials: creds,
Niceness: t.Niceness(),
NetworkNamespace: netns,
AllowedCPUMask: t.CPUMask(),
UTSNamespace: utsns,
IPCNamespace: ipcns,
MountNamespace: mntns,
RSeqAddr: rseqAddr,
RSeqSignature: rseqSignature,
ContainerID: t.ContainerID(),
UserCounters: uc,
SessionKeyring: sessionKeyring,
}
if args.Flags&linux.CLONE_THREAD == 0 {
cfg.Parent = t
+23 -27
View File
@@ -81,9 +81,6 @@ type TaskConfig struct {
// IPCNamespace is the IPCNamespace of the new task.
IPCNamespace *IPCNamespace
// AbstractSocketNamespace is the AbstractSocketNamespace of the new task.
AbstractSocketNamespace *AbstractSocketNamespace
// MountNamespace is the MountNamespace of the new task.
MountNamespace *vfs.MountNamespace
@@ -152,30 +149,29 @@ func (ts *TaskSet) newTask(ctx context.Context, cfg *TaskConfig) (*Task, error)
parent: cfg.Parent,
children: make(map[*Task]struct{}),
},
runState: (*runApp)(nil),
interruptChan: make(chan struct{}, 1),
signalMask: atomicbitops.FromUint64(uint64(cfg.SignalMask)),
signalStack: linux.SignalStack{Flags: linux.SS_DISABLE},
image: *image,
fsContext: cfg.FSContext,
fdTable: cfg.FDTable,
k: cfg.Kernel,
ptraceTracees: make(map[*Task]struct{}),
allowedCPUMask: cfg.AllowedCPUMask.Copy(),
ioUsage: &usage.IO{},
niceness: cfg.Niceness,
utsns: cfg.UTSNamespace,
ipcns: cfg.IPCNamespace,
abstractSockets: cfg.AbstractSocketNamespace,
mountNamespace: cfg.MountNamespace,
rseqCPU: -1,
rseqAddr: cfg.RSeqAddr,
rseqSignature: cfg.RSeqSignature,
futexWaiter: futex.NewWaiter(),
containerID: cfg.ContainerID,
cgroups: make(map[Cgroup]struct{}),
userCounters: cfg.UserCounters,
sessionKeyring: cfg.SessionKeyring,
runState: (*runApp)(nil),
interruptChan: make(chan struct{}, 1),
signalMask: atomicbitops.FromUint64(uint64(cfg.SignalMask)),
signalStack: linux.SignalStack{Flags: linux.SS_DISABLE},
image: *image,
fsContext: cfg.FSContext,
fdTable: cfg.FDTable,
k: cfg.Kernel,
ptraceTracees: make(map[*Task]struct{}),
allowedCPUMask: cfg.AllowedCPUMask.Copy(),
ioUsage: &usage.IO{},
niceness: cfg.Niceness,
utsns: cfg.UTSNamespace,
ipcns: cfg.IPCNamespace,
mountNamespace: cfg.MountNamespace,
rseqCPU: -1,
rseqAddr: cfg.RSeqAddr,
rseqSignature: cfg.RSeqSignature,
futexWaiter: futex.NewWaiter(),
containerID: cfg.ContainerID,
cgroups: make(map[Cgroup]struct{}),
userCounters: cfg.UserCounters,
sessionKeyring: cfg.SessionKeyring,
}
t.netns = cfg.NetworkNamespace
t.creds.Store(cfg.Credentials)
+24 -23
View File
@@ -30,6 +30,7 @@ import (
"gvisor.dev/gvisor/pkg/marshal"
"gvisor.dev/gvisor/pkg/sentry/arch"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/sockfs"
"gvisor.dev/gvisor/pkg/sentry/inet"
"gvisor.dev/gvisor/pkg/sentry/kernel"
ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time"
"gvisor.dev/gvisor/pkg/sentry/socket"
@@ -54,14 +55,15 @@ type Socket struct {
socket.SendReceiveTimeout
socketRefs
ep transport.Endpoint
stype linux.SockType
namespace *inet.Namespace
ep transport.Endpoint
stype linux.SockType
// abstractName and abstractNamespace indicate the name and namespace of the
// socket if it is bound to an abstract socket namespace. Once the socket is
// bound, they cannot be modified.
abstractName string
abstractNamespace *kernel.AbstractSocketNamespace
abstractName string
abstractBound bool
}
var _ = socket.Socket(&Socket{})
@@ -73,8 +75,10 @@ func NewSockfsFile(t *kernel.Task, ep transport.Endpoint, stype linux.SockType)
d := sockfs.NewDentry(t, mnt)
defer d.DecRef(t)
fd, err := NewFileDescription(ep, stype, linux.O_RDWR, mnt, d, &vfs.FileLocks{})
ns := t.GetNetworkNamespace()
fd, err := NewFileDescription(ep, stype, linux.O_RDWR, ns, mnt, d, &vfs.FileLocks{})
if err != nil {
ns.DecRef(t)
return nil, syserr.FromError(err)
}
return fd, nil
@@ -82,7 +86,7 @@ func NewSockfsFile(t *kernel.Task, ep transport.Endpoint, stype linux.SockType)
// NewFileDescription creates and returns a socket file description
// corresponding to the given mount and dentry.
func NewFileDescription(ep transport.Endpoint, stype linux.SockType, flags uint32, mnt *vfs.Mount, d *vfs.Dentry, locks *vfs.FileLocks) (*vfs.FileDescription, error) {
func NewFileDescription(ep transport.Endpoint, stype linux.SockType, flags uint32, ns *inet.Namespace, mnt *vfs.Mount, d *vfs.Dentry, locks *vfs.FileLocks) (*vfs.FileDescription, error) {
// You can create AF_UNIX, SOCK_RAW sockets. They're the same as
// SOCK_DGRAM and don't require CAP_NET_RAW.
if stype == linux.SOCK_RAW {
@@ -90,8 +94,9 @@ func NewFileDescription(ep transport.Endpoint, stype linux.SockType, flags uint3
}
sock := &Socket{
ep: ep,
stype: stype,
ep: ep,
stype: stype,
namespace: ns,
}
sock.InitRefs()
sock.LockFD.Init(locks)
@@ -111,8 +116,11 @@ func (s *Socket) DecRef(ctx context.Context) {
s.socketRefs.DecRef(func() {
kernel.KernelFromContext(ctx).DeleteSocket(&s.vfsfd)
s.ep.Close(ctx)
if s.abstractNamespace != nil {
s.abstractNamespace.Remove(s.abstractName, s)
if s.abstractBound {
s.namespace.AbstractSockets().Remove(s.abstractName, s)
}
if s.namespace != nil {
s.namespace.DecRef(ctx)
}
})
}
@@ -214,10 +222,7 @@ func (s *Socket) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error {
// If path is empty, the socket is autobound to an abstract address.
if len(p) == 0 || p[0] == 0 {
// Abstract socket. See net/unix/af_unix.c:unix_bind_abstract().
if t.IsNetworkNamespaced() {
return syserr.ErrInvalidEndpointState
}
asn := t.AbstractSockets()
asn := s.namespace.AbstractSockets()
p, err := asn.Bind(t, p, bep, s)
if err != nil {
return err
@@ -229,7 +234,7 @@ func (s *Socket) Bind(t *kernel.Task, sockaddr []byte) *syserr.Error {
}
// The socket has been successfully bound. We can update the following.
s.abstractName = name
s.abstractNamespace = asn
s.abstractBound = true
return nil
}
@@ -518,7 +523,7 @@ func (s *Socket) Listen(t *kernel.Task, backlog int) *syserr.Error {
// extractEndpoint retrieves the transport.BoundEndpoint associated with a Unix
// socket path. The Release must be called on the transport.BoundEndpoint when
// the caller is done with it.
func extractEndpoint(t *kernel.Task, sockaddr []byte) (transport.BoundEndpoint, *syserr.Error) {
func (s *Socket) extractEndpoint(t *kernel.Task, sockaddr []byte) (transport.BoundEndpoint, *syserr.Error) {
path, err := extractPath(sockaddr)
if err != nil {
return nil, err
@@ -530,11 +535,7 @@ func extractEndpoint(t *kernel.Task, sockaddr []byte) (transport.BoundEndpoint,
// Is it abstract?
if path[0] == 0 {
if t.IsNetworkNamespaced() {
return nil, syserr.ErrInvalidArgument
}
ep := t.AbstractSockets().BoundEndpoint(path[1:])
ep := s.namespace.AbstractSockets().BoundEndpoint(path[1:])
if ep == nil {
// No socket found.
return nil, syserr.ErrConnectionRefused
@@ -569,7 +570,7 @@ func extractEndpoint(t *kernel.Task, sockaddr []byte) (transport.BoundEndpoint,
// Connect implements the linux syscall connect(2) for unix sockets.
func (s *Socket) Connect(t *kernel.Task, sockaddr []byte, blocking bool) *syserr.Error {
ep, err := extractEndpoint(t, sockaddr)
ep, err := s.extractEndpoint(t, sockaddr)
if err != nil {
return err
}
@@ -609,7 +610,7 @@ func (s *Socket) SendMsg(t *kernel.Task, src usermem.IOSequence, to []byte, flag
}
return 0, syserr.ErrNotSupported
default:
ep, err := extractEndpoint(t, to)
ep, err := s.extractEndpoint(t, to)
if err != nil {
return 0, err
}
+20 -22
View File
@@ -441,16 +441,15 @@ func New(args Args) (*Loader, error) {
// Initiate the Kernel object, which is required by the Context passed
// to createVFS in order to mount (among other things) procfs.
if err = k.Init(kernel.InitKernelArgs{
FeatureSet: cpuid.HostFeatureSet().Fixed(),
Timekeeper: tk,
RootUserNamespace: creds.UserNamespace,
RootNetworkNamespace: netns,
ApplicationCores: uint(args.NumCPU),
Vdso: vdso,
RootUTSNamespace: kernel.NewUTSNamespace(args.Spec.Hostname, args.Spec.Hostname, creds.UserNamespace),
RootIPCNamespace: kernel.NewIPCNamespace(creds.UserNamespace),
RootAbstractSocketNamespace: kernel.NewAbstractSocketNamespace(),
PIDNamespace: kernel.NewRootPIDNamespace(creds.UserNamespace),
FeatureSet: cpuid.HostFeatureSet().Fixed(),
Timekeeper: tk,
RootUserNamespace: creds.UserNamespace,
RootNetworkNamespace: netns,
ApplicationCores: uint(args.NumCPU),
Vdso: vdso,
RootUTSNamespace: kernel.NewUTSNamespace(args.Spec.Hostname, args.Spec.Hostname, creds.UserNamespace),
RootIPCNamespace: kernel.NewIPCNamespace(creds.UserNamespace),
PIDNamespace: kernel.NewRootPIDNamespace(creds.UserNamespace),
}); err != nil {
return nil, fmt.Errorf("initializing kernel: %w", err)
}
@@ -559,18 +558,17 @@ func createProcessArgs(id string, spec *specs.Spec, creds *auth.Credentials, k *
// Create the process arguments.
procArgs := kernel.CreateProcessArgs{
Argv: spec.Process.Args,
Envv: env,
WorkingDirectory: wd,
Credentials: creds,
Umask: 0022,
Limits: ls,
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
UTSNamespace: k.RootUTSNamespace(),
IPCNamespace: k.RootIPCNamespace(),
AbstractSocketNamespace: k.RootAbstractSocketNamespace(),
ContainerID: id,
PIDNamespace: pidns,
Argv: spec.Process.Args,
Envv: env,
WorkingDirectory: wd,
Credentials: creds,
Umask: 0022,
Limits: ls,
MaxSymlinkTraversals: linux.MaxSymlinkTraversals,
UTSNamespace: k.RootUTSNamespace(),
IPCNamespace: k.RootIPCNamespace(),
ContainerID: id,
PIDNamespace: pidns,
}
return procArgs, nil
+3
View File
@@ -3673,6 +3673,9 @@ cc_binary(
":unix_domain_socket_test_util",
"//test/util:socket_util",
gtest,
"//test/util:capability_util",
"//test/util:cleanup",
"//test/util:file_descriptor",
"//test/util:test_main",
"//test/util:test_util",
],
@@ -13,12 +13,17 @@
// limitations under the License.
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/un.h>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "test/syscalls/linux/unix_domain_socket_test_util.h"
#include "test/util/cleanup.h"
#include "test/util/file_descriptor.h"
#include "test/util/linux_capability_util.h"
#include "test/util/socket_util.h"
#include "test/util/test_util.h"
@@ -118,6 +123,44 @@ TEST_P(UnboundAbstractUnixSocketPairTest, AutoBindAddrInUse) {
SyscallFailsWithErrno(EADDRINUSE));
}
TEST_P(UnboundAbstractUnixSocketPairTest, BindConnectInSubNamespace) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
const FileDescriptor ns =
ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/ns/net", O_RDONLY));
auto cleanup =
Cleanup([&ns] { ASSERT_THAT(setns(ns.get(), 0), SyscallSucceeds()); });
ASSERT_THAT(unshare(CLONE_NEWNET), SyscallSucceeds());
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
ASSERT_THAT(unshare(CLONE_NEWNET), SyscallSucceeds());
struct sockaddr_un addr = {.sun_family = AF_UNIX};
ASSERT_THAT(
bind(sockets->first_fd(), reinterpret_cast<struct sockaddr*>(&addr),
sizeof(sa_family_t)),
SyscallSucceeds());
socklen_t addr_len = sizeof(addr);
ASSERT_THAT(getsockname(sockets->first_fd(),
reinterpret_cast<struct sockaddr*>(&addr), &addr_len),
SyscallSucceeds());
if ((GetParam().type & SOCK_DGRAM) == 0) {
ASSERT_THAT(listen(sockets->first_fd(), 1 /* backlog */),
SyscallSucceeds());
}
EXPECT_THAT(connect(sockets->second_fd(),
reinterpret_cast<struct sockaddr*>(&addr), addr_len),
SyscallSucceeds());
auto socketsInSubNS = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
EXPECT_THAT(connect(socketsInSubNS->second_fd(),
reinterpret_cast<struct sockaddr*>(&addr), addr_len),
SyscallFailsWithErrno(ECONNREFUSED));
EXPECT_THAT(bind(socketsInSubNS->first_fd(),
reinterpret_cast<struct sockaddr*>(&addr), addr_len),
SyscallSucceeds());
}
TEST_P(UnboundAbstractUnixSocketPairTest, ListenZeroBacklog) {
SKIP_IF((GetParam().type & SOCK_DGRAM) != 0);
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());