Skip to content

Commit ac3f477

Browse files
AnilAltinaygvisor-bot
authored andcommitted
Implement SO_PEERCRED socket option for UNIX sockets and its tests.
PiperOrigin-RevId: 784391386
1 parent a15d70c commit ac3f477

File tree

15 files changed

+384
-9
lines changed

15 files changed

+384
-9
lines changed

pkg/sentry/socket/hostinet/socket.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"gvisor.dev/gvisor/pkg/errors/linuxerr"
2525
"gvisor.dev/gvisor/pkg/fdnotifier"
2626
"gvisor.dev/gvisor/pkg/log"
27+
"gvisor.dev/gvisor/pkg/marshal"
2728
"gvisor.dev/gvisor/pkg/marshal/primitive"
2829
"gvisor.dev/gvisor/pkg/safemem"
2930
"gvisor.dev/gvisor/pkg/sentry/arch"
@@ -828,3 +829,8 @@ func init() {
828829
registered[fam] = struct{}{}
829830
}
830831
}
832+
833+
// GetPeerCreds implements socket.Socket.GetPeerCreds
834+
func (s *Socket) GetPeerCreds(t *kernel.Task) (marshal.Marshallable, *syserr.Error) {
835+
return nil, syserr.ErrNotSupported
836+
}

pkg/sentry/socket/netlink/socket.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,11 @@ func (s *Socket) GetPeerName(t *kernel.Task) (linux.SockAddr, uint32, *syserr.Er
568568
return sa, uint32(sa.SizeBytes()), nil
569569
}
570570

