gvisor/sock/unix: pass creds when a message is sent between unconnected sockets

and don't report a sender address if it doesn't have one

PiperOrigin-RevId: 251371284
This commit is contained in:
Andrei Vagin
2019-06-03 21:48:19 -07:00
committed by Shentubot
parent 00f8663887
commit 90a116890f
6 changed files with 49 additions and 16 deletions
+5
View File
@@ -139,3 +139,8 @@ func (e *endpoint) UnidirectionalConnect() (transport.ConnectedEndpoint, *syserr
func (e *endpoint) Release() {
e.inode.DecRef()
}
// Passcred implements transport.BoundEndpoint.Passcred.
func (e *endpoint) Passcred() bool {
return false
}
+10 -2
View File
@@ -406,12 +406,20 @@ func makeCreds(t *kernel.Task, socketOrEndpoint interface{}) SCMCredentials {
return nil
}
if cr, ok := socketOrEndpoint.(transport.Credentialer); ok && (cr.Passcred() || cr.ConnectedPasscred()) {
tcred := t.Credentials()
return &scmCredentials{t, tcred.EffectiveKUID, tcred.EffectiveKGID}
return MakeCreds(t)
}
return nil
}
// MakeCreds creates default SCMCredentials.
func MakeCreds(t *kernel.Task) SCMCredentials {
if t == nil {
return nil
}
tcred := t.Credentials()
return &scmCredentials{t, tcred.EffectiveKUID, tcred.EffectiveKGID}
}
// New creates default control messages if needed.
func New(t *kernel.Task, socketOrEndpoint interface{}, rights SCMRights) transport.ControlMessages {
return transport.ControlMessages{
+4
View File
@@ -237,6 +237,10 @@ type BoundEndpoint interface {
// endpoint.
UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error)
// Passcred returns whether or not the SO_PASSCRED socket option is
// enabled on this end.
Passcred() bool
// Release releases any resources held by the BoundEndpoint. It must be
// called before dropping all references to a BoundEndpoint returned by a
// function.
+5 -1
View File
@@ -385,6 +385,10 @@ func (s *SocketOperations) SendMsg(t *kernel.Task, src usermem.IOSequence, to []
}
defer ep.Release()
w.To = ep
if ep.Passcred() && w.Control.Credentials == nil {
w.Control.Credentials = control.MakeCreds(t)
}
}
n, err := src.CopyInTo(t, &w)
@@ -516,7 +520,7 @@ func (s *SocketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
if n, err := dst.CopyOutFrom(t, &r); err != syserror.ErrWouldBlock || dontWait {
var from interface{}
var fromLen uint32
if r.From != nil {
if r.From != nil && len([]byte(r.From.Addr)) != 0 {
from, fromLen = epsocket.ConvertAddress(linux.AF_UNIX, *r.From)
}
+1 -13
View File
@@ -448,19 +448,7 @@ TEST_P(AllSocketPairTest, UnboundSenderAddr) {
RetryEINTR(recvfrom)(accepted_fd.get(), &i, sizeof(i), 0,
reinterpret_cast<sockaddr*>(&addr), &addr_len),
SyscallSucceedsWithValue(sizeof(i)));
if (!IsRunningOnGvisor()) {
// Linux returns a zero length for addresses from recvfrom(2) and
// recvmsg(2). This differs from the behavior of getpeername(2) and
// getsockname(2). For simplicity, we use the getpeername(2) and
// getsockname(2) behavior for recvfrom(2) and recvmsg(2).
EXPECT_EQ(addr_len, 0);
return;
}
EXPECT_EQ(addr_len, 2);
EXPECT_EQ(
memcmp(&addr, sockets->second_addr(),
std::min((size_t)addr_len, (size_t)sockets->second_addr_len())),
0);
EXPECT_EQ(addr_len, 0);
}
TEST_P(AllSocketPairTest, BoundSenderAddr) {
@@ -13,7 +13,9 @@
// limitations under the License.
#include <stdio.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "gtest/gtest.h"
#include "gtest/gtest.h"
#include "test/syscalls/linux/socket_test_util.h"
@@ -142,6 +144,28 @@ TEST_P(UnboundDgramUnixSocketPairTest, SendtoWithoutConnect) {
SyscallSucceedsWithValue(sizeof(data)));
}
TEST_P(UnboundDgramUnixSocketPairTest, SendtoWithoutConnectPassCreds) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
ASSERT_THAT(bind(sockets->first_fd(), sockets->first_addr(),
sockets->first_addr_size()),
SyscallSucceeds());
SetSoPassCred(sockets->first_fd());
char data = 'a';
ASSERT_THAT(
RetryEINTR(sendto)(sockets->second_fd(), &data, sizeof(data), 0,
sockets->first_addr(), sockets->first_addr_size()),
SyscallSucceedsWithValue(sizeof(data)));
ucred creds;
creds.pid = -1;
char buf[sizeof(data) + 1];
ASSERT_NO_FATAL_FAILURE(
RecvCreds(sockets->first_fd(), &creds, buf, sizeof(buf), sizeof(data)));
EXPECT_EQ(0, memcmp(&data, buf, sizeof(data)));
EXPECT_THAT(getpid(), SyscallSucceedsWithValue(creds.pid));
}
INSTANTIATE_TEST_SUITE_P(
AllUnixDomainSockets, UnboundDgramUnixSocketPairTest,
::testing::ValuesIn(VecCat<SocketPairKind>(