Correct hostinet receive flag handling

Accept and discard Linux-inert send-only flags on hostinet receive calls, add native and runsc syscall coverage, and bind the resulting immutable runtime build.
This commit is contained in:
ms2k 2026-07-31 04:07:41 +09:00
commit b240bc1d12

View file

@ -0,0 +1,74 @@
diff --git a/pkg/sentry/socket/hostinet/socket.go b/pkg/sentry/socket/hostinet/socket.go
--- a/pkg/sentry/socket/hostinet/socket.go
+++ b/pkg/sentry/socket/hostinet/socket.go
@@ -516,7 +516,7 @@
func (s *Socket) recvMsgFromHost(iovs []unix.Iovec, flags int, senderRequested bool, controlLen uint64) (uint64, int, []byte, []byte, error) {
// We always do a non-blocking recv*().
- sysflags := flags | unix.MSG_DONTWAIT
+ sysflags := flags&^ignoredRecvMsgFlags | unix.MSG_DONTWAIT
msg := unix.Msghdr{}
if len(iovs) > 0 {
@@ -545,13 +545,18 @@
return n, int(msg.Flags), senderAddrBuf[:msg.Namelen], controlBuf[:msg.Controllen], err
}
-const allowedRecvMsgFlags = unix.MSG_CTRUNC |
- unix.MSG_DONTWAIT |
- unix.MSG_ERRQUEUE |
- unix.MSG_OOB |
- unix.MSG_PEEK |
- unix.MSG_TRUNC |
- unix.MSG_WAITALL
+const (
+ // Linux accepts these send-only flags on receive calls and ignores them.
+ ignoredRecvMsgFlags = unix.MSG_DONTROUTE | unix.MSG_NOSIGNAL
+ allowedRecvMsgFlags = ignoredRecvMsgFlags |
+ unix.MSG_CTRUNC |
+ unix.MSG_DONTWAIT |
+ unix.MSG_ERRQUEUE |
+ unix.MSG_OOB |
+ unix.MSG_PEEK |
+ unix.MSG_TRUNC |
+ unix.MSG_WAITALL
+)
// RecvMsg implements socket.Socket.RecvMsg.
func (s *Socket) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags int, haveDeadline bool, deadline ktime.Time, senderRequested bool, controlLen uint64) (int, int, linux.SockAddr, uint32, socket.ControlMessages, *syserr.Error) {
diff --git a/test/syscalls/linux/socket_ip_tcp_generic.cc b/test/syscalls/linux/socket_ip_tcp_generic.cc
--- a/test/syscalls/linux/socket_ip_tcp_generic.cc
+++ b/test/syscalls/linux/socket_ip_tcp_generic.cc
@@ -14,6 +14,8 @@
#include "test/syscalls/linux/socket_ip_tcp_generic.h"
+#include <array>
+
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -103,6 +105,23 @@
EXPECT_GT(opt.tcpi_rto, 0);
}
+TEST_P(TCPSocketPairTest, ReceiveIgnoresSendOnlyFlags) {
+ auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
+
+ constexpr std::array<int, 2> kFlags = {MSG_DONTROUTE, MSG_NOSIGNAL};
+ constexpr char kPayload = 'x';
+ for (int flags : kFlags) {
+ ASSERT_THAT(RetryEINTR(send)(sockets->first_fd(), &kPayload,
+ sizeof(kPayload), 0),
+ SyscallSucceedsWithValue(sizeof(kPayload)));
+ char received = 0;
+ ASSERT_THAT(RetryEINTR(recv)(sockets->second_fd(), &received,
+ sizeof(received), flags),
+ SyscallSucceedsWithValue(sizeof(received)));
+ EXPECT_EQ(received, kPayload);
+ }
+}
+
// This test validates that an RST is sent instead of a FIN when data is
// unread on calls to close(2).
TEST_P(TCPSocketPairTest, RSTSentOnCloseWithUnreadData) {