571+
// GetPeerCreds implements socket.Socket.GetPeerCreds.
572+
func (s *Socket) GetPeerCreds(t *kernel.Task) (marshal.Marshallable, *syserr.Error) {
573+
return nil, syserr.ErrNotSupported
574+
}
575+
571576
// RecvMsg implements socket.Socket.RecvMsg.
572577
func (s *Socket) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags int, haveDeadline bool, deadline ktime.Time, senderRequested bool, controlDataLen uint64) (int, int, linux.SockAddr, uint32, socket.ControlMessages, *syserr.Error) {
573578
from := &linux.SockAddrNetlink{

pkg/sentry/socket/netstack/netstack.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -980,14 +980,7 @@ func getSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, family
980980
if family != linux.AF_UNIX || outLen < unix.SizeofUcred {
981981
return nil, syserr.ErrInvalidArgument
982982
}
983-
984-
tcred := t.Credentials()
985-
creds := linux.ControlMessageCredentials{
986-
PID: int32(t.ThreadGroup().ID()),
987-
UID: uint32(tcred.EffectiveKUID.In(tcred.UserNamespace).OrOverflow()),
988-
GID: uint32(tcred.EffectiveKGID.In(tcred.UserNamespace).OrOverflow()),
989-
}
990-
return &creds, nil
983+
return s.GetPeerCreds(t)
991984

992985
case linux.SO_PASSCRED:
993986
if outLen < sizeOfInt32 {
@@ -3026,6 +3019,10 @@ func (s *sock) GetPeerName(*kernel.Task) (linux.SockAddr, uint32, *syserr.Error)
30263019
return a, l, nil
30273020
}
30283021

3022+
func (s *sock) GetPeerCreds(*kernel.Task) (marshal.Marshallable, *syserr.Error) {
3023+
return nil, syserr.ErrNotSupported
3024+
}
3025+
30293026
func (s *sock) fillCmsgInq(cmsg *socket.ControlMessages) {
30303027
if !s.sockOptInq {
30313028
return

pkg/sentry/socket/plugin/stack/socket.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,11 @@ func (s *socketOperations) GetPeerName(t *kernel.Task) (linux.SockAddr, uint32,
569569
return socket.UnmarshalSockAddr(s.family, addr), addrlen, nil
570570
}
571571

572+
// GetPeerCreds implements socket.Socket.GetPeerCreds.
573+
func (s *socketOperations) GetPeerCreds(t *kernel.Task) (marshal.Marshallable, *syserr.Error) {
574+
return nil, syserr.ErrInvalidEndpointState
575+
}
576+
572577
// recv is a helper function for doing non-blocking read once.
573578
// It returns:
574579
// 1. number of bytes received;

pkg/sentry/socket/socket.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,9 @@ type Socket interface {
257257
// necessarily the actual length of the address.
258258
GetPeerName(t *kernel.Task) (addr linux.SockAddr, addrLen uint32, err *syserr.Error)
259259

260+
// GetPeerCreds returns the peer credentials of the socket.
261+
GetPeerCreds(t *kernel.Task) (marshal.Marshallable, *syserr.Error)
262+
260263
// RecvMsg implements the recvmsg(2) linux unix.
261264
//
262265
// senderAddrLen is the address length to be returned to the application,

pkg/sentry/socket/unix/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ go_library(
4242
"//pkg/sentry/fsutil",
4343
"//pkg/sentry/inet",
4444
"//pkg/sentry/kernel",
45+
"//pkg/sentry/kernel/auth",
4546
"//pkg/sentry/ktime",
4647
"//pkg/sentry/socket",
4748
"//pkg/sentry/socket/control",

pkg/sentry/socket/unix/transport/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ go_library(
9797
"//pkg/log",
9898
"//pkg/refs",
9999
"//pkg/sentry/hostfd",
100+
"//pkg/sentry/kernel/auth",
100101
"//pkg/sentry/uniqueid",
101102
"//pkg/sync",
102103
"//pkg/sync/locking",

pkg/sentry/socket/unix/transport/connectioned.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,14 @@ type connectionedEndpoint struct {
106106
// tcpip.SockStream.
107107
stype linux.SockType
108108

109+
// peerCreds is used to store the peer credentials.
110+
// This will store the socket's own credentials until the connection is
111+
// established with connect(2). Once the connection is established, this
112+
// will store the peer's credentials. The use of this option is possible
113+
// only for connected `AF_UNIX` stream sockets and for `AF_UNIX` stream and
114+
// datagram socket pairs created using socketpair(2)
115+
peerCreds CredentialsControlMessage
116+
109117
// acceptedChan is per the TCP endpoint implementation. Note that the
110118
// sockets in this channel are _already in the connected state_, and
111119
// have another associated connectionedEndpoint.
@@ -274,6 +282,16 @@ func (e *connectionedEndpoint) Close(ctx context.Context) {
274282
}
275283
}
276284

285+
func (e *connectionedEndpoint) swapPeerCreds(ctx context.Context, cend ConnectingEndpoint, ne *connectionedEndpoint) *syserr.Error {
286+
ce, ok := cend.(*connectionedEndpoint)
287+
if !ok {
288+
return syserr.ErrInvalidEndpointState
289+
}
290+
// Swap peer credentials between the two endpoints.
291+
ne.peerCreds, ce.peerCreds = ce.peerCreds, ne.peerCreds
292+
return nil
293+
}
294+
277295
// BidirectionalConnect implements BoundEndpoint.BidirectionalConnect.
278296
func (e *connectionedEndpoint) BidirectionalConnect(ctx context.Context, ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint), opts UnixSocketOpts) *syserr.Error {
279297
if ce.Type() != e.stype {
@@ -327,6 +345,7 @@ func (e *connectionedEndpoint) BidirectionalConnect(ctx context.Context, ce Conn
327345
ne.ops.SetSendBufferSize(defaultBufferSize, false /* notify */)
328346
ne.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
329347
ne.SocketOptions().SetPassCred(e.SocketOptions().GetPassCred())
348+
ne.peerCreds = e.peerCreds
330349

331350
readQueue := &queue{ReaderQueue: ce.WaiterQueue(), WriterQueue: ne.Queue, limit: defaultBufferSize}
332351
readQueue.InitRefs()
@@ -354,6 +373,9 @@ func (e *connectionedEndpoint) BidirectionalConnect(ctx context.Context, ce Conn
354373
}
355374
readQueue.IncRef()
356375
if e.stype == linux.SOCK_STREAM {
376+
if err := e.swapPeerCreds(ctx, ce, ne); err != nil {
377+
return err
378+
}
357379
returnConnect(&streamQueueReceiver{queueReceiver: queueReceiver{readQueue: readQueue}}, connected)
358380
} else {
359381
returnConnect(&queueReceiver{readQueue: readQueue}, connected)
@@ -655,3 +677,11 @@ func (e *connectionedEndpoint) EventUnregister(we *waiter.Entry) {
655677
func (e *connectionedEndpoint) GetAcceptConn() bool {
656678
return e.Listening()
657679
}
680+
681+
func (e *connectionedEndpoint) PeerCreds() CredentialsControlMessage {
682+
return e.peerCreds
683+
}
684+
685+
func (e *connectionedEndpoint) SetPeerCreds(creds CredentialsControlMessage) {
686+
e.peerCreds = creds
687+
}

pkg/sentry/socket/unix/transport/connectionless.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ func (*connectionlessEndpoint) Accept(context.Context, *Address, UnixSocketOpts)
158158
return nil, syserr.ErrNotSupported
159159
}
160160

161+
func (e *connectionlessEndpoint) PeerCreds() CredentialsControlMessage {
162+
return nil
163+
}
164+
165+
func (e *connectionlessEndpoint) SetPeerCreds(creds CredentialsControlMessage) {
166+
// no-op
167+
}
168+
161169
// Bind binds the connection.
162170
//
163171
// For Unix endpoints, this _only sets the address associated with the socket_.

pkg/sentry/socket/unix/transport/unix.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ type CredentialsControlMessage interface {
5252
Equals(CredentialsControlMessage) bool
5353
}
5454

55+
// A PeerCredentialer is a socket or endpoint that supports the SO_PEERCREDS socket
56+
// option.
57+
type PeerCredentialer interface {
58+
// PeerCreds returns the peer credentials.
59+
PeerCreds() CredentialsControlMessage
60+
61+
// SetPeerCreds sets the peer credentials.
62+
SetPeerCreds(creds CredentialsControlMessage)
63+
}
64+
5565
// A ControlMessages represents a collection of socket control messages.
5666
//
5767
// +stateify savable
@@ -151,6 +161,7 @@ type UnixSocketOpts struct {
151161
// etc. to Unix socket implementations.
152162
type Endpoint interface {
153163
Credentialer
164+
PeerCredentialer
154165
waiter.Waitable
155166

156167
// Close puts the endpoint in a closed state and frees all resources

0 commit comments

Comments
 (0)