summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBrian Geffon <bgeffon@google.com>2018-06-17 17:05:36 -0700
committerShentubot <shentubot@google.com>2018-06-17 17:06:40 -0700
commit563a71ef243360bc20db0e481b3adbfb07cd8702 (patch)
treec4bcfc2b58224fe879166bb1b0b5ef9401dcdb25
parent0786707cd94b8feffaeb083077eccaf10873e682 (diff)
Add rpcinet support for control messages.
Add support for control messages, but at this time the only control message that the sentry will support here is SO_TIMESTAMP. PiperOrigin-RevId: 200922230 Change-Id: I63a852d9305255625d9df1d989bd46a66e93c446
-rw-r--r--pkg/sentry/socket/rpcinet/socket.go37
-rw-r--r--pkg/sentry/socket/rpcinet/syscall_rpc.proto2
2 files changed, 37 insertions, 2 deletions
diff --git a/pkg/sentry/socket/rpcinet/socket.go b/pkg/sentry/socket/rpcinet/socket.go
index d8c1f2c1a..b4b380ac6 100644
--- a/pkg/sentry/socket/rpcinet/socket.go
+++ b/pkg/sentry/socket/rpcinet/socket.go
@@ -477,6 +477,37 @@ func rpcRecvMsg(t *kernel.Task, req *pb.SyscallRequest_Recvmsg) (*pb.RecvmsgResp
return res.(*pb.RecvmsgResponse_Payload).Payload, nil
}
+// Because we only support SO_TIMESTAMP we will search control messages for
+// that value and set it if so, all other control messages will be ignored.
+func (s *socketOperations) extractControlMessages(payload *pb.RecvmsgResponse_ResultPayload) socket.ControlMessages {
+ c := socket.ControlMessages{}
+ if len(payload.GetCmsgData()) > 0 {
+ // Parse the control messages looking for SO_TIMESTAMP.
+ msgs, e := syscall.ParseSocketControlMessage(payload.GetCmsgData())
+ if e != nil {
+ return socket.ControlMessages{}
+ }
+ for _, m := range msgs {
+ if m.Header.Level != linux.SOL_SOCKET || m.Header.Type != linux.SO_TIMESTAMP {
+ continue
+ }
+
+ // Let's parse the time stamp and set it.
+ if len(m.Data) < linux.SizeOfTimeval {
+ // Give up on locating the SO_TIMESTAMP option.
+ return socket.ControlMessages{}
+ }
+
+ var v linux.Timeval
+ binary.Unmarshal(m.Data[:linux.SizeOfTimeval], usermem.ByteOrder, &v)
+ c.IP.HasTimestamp = true
+ c.IP.Timestamp = v.ToNsecCapped()
+ break
+ }
+ }
+ return c
+}
+
// RecvMsg implements socket.Socket.RecvMsg.
func (s *socketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags int, haveDeadline bool, deadline ktime.Time, senderRequested bool, controlDataLen uint64) (int, interface{}, uint32, socket.ControlMessages, *syserr.Error) {
req := &pb.SyscallRequest_Recvmsg{&pb.RecvmsgRequest{
@@ -497,7 +528,8 @@ func (s *socketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
panic("CopyOut failed to copy full buffer")
}
}
- return int(res.Length), res.Address.GetAddress(), res.Address.GetLength(), socket.ControlMessages{}, syserr.FromError(e)
+ c := s.extractControlMessages(res)
+ return int(res.Length), res.Address.GetAddress(), res.Address.GetLength(), c, syserr.FromError(e)
}
if err != syserr.ErrWouldBlock && err != syserr.ErrTryAgain || flags&linux.MSG_DONTWAIT != 0 {
return 0, nil, 0, socket.ControlMessages{}, err
@@ -520,7 +552,8 @@ func (s *socketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags
panic("CopyOut failed to copy full buffer")
}
}
- return int(res.Length), res.Address.GetAddress(), res.Address.GetLength(), socket.ControlMessages{}, syserr.FromError(e)
+ c := s.extractControlMessages(res)
+ return int(res.Length), res.Address.GetAddress(), res.Address.GetLength(), c, syserr.FromError(e)
}
if err != syserr.ErrWouldBlock && err != syserr.ErrTryAgain {
return 0, nil, 0, socket.ControlMessages{}, err
diff --git a/pkg/sentry/socket/rpcinet/syscall_rpc.proto b/pkg/sentry/socket/rpcinet/syscall_rpc.proto
index 996962aae..c056e4c9d 100644
--- a/pkg/sentry/socket/rpcinet/syscall_rpc.proto
+++ b/pkg/sentry/socket/rpcinet/syscall_rpc.proto
@@ -40,6 +40,7 @@ message RecvmsgRequest {
bool sender = 3;
bool peek = 4;
bool trunc = 5;
+ uint32 cmsg_length = 6;
}
message OpenRequest {
@@ -110,6 +111,7 @@ message RecvmsgResponse {
bytes data = 1 [ctype = CORD];
AddressResponse address = 2;
uint32 length = 3;
+ bytes cmsg_data = 4;
}
oneof result {
uint32 error_number = 1;