From 05ff1ffaadaa0ac370365eb14febc761506735ce Mon Sep 17 00:00:00 2001 From: Rahat Mahmood Date: Thu, 13 Jun 2019 17:23:35 -0700 Subject: Implement getsockopt() SO_DOMAIN, SO_PROTOCOL and SO_TYPE. SO_TYPE was already implemented for everything but netlink sockets. PiperOrigin-RevId: 253138157 --- pkg/sentry/socket/epsocket/epsocket.go | 6 --- pkg/sentry/socket/epsocket/provider.go | 2 +- pkg/sentry/socket/hostinet/socket.go | 2 +- pkg/sentry/syscalls/linux/BUILD | 1 + pkg/sentry/syscalls/linux/sys_socket.go | 32 +++++++++++++- test/syscalls/linux/BUILD | 2 + test/syscalls/linux/ip_socket_test_util.cc | 51 +++++++++++++--------- test/syscalls/linux/socket_generic.cc | 50 +++++++++++++++++++++ test/syscalls/linux/socket_netlink_route.cc | 45 ++++++++++++++++--- test/syscalls/linux/socket_test_util.cc | 7 +-- test/syscalls/linux/socket_test_util.h | 7 +++ .../syscalls/linux/unix_domain_socket_test_util.cc | 19 ++++---- 12 files changed, 177 insertions(+), 47 deletions(-) diff --git a/pkg/sentry/socket/epsocket/epsocket.go b/pkg/sentry/socket/epsocket/epsocket.go index 8b783ae2f..ce3b247d0 100644 --- a/pkg/sentry/socket/epsocket/epsocket.go +++ b/pkg/sentry/socket/epsocket/epsocket.go @@ -668,12 +668,6 @@ func GetSockOpt(t *kernel.Task, s socket.Socket, ep commonEndpoint, family int, func getSockOptSocket(t *kernel.Task, s socket.Socket, ep commonEndpoint, family int, skType linux.SockType, name, outLen int) (interface{}, *syserr.Error) { // TODO(b/124056281): Stop rejecting short optLen values in getsockopt. switch name { - case linux.SO_TYPE: - if outLen < sizeOfInt32 { - return nil, syserr.ErrInvalidArgument - } - return int32(skType), nil - case linux.SO_ERROR: if outLen < sizeOfInt32 { return nil, syserr.ErrInvalidArgument diff --git a/pkg/sentry/socket/epsocket/provider.go b/pkg/sentry/socket/epsocket/provider.go index 37f3160cd..6d2b5d038 100644 --- a/pkg/sentry/socket/epsocket/provider.go +++ b/pkg/sentry/socket/epsocket/provider.go @@ -111,7 +111,7 @@ func (p *provider) Socket(t *kernel.Task, stype linux.SockType, protocol int) (* return nil, syserr.TranslateNetstackError(e) } - return New(t, p.family, stype, protocol, wq, ep) + return New(t, p.family, stype, int(transProto), wq, ep) } // Pair just returns nil sockets (not supported). diff --git a/pkg/sentry/socket/hostinet/socket.go b/pkg/sentry/socket/hostinet/socket.go index 2ca952920..cef007aca 100644 --- a/pkg/sentry/socket/hostinet/socket.go +++ b/pkg/sentry/socket/hostinet/socket.go @@ -288,7 +288,7 @@ func (s *socketOperations) GetSockOpt(t *kernel.Task, level int, name int, outLe } case syscall.SOL_SOCKET: switch name { - case syscall.SO_ERROR, syscall.SO_KEEPALIVE, syscall.SO_SNDBUF, syscall.SO_RCVBUF, syscall.SO_REUSEADDR, syscall.SO_TYPE: + case syscall.SO_ERROR, syscall.SO_KEEPALIVE, syscall.SO_SNDBUF, syscall.SO_RCVBUF, syscall.SO_REUSEADDR: optlen = sizeofInt32 case syscall.SO_LINGER: optlen = syscall.SizeofLinger diff --git a/pkg/sentry/syscalls/linux/BUILD b/pkg/sentry/syscalls/linux/BUILD index 428c67799..6e5be0158 100644 --- a/pkg/sentry/syscalls/linux/BUILD +++ b/pkg/sentry/syscalls/linux/BUILD @@ -86,6 +86,7 @@ go_library( "//pkg/sentry/syscalls", "//pkg/sentry/usage", "//pkg/sentry/usermem", + "//pkg/syserr", "//pkg/syserror", "//pkg/waiter", ], diff --git a/pkg/sentry/syscalls/linux/sys_socket.go b/pkg/sentry/syscalls/linux/sys_socket.go index 4e3c682ed..ccdb079bb 100644 --- a/pkg/sentry/syscalls/linux/sys_socket.go +++ b/pkg/sentry/syscalls/linux/sys_socket.go @@ -29,6 +29,7 @@ import ( "gvisor.dev/gvisor/pkg/sentry/socket/control" "gvisor.dev/gvisor/pkg/sentry/socket/unix/transport" "gvisor.dev/gvisor/pkg/sentry/usermem" + "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/syserror" ) @@ -61,6 +62,8 @@ const controlLenOffset = 40 // to the Flags field. const flagsOffset = 48 +const sizeOfInt32 = 4 + // messageHeader64Len is the length of a MessageHeader64 struct. var messageHeader64Len = uint64(binary.Size(MessageHeader64{})) @@ -466,7 +469,7 @@ func GetSockOpt(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy } // Call syscall implementation then copy both value and value len out. - v, e := s.GetSockOpt(t, int(level), int(name), int(optLen)) + v, e := getSockOpt(t, s, int(level), int(name), int(optLen)) if e != nil { return 0, nil, e.ToError() } @@ -487,6 +490,33 @@ func GetSockOpt(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sy return 0, nil, nil } +// getSockOpt tries to handle common socket options, or dispatches to a specific +// socket implementation. +func getSockOpt(t *kernel.Task, s socket.Socket, level, name, len int) (interface{}, *syserr.Error) { + if level == linux.SOL_SOCKET { + switch name { + case linux.SO_TYPE, linux.SO_DOMAIN, linux.SO_PROTOCOL: + if len < sizeOfInt32 { + return nil, syserr.ErrInvalidArgument + } + } + + switch name { + case linux.SO_TYPE: + _, skType, _ := s.Type() + return int32(skType), nil + case linux.SO_DOMAIN: + family, _, _ := s.Type() + return int32(family), nil + case linux.SO_PROTOCOL: + _, _, protocol := s.Type() + return int32(protocol), nil + } + } + + return s.GetSockOpt(t, level, name, len) +} + // SetSockOpt implements the linux syscall setsockopt(2). // // Note that unlike Linux, enabling SO_PASSCRED does not autobind the socket. diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 9bafc6e4f..2f6704842 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -1909,6 +1909,7 @@ cc_library( ":unix_domain_socket_test_util", "//test/util:test_util", "@com_google_absl//absl/strings", + "@com_google_absl//absl/strings:str_format", "@com_google_googletest//:gtest", ], alwayslink = 1, @@ -2427,6 +2428,7 @@ cc_binary( "//test/util:file_descriptor", "//test/util:test_main", "//test/util:test_util", + "@com_google_absl//absl/strings:str_format", "@com_google_googletest//:gtest", ], ) diff --git a/test/syscalls/linux/ip_socket_test_util.cc b/test/syscalls/linux/ip_socket_test_util.cc index 7612919d4..5fc4e9115 100644 --- a/test/syscalls/linux/ip_socket_test_util.cc +++ b/test/syscalls/linux/ip_socket_test_util.cc @@ -45,70 +45,79 @@ SocketPairKind IPv6TCPAcceptBindSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "connected IPv6 TCP socket"); return SocketPairKind{ - description, TCPAcceptBindSocketPairCreator(AF_INET6, type | SOCK_STREAM, - 0, /* dual_stack = */ false)}; + description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP, + TCPAcceptBindSocketPairCreator(AF_INET6, type | SOCK_STREAM, 0, + /* dual_stack = */ false)}; } SocketPairKind IPv4TCPAcceptBindSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "connected IPv4 TCP socket"); return SocketPairKind{ - description, TCPAcceptBindSocketPairCreator(AF_INET, type | SOCK_STREAM, - 0, /* dual_stack = */ false)}; + description, AF_INET, type | SOCK_STREAM, IPPROTO_TCP, + TCPAcceptBindSocketPairCreator(AF_INET, type | SOCK_STREAM, 0, + /* dual_stack = */ false)}; } SocketPairKind DualStackTCPAcceptBindSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "connected dual stack TCP socket"); return SocketPairKind{ - description, TCPAcceptBindSocketPairCreator(AF_INET6, type | SOCK_STREAM, - 0, /* dual_stack = */ true)}; + description, AF_INET6, type | SOCK_STREAM, IPPROTO_TCP, + TCPAcceptBindSocketPairCreator(AF_INET6, type | SOCK_STREAM, 0, + /* dual_stack = */ true)}; } SocketPairKind IPv6UDPBidirectionalBindSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "connected IPv6 UDP socket"); - return SocketPairKind{description, UDPBidirectionalBindSocketPairCreator( - AF_INET6, type | SOCK_DGRAM, 0, - /* dual_stack = */ false)}; + return SocketPairKind{ + description, AF_INET6, type | SOCK_DGRAM, IPPROTO_UDP, + UDPBidirectionalBindSocketPairCreator(AF_INET6, type | SOCK_DGRAM, 0, + /* dual_stack = */ false)}; } SocketPairKind IPv4UDPBidirectionalBindSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "connected IPv4 UDP socket"); - return SocketPairKind{description, UDPBidirectionalBindSocketPairCreator( - AF_INET, type | SOCK_DGRAM, 0, - /* dual_stack = */ false)}; + return SocketPairKind{ + description, AF_INET, type | SOCK_DGRAM, IPPROTO_UDP, + UDPBidirectionalBindSocketPairCreator(AF_INET, type | SOCK_DGRAM, 0, + /* dual_stack = */ false)}; } SocketPairKind DualStackUDPBidirectionalBindSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "connected dual stack UDP socket"); - return SocketPairKind{description, UDPBidirectionalBindSocketPairCreator( - AF_INET6, type | SOCK_DGRAM, 0, - /* dual_stack = */ true)}; + return SocketPairKind{ + description, AF_INET6, type | SOCK_DGRAM, IPPROTO_UDP, + UDPBidirectionalBindSocketPairCreator(AF_INET6, type | SOCK_DGRAM, 0, + /* dual_stack = */ true)}; } SocketPairKind IPv4UDPUnboundSocketPair(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "IPv4 UDP socket"); return SocketPairKind{ - description, UDPUnboundSocketPairCreator(AF_INET, type | SOCK_DGRAM, 0, - /* dual_stack = */ false)}; + description, AF_INET, type | SOCK_DGRAM, IPPROTO_UDP, + UDPUnboundSocketPairCreator(AF_INET, type | SOCK_DGRAM, 0, + /* dual_stack = */ false)}; } SocketKind IPv4UDPUnboundSocket(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "IPv4 UDP socket"); - return SocketKind{description, UnboundSocketCreator( - AF_INET, type | SOCK_DGRAM, IPPROTO_UDP)}; + return SocketKind{ + description, AF_INET, type | SOCK_DGRAM, IPPROTO_UDP, + UnboundSocketCreator(AF_INET, type | SOCK_DGRAM, IPPROTO_UDP)}; } SocketKind IPv4TCPUnboundSocket(int type) { std::string description = absl::StrCat(DescribeSocketType(type), "IPv4 TCP socket"); - return SocketKind{description, UnboundSocketCreator( - AF_INET, type | SOCK_STREAM, IPPROTO_TCP)}; + return SocketKind{ + description, AF_INET, type | SOCK_STREAM, IPPROTO_TCP, + UnboundSocketCreator(AF_INET, type | SOCK_STREAM, IPPROTO_TCP)}; } } // namespace testing diff --git a/test/syscalls/linux/socket_generic.cc b/test/syscalls/linux/socket_generic.cc index f99f3fe62..51d614639 100644 --- a/test/syscalls/linux/socket_generic.cc +++ b/test/syscalls/linux/socket_generic.cc @@ -21,6 +21,7 @@ #include "gtest/gtest.h" #include "gtest/gtest.h" +#include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "test/syscalls/linux/socket_test_util.h" #include "test/syscalls/linux/unix_domain_socket_test_util.h" @@ -687,5 +688,54 @@ TEST_P(AllSocketPairTest, RecvTimeoutWaitAll) { EXPECT_EQ(0, memcmp(sent_data, received_data, sizeof(sent_data))); } +TEST_P(AllSocketPairTest, GetSockoptType) { + int type = GetParam().type; + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + for (const int fd : {sockets->first_fd(), sockets->second_fd()}) { + int opt; + socklen_t optlen = sizeof(opt); + EXPECT_THAT(getsockopt(fd, SOL_SOCKET, SO_TYPE, &opt, &optlen), + SyscallSucceeds()); + + // Type may have SOCK_NONBLOCK and SOCK_CLOEXEC ORed into it. Remove these + // before comparison. + type &= ~(SOCK_NONBLOCK | SOCK_CLOEXEC); + EXPECT_EQ(opt, type) << absl::StrFormat( + "getsockopt(%d, SOL_SOCKET, SO_TYPE, &opt, &optlen) => opt=%d was " + "unexpected", + fd, opt); + } +} + +TEST_P(AllSocketPairTest, GetSockoptDomain) { + const int domain = GetParam().domain; + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + for (const int fd : {sockets->first_fd(), sockets->second_fd()}) { + int opt; + socklen_t optlen = sizeof(opt); + EXPECT_THAT(getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &opt, &optlen), + SyscallSucceeds()); + EXPECT_EQ(opt, domain) << absl::StrFormat( + "getsockopt(%d, SOL_SOCKET, SO_DOMAIN, &opt, &optlen) => opt=%d was " + "unexpected", + fd, opt); + } +} + +TEST_P(AllSocketPairTest, GetSockoptProtocol) { + const int protocol = GetParam().protocol; + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + for (const int fd : {sockets->first_fd(), sockets->second_fd()}) { + int opt; + socklen_t optlen = sizeof(opt); + EXPECT_THAT(getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &opt, &optlen), + SyscallSucceeds()); + EXPECT_EQ(opt, protocol) << absl::StrFormat( + "getsockopt(%d, SOL_SOCKET, SO_PROTOCOL, &opt, &optlen) => opt=%d was " + "unexpected", + fd, opt); + } +} + } // namespace testing } // namespace gvisor diff --git a/test/syscalls/linux/socket_netlink_route.cc b/test/syscalls/linux/socket_netlink_route.cc index c8693225f..53dd1ca78 100644 --- a/test/syscalls/linux/socket_netlink_route.cc +++ b/test/syscalls/linux/socket_netlink_route.cc @@ -23,6 +23,7 @@ #include #include "gtest/gtest.h" +#include "absl/strings/str_format.h" #include "test/syscalls/linux/socket_netlink_util.h" #include "test/syscalls/linux/socket_test_util.h" #include "test/util/cleanup.h" @@ -144,24 +145,56 @@ TEST(NetlinkRouteTest, GetPeerName) { EXPECT_EQ(addr.nl_pid, 0); } -using IntSockOptTest = ::testing::TestWithParam; +// Parameters for GetSockOpt test. They are: +// 0: Socket option to query. +// 1: A predicate to run on the returned sockopt value. Should return true if +// the value is considered ok. +// 2: A description of what the sockopt value is expected to be. Should complete +// the sentence " was unexpected, expected " +using SockOptTest = + ::testing::TestWithParam, std::string>>; + +TEST_P(SockOptTest, GetSockOpt) { + int sockopt = std::get<0>(GetParam()); + auto verifier = std::get<1>(GetParam()); + std::string verifier_description = std::get<2>(GetParam()); -TEST_P(IntSockOptTest, GetSockOpt) { FileDescriptor fd = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)); int res; socklen_t len = sizeof(res); - EXPECT_THAT(getsockopt(fd.get(), SOL_SOCKET, GetParam(), &res, &len), + EXPECT_THAT(getsockopt(fd.get(), SOL_SOCKET, sockopt, &res, &len), SyscallSucceeds()); EXPECT_EQ(len, sizeof(res)); - EXPECT_GT(res, 0); + EXPECT_TRUE(verifier(res)) << absl::StrFormat( + "getsockopt(%d, SOL_SOCKET, %d, &res, &len) => res=%d was unexpected, " + "expected %s", + fd.get(), sockopt, res, verifier_description); +} + +std::function IsPositive() { + return [](int val) { return val > 0; }; +} + +std::function IsEqual(int target) { + return [target](int val) { return val == target; }; } -INSTANTIATE_TEST_SUITE_P(NetlinkRouteTest, IntSockOptTest, - ::testing::Values(SO_SNDBUF, SO_RCVBUF)); +INSTANTIATE_TEST_SUITE_P( + NetlinkRouteTest, SockOptTest, + ::testing::Values( + std::make_tuple(SO_SNDBUF, IsPositive(), "positive send buffer size"), + std::make_tuple(SO_RCVBUF, IsPositive(), + "positive receive buffer size"), + std::make_tuple(SO_TYPE, IsEqual(SOCK_RAW), + absl::StrFormat("SOCK_RAW (%d)", SOCK_RAW)), + std::make_tuple(SO_DOMAIN, IsEqual(AF_NETLINK), + absl::StrFormat("AF_NETLINK (%d)", AF_NETLINK)), + std::make_tuple(SO_PROTOCOL, IsEqual(NETLINK_ROUTE), + absl::StrFormat("NETLINK_ROUTE (%d)", NETLINK_ROUTE)))); // Validates the reponses to RTM_GETLINK + NLM_F_DUMP. void CheckGetLinkResponse(const struct nlmsghdr* hdr, int seq, int port) { diff --git a/test/syscalls/linux/socket_test_util.cc b/test/syscalls/linux/socket_test_util.cc index da69de37c..4f65cf5ae 100644 --- a/test/syscalls/linux/socket_test_util.cc +++ b/test/syscalls/linux/socket_test_util.cc @@ -457,7 +457,8 @@ Creator UDPUnboundSocketPairCreator(int domain, int type, SocketPairKind Reversed(SocketPairKind const& base) { auto const& creator = base.creator; return SocketPairKind{ - absl::StrCat("reversed ", base.description), + absl::StrCat("reversed ", base.description), base.domain, base.type, + base.protocol, [creator]() -> PosixErrorOr> { ASSIGN_OR_RETURN_ERRNO(auto creator_value, creator()); return absl::make_unique(std::move(creator_value)); @@ -542,8 +543,8 @@ struct sockaddr_storage AddrFDSocketPair::to_storage(const sockaddr_in6& addr) { SocketKind SimpleSocket(int fam, int type, int proto) { return SocketKind{ - absl::StrCat("Family ", fam, ", type ", type, ", proto ", proto), - SyscallSocketCreator(fam, type, proto)}; + absl::StrCat("Family ", fam, ", type ", type, ", proto ", proto), fam, + type, proto, SyscallSocketCreator(fam, type, proto)}; } ssize_t SendLargeSendMsg(const std::unique_ptr& sockets, diff --git a/test/syscalls/linux/socket_test_util.h b/test/syscalls/linux/socket_test_util.h index 058313986..4fd59767a 100644 --- a/test/syscalls/linux/socket_test_util.h +++ b/test/syscalls/linux/socket_test_util.h @@ -287,6 +287,9 @@ Creator UnboundSocketCreator(int domain, int type, // a function that creates such a socket pair. struct SocketPairKind { std::string description; + int domain; + int type; + int protocol; Creator creator; // Create creates a socket pair of this kind. @@ -297,6 +300,9 @@ struct SocketPairKind { // a function that creates such a socket. struct SocketKind { std::string description; + int domain; + int type; + int protocol; Creator creator; // Create creates a socket pair of this kind. @@ -353,6 +359,7 @@ Middleware SetSockOpt(int level, int optname, T* value) { return SocketPairKind{ absl::StrCat("setsockopt(", level, ", ", optname, ", ", *value, ") ", base.description), + base.domain, base.type, base.protocol, [creator, level, optname, value]() -> PosixErrorOr> { ASSIGN_OR_RETURN_ERRNO(auto creator_value, creator()); diff --git a/test/syscalls/linux/unix_domain_socket_test_util.cc b/test/syscalls/linux/unix_domain_socket_test_util.cc index 6f49e3660..ff28850b2 100644 --- a/test/syscalls/linux/unix_domain_socket_test_util.cc +++ b/test/syscalls/linux/unix_domain_socket_test_util.cc @@ -47,7 +47,7 @@ std::string DescribeUnixDomainSocketType(int type) { } SocketPairKind UnixDomainSocketPair(int type) { - return SocketPairKind{DescribeUnixDomainSocketType(type), + return SocketPairKind{DescribeUnixDomainSocketType(type), AF_UNIX, type, 0, SyscallSocketPairCreator(AF_UNIX, type, 0)}; } @@ -56,11 +56,12 @@ SocketPairKind FilesystemBoundUnixDomainSocketPair(int type) { " created with filesystem binding"); if ((type & SOCK_DGRAM) == SOCK_DGRAM) { return SocketPairKind{ - description, + description, AF_UNIX, type, 0, FilesystemBidirectionalBindSocketPairCreator(AF_UNIX, type, 0)}; } return SocketPairKind{ - description, FilesystemAcceptBindSocketPairCreator(AF_UNIX, type, 0)}; + description, AF_UNIX, type, 0, + FilesystemAcceptBindSocketPairCreator(AF_UNIX, type, 0)}; } SocketPairKind AbstractBoundUnixDomainSocketPair(int type) { @@ -68,17 +69,17 @@ SocketPairKind AbstractBoundUnixDomainSocketPair(int type) { " created with abstract namespace binding"); if ((type & SOCK_DGRAM) == SOCK_DGRAM) { return SocketPairKind{ - description, + description, AF_UNIX, type, 0, AbstractBidirectionalBindSocketPairCreator(AF_UNIX, type, 0)}; } - return SocketPairKind{description, + return SocketPairKind{description, AF_UNIX, type, 0, AbstractAcceptBindSocketPairCreator(AF_UNIX, type, 0)}; } SocketPairKind SocketpairGoferUnixDomainSocketPair(int type) { std::string description = absl::StrCat(DescribeUnixDomainSocketType(type), " created with the socketpair gofer"); - return SocketPairKind{description, + return SocketPairKind{description, AF_UNIX, type, 0, SocketpairGoferSocketPairCreator(AF_UNIX, type, 0)}; } @@ -87,13 +88,15 @@ SocketPairKind SocketpairGoferFileSocketPair(int type) { absl::StrCat(((type & O_NONBLOCK) != 0) ? "non-blocking " : "", ((type & O_CLOEXEC) != 0) ? "close-on-exec " : "", "file socket created with the socketpair gofer"); - return SocketPairKind{description, + // The socketpair gofer always creates SOCK_STREAM sockets on open(2). + return SocketPairKind{description, AF_UNIX, SOCK_STREAM, 0, SocketpairGoferFileSocketPairCreator(type)}; } SocketPairKind FilesystemUnboundUnixDomainSocketPair(int type) { return SocketPairKind{absl::StrCat(DescribeUnixDomainSocketType(type), " unbound with a filesystem address"), + AF_UNIX, type, 0, FilesystemUnboundSocketPairCreator(AF_UNIX, type, 0)}; } @@ -101,7 +104,7 @@ SocketPairKind AbstractUnboundUnixDomainSocketPair(int type) { return SocketPairKind{ absl::StrCat(DescribeUnixDomainSocketType(type), " unbound with an abstract namespace address"), - AbstractUnboundSocketPairCreator(AF_UNIX, type, 0)}; + AF_UNIX, type, 0, AbstractUnboundSocketPairCreator(AF_UNIX, type, 0)}; } void SendSingleFD(int sock, int fd, char buf[], int buf_size) { -- cgit v1.2.3 From 0a5ee6f7b20ef4f5533766d753b85005f79ae613 Mon Sep 17 00:00:00 2001 From: Ian Gudger Date: Thu, 13 Jun 2019 17:24:58 -0700 Subject: Fix deadlock in fasync. The deadlock can occur when both ends of a connected Unix socket which has FIOASYNC enabled on at least one end are closed at the same time. One end notifies that it is closing, calling (*waiter.Queue).Notify which takes waiter.Queue.mu (as a read lock) and then calls (*FileAsync).Callback, which takes FileAsync.mu. The other end tries to unregister for notifications by calling (*FileAsync).Unregister, which takes FileAsync.mu and calls (*waiter.Queue).EventUnregister which takes waiter.Queue.mu. This is fixed by moving the calls to waiter.Waitable.EventRegister and waiter.Waitable.EventUnregister outside of the protection of any mutex used in (*FileAsync).Callback. The new test is related, but does not cover this particular situation. Also fix a data race on FileAsync.e.Callback. (*FileAsync).Callback checked FileAsync.e.Callback under the protection of FileAsync.mu, but the waiter calling (*FileAsync).Callback could not and did not. This is fixed by making FileAsync.e.Callback immutable before passing it to the waiter for the first time. Fixes #346 PiperOrigin-RevId: 253138340 --- pkg/sentry/kernel/fasync/fasync.go | 45 +++++++++++++++++++++++++++++--------- test/syscalls/linux/ioctl.cc | 31 ++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/pkg/sentry/kernel/fasync/fasync.go b/pkg/sentry/kernel/fasync/fasync.go index bcaca58f7..6b0bb0324 100644 --- a/pkg/sentry/kernel/fasync/fasync.go +++ b/pkg/sentry/kernel/fasync/fasync.go @@ -34,9 +34,23 @@ func New() fs.FileAsync { // // +stateify savable type FileAsync struct { - mu sync.Mutex `state:"nosave"` - e waiter.Entry - requester *auth.Credentials + // e is immutable after first use (which is protected by mu below). + e waiter.Entry + + // regMu protects registeration and unregistration actions on e. + // + // regMu must be held while registration decisions are being made + // through the registration action itself. + // + // Lock ordering: regMu, mu. + regMu sync.Mutex `state:"nosave"` + + // mu protects all following fields. + // + // Lock ordering: e.mu, mu. + mu sync.Mutex `state:"nosave"` + requester *auth.Credentials + registered bool // Only one of the following is allowed to be non-nil. recipientPG *kernel.ProcessGroup @@ -47,7 +61,7 @@ type FileAsync struct { // Callback sends a signal. func (a *FileAsync) Callback(e *waiter.Entry) { a.mu.Lock() - if a.e.Callback == nil { + if !a.registered { a.mu.Unlock() return } @@ -80,14 +94,21 @@ func (a *FileAsync) Callback(e *waiter.Entry) { // // The file must not be currently registered. func (a *FileAsync) Register(w waiter.Waitable) { + a.regMu.Lock() + defer a.regMu.Unlock() a.mu.Lock() - defer a.mu.Unlock() - if a.e.Callback != nil { + if a.registered { + a.mu.Unlock() panic("registering already registered file") } - a.e.Callback = a + if a.e.Callback == nil { + a.e.Callback = a + } + a.registered = true + + a.mu.Unlock() w.EventRegister(&a.e, waiter.EventIn|waiter.EventOut|waiter.EventErr|waiter.EventHUp) } @@ -95,15 +116,19 @@ func (a *FileAsync) Register(w waiter.Waitable) { // // The file must be currently registered. func (a *FileAsync) Unregister(w waiter.Waitable) { + a.regMu.Lock() + defer a.regMu.Unlock() a.mu.Lock() - defer a.mu.Unlock() - if a.e.Callback == nil { + if !a.registered { + a.mu.Unlock() panic("unregistering unregistered file") } + a.registered = false + + a.mu.Unlock() w.EventUnregister(&a.e) - a.e.Callback = nil } // Owner returns who is currently getting signals. All return values will be diff --git a/test/syscalls/linux/ioctl.cc b/test/syscalls/linux/ioctl.cc index c525d41d2..4948a76f0 100644 --- a/test/syscalls/linux/ioctl.cc +++ b/test/syscalls/linux/ioctl.cc @@ -229,6 +229,37 @@ TEST_F(IoctlTest, FIOASYNCSelfTarget2) { EXPECT_EQ(io_received, 1); } +// Check that closing an FD does not result in an event. +TEST_F(IoctlTest, FIOASYNCSelfTargetClose) { + // Count SIGIOs received. + struct sigaction sa; + io_received = 0; + sa.sa_sigaction = inc_io_handler; + sigfillset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + auto sa_cleanup = ASSERT_NO_ERRNO_AND_VALUE(ScopedSigaction(SIGIO, sa)); + + // Actually allow SIGIO delivery. + auto mask_cleanup = + ASSERT_NO_ERRNO_AND_VALUE(ScopedSignalMask(SIG_UNBLOCK, SIGIO)); + + for (int i = 0; i < 2; i++) { + auto pair = ASSERT_NO_ERRNO_AND_VALUE( + UnixDomainSocketPair(SOCK_SEQPACKET).Create()); + + pid_t pid = getpid(); + EXPECT_THAT(ioctl(pair->second_fd(), FIOSETOWN, &pid), SyscallSucceeds()); + + int set = 1; + EXPECT_THAT(ioctl(pair->second_fd(), FIOASYNC, &set), SyscallSucceeds()); + } + + // FIXME(b/120624367): gVisor erroneously sends SIGIO on close. + SKIP_IF(IsRunningOnGvisor()); + + EXPECT_EQ(io_received, 0); +} + TEST_F(IoctlTest, FIOASYNCInvalidPID) { auto pair = ASSERT_NO_ERRNO_AND_VALUE(UnixDomainSocketPair(SOCK_SEQPACKET).Create()); -- cgit v1.2.3 From 3e9b8ecbfe21ba6c8c788be469fc6cea6a4a40b7 Mon Sep 17 00:00:00 2001 From: Ian Gudger Date: Thu, 13 Jun 2019 18:39:43 -0700 Subject: Plumb context through more layers of filesytem. All functions which allocate objects containing AtomicRefCounts will soon need a context. PiperOrigin-RevId: 253147709 --- pkg/sentry/fs/anon/anon.go | 2 +- pkg/sentry/fs/ashmem/area.go | 4 +-- pkg/sentry/fs/copy_up_test.go | 2 +- pkg/sentry/fs/dev/dev.go | 28 ++++++++++---------- pkg/sentry/fs/dev/fs.go | 2 +- pkg/sentry/fs/dirent.go | 4 +-- pkg/sentry/fs/dirent_refs_test.go | 29 +++++++++++---------- pkg/sentry/fs/fdpipe/pipe_opener_test.go | 2 +- pkg/sentry/fs/fdpipe/pipe_test.go | 12 ++++----- pkg/sentry/fs/file_overlay_test.go | 12 ++++----- pkg/sentry/fs/filetest/filetest.go | 2 +- pkg/sentry/fs/fsutil/inode_cached_test.go | 6 ++--- pkg/sentry/fs/gofer/gofer_test.go | 6 ++--- pkg/sentry/fs/gofer/path.go | 6 ++--- pkg/sentry/fs/gofer/session.go | 4 +-- pkg/sentry/fs/gofer/socket.go | 9 ++++--- pkg/sentry/fs/host/file.go | 2 +- pkg/sentry/fs/host/fs.go | 2 +- pkg/sentry/fs/host/inode.go | 6 ++--- pkg/sentry/fs/host/inode_test.go | 2 +- pkg/sentry/fs/host/socket.go | 10 ++++---- pkg/sentry/fs/inode.go | 2 +- pkg/sentry/fs/inode_overlay.go | 16 ++++++------ pkg/sentry/fs/inode_overlay_test.go | 10 ++++---- pkg/sentry/fs/mock.go | 6 ++--- pkg/sentry/fs/mount.go | 18 ++++++------- pkg/sentry/fs/mount_overlay.go | 4 +-- pkg/sentry/fs/mounts.go | 2 +- pkg/sentry/fs/mounts_test.go | 8 +++--- pkg/sentry/fs/overlay.go | 8 +++--- pkg/sentry/fs/proc/exec_args.go | 2 +- pkg/sentry/fs/proc/fds.go | 10 ++++---- pkg/sentry/fs/proc/fs.go | 2 +- pkg/sentry/fs/proc/inode.go | 6 ++--- pkg/sentry/fs/proc/net.go | 2 +- pkg/sentry/fs/proc/proc.go | 10 ++++---- pkg/sentry/fs/proc/rpcinet_proc.go | 10 ++++---- pkg/sentry/fs/proc/seqfile/seqfile.go | 2 +- pkg/sentry/fs/proc/seqfile/seqfile_test.go | 8 +++--- pkg/sentry/fs/proc/sys.go | 8 +++--- pkg/sentry/fs/proc/sys_net.go | 10 ++++---- pkg/sentry/fs/proc/task.go | 30 +++++++++++----------- pkg/sentry/fs/proc/uid_gid_map.go | 2 +- pkg/sentry/fs/proc/uptime.go | 2 +- pkg/sentry/fs/ramfs/dir.go | 6 ++--- pkg/sentry/fs/ramfs/tree.go | 2 +- pkg/sentry/fs/ramfs/tree_test.go | 2 +- pkg/sentry/fs/sys/devices.go | 2 +- pkg/sentry/fs/sys/fs.go | 2 +- pkg/sentry/fs/sys/sys.go | 6 ++--- pkg/sentry/fs/timerfd/timerfd.go | 2 +- pkg/sentry/fs/tmpfs/file_test.go | 6 ++--- pkg/sentry/fs/tmpfs/fs.go | 4 +-- pkg/sentry/fs/tmpfs/inode_file.go | 2 +- pkg/sentry/fs/tmpfs/tmpfs.go | 10 ++++---- pkg/sentry/fs/tty/dir.go | 6 ++--- pkg/sentry/fs/tty/fs.go | 2 +- pkg/sentry/fs/tty/master.go | 2 +- pkg/sentry/fs/tty/slave.go | 2 +- pkg/sentry/kernel/epoll/epoll.go | 2 +- pkg/sentry/kernel/eventfd/eventfd.go | 2 +- pkg/sentry/kernel/pipe/node_test.go | 4 +-- pkg/sentry/kernel/pipe/pipe.go | 4 +-- pkg/sentry/loader/vdso.go | 9 ++++--- pkg/sentry/socket/netlink/socket.go | 4 +-- pkg/sentry/socket/socket.go | 4 +-- pkg/sentry/socket/unix/io.go | 9 +++++-- pkg/sentry/socket/unix/transport/BUILD | 1 + pkg/sentry/socket/unix/transport/connectioned.go | 24 ++++++++++------- pkg/sentry/socket/unix/transport/connectionless.go | 22 ++++++++++------ pkg/sentry/socket/unix/transport/unix.go | 15 ++++++----- pkg/sentry/socket/unix/unix.go | 14 ++++++---- pkg/sentry/syscalls/linux/sys_file.go | 2 +- pkg/sentry/syscalls/linux/sys_inotify.go | 2 +- runsc/boot/fs.go | 4 +-- runsc/boot/loader.go | 4 ++- 76 files changed, 270 insertions(+), 242 deletions(-) diff --git a/pkg/sentry/fs/anon/anon.go b/pkg/sentry/fs/anon/anon.go index 28bd0998f..7323c7222 100644 --- a/pkg/sentry/fs/anon/anon.go +++ b/pkg/sentry/fs/anon/anon.go @@ -33,7 +33,7 @@ func NewInode(ctx context.Context) *fs.Inode { User: fs.PermMask{Read: true, Write: true}, }, linux.ANON_INODE_FS_MAGIC), } - return fs.NewInode(iops, fs.NewPseudoMountSource(), fs.StableAttr{ + return fs.NewInode(ctx, iops, fs.NewPseudoMountSource(ctx), fs.StableAttr{ Type: fs.Anonymous, DeviceID: PseudoDevice.DeviceID(), InodeID: PseudoDevice.NextIno(), diff --git a/pkg/sentry/fs/ashmem/area.go b/pkg/sentry/fs/ashmem/area.go index cae3e4dda..e1971f91c 100644 --- a/pkg/sentry/fs/ashmem/area.go +++ b/pkg/sentry/fs/ashmem/area.go @@ -116,8 +116,8 @@ func (a *Area) ConfigureMMap(ctx context.Context, file *fs.File, opts *memmap.MM if a.tmpfsFile == nil { tmpfsInodeOps := tmpfs.NewInMemoryFile(ctx, usage.Tmpfs, fs.UnstableAttr{}) - tmpfsInode := fs.NewInode(tmpfsInodeOps, fs.NewPseudoMountSource(), fs.StableAttr{}) - dirent := fs.NewDirent(tmpfsInode, namePrefix+"/"+a.name) + tmpfsInode := fs.NewInode(ctx, tmpfsInodeOps, fs.NewPseudoMountSource(ctx), fs.StableAttr{}) + dirent := fs.NewDirent(ctx, tmpfsInode, namePrefix+"/"+a.name) tmpfsFile, err := tmpfsInode.GetFile(ctx, dirent, fs.FileFlags{Read: true, Write: true}) // Drop the extra reference on the Dirent. dirent.DecRef() diff --git a/pkg/sentry/fs/copy_up_test.go b/pkg/sentry/fs/copy_up_test.go index 72110f856..1d80bf15a 100644 --- a/pkg/sentry/fs/copy_up_test.go +++ b/pkg/sentry/fs/copy_up_test.go @@ -102,7 +102,7 @@ func makeOverlayTestFiles(t *testing.T) []*overlayTestFile { if err != nil { t.Fatalf("failed to mount tmpfs: %v", err) } - lowerRoot := fs.NewDirent(lower, "") + lowerRoot := fs.NewDirent(ctx, lower, "") // Make a deep set of subdirectories that everyone shares. next := lowerRoot diff --git a/pkg/sentry/fs/dev/dev.go b/pkg/sentry/fs/dev/dev.go index 317be246c..fb6c30ff0 100644 --- a/pkg/sentry/fs/dev/dev.go +++ b/pkg/sentry/fs/dev/dev.go @@ -40,8 +40,8 @@ const ( urandomDevMinor uint32 = 9 ) -func newCharacterDevice(iops fs.InodeOperations, msrc *fs.MountSource) *fs.Inode { - return fs.NewInode(iops, msrc, fs.StableAttr{ +func newCharacterDevice(ctx context.Context, iops fs.InodeOperations, msrc *fs.MountSource) *fs.Inode { + return fs.NewInode(ctx, iops, msrc, fs.StableAttr{ DeviceID: devDevice.DeviceID(), InodeID: devDevice.NextIno(), BlockSize: usermem.PageSize, @@ -49,8 +49,8 @@ func newCharacterDevice(iops fs.InodeOperations, msrc *fs.MountSource) *fs.Inode }) } -func newMemDevice(iops fs.InodeOperations, msrc *fs.MountSource, minor uint32) *fs.Inode { - return fs.NewInode(iops, msrc, fs.StableAttr{ +func newMemDevice(ctx context.Context, iops fs.InodeOperations, msrc *fs.MountSource, minor uint32) *fs.Inode { + return fs.NewInode(ctx, iops, msrc, fs.StableAttr{ DeviceID: devDevice.DeviceID(), InodeID: devDevice.NextIno(), BlockSize: usermem.PageSize, @@ -62,7 +62,7 @@ func newMemDevice(iops fs.InodeOperations, msrc *fs.MountSource, minor uint32) * func newDirectory(ctx context.Context, msrc *fs.MountSource) *fs.Inode { iops := ramfs.NewDir(ctx, nil, fs.RootOwner, fs.FilePermsFromMode(0555)) - return fs.NewInode(iops, msrc, fs.StableAttr{ + return fs.NewInode(ctx, iops, msrc, fs.StableAttr{ DeviceID: devDevice.DeviceID(), InodeID: devDevice.NextIno(), BlockSize: usermem.PageSize, @@ -72,7 +72,7 @@ func newDirectory(ctx context.Context, msrc *fs.MountSource) *fs.Inode { func newSymlink(ctx context.Context, target string, msrc *fs.MountSource) *fs.Inode { iops := ramfs.NewSymlink(ctx, fs.RootOwner, target) - return fs.NewInode(iops, msrc, fs.StableAttr{ + return fs.NewInode(ctx, iops, msrc, fs.StableAttr{ DeviceID: devDevice.DeviceID(), InodeID: devDevice.NextIno(), BlockSize: usermem.PageSize, @@ -88,17 +88,17 @@ func New(ctx context.Context, msrc *fs.MountSource, binderEnabled bool, ashmemEn "stdout": newSymlink(ctx, "/proc/self/fd/1", msrc), "stderr": newSymlink(ctx, "/proc/self/fd/2", msrc), - "null": newMemDevice(newNullDevice(ctx, fs.RootOwner, 0666), msrc, nullDevMinor), - "zero": newMemDevice(newZeroDevice(ctx, fs.RootOwner, 0666), msrc, zeroDevMinor), - "full": newMemDevice(newFullDevice(ctx, fs.RootOwner, 0666), msrc, fullDevMinor), + "null": newMemDevice(ctx, newNullDevice(ctx, fs.RootOwner, 0666), msrc, nullDevMinor), + "zero": newMemDevice(ctx, newZeroDevice(ctx, fs.RootOwner, 0666), msrc, zeroDevMinor), + "full": newMemDevice(ctx, newFullDevice(ctx, fs.RootOwner, 0666), msrc, fullDevMinor), // This is not as good as /dev/random in linux because go // runtime uses sys_random and /dev/urandom internally. // According to 'man 4 random', this will be sufficient unless // application uses this to generate long-lived GPG/SSL/SSH // keys. - "random": newMemDevice(newRandomDevice(ctx, fs.RootOwner, 0444), msrc, randomDevMinor), - "urandom": newMemDevice(newRandomDevice(ctx, fs.RootOwner, 0444), msrc, urandomDevMinor), + "random": newMemDevice(ctx, newRandomDevice(ctx, fs.RootOwner, 0444), msrc, randomDevMinor), + "urandom": newMemDevice(ctx, newRandomDevice(ctx, fs.RootOwner, 0444), msrc, urandomDevMinor), "shm": tmpfs.NewDir(ctx, nil, fs.RootOwner, fs.FilePermsFromMode(0777), msrc), @@ -120,16 +120,16 @@ func New(ctx context.Context, msrc *fs.MountSource, binderEnabled bool, ashmemEn if binderEnabled { binder := binder.NewDevice(ctx, fs.RootOwner, fs.FilePermsFromMode(0666)) - contents["binder"] = newCharacterDevice(binder, msrc) + contents["binder"] = newCharacterDevice(ctx, binder, msrc) } if ashmemEnabled { ashmem := ashmem.NewDevice(ctx, fs.RootOwner, fs.FilePermsFromMode(0666)) - contents["ashmem"] = newCharacterDevice(ashmem, msrc) + contents["ashmem"] = newCharacterDevice(ctx, ashmem, msrc) } iops := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return fs.NewInode(iops, msrc, fs.StableAttr{ + return fs.NewInode(ctx, iops, msrc, fs.StableAttr{ DeviceID: devDevice.DeviceID(), InodeID: devDevice.NextIno(), BlockSize: usermem.PageSize, diff --git a/pkg/sentry/fs/dev/fs.go b/pkg/sentry/fs/dev/fs.go index 9ea6e91e9..6dbc8c382 100644 --- a/pkg/sentry/fs/dev/fs.go +++ b/pkg/sentry/fs/dev/fs.go @@ -95,5 +95,5 @@ func (f *filesystem) Mount(ctx context.Context, device string, flags fs.MountSou } // Construct the devtmpfs root. - return New(ctx, fs.NewNonCachingMountSource(f, flags), binderEnabled, ashmemEnabled), nil + return New(ctx, fs.NewNonCachingMountSource(ctx, f, flags), binderEnabled, ashmemEnabled), nil } diff --git a/pkg/sentry/fs/dirent.go b/pkg/sentry/fs/dirent.go index 9694d915d..ca417d2bc 100644 --- a/pkg/sentry/fs/dirent.go +++ b/pkg/sentry/fs/dirent.go @@ -206,7 +206,7 @@ type Dirent struct { // NewDirent returns a new root Dirent, taking the caller's reference on inode. The caller // holds the only reference to the Dirent. Parents may call hashChild to parent this Dirent. -func NewDirent(inode *Inode, name string) *Dirent { +func NewDirent(ctx context.Context, inode *Inode, name string) *Dirent { d := newDirent(inode, name) allDirents.add(d) d.userVisible = true @@ -1068,7 +1068,7 @@ func (d *Dirent) mount(ctx context.Context, inode *Inode) (newChild *Dirent, err // // Note that NewDirent returns with one reference taken; the reference // is donated to the caller as the mount reference. - replacement := NewDirent(inode, d.name) + replacement := NewDirent(ctx, inode, d.name) replacement.mounted = true weakRef, ok := d.parent.hashChild(replacement) diff --git a/pkg/sentry/fs/dirent_refs_test.go b/pkg/sentry/fs/dirent_refs_test.go index 73ffd15a6..884e3ff06 100644 --- a/pkg/sentry/fs/dirent_refs_test.go +++ b/pkg/sentry/fs/dirent_refs_test.go @@ -31,7 +31,7 @@ func TestWalkPositive(t *testing.T) { // refs == -1 -> has been destroyed. ctx := contexttest.Context(t) - root := NewDirent(newMockDirInode(ctx, nil), "root") + root := NewDirent(ctx, newMockDirInode(ctx, nil), "root") if got := root.ReadRefs(); got != 1 { t.Fatalf("root has a ref count of %d, want %d", got, 1) @@ -73,7 +73,7 @@ func TestWalkNegative(t *testing.T) { // refs == -1 -> has been destroyed. ctx := contexttest.Context(t) - root := NewDirent(NewEmptyDir(ctx, nil), "root") + root := NewDirent(ctx, NewEmptyDir(ctx, nil), "root") mn := root.Inode.InodeOperations.(*mockInodeOperationsLookupNegative) if got := root.ReadRefs(); got != 1 { @@ -144,7 +144,7 @@ type mockInodeOperationsLookupNegative struct { func NewEmptyDir(ctx context.Context, cache *DirentCache) *Inode { m := NewMockMountSource(cache) - return NewInode(&mockInodeOperationsLookupNegative{ + return NewInode(ctx, &mockInodeOperationsLookupNegative{ MockInodeOperations: NewMockInodeOperations(ctx), }, m, StableAttr{Type: Directory}) } @@ -162,7 +162,7 @@ func TestHashNegativeToPositive(t *testing.T) { // refs == -1 -> has been destroyed. ctx := contexttest.Context(t) - root := NewDirent(NewEmptyDir(ctx, nil), "root") + root := NewDirent(ctx, NewEmptyDir(ctx, nil), "root") name := "d" _, err := root.walk(ctx, root, name, false) @@ -215,7 +215,6 @@ func TestRevalidate(t *testing.T) { // refs == 0 -> one reference. // refs == -1 -> has been destroyed. - ctx := contexttest.Context(t) for _, test := range []struct { // desc is the test's description. desc string @@ -233,7 +232,8 @@ func TestRevalidate(t *testing.T) { }, } { t.Run(test.desc, func(t *testing.T) { - root := NewDirent(NewMockInodeRevalidate(ctx, test.makeNegative), "root") + ctx := contexttest.Context(t) + root := NewDirent(ctx, NewMockInodeRevalidate(ctx, test.makeNegative), "root") name := "d" d1, err := root.walk(ctx, root, name, false) @@ -263,7 +263,7 @@ func NewMockInodeRevalidate(ctx context.Context, makeNegative bool) *Inode { mn := NewMockInodeOperations(ctx) m := NewMockMountSource(nil) m.MountSourceOperations.(*MockMountSourceOps).revalidate = true - return NewInode(&MockInodeOperationsRevalidate{MockInodeOperations: mn, makeNegative: makeNegative}, m, StableAttr{Type: Directory}) + return NewInode(ctx, &MockInodeOperationsRevalidate{MockInodeOperations: mn, makeNegative: makeNegative}, m, StableAttr{Type: Directory}) } func (m *MockInodeOperationsRevalidate) Lookup(ctx context.Context, dir *Inode, p string) (*Dirent, error) { @@ -290,12 +290,12 @@ func TestCreateExtraRefs(t *testing.T) { }{ { desc: "Create caching", - root: NewDirent(NewEmptyDir(ctx, NewDirentCache(1)), "root"), + root: NewDirent(ctx, NewEmptyDir(ctx, NewDirentCache(1)), "root"), refs: 2, }, { desc: "Create not caching", - root: NewDirent(NewEmptyDir(ctx, nil), "root"), + root: NewDirent(ctx, NewEmptyDir(ctx, nil), "root"), refs: 1, }, } { @@ -328,11 +328,11 @@ func TestRemoveExtraRefs(t *testing.T) { }{ { desc: "Remove caching", - root: NewDirent(NewEmptyDir(ctx, NewDirentCache(1)), "root"), + root: NewDirent(ctx, NewEmptyDir(ctx, NewDirentCache(1)), "root"), }, { desc: "Remove not caching", - root: NewDirent(NewEmptyDir(ctx, nil), "root"), + root: NewDirent(ctx, NewEmptyDir(ctx, nil), "root"), }, } { t.Run(test.desc, func(t *testing.T) { @@ -366,7 +366,6 @@ func TestRenameExtraRefs(t *testing.T) { // refs == 0 -> one reference. // refs == -1 -> has been destroyed. - ctx := contexttest.Context(t) for _, test := range []struct { // desc is the test's description. desc string @@ -384,10 +383,12 @@ func TestRenameExtraRefs(t *testing.T) { }, } { t.Run(test.desc, func(t *testing.T) { + ctx := contexttest.Context(t) + dirAttr := StableAttr{Type: Directory} - oldParent := NewDirent(NewMockInode(ctx, NewMockMountSource(test.cache), dirAttr), "old_parent") - newParent := NewDirent(NewMockInode(ctx, NewMockMountSource(test.cache), dirAttr), "new_parent") + oldParent := NewDirent(ctx, NewMockInode(ctx, NewMockMountSource(test.cache), dirAttr), "old_parent") + newParent := NewDirent(ctx, NewMockInode(ctx, NewMockMountSource(test.cache), dirAttr), "new_parent") renamed, err := oldParent.Walk(ctx, oldParent, "old_child") if err != nil { diff --git a/pkg/sentry/fs/fdpipe/pipe_opener_test.go b/pkg/sentry/fs/fdpipe/pipe_opener_test.go index 7ae61b711..8e4d839e1 100644 --- a/pkg/sentry/fs/fdpipe/pipe_opener_test.go +++ b/pkg/sentry/fs/fdpipe/pipe_opener_test.go @@ -359,7 +359,7 @@ func TestCopiedReadAheadBuffer(t *testing.T) { inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{ Type: fs.Pipe, }) - file := fs.NewFile(ctx, fs.NewDirent(inode, "pipe"), fs.FileFlags{Read: true}, pipeOps) + file := fs.NewFile(ctx, fs.NewDirent(ctx, inode, "pipe"), fs.FileFlags{Read: true}, pipeOps) // Check that the file we opened points to a pipe with a non-empty read ahead buffer. bufsize := len(pipeOps.readAheadBuffer) diff --git a/pkg/sentry/fs/fdpipe/pipe_test.go b/pkg/sentry/fs/fdpipe/pipe_test.go index 21ea14359..ecda8df79 100644 --- a/pkg/sentry/fs/fdpipe/pipe_test.go +++ b/pkg/sentry/fs/fdpipe/pipe_test.go @@ -50,11 +50,11 @@ func mockPipeDirent(t *testing.T) *fs.Dirent { User: fs.PermMask{Read: true, Write: true}, }, } - inode := fs.NewInode(node, fs.NewMockMountSource(nil), fs.StableAttr{ + inode := fs.NewInode(ctx, node, fs.NewMockMountSource(nil), fs.StableAttr{ Type: fs.Pipe, BlockSize: usermem.PageSize, }) - return fs.NewDirent(inode, "") + return fs.NewDirent(ctx, inode, "") } func TestNewPipe(t *testing.T) { @@ -285,7 +285,7 @@ func TestPipeRequest(t *testing.T) { defer p.Release() inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe}) - file := fs.NewFile(ctx, fs.NewDirent(inode, "pipe"), fs.FileFlags{Read: true}, p) + file := fs.NewFile(ctx, fs.NewDirent(ctx, inode, "pipe"), fs.FileFlags{Read: true}, p) // Issue request via the appropriate function. switch c := test.context.(type) { @@ -339,7 +339,7 @@ func TestPipeReadAheadBuffer(t *testing.T) { inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{ Type: fs.Pipe, }) - file := fs.NewFile(ctx, fs.NewDirent(inode, "pipe"), fs.FileFlags{Read: true}, p) + file := fs.NewFile(ctx, fs.NewDirent(ctx, inode, "pipe"), fs.FileFlags{Read: true}, p) // In total we expect to read data + buffered. total := append(buffered, data...) @@ -385,7 +385,7 @@ func TestPipeReadsAccumulate(t *testing.T) { inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{ Type: fs.Pipe, }) - file := fs.NewFile(ctx, fs.NewDirent(inode, "pipe"), fs.FileFlags{Read: true}, p) + file := fs.NewFile(ctx, fs.NewDirent(ctx, inode, "pipe"), fs.FileFlags{Read: true}, p) // Write some some bytes to the pipe. data := []byte("some message") @@ -453,7 +453,7 @@ func TestPipeWritesAccumulate(t *testing.T) { inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{ Type: fs.Pipe, }) - file := fs.NewFile(ctx, fs.NewDirent(inode, "pipe"), fs.FileFlags{Read: true}, p) + file := fs.NewFile(ctx, fs.NewDirent(ctx, inode, "pipe"), fs.FileFlags{Read: true}, p) // Construct a segment vec that is larger than the pipe size to trigger an EWOULDBLOCK. wantBytes := 65536 * 2 diff --git a/pkg/sentry/fs/file_overlay_test.go b/pkg/sentry/fs/file_overlay_test.go index 1df826f6c..2fb824d5c 100644 --- a/pkg/sentry/fs/file_overlay_test.go +++ b/pkg/sentry/fs/file_overlay_test.go @@ -29,7 +29,7 @@ func TestReaddir(t *testing.T) { ctx := contexttest.Context(t) ctx = &rootContext{ Context: ctx, - root: fs.NewDirent(newTestRamfsDir(ctx, nil, nil), "root"), + root: fs.NewDirent(ctx, newTestRamfsDir(ctx, nil, nil), "root"), } for _, test := range []struct { // Test description. @@ -103,7 +103,7 @@ func TestReaddir(t *testing.T) { }, } { t.Run(test.desc, func(t *testing.T) { - openDir, err := test.dir.GetFile(ctx, fs.NewDirent(test.dir, "stub"), fs.FileFlags{Read: true}) + openDir, err := test.dir.GetFile(ctx, fs.NewDirent(ctx, test.dir, "stub"), fs.FileFlags{Read: true}) if err != nil { t.Fatalf("GetFile got error %v, want nil", err) } @@ -126,7 +126,7 @@ func TestReaddirRevalidation(t *testing.T) { ctx := contexttest.Context(t) ctx = &rootContext{ Context: ctx, - root: fs.NewDirent(newTestRamfsDir(ctx, nil, nil), "root"), + root: fs.NewDirent(ctx, newTestRamfsDir(ctx, nil, nil), "root"), } // Create an overlay with two directories, each with one file. @@ -139,7 +139,7 @@ func TestReaddirRevalidation(t *testing.T) { upperDir := upper.InodeOperations.(*dir).InodeOperations.(*ramfs.Dir) // Check that overlay returns the files from both upper and lower. - openDir, err := overlay.GetFile(ctx, fs.NewDirent(overlay, "stub"), fs.FileFlags{Read: true}) + openDir, err := overlay.GetFile(ctx, fs.NewDirent(ctx, overlay, "stub"), fs.FileFlags{Read: true}) if err != nil { t.Fatalf("GetFile got error %v, want nil", err) } @@ -156,7 +156,7 @@ func TestReaddirRevalidation(t *testing.T) { if err := upperDir.Remove(ctx, upper, "a"); err != nil { t.Fatalf("error removing child: %v", err) } - upperDir.AddChild(ctx, "c", fs.NewInode(fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermissions{}, 0), + upperDir.AddChild(ctx, "c", fs.NewInode(ctx, fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermissions{}, 0), upper.MountSource, fs.StableAttr{Type: fs.RegularFile})) // Seek to beginning of the directory and do the readdir again. @@ -186,7 +186,7 @@ func TestReaddirOverlayFrozen(t *testing.T) { overlayInode := fs.NewTestOverlayDir(ctx, upper, lower, false) // Set that overlay as the root. - root := fs.NewDirent(overlayInode, "root") + root := fs.NewDirent(ctx, overlayInode, "root") ctx = &rootContext{ Context: ctx, root: root, diff --git a/pkg/sentry/fs/filetest/filetest.go b/pkg/sentry/fs/filetest/filetest.go index 856477480..22270a494 100644 --- a/pkg/sentry/fs/filetest/filetest.go +++ b/pkg/sentry/fs/filetest/filetest.go @@ -46,7 +46,7 @@ type TestFileOperations struct { // NewTestFile creates and initializes a new test file. func NewTestFile(tb testing.TB) *fs.File { ctx := contexttest.Context(tb) - dirent := fs.NewDirent(anon.NewInode(ctx), "test") + dirent := fs.NewDirent(ctx, anon.NewInode(ctx), "test") return fs.NewFile(ctx, dirent, fs.FileFlags{}, &TestFileOperations{}) } diff --git a/pkg/sentry/fs/fsutil/inode_cached_test.go b/pkg/sentry/fs/fsutil/inode_cached_test.go index 82a67b2e5..dc19255ed 100644 --- a/pkg/sentry/fs/fsutil/inode_cached_test.go +++ b/pkg/sentry/fs/fsutil/inode_cached_test.go @@ -253,11 +253,11 @@ func (noopMappingSpace) Invalidate(ar usermem.AddrRange, opts memmap.InvalidateO } func anonInode(ctx context.Context) *fs.Inode { - return fs.NewInode(&SimpleFileInode{ + return fs.NewInode(ctx, &SimpleFileInode{ InodeSimpleAttributes: NewInodeSimpleAttributes(ctx, fs.FileOwnerFromContext(ctx), fs.FilePermissions{ User: fs.PermMask{Read: true, Write: true}, }, 0), - }, fs.NewPseudoMountSource(), fs.StableAttr{ + }, fs.NewPseudoMountSource(ctx), fs.StableAttr{ Type: fs.Anonymous, BlockSize: usermem.PageSize, }) @@ -276,7 +276,7 @@ func TestRead(t *testing.T) { // Construct a 3-page file. buf := pagesOf('a', 'b', 'c') - file := fs.NewFile(ctx, fs.NewDirent(anonInode(ctx), "anon"), fs.FileFlags{}, nil) + file := fs.NewFile(ctx, fs.NewDirent(ctx, anonInode(ctx), "anon"), fs.FileFlags{}, nil) uattr := fs.UnstableAttr{ Size: int64(len(buf)), } diff --git a/pkg/sentry/fs/gofer/gofer_test.go b/pkg/sentry/fs/gofer/gofer_test.go index f671f219d..7fc3c32ae 100644 --- a/pkg/sentry/fs/gofer/gofer_test.go +++ b/pkg/sentry/fs/gofer/gofer_test.go @@ -62,8 +62,8 @@ func rootTest(t *testing.T, name string, cp cachePolicy, fn func(context.Context sattr, rootInodeOperations := newInodeOperations(ctx, s, contextFile{ file: rootFile, }, root.QID, p9.AttrMaskAll(), root.Attr, false /* socket */) - m := fs.NewMountSource(s, &filesystem{}, fs.MountSourceFlags{}) - rootInode := fs.NewInode(rootInodeOperations, m, sattr) + m := fs.NewMountSource(ctx, s, &filesystem{}, fs.MountSourceFlags{}) + rootInode := fs.NewInode(ctx, rootInodeOperations, m, sattr) // Ensure that the cache is fully invalidated, so that any // close actions actually take place before the full harness is @@ -207,7 +207,7 @@ func TestRevalidation(t *testing.T) { name := fmt.Sprintf("cachepolicy=%s", test.cachePolicy) rootTest(t, name, test.cachePolicy, func(ctx context.Context, h *p9test.Harness, rootFile *p9test.Mock, rootInode *fs.Inode) { // Wrap in a dirent object. - rootDir := fs.NewDirent(rootInode, "root") + rootDir := fs.NewDirent(ctx, rootInode, "root") // Create a mock file a child of the root. We save when // this is generated, so that when the time changed, we diff --git a/pkg/sentry/fs/gofer/path.go b/pkg/sentry/fs/gofer/path.go index 24f6cc093..b91386909 100644 --- a/pkg/sentry/fs/gofer/path.go +++ b/pkg/sentry/fs/gofer/path.go @@ -73,7 +73,7 @@ func (i *inodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name string sattr, node := newInodeOperations(ctx, i.fileState.s, newFile, qids[0], mask, p9attr, false) // Construct a positive Dirent. - return fs.NewDirent(fs.NewInode(node, dir.MountSource, sattr), name), nil + return fs.NewDirent(ctx, fs.NewInode(ctx, node, dir.MountSource, sattr), name), nil } // Creates a new Inode at name and returns its File based on the session's cache policy. @@ -141,7 +141,7 @@ func (i *inodeOperations) Create(ctx context.Context, dir *fs.Inode, name string sattr, iops := newInodeOperations(ctx, i.fileState.s, unopened, qid, mask, p9attr, false) // Construct the positive Dirent. - d := fs.NewDirent(fs.NewInode(iops, dir.MountSource, sattr), name) + d := fs.NewDirent(ctx, fs.NewInode(ctx, iops, dir.MountSource, sattr), name) defer d.DecRef() // Construct the new file, caching the handles if allowed. @@ -277,7 +277,7 @@ func (i *inodeOperations) Bind(ctx context.Context, dir *fs.Inode, name string, sattr, iops := newInodeOperations(ctx, i.fileState.s, unopened, qid, mask, attr, true) // Construct the positive Dirent. - childDir := fs.NewDirent(fs.NewInode(iops, dir.MountSource, sattr), name) + childDir := fs.NewDirent(ctx, fs.NewInode(ctx, iops, dir.MountSource, sattr), name) i.session().endpoints.add(key, childDir, ep) return childDir, nil } diff --git a/pkg/sentry/fs/gofer/session.go b/pkg/sentry/fs/gofer/session.go index 1763c8692..7ad0d8bc5 100644 --- a/pkg/sentry/fs/gofer/session.go +++ b/pkg/sentry/fs/gofer/session.go @@ -251,7 +251,7 @@ func Root(ctx context.Context, dev string, filesystem fs.Filesystem, superBlockF } // Construct the MountSource with the session and superBlockFlags. - m := fs.NewMountSource(s, filesystem, superBlockFlags) + m := fs.NewMountSource(ctx, s, filesystem, superBlockFlags) // Given that gofer files can consume host FDs, restrict the number // of files that can be held by the cache. @@ -286,7 +286,7 @@ func Root(ctx context.Context, dev string, filesystem fs.Filesystem, superBlockF } sattr, iops := newInodeOperations(ctx, s, s.attach, qid, valid, attr, false) - return fs.NewInode(iops, m, sattr), nil + return fs.NewInode(ctx, iops, m, sattr), nil } // newEndpointMaps creates a new endpointMaps. diff --git a/pkg/sentry/fs/gofer/socket.go b/pkg/sentry/fs/gofer/socket.go index 6a9994264..a45a8f36c 100644 --- a/pkg/sentry/fs/gofer/socket.go +++ b/pkg/sentry/fs/gofer/socket.go @@ -18,6 +18,7 @@ import ( "gvisor.dev/gvisor/pkg/abi/linux" "gvisor.dev/gvisor/pkg/log" "gvisor.dev/gvisor/pkg/p9" + "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/sentry/fs" "gvisor.dev/gvisor/pkg/sentry/fs/host" "gvisor.dev/gvisor/pkg/sentry/socket/unix/transport" @@ -75,7 +76,7 @@ func sockTypeToP9(t linux.SockType) (p9.ConnectFlags, bool) { } // BidirectionalConnect implements ConnectableEndpoint.BidirectionalConnect. -func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnConnect func(transport.Receiver, transport.ConnectedEndpoint)) *syserr.Error { +func (e *endpoint) BidirectionalConnect(ctx context.Context, ce transport.ConnectingEndpoint, returnConnect func(transport.Receiver, transport.ConnectedEndpoint)) *syserr.Error { cf, ok := sockTypeToP9(ce.Type()) if !ok { return syserr.ErrConnectionRefused @@ -100,7 +101,7 @@ func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnC return syserr.ErrConnectionRefused } - c, serr := host.NewConnectedEndpoint(hostFile, ce.WaiterQueue(), e.path) + c, serr := host.NewConnectedEndpoint(ctx, hostFile, ce.WaiterQueue(), e.path) if serr != nil { ce.Unlock() log.Warningf("Gofer returned invalid host socket for BidirectionalConnect; file %+v flags %+v: %v", e.file, cf, serr) @@ -116,13 +117,13 @@ func (e *endpoint) BidirectionalConnect(ce transport.ConnectingEndpoint, returnC // UnidirectionalConnect implements // transport.BoundEndpoint.UnidirectionalConnect. -func (e *endpoint) UnidirectionalConnect() (transport.ConnectedEndpoint, *syserr.Error) { +func (e *endpoint) UnidirectionalConnect(ctx context.Context) (transport.ConnectedEndpoint, *syserr.Error) { hostFile, err := e.file.Connect(p9.DgramSocket) if err != nil { return nil, syserr.ErrConnectionRefused } - c, serr := host.NewConnectedEndpoint(hostFile, &waiter.Queue{}, e.path) + c, serr := host.NewConnectedEndpoint(ctx, hostFile, &waiter.Queue{}, e.path) if serr != nil { log.Warningf("Gofer returned invalid host socket for UnidirectionalConnect; file %+v: %v", e.file, serr) return nil, serr diff --git a/pkg/sentry/fs/host/file.go b/pkg/sentry/fs/host/file.go index 45d5c8695..bd665a6b1 100644 --- a/pkg/sentry/fs/host/file.go +++ b/pkg/sentry/fs/host/file.go @@ -109,7 +109,7 @@ func newFileFromDonatedFD(ctx context.Context, donated int, mounter fs.FileOwner iops := inode.InodeOperations.(*inodeOperations) name := fmt.Sprintf("host:[%d]", inode.StableAttr.InodeID) - dirent := fs.NewDirent(inode, name) + dirent := fs.NewDirent(ctx, inode, name) defer dirent.DecRef() if isTTY { diff --git a/pkg/sentry/fs/host/fs.go b/pkg/sentry/fs/host/fs.go index 914d95d27..68d2697c0 100644 --- a/pkg/sentry/fs/host/fs.go +++ b/pkg/sentry/fs/host/fs.go @@ -262,7 +262,7 @@ func childDentAttrs(ctx context.Context, d *fs.Dirent) map[string]fs.DentAttr { // newMountSource constructs a new host fs.MountSource // relative to a root path. The root should match the mount point. func newMountSource(ctx context.Context, root string, mounter fs.FileOwner, filesystem fs.Filesystem, flags fs.MountSourceFlags, dontTranslateOwnership bool) *fs.MountSource { - return fs.NewMountSource(&superOperations{ + return fs.NewMountSource(ctx, &superOperations{ root: root, inodeMappings: make(map[uint64]string), mounter: mounter, diff --git a/pkg/sentry/fs/host/inode.go b/pkg/sentry/fs/host/inode.go index ca352a8c2..679d8321a 100644 --- a/pkg/sentry/fs/host/inode.go +++ b/pkg/sentry/fs/host/inode.go @@ -205,7 +205,7 @@ func newInode(ctx context.Context, msrc *fs.MountSource, fd int, saveable bool, } // Return the fs.Inode. - return fs.NewInode(iops, msrc, fileState.sattr), nil + return fs.NewInode(ctx, iops, msrc, fileState.sattr), nil } // Mappable implements fs.InodeOperations.Mappable. @@ -245,7 +245,7 @@ func (i *inodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name string } // Return the fs.Dirent. - return fs.NewDirent(inode, name), nil + return fs.NewDirent(ctx, inode, name), nil } // Create implements fs.InodeOperations.Create. @@ -265,7 +265,7 @@ func (i *inodeOperations) Create(ctx context.Context, dir *fs.Inode, name string return nil, err } - d := fs.NewDirent(inode, name) + d := fs.NewDirent(ctx, inode, name) defer d.DecRef() return inode.GetFile(ctx, d, flags) } diff --git a/pkg/sentry/fs/host/inode_test.go b/pkg/sentry/fs/host/inode_test.go index bd2d856ee..18994c456 100644 --- a/pkg/sentry/fs/host/inode_test.go +++ b/pkg/sentry/fs/host/inode_test.go @@ -56,7 +56,7 @@ func TestMultipleReaddir(t *testing.T) { t.Fatalf("Failed to create inode: %v", err) } - dirent := fs.NewDirent(n, "readdir") + dirent := fs.NewDirent(ctx, n, "readdir") openFile, err := n.GetFile(ctx, dirent, fs.FileFlags{Read: true}) if err != nil { t.Fatalf("Failed to get file: %v", err) diff --git a/pkg/sentry/fs/host/socket.go b/pkg/sentry/fs/host/socket.go index a40890b41..7fedc88bc 100644 --- a/pkg/sentry/fs/host/socket.go +++ b/pkg/sentry/fs/host/socket.go @@ -118,7 +118,7 @@ func (c *ConnectedEndpoint) init() *syserr.Error { // The caller is responsible for calling Init(). Additionaly, Release needs to // be called twice because ConnectedEndpoint is both a transport.Receiver and // transport.ConnectedEndpoint. -func NewConnectedEndpoint(file *fd.FD, queue *waiter.Queue, path string) (*ConnectedEndpoint, *syserr.Error) { +func NewConnectedEndpoint(ctx context.Context, file *fd.FD, queue *waiter.Queue, path string) (*ConnectedEndpoint, *syserr.Error) { e := ConnectedEndpoint{ path: path, queue: queue, @@ -151,7 +151,7 @@ func (c *ConnectedEndpoint) Init() { func NewSocketWithDirent(ctx context.Context, d *fs.Dirent, f *fd.FD, flags fs.FileFlags) (*fs.File, error) { f2 := fd.New(f.FD()) var q waiter.Queue - e, err := NewConnectedEndpoint(f2, &q, "" /* path */) + e, err := NewConnectedEndpoint(ctx, f2, &q, "" /* path */) if err != nil { f2.Release() return nil, err.ToError() @@ -162,7 +162,7 @@ func NewSocketWithDirent(ctx context.Context, d *fs.Dirent, f *fd.FD, flags fs.F e.Init() - ep := transport.NewExternal(e.stype, uniqueid.GlobalProviderFromContext(ctx), &q, e, e) + ep := transport.NewExternal(ctx, e.stype, uniqueid.GlobalProviderFromContext(ctx), &q, e, e) return unixsocket.NewWithDirent(ctx, d, ep, e.stype, flags), nil } @@ -181,7 +181,7 @@ func newSocket(ctx context.Context, orgfd int, saveable bool) (*fs.File, error) } f := fd.New(ownedfd) var q waiter.Queue - e, err := NewConnectedEndpoint(f, &q, "" /* path */) + e, err := NewConnectedEndpoint(ctx, f, &q, "" /* path */) if err != nil { if saveable { f.Close() @@ -194,7 +194,7 @@ func newSocket(ctx context.Context, orgfd int, saveable bool) (*fs.File, error) e.srfd = srfd e.Init() - ep := transport.NewExternal(e.stype, uniqueid.GlobalProviderFromContext(ctx), &q, e, e) + ep := transport.NewExternal(ctx, e.stype, uniqueid.GlobalProviderFromContext(ctx), &q, e, e) return unixsocket.New(ctx, ep, e.stype), nil } diff --git a/pkg/sentry/fs/inode.go b/pkg/sentry/fs/inode.go index a19744ab1..a889586aa 100644 --- a/pkg/sentry/fs/inode.go +++ b/pkg/sentry/fs/inode.go @@ -76,7 +76,7 @@ type LockCtx struct { // NewInode constructs an Inode from InodeOperations, a MountSource, and stable attributes. // // NewInode takes a reference on msrc. -func NewInode(iops InodeOperations, msrc *MountSource, sattr StableAttr) *Inode { +func NewInode(ctx context.Context, iops InodeOperations, msrc *MountSource, sattr StableAttr) *Inode { msrc.IncRef() return &Inode{ InodeOperations: iops, diff --git a/pkg/sentry/fs/inode_overlay.go b/pkg/sentry/fs/inode_overlay.go index 805187f60..57b8b14e3 100644 --- a/pkg/sentry/fs/inode_overlay.go +++ b/pkg/sentry/fs/inode_overlay.go @@ -111,7 +111,7 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name parent.copyMu.RUnlock() return nil, false, err } - d, err := NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil + d, err := NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil parent.copyMu.RUnlock() return d, true, err } @@ -201,7 +201,7 @@ func overlayLookup(ctx context.Context, parent *overlayEntry, inode *Inode, name parent.copyMu.RUnlock() return nil, false, err } - d, err := NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil + d, err := NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil parent.copyMu.RUnlock() return d, upperInode != nil, err } @@ -245,7 +245,7 @@ func overlayCreate(ctx context.Context, o *overlayEntry, parent *Dirent, name st // overlay file. overlayInode := newOverlayInode(ctx, entry, parent.Inode.MountSource) // d will own the inode reference. - overlayDirent := NewDirent(overlayInode, name) + overlayDirent := NewDirent(ctx, overlayInode, name) // The overlay file created below with NewFile will take a reference on // the overlayDirent, and it should be the only thing holding a // reference at the time of creation, so we must drop this reference. @@ -422,7 +422,7 @@ func overlayBind(ctx context.Context, o *overlayEntry, parent *Dirent, name stri inode.DecRef() return nil, err } - return NewDirent(newOverlayInode(ctx, entry, inode.MountSource), name), nil + return NewDirent(ctx, newOverlayInode(ctx, entry, inode.MountSource), name), nil } func overlayBoundEndpoint(o *overlayEntry, path string) transport.BoundEndpoint { @@ -648,13 +648,13 @@ func NewTestOverlayDir(ctx context.Context, upper, lower *Inode, revalidate bool fs := &overlayFilesystem{} var upperMsrc *MountSource if revalidate { - upperMsrc = NewRevalidatingMountSource(fs, MountSourceFlags{}) + upperMsrc = NewRevalidatingMountSource(ctx, fs, MountSourceFlags{}) } else { - upperMsrc = NewNonCachingMountSource(fs, MountSourceFlags{}) + upperMsrc = NewNonCachingMountSource(ctx, fs, MountSourceFlags{}) } - msrc := NewMountSource(&overlayMountSourceOperations{ + msrc := NewMountSource(ctx, &overlayMountSourceOperations{ upper: upperMsrc, - lower: NewNonCachingMountSource(fs, MountSourceFlags{}), + lower: NewNonCachingMountSource(ctx, fs, MountSourceFlags{}), }, fs, MountSourceFlags{}) overlay := &overlayEntry{ upper: upper, diff --git a/pkg/sentry/fs/inode_overlay_test.go b/pkg/sentry/fs/inode_overlay_test.go index 7e56d5969..8935aad65 100644 --- a/pkg/sentry/fs/inode_overlay_test.go +++ b/pkg/sentry/fs/inode_overlay_test.go @@ -275,12 +275,12 @@ func TestLookupRevalidation(t *testing.T) { }, } { t.Run(tc.desc, func(t *testing.T) { - root := fs.NewDirent(newTestRamfsDir(ctx, nil, nil), "root") + root := fs.NewDirent(ctx, newTestRamfsDir(ctx, nil, nil), "root") ctx = &rootContext{ Context: ctx, root: root, } - overlay := fs.NewDirent(fs.NewTestOverlayDir(ctx, tc.upper, tc.lower, tc.revalidate), "overlay") + overlay := fs.NewDirent(ctx, fs.NewTestOverlayDir(ctx, tc.upper, tc.lower, tc.revalidate), "overlay") // Lookup the file twice through the overlay. first, err := overlay.Walk(ctx, root, fileName) if err != nil { @@ -442,7 +442,7 @@ func (f *dirFile) Readdir(ctx context.Context, file *fs.File, ser fs.DentrySeria } func newTestRamfsInode(ctx context.Context, msrc *fs.MountSource) *fs.Inode { - inode := fs.NewInode(&inode{ + inode := fs.NewInode(ctx, &inode{ InodeStaticFileGetter: fsutil.InodeStaticFileGetter{ Contents: []byte("foobar"), }, @@ -451,7 +451,7 @@ func newTestRamfsInode(ctx context.Context, msrc *fs.MountSource) *fs.Inode { } func newTestRamfsDir(ctx context.Context, contains []dirContent, negative []string) *fs.Inode { - msrc := fs.NewPseudoMountSource() + msrc := fs.NewPseudoMountSource(ctx) contents := make(map[string]*fs.Inode) for _, c := range contains { if c.dir { @@ -463,7 +463,7 @@ func newTestRamfsDir(ctx context.Context, contains []dirContent, negative []stri dops := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermissions{ User: fs.PermMask{Read: true, Execute: true}, }) - return fs.NewInode(&dir{ + return fs.NewInode(ctx, &dir{ InodeOperations: dops, negative: negative, }, msrc, fs.StableAttr{Type: fs.Directory}) diff --git a/pkg/sentry/fs/mock.go b/pkg/sentry/fs/mock.go index c4e12acfe..b3c4ad80b 100644 --- a/pkg/sentry/fs/mock.go +++ b/pkg/sentry/fs/mock.go @@ -34,7 +34,7 @@ type MockInodeOperations struct { // NewMockInode returns a mock *Inode using MockInodeOperations. func NewMockInode(ctx context.Context, msrc *MountSource, sattr StableAttr) *Inode { - return NewInode(NewMockInodeOperations(ctx), msrc, sattr) + return NewInode(ctx, NewMockInodeOperations(ctx), msrc, sattr) } // NewMockInodeOperations returns a *MockInodeOperations. @@ -93,7 +93,7 @@ func (n *MockInodeOperations) IsVirtual() bool { // Lookup implements fs.InodeOperations.Lookup. func (n *MockInodeOperations) Lookup(ctx context.Context, dir *Inode, p string) (*Dirent, error) { n.walkCalled = true - return NewDirent(NewInode(&MockInodeOperations{}, dir.MountSource, StableAttr{}), p), nil + return NewDirent(ctx, NewInode(ctx, &MockInodeOperations{}, dir.MountSource, StableAttr{}), p), nil } // SetPermissions implements fs.InodeOperations.SetPermissions. @@ -114,7 +114,7 @@ func (n *MockInodeOperations) SetTimestamps(context.Context, *Inode, TimeSpec) e // Create implements fs.InodeOperations.Create. func (n *MockInodeOperations) Create(ctx context.Context, dir *Inode, p string, flags FileFlags, perms FilePermissions) (*File, error) { n.createCalled = true - d := NewDirent(NewInode(&MockInodeOperations{}, dir.MountSource, StableAttr{}), p) + d := NewDirent(ctx, NewInode(ctx, &MockInodeOperations{}, dir.MountSource, StableAttr{}), p) return &File{Dirent: d}, nil } diff --git a/pkg/sentry/fs/mount.go b/pkg/sentry/fs/mount.go index ae9a4279a..2eb6a9d82 100644 --- a/pkg/sentry/fs/mount.go +++ b/pkg/sentry/fs/mount.go @@ -127,7 +127,7 @@ const DefaultDirentCacheSize uint64 = 1000 // NewMountSource returns a new MountSource. Filesystem may be nil if there is no // filesystem backing the mount. -func NewMountSource(mops MountSourceOperations, filesystem Filesystem, flags MountSourceFlags) *MountSource { +func NewMountSource(ctx context.Context, mops MountSourceOperations, filesystem Filesystem, flags MountSourceFlags) *MountSource { fsType := "none" if filesystem != nil { fsType = filesystem.Name() @@ -188,16 +188,16 @@ func (msrc *MountSource) SetDirentCacheLimiter(l *DirentCacheLimiter) { // NewCachingMountSource returns a generic mount that will cache dirents // aggressively. -func NewCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource { - return NewMountSource(&SimpleMountSourceOperations{ +func NewCachingMountSource(ctx context.Context, filesystem Filesystem, flags MountSourceFlags) *MountSource { + return NewMountSource(ctx, &SimpleMountSourceOperations{ keep: true, revalidate: false, }, filesystem, flags) } // NewNonCachingMountSource returns a generic mount that will never cache dirents. -func NewNonCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource { - return NewMountSource(&SimpleMountSourceOperations{ +func NewNonCachingMountSource(ctx context.Context, filesystem Filesystem, flags MountSourceFlags) *MountSource { + return NewMountSource(ctx, &SimpleMountSourceOperations{ keep: false, revalidate: false, }, filesystem, flags) @@ -205,8 +205,8 @@ func NewNonCachingMountSource(filesystem Filesystem, flags MountSourceFlags) *Mo // NewRevalidatingMountSource returns a generic mount that will cache dirents, // but will revalidate them on each lookup. -func NewRevalidatingMountSource(filesystem Filesystem, flags MountSourceFlags) *MountSource { - return NewMountSource(&SimpleMountSourceOperations{ +func NewRevalidatingMountSource(ctx context.Context, filesystem Filesystem, flags MountSourceFlags) *MountSource { + return NewMountSource(ctx, &SimpleMountSourceOperations{ keep: true, revalidate: true, }, filesystem, flags) @@ -214,8 +214,8 @@ func NewRevalidatingMountSource(filesystem Filesystem, flags MountSourceFlags) * // NewPseudoMountSource returns a "pseudo" mount source that is not backed by // an actual filesystem. It is always non-caching. -func NewPseudoMountSource() *MountSource { - return NewMountSource(&SimpleMountSourceOperations{ +func NewPseudoMountSource(ctx context.Context) *MountSource { + return NewMountSource(ctx, &SimpleMountSourceOperations{ keep: false, revalidate: false, }, nil, MountSourceFlags{}) diff --git a/pkg/sentry/fs/mount_overlay.go b/pkg/sentry/fs/mount_overlay.go index cb413e8dc..bc0ce7adc 100644 --- a/pkg/sentry/fs/mount_overlay.go +++ b/pkg/sentry/fs/mount_overlay.go @@ -28,10 +28,10 @@ type overlayMountSourceOperations struct { lower *MountSource } -func newOverlayMountSource(upper, lower *MountSource, flags MountSourceFlags) *MountSource { +func newOverlayMountSource(ctx context.Context, upper, lower *MountSource, flags MountSourceFlags) *MountSource { upper.IncRef() lower.IncRef() - msrc := NewMountSource(&overlayMountSourceOperations{ + msrc := NewMountSource(ctx, &overlayMountSourceOperations{ upper: upper, lower: lower, }, &overlayFilesystem{}, flags) diff --git a/pkg/sentry/fs/mounts.go b/pkg/sentry/fs/mounts.go index c15d76e90..a5d6f8b9a 100644 --- a/pkg/sentry/fs/mounts.go +++ b/pkg/sentry/fs/mounts.go @@ -166,7 +166,7 @@ func NewMountNamespace(ctx context.Context, root *Inode) (*MountNamespace, error // Set the root dirent and id on the root mount. The reference returned from // NewDirent will be donated to the MountNamespace constructed below. - d := NewDirent(root, "/") + d := NewDirent(ctx, root, "/") mnts := map[*Dirent]*Mount{ d: newRootMount(1, d), diff --git a/pkg/sentry/fs/mounts_test.go b/pkg/sentry/fs/mounts_test.go index 764318895..c4c771f2c 100644 --- a/pkg/sentry/fs/mounts_test.go +++ b/pkg/sentry/fs/mounts_test.go @@ -30,17 +30,17 @@ import ( // |-bar (file) func createMountNamespace(ctx context.Context) (*fs.MountNamespace, error) { perms := fs.FilePermsFromMode(0777) - m := fs.NewPseudoMountSource() + m := fs.NewPseudoMountSource(ctx) barFile := fsutil.NewSimpleFileInode(ctx, fs.RootOwner, perms, 0) fooDir := ramfs.NewDir(ctx, map[string]*fs.Inode{ - "bar": fs.NewInode(barFile, m, fs.StableAttr{Type: fs.RegularFile}), + "bar": fs.NewInode(ctx, barFile, m, fs.StableAttr{Type: fs.RegularFile}), }, fs.RootOwner, perms) rootDir := ramfs.NewDir(ctx, map[string]*fs.Inode{ - "foo": fs.NewInode(fooDir, m, fs.StableAttr{Type: fs.Directory}), + "foo": fs.NewInode(ctx, fooDir, m, fs.StableAttr{Type: fs.Directory}), }, fs.RootOwner, perms) - return fs.NewMountNamespace(ctx, fs.NewInode(rootDir, m, fs.StableAttr{Type: fs.Directory})) + return fs.NewMountNamespace(ctx, fs.NewInode(ctx, rootDir, m, fs.StableAttr{Type: fs.Directory})) } func TestFindLink(t *testing.T) { diff --git a/pkg/sentry/fs/overlay.go b/pkg/sentry/fs/overlay.go index 0ad11131c..c87f24997 100644 --- a/pkg/sentry/fs/overlay.go +++ b/pkg/sentry/fs/overlay.go @@ -104,7 +104,7 @@ func NewOverlayRoot(ctx context.Context, upper *Inode, lower *Inode, flags Mount return nil, fmt.Errorf("cannot nest overlay in upper file of another overlay") } - msrc := newOverlayMountSource(upper.MountSource, lower.MountSource, flags) + msrc := newOverlayMountSource(ctx, upper.MountSource, lower.MountSource, flags) overlay, err := newOverlayEntry(ctx, upper, lower, true) if err != nil { msrc.DecRef() @@ -127,7 +127,7 @@ func NewOverlayRootFile(ctx context.Context, upperMS *MountSource, lower *Inode, if !IsRegular(lower.StableAttr) { return nil, fmt.Errorf("lower Inode is not a regular file") } - msrc := newOverlayMountSource(upperMS, lower.MountSource, flags) + msrc := newOverlayMountSource(ctx, upperMS, lower.MountSource, flags) overlay, err := newOverlayEntry(ctx, nil, lower, true) if err != nil { msrc.DecRef() @@ -140,9 +140,9 @@ func NewOverlayRootFile(ctx context.Context, upperMS *MountSource, lower *Inode, func newOverlayInode(ctx context.Context, o *overlayEntry, msrc *MountSource) *Inode { var inode *Inode if o.upper != nil { - inode = NewInode(nil, msrc, o.upper.StableAttr) + inode = NewInode(ctx, nil, msrc, o.upper.StableAttr) } else { - inode = NewInode(nil, msrc, o.lower.StableAttr) + inode = NewInode(ctx, nil, msrc, o.lower.StableAttr) } inode.overlay = o return inode diff --git a/pkg/sentry/fs/proc/exec_args.go b/pkg/sentry/fs/proc/exec_args.go index 9de0177e8..1d3a2d426 100644 --- a/pkg/sentry/fs/proc/exec_args.go +++ b/pkg/sentry/fs/proc/exec_args.go @@ -64,7 +64,7 @@ func newExecArgInode(t *kernel.Task, msrc *fs.MountSource, arg execArgType) *fs. arg: arg, t: t, } - return newProcInode(f, msrc, fs.SpecialFile, t) + return newProcInode(t, f, msrc, fs.SpecialFile, t) } // GetFile implements fs.InodeOperations.GetFile. diff --git a/pkg/sentry/fs/proc/fds.go b/pkg/sentry/fs/proc/fds.go index 1e4e72b87..ea7aded9a 100644 --- a/pkg/sentry/fs/proc/fds.go +++ b/pkg/sentry/fs/proc/fds.go @@ -105,7 +105,7 @@ func newFd(t *kernel.Task, f *fs.File, msrc *fs.MountSource) *fs.Inode { Symlink: *ramfs.NewSymlink(t, fs.RootOwner, ""), file: f, } - return newProcInode(fd, msrc, fs.Symlink, t) + return newProcInode(t, fd, msrc, fs.Symlink, t) } // GetFile returns the fs.File backing this fd. The dirent and flags @@ -168,7 +168,7 @@ func newFdDir(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { Dir: *ramfs.NewDir(t, nil, fs.RootOwner, fs.FilePermissions{User: fs.PermMask{Read: true, Execute: true}}), t: t, } - return newProcInode(f, msrc, fs.SpecialDirectory, t) + return newProcInode(t, f, msrc, fs.SpecialDirectory, t) } // Check implements InodeOperations.Check. @@ -198,7 +198,7 @@ func (f *fdDir) Lookup(ctx context.Context, dir *fs.Inode, p string) (*fs.Dirent if err != nil { return nil, err } - return fs.NewDirent(n, p), nil + return fs.NewDirent(ctx, n, p), nil } // GetFile implements fs.FileOperations.GetFile. @@ -252,7 +252,7 @@ func newFdInfoDir(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { Dir: *ramfs.NewDir(t, nil, fs.RootOwner, fs.FilePermsFromMode(0500)), t: t, } - return newProcInode(fdid, msrc, fs.SpecialDirectory, t) + return newProcInode(t, fdid, msrc, fs.SpecialDirectory, t) } // Lookup loads an fd in /proc/TID/fdinfo into a Dirent. @@ -272,7 +272,7 @@ func (fdid *fdInfoDir) Lookup(ctx context.Context, dir *fs.Inode, p string) (*fs if err != nil { return nil, err } - return fs.NewDirent(inode, p), nil + return fs.NewDirent(ctx, inode, p), nil } // GetFile implements fs.FileOperations.GetFile. diff --git a/pkg/sentry/fs/proc/fs.go b/pkg/sentry/fs/proc/fs.go index f4ac4949a..715591ae5 100644 --- a/pkg/sentry/fs/proc/fs.go +++ b/pkg/sentry/fs/proc/fs.go @@ -77,5 +77,5 @@ func (f *filesystem) Mount(ctx context.Context, device string, flags fs.MountSou // Construct the procfs root. Since procfs files are all virtual, we // never want them cached. - return New(ctx, fs.NewNonCachingMountSource(f, flags), cgroups) + return New(ctx, fs.NewNonCachingMountSource(ctx, f, flags), cgroups) } diff --git a/pkg/sentry/fs/proc/inode.go b/pkg/sentry/fs/proc/inode.go index 1d81488cd..0c04f81fa 100644 --- a/pkg/sentry/fs/proc/inode.go +++ b/pkg/sentry/fs/proc/inode.go @@ -115,11 +115,11 @@ func newStaticProcInode(ctx context.Context, msrc *fs.MountSource, contents []by Contents: contents, }, } - return newProcInode(iops, msrc, fs.SpecialFile, nil) + return newProcInode(ctx, iops, msrc, fs.SpecialFile, nil) } // newProcInode creates a new inode from the given inode operations. -func newProcInode(iops fs.InodeOperations, msrc *fs.MountSource, typ fs.InodeType, t *kernel.Task) *fs.Inode { +func newProcInode(ctx context.Context, iops fs.InodeOperations, msrc *fs.MountSource, typ fs.InodeType, t *kernel.Task) *fs.Inode { sattr := fs.StableAttr{ DeviceID: device.ProcDevice.DeviceID(), InodeID: device.ProcDevice.NextIno(), @@ -129,5 +129,5 @@ func newProcInode(iops fs.InodeOperations, msrc *fs.MountSource, typ fs.InodeTyp if t != nil { iops = &taskOwnedInodeOps{iops, t} } - return fs.NewInode(iops, msrc, sattr) + return fs.NewInode(ctx, iops, msrc, sattr) } diff --git a/pkg/sentry/fs/proc/net.go b/pkg/sentry/fs/proc/net.go index cbc8f4dbf..caa1a5c4d 100644 --- a/pkg/sentry/fs/proc/net.go +++ b/pkg/sentry/fs/proc/net.go @@ -70,7 +70,7 @@ func (p *proc) newNetDir(ctx context.Context, k *kernel.Kernel, msrc *fs.MountSo } } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } // ifinet6 implements seqfile.SeqSource for /proc/net/if_inet6. diff --git a/pkg/sentry/fs/proc/proc.go b/pkg/sentry/fs/proc/proc.go index 170e2af4f..0ef13f2f5 100644 --- a/pkg/sentry/fs/proc/proc.go +++ b/pkg/sentry/fs/proc/proc.go @@ -68,7 +68,7 @@ func New(ctx context.Context, msrc *fs.MountSource, cgroupControllers map[string "filesystems": seqfile.NewSeqFileInode(ctx, &filesystemsData{}, msrc), "loadavg": seqfile.NewSeqFileInode(ctx, &loadavgData{}, msrc), "meminfo": seqfile.NewSeqFileInode(ctx, &meminfoData{k}, msrc), - "mounts": newProcInode(ramfs.NewSymlink(ctx, fs.RootOwner, "self/mounts"), msrc, fs.Symlink, nil), + "mounts": newProcInode(ctx, ramfs.NewSymlink(ctx, fs.RootOwner, "self/mounts"), msrc, fs.Symlink, nil), "self": newSelf(ctx, pidns, msrc), "stat": seqfile.NewSeqFileInode(ctx, &statData{k}, msrc), "thread-self": newThreadSelf(ctx, pidns, msrc), @@ -94,7 +94,7 @@ func New(ctx context.Context, msrc *fs.MountSource, cgroupControllers map[string p.AddChild(ctx, "net", p.newNetDir(ctx, k, msrc)) } - return newProcInode(p, msrc, fs.SpecialDirectory, nil), nil + return newProcInode(ctx, p, msrc, fs.SpecialDirectory, nil), nil } // self is a magical link. @@ -112,7 +112,7 @@ func newSelf(ctx context.Context, pidns *kernel.PIDNamespace, msrc *fs.MountSour Symlink: *ramfs.NewSymlink(ctx, fs.RootOwner, ""), pidns: pidns, } - return newProcInode(s, msrc, fs.Symlink, nil) + return newProcInode(ctx, s, msrc, fs.Symlink, nil) } // newThreadSelf returns a new "threadSelf" node. @@ -121,7 +121,7 @@ func newThreadSelf(ctx context.Context, pidns *kernel.PIDNamespace, msrc *fs.Mou Symlink: *ramfs.NewSymlink(ctx, fs.RootOwner, ""), pidns: pidns, } - return newProcInode(s, msrc, fs.Symlink, nil) + return newProcInode(ctx, s, msrc, fs.Symlink, nil) } // Readlink implements fs.InodeOperations.Readlink. @@ -185,7 +185,7 @@ func (p *proc) Lookup(ctx context.Context, dir *fs.Inode, name string) (*fs.Dire // Wrap it in a taskDir. td := p.newTaskDir(otherTask, dir.MountSource, true) - return fs.NewDirent(td, name), nil + return fs.NewDirent(ctx, td, name), nil } // GetFile implements fs.InodeOperations. diff --git a/pkg/sentry/fs/proc/rpcinet_proc.go b/pkg/sentry/fs/proc/rpcinet_proc.go index d37a83501..c1405a746 100644 --- a/pkg/sentry/fs/proc/rpcinet_proc.go +++ b/pkg/sentry/fs/proc/rpcinet_proc.go @@ -45,7 +45,7 @@ func newRPCInetInode(ctx context.Context, msrc *fs.MountSource, filepath string, filepath: filepath, k: kernel.KernelFromContext(ctx), } - return newProcInode(f, msrc, fs.SpecialFile, nil) + return newProcInode(ctx, f, msrc, fs.SpecialFile, nil) } // GetFile implements fs.InodeOperations.GetFile. @@ -141,7 +141,7 @@ func newRPCInetProcNet(ctx context.Context, msrc *fs.MountSource) *fs.Inode { } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } // newRPCInetProcSysNet will build an inode for /proc/sys/net. @@ -152,7 +152,7 @@ func newRPCInetProcSysNet(ctx context.Context, msrc *fs.MountSource) *fs.Inode { } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } // newRPCInetSysNetCore builds the /proc/sys/net/core directory. @@ -170,7 +170,7 @@ func newRPCInetSysNetCore(ctx context.Context, msrc *fs.MountSource) *fs.Inode { } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } // newRPCInetSysNetIPv4Dir builds the /proc/sys/net/ipv4 directory. @@ -213,5 +213,5 @@ func newRPCInetSysNetIPv4Dir(ctx context.Context, msrc *fs.MountSource) *fs.Inod } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } diff --git a/pkg/sentry/fs/proc/seqfile/seqfile.go b/pkg/sentry/fs/proc/seqfile/seqfile.go index 8ee7f5fa5..d5590e2d3 100644 --- a/pkg/sentry/fs/proc/seqfile/seqfile.go +++ b/pkg/sentry/fs/proc/seqfile/seqfile.go @@ -133,7 +133,7 @@ func NewSeqFileInode(ctx context.Context, source SeqSource, msrc *fs.MountSource BlockSize: usermem.PageSize, Type: fs.SpecialFile, } - return fs.NewInode(iops, msrc, sattr) + return fs.NewInode(ctx, iops, msrc, sattr) } // UnstableAttr returns unstable attributes of the SeqFile. diff --git a/pkg/sentry/fs/proc/seqfile/seqfile_test.go b/pkg/sentry/fs/proc/seqfile/seqfile_test.go index aa795164d..ebfeee835 100644 --- a/pkg/sentry/fs/proc/seqfile/seqfile_test.go +++ b/pkg/sentry/fs/proc/seqfile/seqfile_test.go @@ -120,15 +120,15 @@ func TestSeqFile(t *testing.T) { testSource.Init() // Create a file that can be R/W. - m := fs.NewPseudoMountSource() ctx := contexttest.Context(t) + m := fs.NewPseudoMountSource(ctx) contents := map[string]*fs.Inode{ "foo": NewSeqFileInode(ctx, testSource, m), } root := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0777)) // How about opening it? - inode := fs.NewInode(root, m, fs.StableAttr{Type: fs.Directory}) + inode := fs.NewInode(ctx, root, m, fs.StableAttr{Type: fs.Directory}) dirent2, err := root.Lookup(ctx, inode, "foo") if err != nil { t.Fatalf("failed to walk to foo for n2: %v", err) @@ -196,15 +196,15 @@ func TestSeqFileFileUpdated(t *testing.T) { testSource.update = true // Create a file that can be R/W. - m := fs.NewPseudoMountSource() ctx := contexttest.Context(t) + m := fs.NewPseudoMountSource(ctx) contents := map[string]*fs.Inode{ "foo": NewSeqFileInode(ctx, testSource, m), } root := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0777)) // How about opening it? - inode := fs.NewInode(root, m, fs.StableAttr{Type: fs.Directory}) + inode := fs.NewInode(ctx, root, m, fs.StableAttr{Type: fs.Directory}) dirent2, err := root.Lookup(ctx, inode, "foo") if err != nil { t.Fatalf("failed to walk to foo for dirent2: %v", err) diff --git a/pkg/sentry/fs/proc/sys.go b/pkg/sentry/fs/proc/sys.go index 4288b9a36..cd37776c8 100644 --- a/pkg/sentry/fs/proc/sys.go +++ b/pkg/sentry/fs/proc/sys.go @@ -82,14 +82,14 @@ func (p *proc) newKernelDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode } children := map[string]*fs.Inode{ - "hostname": newProcInode(&h, msrc, fs.SpecialFile, nil), + "hostname": newProcInode(ctx, &h, msrc, fs.SpecialFile, nil), "shmall": newStaticProcInode(ctx, msrc, []byte(strconv.FormatUint(linux.SHMALL, 10))), "shmmax": newStaticProcInode(ctx, msrc, []byte(strconv.FormatUint(linux.SHMMAX, 10))), "shmmni": newStaticProcInode(ctx, msrc, []byte(strconv.FormatUint(linux.SHMMNI, 10))), } d := ramfs.NewDir(ctx, children, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } func (p *proc) newVMDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { @@ -98,7 +98,7 @@ func (p *proc) newVMDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { "overcommit_memory": seqfile.NewSeqFileInode(ctx, &overcommitMemory{}, msrc), } d := ramfs.NewDir(ctx, children, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } func (p *proc) newSysDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { @@ -115,7 +115,7 @@ func (p *proc) newSysDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { } d := ramfs.NewDir(ctx, children, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } // hostname is the inode for a file containing the system hostname. diff --git a/pkg/sentry/fs/proc/sys_net.go b/pkg/sentry/fs/proc/sys_net.go index 7e05240f8..f3b63dfc2 100644 --- a/pkg/sentry/fs/proc/sys_net.go +++ b/pkg/sentry/fs/proc/sys_net.go @@ -74,7 +74,7 @@ func newTCPMemInode(ctx context.Context, msrc *fs.MountSource, s inet.Stack, dir BlockSize: usermem.PageSize, Type: fs.SpecialFile, } - return fs.NewInode(tm, msrc, sattr) + return fs.NewInode(ctx, tm, msrc, sattr) } // GetFile implements fs.InodeOperations.GetFile. @@ -184,7 +184,7 @@ func newTCPSackInode(ctx context.Context, msrc *fs.MountSource, s inet.Stack) *f BlockSize: usermem.PageSize, Type: fs.SpecialFile, } - return fs.NewInode(ts, msrc, sattr) + return fs.NewInode(ctx, ts, msrc, sattr) } // GetFile implements fs.InodeOperations.GetFile. @@ -277,7 +277,7 @@ func (p *proc) newSysNetCore(ctx context.Context, msrc *fs.MountSource, s inet.S } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } func (p *proc) newSysNetIPv4Dir(ctx context.Context, msrc *fs.MountSource, s inet.Stack) *fs.Inode { @@ -339,7 +339,7 @@ func (p *proc) newSysNetIPv4Dir(ctx context.Context, msrc *fs.MountSource, s ine } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } func (p *proc) newSysNetDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { @@ -351,5 +351,5 @@ func (p *proc) newSysNetDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode } } d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return newProcInode(d, msrc, fs.SpecialDirectory, nil) + return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil) } diff --git a/pkg/sentry/fs/proc/task.go b/pkg/sentry/fs/proc/task.go index 412c0204a..b2e36aeee 100644 --- a/pkg/sentry/fs/proc/task.go +++ b/pkg/sentry/fs/proc/task.go @@ -101,7 +101,7 @@ func (p *proc) newTaskDir(t *kernel.Task, msrc *fs.MountSource, showSubtasks boo Dir: *ramfs.NewDir(t, contents, fs.RootOwner, fs.FilePermsFromMode(0555)), t: t, } - return newProcInode(d, msrc, fs.SpecialDirectory, t) + return newProcInode(t, d, msrc, fs.SpecialDirectory, t) } // subtasks represents a /proc/TID/task directory. @@ -122,7 +122,7 @@ func (p *proc) newSubtasks(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { t: t, p: p, } - return newProcInode(s, msrc, fs.SpecialDirectory, t) + return newProcInode(t, s, msrc, fs.SpecialDirectory, t) } // UnstableAttr returns unstable attributes of the subtasks. @@ -223,7 +223,7 @@ func (s *subtasks) Lookup(ctx context.Context, dir *fs.Inode, p string) (*fs.Dir } td := s.p.newTaskDir(task, dir.MountSource, false) - return fs.NewDirent(td, p), nil + return fs.NewDirent(ctx, td, p), nil } // exe is an fs.InodeOperations symlink for the /proc/PID/exe file. @@ -240,7 +240,7 @@ func newExe(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { Symlink: *ramfs.NewSymlink(t, fs.RootOwner, ""), t: t, } - return newProcInode(exeSymlink, msrc, fs.Symlink, t) + return newProcInode(t, exeSymlink, msrc, fs.Symlink, t) } func (e *exe) executable() (d *fs.Dirent, err error) { @@ -308,7 +308,7 @@ func newNamespaceSymlink(t *kernel.Task, msrc *fs.MountSource, name string) *fs. Symlink: *ramfs.NewSymlink(t, fs.RootOwner, target), t: t, } - return newProcInode(n, msrc, fs.Symlink, t) + return newProcInode(t, n, msrc, fs.Symlink, t) } // Getlink implements fs.InodeOperations.Getlink. @@ -319,7 +319,7 @@ func (n *namespaceSymlink) Getlink(ctx context.Context, inode *fs.Inode) (*fs.Di // Create a new regular file to fake the namespace file. iops := fsutil.NewNoReadWriteFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(0777), linux.PROC_SUPER_MAGIC) - return fs.NewDirent(newProcInode(iops, inode.MountSource, fs.RegularFile, nil), n.Symlink.Target), nil + return fs.NewDirent(ctx, newProcInode(ctx, iops, inode.MountSource, fs.RegularFile, nil), n.Symlink.Target), nil } func newNamespaceDir(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { @@ -329,7 +329,7 @@ func newNamespaceDir(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { "user": newNamespaceSymlink(t, msrc, "user"), } d := ramfs.NewDir(t, contents, fs.RootOwner, fs.FilePermsFromMode(0511)) - return newProcInode(d, msrc, fs.SpecialDirectory, t) + return newProcInode(t, d, msrc, fs.SpecialDirectory, t) } // mapsData implements seqfile.SeqSource for /proc/[pid]/maps. @@ -340,7 +340,7 @@ type mapsData struct { } func newMaps(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { - return newProcInode(seqfile.NewSeqFile(t, &mapsData{t}), msrc, fs.SpecialFile, t) + return newProcInode(t, seqfile.NewSeqFile(t, &mapsData{t}), msrc, fs.SpecialFile, t) } func (md *mapsData) mm() *mm.MemoryManager { @@ -380,7 +380,7 @@ type smapsData struct { } func newSmaps(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { - return newProcInode(seqfile.NewSeqFile(t, &smapsData{t}), msrc, fs.SpecialFile, t) + return newProcInode(t, seqfile.NewSeqFile(t, &smapsData{t}), msrc, fs.SpecialFile, t) } func (sd *smapsData) mm() *mm.MemoryManager { @@ -426,7 +426,7 @@ type taskStatData struct { } func newTaskStat(t *kernel.Task, msrc *fs.MountSource, showSubtasks bool, pidns *kernel.PIDNamespace) *fs.Inode { - return newProcInode(seqfile.NewSeqFile(t, &taskStatData{t, showSubtasks /* tgstats */, pidns}), msrc, fs.SpecialFile, t) + return newProcInode(t, seqfile.NewSeqFile(t, &taskStatData{t, showSubtasks /* tgstats */, pidns}), msrc, fs.SpecialFile, t) } // NeedsUpdate returns whether the generation is old or not. @@ -511,7 +511,7 @@ type statmData struct { } func newStatm(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { - return newProcInode(seqfile.NewSeqFile(t, &statmData{t}), msrc, fs.SpecialFile, t) + return newProcInode(t, seqfile.NewSeqFile(t, &statmData{t}), msrc, fs.SpecialFile, t) } // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. @@ -548,7 +548,7 @@ type statusData struct { } func newStatus(t *kernel.Task, msrc *fs.MountSource, pidns *kernel.PIDNamespace) *fs.Inode { - return newProcInode(seqfile.NewSeqFile(t, &statusData{t, pidns}), msrc, fs.SpecialFile, t) + return newProcInode(t, seqfile.NewSeqFile(t, &statusData{t, pidns}), msrc, fs.SpecialFile, t) } // NeedsUpdate implements seqfile.SeqSource.NeedsUpdate. @@ -615,7 +615,7 @@ type ioData struct { } func newIO(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { - return newProcInode(seqfile.NewSeqFile(t, &ioData{t.ThreadGroup()}), msrc, fs.SpecialFile, t) + return newProcInode(t, seqfile.NewSeqFile(t, &ioData{t.ThreadGroup()}), msrc, fs.SpecialFile, t) } // NeedsUpdate returns whether the generation is old or not. @@ -664,7 +664,7 @@ func newComm(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { SimpleFileInode: *fsutil.NewSimpleFileInode(t, fs.RootOwner, fs.FilePermsFromMode(0444), linux.PROC_SUPER_MAGIC), t: t, } - return newProcInode(c, msrc, fs.SpecialFile, t) + return newProcInode(t, c, msrc, fs.SpecialFile, t) } // Check implements fs.InodeOperations.Check. @@ -736,7 +736,7 @@ func newAuxvec(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { SimpleFileInode: *fsutil.NewSimpleFileInode(t, fs.RootOwner, fs.FilePermsFromMode(0444), linux.PROC_SUPER_MAGIC), t: t, } - return newProcInode(a, msrc, fs.SpecialFile, t) + return newProcInode(t, a, msrc, fs.SpecialFile, t) } // GetFile implements fs.InodeOperations.GetFile. diff --git a/pkg/sentry/fs/proc/uid_gid_map.go b/pkg/sentry/fs/proc/uid_gid_map.go index d734a48f4..eea37d15c 100644 --- a/pkg/sentry/fs/proc/uid_gid_map.go +++ b/pkg/sentry/fs/proc/uid_gid_map.go @@ -66,7 +66,7 @@ func newGIDMap(t *kernel.Task, msrc *fs.MountSource) *fs.Inode { } func newIDMap(t *kernel.Task, msrc *fs.MountSource, gids bool) *fs.Inode { - return newProcInode(&idMapInodeOperations{ + return newProcInode(t, &idMapInodeOperations{ InodeSimpleAttributes: fsutil.NewInodeSimpleAttributes(t, fs.RootOwner, fs.FilePermsFromMode(0644), linux.PROC_SUPER_MAGIC), t: t, gids: gids, diff --git a/pkg/sentry/fs/proc/uptime.go b/pkg/sentry/fs/proc/uptime.go index 37e9ae379..4e903917a 100644 --- a/pkg/sentry/fs/proc/uptime.go +++ b/pkg/sentry/fs/proc/uptime.go @@ -44,7 +44,7 @@ func newUptime(ctx context.Context, msrc *fs.MountSource) *fs.Inode { SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(0444), linux.PROC_SUPER_MAGIC), startTime: ktime.NowFromContext(ctx), } - return newProcInode(u, msrc, fs.SpecialFile, nil) + return newProcInode(ctx, u, msrc, fs.SpecialFile, nil) } // GetFile implements fs.InodeOperations.GetFile. diff --git a/pkg/sentry/fs/ramfs/dir.go b/pkg/sentry/fs/ramfs/dir.go index b5da36c1c..db97f400b 100644 --- a/pkg/sentry/fs/ramfs/dir.go +++ b/pkg/sentry/fs/ramfs/dir.go @@ -269,7 +269,7 @@ func (d *Dir) Lookup(ctx context.Context, _ *fs.Inode, p string) (*fs.Dirent, er // Take a reference on the inode before returning it. This reference // is owned by the dirent we are about to create. inode.IncRef() - return fs.NewDirent(inode, p), nil + return fs.NewDirent(ctx, inode, p), nil } // walkLocked must be called with d.mu held. @@ -321,7 +321,7 @@ func (d *Dir) Create(ctx context.Context, dir *fs.Inode, name string, flags fs.F inode.IncRef() // Create the Dirent and corresponding file. - created := fs.NewDirent(inode, name) + created := fs.NewDirent(ctx, inode, name) defer created.DecRef() return created.Inode.GetFile(ctx, created, flags) } @@ -382,7 +382,7 @@ func (d *Dir) Bind(ctx context.Context, dir *fs.Inode, name string, ep transport } // Take another ref on inode which will be donated to the new dirent. inode.IncRef() - return fs.NewDirent(inode, name), nil + return fs.NewDirent(ctx, inode, name), nil } // CreateFifo implements fs.InodeOperations.CreateFifo. diff --git a/pkg/sentry/fs/ramfs/tree.go b/pkg/sentry/fs/ramfs/tree.go index 4d9deb174..702cc4a1e 100644 --- a/pkg/sentry/fs/ramfs/tree.go +++ b/pkg/sentry/fs/ramfs/tree.go @@ -68,7 +68,7 @@ func makeSubdir(ctx context.Context, msrc *fs.MountSource, root *Dir, subdir str // emptyDir returns an empty *ramfs.Dir with all permissions granted. func emptyDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode { dir := NewDir(ctx, make(map[string]*fs.Inode), fs.RootOwner, fs.FilePermsFromMode(0777)) - return fs.NewInode(dir, msrc, fs.StableAttr{ + return fs.NewInode(ctx, dir, msrc, fs.StableAttr{ DeviceID: anon.PseudoDevice.DeviceID(), InodeID: anon.PseudoDevice.NextIno(), BlockSize: usermem.PageSize, diff --git a/pkg/sentry/fs/ramfs/tree_test.go b/pkg/sentry/fs/ramfs/tree_test.go index da259a971..61a7e2900 100644 --- a/pkg/sentry/fs/ramfs/tree_test.go +++ b/pkg/sentry/fs/ramfs/tree_test.go @@ -22,7 +22,6 @@ import ( ) func TestMakeDirectoryTree(t *testing.T) { - mount := fs.NewPseudoMountSource() for _, test := range []struct { name string @@ -54,6 +53,7 @@ func TestMakeDirectoryTree(t *testing.T) { }, } { ctx := contexttest.Context(t) + mount := fs.NewPseudoMountSource(ctx) tree, err := MakeDirectoryTree(ctx, mount, test.subdirs) if err != nil { t.Errorf("%s: failed to make ramfs tree, got error %v, want nil", test.name, err) diff --git a/pkg/sentry/fs/sys/devices.go b/pkg/sentry/fs/sys/devices.go index a6009ba8a..4f78ca8d2 100644 --- a/pkg/sentry/fs/sys/devices.go +++ b/pkg/sentry/fs/sys/devices.go @@ -58,7 +58,7 @@ func newPossible(ctx context.Context, msrc *fs.MountSource) *fs.Inode { Contents: contents, }, } - return newFile(c, msrc) + return newFile(ctx, c, msrc) } func newCPU(ctx context.Context, msrc *fs.MountSource) *fs.Inode { diff --git a/pkg/sentry/fs/sys/fs.go b/pkg/sentry/fs/sys/fs.go index 257048df5..b31c46bf9 100644 --- a/pkg/sentry/fs/sys/fs.go +++ b/pkg/sentry/fs/sys/fs.go @@ -61,5 +61,5 @@ func (f *filesystem) Mount(ctx context.Context, device string, flags fs.MountSou // device is always ignored. // sysfs ignores data, see fs/sysfs/mount.c:sysfs_mount. - return New(ctx, fs.NewNonCachingMountSource(f, flags)), nil + return New(ctx, fs.NewNonCachingMountSource(ctx, f, flags)), nil } diff --git a/pkg/sentry/fs/sys/sys.go b/pkg/sentry/fs/sys/sys.go index 9db41a1b8..b14bf3f55 100644 --- a/pkg/sentry/fs/sys/sys.go +++ b/pkg/sentry/fs/sys/sys.go @@ -22,19 +22,19 @@ import ( "gvisor.dev/gvisor/pkg/sentry/usermem" ) -func newFile(node fs.InodeOperations, msrc *fs.MountSource) *fs.Inode { +func newFile(ctx context.Context, node fs.InodeOperations, msrc *fs.MountSource) *fs.Inode { sattr := fs.StableAttr{ DeviceID: sysfsDevice.DeviceID(), InodeID: sysfsDevice.NextIno(), BlockSize: usermem.PageSize, Type: fs.SpecialFile, } - return fs.NewInode(node, msrc, sattr) + return fs.NewInode(ctx, node, msrc, sattr) } func newDir(ctx context.Context, msrc *fs.MountSource, contents map[string]*fs.Inode) *fs.Inode { d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555)) - return fs.NewInode(d, msrc, fs.StableAttr{ + return fs.NewInode(ctx, d, msrc, fs.StableAttr{ DeviceID: sysfsDevice.DeviceID(), InodeID: sysfsDevice.NextIno(), BlockSize: usermem.PageSize, diff --git a/pkg/sentry/fs/timerfd/timerfd.go b/pkg/sentry/fs/timerfd/timerfd.go index 704a846a4..59403d9db 100644 --- a/pkg/sentry/fs/timerfd/timerfd.go +++ b/pkg/sentry/fs/timerfd/timerfd.go @@ -53,7 +53,7 @@ type TimerOperations struct { // NewFile returns a timerfd File that receives time from c. func NewFile(ctx context.Context, c ktime.Clock) *fs.File { - dirent := fs.NewDirent(anon.NewInode(ctx), "anon_inode:[timerfd]") + dirent := fs.NewDirent(ctx, anon.NewInode(ctx), "anon_inode:[timerfd]") // Release the initial dirent reference after NewFile takes a reference. defer dirent.DecRef() tops := &TimerOperations{} diff --git a/pkg/sentry/fs/tmpfs/file_test.go b/pkg/sentry/fs/tmpfs/file_test.go index 591f20c52..0075ef023 100644 --- a/pkg/sentry/fs/tmpfs/file_test.go +++ b/pkg/sentry/fs/tmpfs/file_test.go @@ -26,9 +26,9 @@ import ( ) func newFileInode(ctx context.Context) *fs.Inode { - m := fs.NewCachingMountSource(&Filesystem{}, fs.MountSourceFlags{}) + m := fs.NewCachingMountSource(ctx, &Filesystem{}, fs.MountSourceFlags{}) iops := NewInMemoryFile(ctx, usage.Tmpfs, fs.WithCurrentTime(ctx, fs.UnstableAttr{})) - return fs.NewInode(iops, m, fs.StableAttr{ + return fs.NewInode(ctx, iops, m, fs.StableAttr{ DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), BlockSize: usermem.PageSize, @@ -38,7 +38,7 @@ func newFileInode(ctx context.Context) *fs.Inode { func newFile(ctx context.Context) *fs.File { inode := newFileInode(ctx) - f, _ := inode.GetFile(ctx, fs.NewDirent(inode, "stub"), fs.FileFlags{Read: true, Write: true}) + f, _ := inode.GetFile(ctx, fs.NewDirent(ctx, inode, "stub"), fs.FileFlags{Read: true, Write: true}) return f } diff --git a/pkg/sentry/fs/tmpfs/fs.go b/pkg/sentry/fs/tmpfs/fs.go index bfaf3cde3..a5fcdf969 100644 --- a/pkg/sentry/fs/tmpfs/fs.go +++ b/pkg/sentry/fs/tmpfs/fs.go @@ -136,9 +136,9 @@ func (f *Filesystem) Mount(ctx context.Context, device string, flags fs.MountSou var msrc *fs.MountSource switch options[cacheKey] { case "", cacheAll: - msrc = fs.NewCachingMountSource(f, flags) + msrc = fs.NewCachingMountSource(ctx, f, flags) case cacheRevalidate: - msrc = fs.NewRevalidatingMountSource(f, flags) + msrc = fs.NewRevalidatingMountSource(ctx, f, flags) default: return nil, fmt.Errorf("invalid cache policy option %q", options[cacheKey]) } diff --git a/pkg/sentry/fs/tmpfs/inode_file.go b/pkg/sentry/fs/tmpfs/inode_file.go index d20dce173..f86dfaa36 100644 --- a/pkg/sentry/fs/tmpfs/inode_file.go +++ b/pkg/sentry/fs/tmpfs/inode_file.go @@ -128,7 +128,7 @@ func NewMemfdInode(ctx context.Context, allowSeals bool) *fs.Inode { if allowSeals { iops.seals = 0 } - return fs.NewInode(iops, fs.NewNonCachingMountSource(nil, fs.MountSourceFlags{}), fs.StableAttr{ + return fs.NewInode(ctx, iops, fs.NewNonCachingMountSource(ctx, nil, fs.MountSourceFlags{}), fs.StableAttr{ Type: fs.RegularFile, DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), diff --git a/pkg/sentry/fs/tmpfs/tmpfs.go b/pkg/sentry/fs/tmpfs/tmpfs.go index e8178c9dd..0f4497cd6 100644 --- a/pkg/sentry/fs/tmpfs/tmpfs.go +++ b/pkg/sentry/fs/tmpfs/tmpfs.go @@ -90,7 +90,7 @@ func NewDir(ctx context.Context, contents map[string]*fs.Inode, owner fs.FileOwn // Manually set the CreateOps. d.ramfsDir.CreateOps = d.newCreateOps() - return fs.NewInode(d, msrc, fs.StableAttr{ + return fs.NewInode(ctx, d, msrc, fs.StableAttr{ DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), BlockSize: usermem.PageSize, @@ -218,7 +218,7 @@ func (d *Dir) newCreateOps() *ramfs.CreateOps { Links: 0, }) iops := NewInMemoryFile(ctx, usage.Tmpfs, uattr) - return fs.NewInode(iops, dir.MountSource, fs.StableAttr{ + return fs.NewInode(ctx, iops, dir.MountSource, fs.StableAttr{ DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), BlockSize: usermem.PageSize, @@ -262,7 +262,7 @@ type Symlink struct { // NewSymlink returns a new symlink with the provided permissions. func NewSymlink(ctx context.Context, target string, owner fs.FileOwner, msrc *fs.MountSource) *fs.Inode { s := &Symlink{Symlink: *ramfs.NewSymlink(ctx, owner, target)} - return fs.NewInode(s, msrc, fs.StableAttr{ + return fs.NewInode(ctx, s, msrc, fs.StableAttr{ DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), BlockSize: usermem.PageSize, @@ -292,7 +292,7 @@ type Socket struct { // NewSocket returns a new socket with the provided permissions. func NewSocket(ctx context.Context, socket transport.BoundEndpoint, owner fs.FileOwner, perms fs.FilePermissions, msrc *fs.MountSource) *fs.Inode { s := &Socket{Socket: *ramfs.NewSocket(ctx, socket, owner, perms)} - return fs.NewInode(s, msrc, fs.StableAttr{ + return fs.NewInode(ctx, s, msrc, fs.StableAttr{ DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), BlockSize: usermem.PageSize, @@ -329,7 +329,7 @@ func NewFifo(ctx context.Context, owner fs.FileOwner, perms fs.FilePermissions, fifoIops := &Fifo{iops} // Build a new Inode. - return fs.NewInode(fifoIops, msrc, fs.StableAttr{ + return fs.NewInode(ctx, fifoIops, msrc, fs.StableAttr{ DeviceID: tmpfsDevice.DeviceID(), InodeID: tmpfsDevice.NextIno(), BlockSize: usermem.PageSize, diff --git a/pkg/sentry/fs/tty/dir.go b/pkg/sentry/fs/tty/dir.go index 679057d1f..58a26742c 100644 --- a/pkg/sentry/fs/tty/dir.go +++ b/pkg/sentry/fs/tty/dir.go @@ -114,7 +114,7 @@ func newDir(ctx context.Context, m *fs.MountSource) *fs.Inode { InodeID: d.master.StableAttr.InodeID, }) - return fs.NewInode(d, m, fs.StableAttr{ + return fs.NewInode(ctx, d, m, fs.StableAttr{ DeviceID: ptsDevice.DeviceID(), // N.B. Linux always uses inode id 1 for the directory. See // fs/devpts/inode.c:devpts_fill_super. @@ -143,7 +143,7 @@ func (d *dirInodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name str // Master? if name == "ptmx" { d.master.IncRef() - return fs.NewDirent(d.master, name), nil + return fs.NewDirent(ctx, d.master, name), nil } // Slave number? @@ -159,7 +159,7 @@ func (d *dirInodeOperations) Lookup(ctx context.Context, dir *fs.Inode, name str } s.IncRef() - return fs.NewDirent(s, name), nil + return fs.NewDirent(ctx, s, name), nil } // Create implements fs.InodeOperations.Create. diff --git a/pkg/sentry/fs/tty/fs.go b/pkg/sentry/fs/tty/fs.go index 08843c115..1bbfbb90a 100644 --- a/pkg/sentry/fs/tty/fs.go +++ b/pkg/sentry/fs/tty/fs.go @@ -67,7 +67,7 @@ func (f *filesystem) Mount(ctx context.Context, device string, flags fs.MountSou return nil, syserror.EINVAL } - return newDir(ctx, fs.NewMountSource(&superOperations{}, f, flags)), nil + return newDir(ctx, fs.NewMountSource(ctx, &superOperations{}, f, flags)), nil } // superOperations implements fs.MountSourceOperations, preventing caching. diff --git a/pkg/sentry/fs/tty/master.go b/pkg/sentry/fs/tty/master.go index c02142ff3..54dd3d6b7 100644 --- a/pkg/sentry/fs/tty/master.go +++ b/pkg/sentry/fs/tty/master.go @@ -46,7 +46,7 @@ func newMasterInode(ctx context.Context, d *dirInodeOperations, owner fs.FileOwn d: d, } - return fs.NewInode(iops, d.msrc, fs.StableAttr{ + return fs.NewInode(ctx, iops, d.msrc, fs.StableAttr{ DeviceID: ptsDevice.DeviceID(), // N.B. Linux always uses inode id 2 for ptmx. See // fs/devpts/inode.c:mknod_ptmx. diff --git a/pkg/sentry/fs/tty/slave.go b/pkg/sentry/fs/tty/slave.go index a382dcd13..2d68978dd 100644 --- a/pkg/sentry/fs/tty/slave.go +++ b/pkg/sentry/fs/tty/slave.go @@ -51,7 +51,7 @@ func newSlaveInode(ctx context.Context, d *dirInodeOperations, t *Terminal, owne t: t, } - return fs.NewInode(iops, d.msrc, fs.StableAttr{ + return fs.NewInode(ctx, iops, d.msrc, fs.StableAttr{ DeviceID: ptsDevice.DeviceID(), // N.B. Linux always uses inode id = tty index + 3. See // fs/devpts/inode.c:devpts_pty_new. diff --git a/pkg/sentry/kernel/epoll/epoll.go b/pkg/sentry/kernel/epoll/epoll.go index 86ddbec12..33c7dccae 100644 --- a/pkg/sentry/kernel/epoll/epoll.go +++ b/pkg/sentry/kernel/epoll/epoll.go @@ -155,7 +155,7 @@ var cycleMu sync.Mutex // NewEventPoll allocates and initializes a new event poll object. func NewEventPoll(ctx context.Context) *fs.File { // name matches fs/eventpoll.c:epoll_create1. - dirent := fs.NewDirent(anon.NewInode(ctx), fmt.Sprintf("anon_inode:[eventpoll]")) + dirent := fs.NewDirent(ctx, anon.NewInode(ctx), fmt.Sprintf("anon_inode:[eventpoll]")) // Release the initial dirent reference after NewFile takes a reference. defer dirent.DecRef() return fs.NewFile(ctx, dirent, fs.FileFlags{}, &EventPoll{ diff --git a/pkg/sentry/kernel/eventfd/eventfd.go b/pkg/sentry/kernel/eventfd/eventfd.go index 610c73d6f..12f0d429b 100644 --- a/pkg/sentry/kernel/eventfd/eventfd.go +++ b/pkg/sentry/kernel/eventfd/eventfd.go @@ -68,7 +68,7 @@ type EventOperations struct { // New creates a new event object with the supplied initial value and mode. func New(ctx context.Context, initVal uint64, semMode bool) *fs.File { // name matches fs/eventfd.c:eventfd_file_create. - dirent := fs.NewDirent(anon.NewInode(ctx), "anon_inode:[eventfd]") + dirent := fs.NewDirent(ctx, anon.NewInode(ctx), "anon_inode:[eventfd]") // Release the initial dirent reference after NewFile takes a reference. defer dirent.DecRef() return fs.NewFile(ctx, dirent, fs.FileFlags{Read: true, Write: true}, &EventOperations{ diff --git a/pkg/sentry/kernel/pipe/node_test.go b/pkg/sentry/kernel/pipe/node_test.go index 7af2afd8c..adbad7764 100644 --- a/pkg/sentry/kernel/pipe/node_test.go +++ b/pkg/sentry/kernel/pipe/node_test.go @@ -63,7 +63,7 @@ var perms fs.FilePermissions = fs.FilePermissions{ func testOpenOrDie(ctx context.Context, t *testing.T, n fs.InodeOperations, flags fs.FileFlags, doneChan chan<- struct{}) (*fs.File, error) { inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe}) - d := fs.NewDirent(inode, "pipe") + d := fs.NewDirent(ctx, inode, "pipe") file, err := n.GetFile(ctx, d, flags) if err != nil { t.Fatalf("open with flags %+v failed: %v", flags, err) @@ -76,7 +76,7 @@ func testOpenOrDie(ctx context.Context, t *testing.T, n fs.InodeOperations, flag func testOpen(ctx context.Context, t *testing.T, n fs.InodeOperations, flags fs.FileFlags, resChan chan<- openResult) (*fs.File, error) { inode := fs.NewMockInode(ctx, fs.NewMockMountSource(nil), fs.StableAttr{Type: fs.Pipe}) - d := fs.NewDirent(inode, "pipe") + d := fs.NewDirent(ctx, inode, "pipe") file, err := n.GetFile(ctx, d, flags) if resChan != nil { resChan <- openResult{file, err} diff --git a/pkg/sentry/kernel/pipe/pipe.go b/pkg/sentry/kernel/pipe/pipe.go index 18e60487f..755326d59 100644 --- a/pkg/sentry/kernel/pipe/pipe.go +++ b/pkg/sentry/kernel/pipe/pipe.go @@ -150,8 +150,8 @@ func NewConnectedPipe(ctx context.Context, sizeBytes, atomicIOBytes int64) (*fs. InodeID: ino, BlockSize: int64(atomicIOBytes), } - ms := fs.NewPseudoMountSource() - d := fs.NewDirent(fs.NewInode(iops, ms, sattr), fmt.Sprintf("pipe:[%d]", ino)) + ms := fs.NewPseudoMountSource(ctx) + d := fs.NewDirent(ctx, fs.NewInode(ctx, iops, ms, sattr), fmt.Sprintf("pipe:[%d]", ino)) // The p.Open calls below will each take a reference on the Dirent. We // must drop the one we already have. defer d.DecRef() diff --git a/pkg/sentry/loader/vdso.go b/pkg/sentry/loader/vdso.go index 4ba56c44d..ada28aea3 100644 --- a/pkg/sentry/loader/vdso.go +++ b/pkg/sentry/loader/vdso.go @@ -69,11 +69,12 @@ type byteReader struct { var _ fs.FileOperations = (*byteReader)(nil) // newByteReaderFile creates a fake file to read data from. -func newByteReaderFile(data []byte) *fs.File { +func newByteReaderFile(ctx context.Context, data []byte) *fs.File { // Create a fake inode. inode := fs.NewInode( + ctx, &fsutil.SimpleFileInode{}, - fs.NewPseudoMountSource(), + fs.NewPseudoMountSource(ctx), fs.StableAttr{ Type: fs.Anonymous, DeviceID: anon.PseudoDevice.DeviceID(), @@ -219,8 +220,8 @@ type VDSO struct { // PrepareVDSO validates the system VDSO and returns a VDSO, containing the // param page for updating by the kernel. -func PrepareVDSO(mfp pgalloc.MemoryFileProvider) (*VDSO, error) { - vdsoFile := newByteReaderFile(vdsoBin) +func PrepareVDSO(ctx context.Context, mfp pgalloc.MemoryFileProvider) (*VDSO, error) { + vdsoFile := newByteReaderFile(ctx, vdsoBin) // First make sure the VDSO is valid. vdsoFile does not use ctx, so a // nil context can be passed. diff --git a/pkg/sentry/socket/netlink/socket.go b/pkg/sentry/socket/netlink/socket.go index 985a5f24a..87c0c77bc 100644 --- a/pkg/sentry/socket/netlink/socket.go +++ b/pkg/sentry/socket/netlink/socket.go @@ -111,7 +111,7 @@ var _ socket.Socket = (*Socket)(nil) // NewSocket creates a new Socket. func NewSocket(t *kernel.Task, skType linux.SockType, protocol Protocol) (*Socket, *syserr.Error) { // Datagram endpoint used to buffer kernel -> user messages. - ep := transport.NewConnectionless() + ep := transport.NewConnectionless(t) // Bind the endpoint for good measure so we can connect to it. The // bound address will never be exposed. @@ -121,7 +121,7 @@ func NewSocket(t *kernel.Task, skType linux.SockType, protocol Protocol) (*Socke } // Create a connection from which the kernel can write messages. - connection, err := ep.(transport.BoundEndpoint).UnidirectionalConnect() + connection, err := ep.(transport.BoundEndpoint).UnidirectionalConnect(t) if err != nil { ep.Close() return nil, err diff --git a/pkg/sentry/socket/socket.go b/pkg/sentry/socket/socket.go index 65f38f61f..933120f34 100644 --- a/pkg/sentry/socket/socket.go +++ b/pkg/sentry/socket/socket.go @@ -199,7 +199,7 @@ func NewDirent(ctx context.Context, d *device.Device) *fs.Dirent { User: fs.PermMask{Read: true, Write: true}, }, linux.SOCKFS_MAGIC), } - inode := fs.NewInode(iops, fs.NewPseudoMountSource(), fs.StableAttr{ + inode := fs.NewInode(ctx, iops, fs.NewPseudoMountSource(ctx), fs.StableAttr{ Type: fs.Socket, DeviceID: d.DeviceID(), InodeID: ino, @@ -207,7 +207,7 @@ func NewDirent(ctx context.Context, d *device.Device) *fs.Dirent { }) // Dirent name matches net/socket.c:sockfs_dname. - return fs.NewDirent(inode, fmt.Sprintf("socket:[%d]", ino)) + return fs.NewDirent(ctx, inode, fmt.Sprintf("socket:[%d]", ino)) } // SendReceiveTimeout stores timeouts for send and receive calls. diff --git a/pkg/sentry/socket/unix/io.go b/pkg/sentry/socket/unix/io.go index 023c2f135..760c7beab 100644 --- a/pkg/sentry/socket/unix/io.go +++ b/pkg/sentry/socket/unix/io.go @@ -15,6 +15,7 @@ package unix import ( + "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/sentry/safemem" "gvisor.dev/gvisor/pkg/sentry/socket/unix/transport" "gvisor.dev/gvisor/pkg/tcpip" @@ -24,6 +25,8 @@ import ( // // EndpointWriter is not thread-safe. type EndpointWriter struct { + Ctx context.Context + // Endpoint is the transport.Endpoint to write to. Endpoint transport.Endpoint @@ -37,7 +40,7 @@ type EndpointWriter struct { // WriteFromBlocks implements safemem.Writer.WriteFromBlocks. func (w *EndpointWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) { return safemem.FromVecWriterFunc{func(bufs [][]byte) (int64, error) { - n, err := w.Endpoint.SendMsg(bufs, w.Control, w.To) + n, err := w.Endpoint.SendMsg(w.Ctx, bufs, w.Control, w.To) if err != nil { return int64(n), err.ToError() } @@ -50,6 +53,8 @@ func (w *EndpointWriter) WriteFromBlocks(srcs safemem.BlockSeq) (uint64, error) // // EndpointReader is not thread-safe. type EndpointReader struct { + Ctx context.Context + // Endpoint is the transport.Endpoint to read from. Endpoint transport.Endpoint @@ -81,7 +86,7 @@ type EndpointReader struct { // ReadToBlocks implements safemem.Reader.ReadToBlocks. func (r *EndpointReader) ReadToBlocks(dsts safemem.BlockSeq) (uint64, error) { return safemem.FromVecReaderFunc{func(bufs [][]byte) (int64, error) { - n, ms, c, ct, err := r.Endpoint.RecvMsg(bufs, r.Creds, r.NumRights, r.Peek, r.From) + n, ms, c, ct, err := r.Endpoint.RecvMsg(r.Ctx, bufs, r.Creds, r.NumRights, r.Peek, r.From) r.Control = c r.ControlTrunc = ct r.MsgSize = ms diff --git a/pkg/sentry/socket/unix/transport/BUILD b/pkg/sentry/socket/unix/transport/BUILD index 82173dea7..0b0240336 100644 --- a/pkg/sentry/socket/unix/transport/BUILD +++ b/pkg/sentry/socket/unix/transport/BUILD @@ -31,6 +31,7 @@ go_library( "//pkg/abi/linux", "//pkg/ilist", "//pkg/refs", + "//pkg/sentry/context", "//pkg/syserr", "//pkg/tcpip", "//pkg/tcpip/buffer", diff --git a/pkg/sentry/socket/unix/transport/connectioned.go b/pkg/sentry/socket/unix/transport/connectioned.go index 9d07cde22..e4c416233 100644 --- a/pkg/sentry/socket/unix/transport/connectioned.go +++ b/pkg/sentry/socket/unix/transport/connectioned.go @@ -18,6 +18,7 @@ import ( "sync" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/waiter" @@ -111,8 +112,13 @@ type connectionedEndpoint struct { acceptedChan chan *connectionedEndpoint `state:".([]*connectionedEndpoint)"` } +var ( + _ = BoundEndpoint((*connectionedEndpoint)(nil)) + _ = Endpoint((*connectionedEndpoint)(nil)) +) + // NewConnectioned creates a new unbound connectionedEndpoint. -func NewConnectioned(stype linux.SockType, uid UniqueIDProvider) Endpoint { +func NewConnectioned(ctx context.Context, stype linux.SockType, uid UniqueIDProvider) Endpoint { return &connectionedEndpoint{ baseEndpoint: baseEndpoint{Queue: &waiter.Queue{}}, id: uid.UniqueID(), @@ -122,7 +128,7 @@ func NewConnectioned(stype linux.SockType, uid UniqueIDProvider) Endpoint { } // NewPair allocates a new pair of connected unix-domain connectionedEndpoints. -func NewPair(stype linux.SockType, uid UniqueIDProvider) (Endpoint, Endpoint) { +func NewPair(ctx context.Context, stype linux.SockType, uid UniqueIDProvider) (Endpoint, Endpoint) { a := &connectionedEndpoint{ baseEndpoint: baseEndpoint{Queue: &waiter.Queue{}}, id: uid.UniqueID(), @@ -163,7 +169,7 @@ func NewPair(stype linux.SockType, uid UniqueIDProvider) (Endpoint, Endpoint) { // NewExternal creates a new externally backed Endpoint. It behaves like a // socketpair. -func NewExternal(stype linux.SockType, uid UniqueIDProvider, queue *waiter.Queue, receiver Receiver, connected ConnectedEndpoint) Endpoint { +func NewExternal(ctx context.Context, stype linux.SockType, uid UniqueIDProvider, queue *waiter.Queue, receiver Receiver, connected ConnectedEndpoint) Endpoint { return &connectionedEndpoint{ baseEndpoint: baseEndpoint{Queue: queue, receiver: receiver, connected: connected}, id: uid.UniqueID(), @@ -238,7 +244,7 @@ func (e *connectionedEndpoint) Close() { } // BidirectionalConnect implements BoundEndpoint.BidirectionalConnect. -func (e *connectionedEndpoint) BidirectionalConnect(ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error { +func (e *connectionedEndpoint) BidirectionalConnect(ctx context.Context, ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error { if ce.Type() != e.stype { return syserr.ErrConnectionRefused } @@ -334,19 +340,19 @@ func (e *connectionedEndpoint) BidirectionalConnect(ce ConnectingEndpoint, retur } // UnidirectionalConnect implements BoundEndpoint.UnidirectionalConnect. -func (e *connectionedEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error) { +func (e *connectionedEndpoint) UnidirectionalConnect(ctx context.Context) (ConnectedEndpoint, *syserr.Error) { return nil, syserr.ErrConnectionRefused } // Connect attempts to directly connect to another Endpoint. // Implements Endpoint.Connect. -func (e *connectionedEndpoint) Connect(server BoundEndpoint) *syserr.Error { +func (e *connectionedEndpoint) Connect(ctx context.Context, server BoundEndpoint) *syserr.Error { returnConnect := func(r Receiver, ce ConnectedEndpoint) { e.receiver = r e.connected = ce } - return server.BidirectionalConnect(e, returnConnect) + return server.BidirectionalConnect(ctx, e, returnConnect) } // Listen starts listening on the connection. @@ -426,13 +432,13 @@ func (e *connectionedEndpoint) Bind(addr tcpip.FullAddress, commit func() *syser // SendMsg writes data and a control message to the endpoint's peer. // This method does not block if the data cannot be written. -func (e *connectionedEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) { +func (e *connectionedEndpoint) SendMsg(ctx context.Context, data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) { // Stream sockets do not support specifying the endpoint. Seqpacket // sockets ignore the passed endpoint. if e.stype == linux.SOCK_STREAM && to != nil { return 0, syserr.ErrNotSupported } - return e.baseEndpoint.SendMsg(data, c, to) + return e.baseEndpoint.SendMsg(ctx, data, c, to) } // Readiness returns the current readiness of the connectionedEndpoint. For diff --git a/pkg/sentry/socket/unix/transport/connectionless.go b/pkg/sentry/socket/unix/transport/connectionless.go index 254148286..cb2b60339 100644 --- a/pkg/sentry/socket/unix/transport/connectionless.go +++ b/pkg/sentry/socket/unix/transport/connectionless.go @@ -16,6 +16,7 @@ package transport import ( "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/waiter" @@ -32,8 +33,13 @@ type connectionlessEndpoint struct { baseEndpoint } +var ( + _ = BoundEndpoint((*connectionlessEndpoint)(nil)) + _ = Endpoint((*connectionlessEndpoint)(nil)) +) + // NewConnectionless creates a new unbound dgram endpoint. -func NewConnectionless() Endpoint { +func NewConnectionless(ctx context.Context) Endpoint { ep := &connectionlessEndpoint{baseEndpoint{Queue: &waiter.Queue{}}} ep.receiver = &queueReceiver{readQueue: &queue{ReaderQueue: ep.Queue, WriterQueue: &waiter.Queue{}, limit: initialLimit}} return ep @@ -72,12 +78,12 @@ func (e *connectionlessEndpoint) Close() { } // BidirectionalConnect implements BoundEndpoint.BidirectionalConnect. -func (e *connectionlessEndpoint) BidirectionalConnect(ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error { +func (e *connectionlessEndpoint) BidirectionalConnect(ctx context.Context, ce ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error { return syserr.ErrConnectionRefused } // UnidirectionalConnect implements BoundEndpoint.UnidirectionalConnect. -func (e *connectionlessEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error) { +func (e *connectionlessEndpoint) UnidirectionalConnect(ctx context.Context) (ConnectedEndpoint, *syserr.Error) { e.Lock() r := e.receiver e.Unlock() @@ -96,12 +102,12 @@ func (e *connectionlessEndpoint) UnidirectionalConnect() (ConnectedEndpoint, *sy // SendMsg writes data and a control message to the specified endpoint. // This method does not block if the data cannot be written. -func (e *connectionlessEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) { +func (e *connectionlessEndpoint) SendMsg(ctx context.Context, data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) { if to == nil { - return e.baseEndpoint.SendMsg(data, c, nil) + return e.baseEndpoint.SendMsg(ctx, data, c, nil) } - connected, err := to.UnidirectionalConnect() + connected, err := to.UnidirectionalConnect(ctx) if err != nil { return 0, syserr.ErrInvalidEndpointState } @@ -124,8 +130,8 @@ func (e *connectionlessEndpoint) Type() linux.SockType { } // Connect attempts to connect directly to server. -func (e *connectionlessEndpoint) Connect(server BoundEndpoint) *syserr.Error { - connected, err := server.UnidirectionalConnect() +func (e *connectionlessEndpoint) Connect(ctx context.Context, server BoundEndpoint) *syserr.Error { + connected, err := server.UnidirectionalConnect(ctx) if err != nil { return err } diff --git a/pkg/sentry/socket/unix/transport/unix.go b/pkg/sentry/socket/unix/transport/unix.go index a4d41e355..b0765ba55 100644 --- a/pkg/sentry/socket/unix/transport/unix.go +++ b/pkg/sentry/socket/unix/transport/unix.go @@ -20,6 +20,7 @@ import ( "sync/atomic" "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/sentry/context" "gvisor.dev/gvisor/pkg/syserr" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/buffer" @@ -120,13 +121,13 @@ type Endpoint interface { // CMTruncated indicates that the numRights hint was used to receive fewer // than the total available SCM_RIGHTS FDs. Additional truncation may be // required by the caller. - RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (recvLen, msgLen uintptr, cm ControlMessages, CMTruncated bool, err *syserr.Error) + RecvMsg(ctx context.Context, data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (recvLen, msgLen uintptr, cm ControlMessages, CMTruncated bool, err *syserr.Error) // SendMsg writes data and a control message to the endpoint's peer. // This method does not block if the data cannot be written. // // SendMsg does not take ownership of any of its arguments on error. - SendMsg([][]byte, ControlMessages, BoundEndpoint) (uintptr, *syserr.Error) + SendMsg(context.Context, [][]byte, ControlMessages, BoundEndpoint) (uintptr, *syserr.Error) // Connect connects this endpoint directly to another. // @@ -134,7 +135,7 @@ type Endpoint interface { // endpoint passed in as a parameter. // // The error codes are the same as Connect. - Connect(server BoundEndpoint) *syserr.Error + Connect(ctx context.Context, server BoundEndpoint) *syserr.Error // Shutdown closes the read and/or write end of the endpoint connection // to its peer. @@ -215,7 +216,7 @@ type BoundEndpoint interface { // // This method will return syserr.ErrConnectionRefused on endpoints with a // type that isn't SockStream or SockSeqpacket. - BidirectionalConnect(ep ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error + BidirectionalConnect(ctx context.Context, ep ConnectingEndpoint, returnConnect func(Receiver, ConnectedEndpoint)) *syserr.Error // UnidirectionalConnect establishes a write-only connection to a unix // endpoint. @@ -225,7 +226,7 @@ type BoundEndpoint interface { // // This method will return syserr.ErrConnectionRefused on a non-SockDgram // endpoint. - UnidirectionalConnect() (ConnectedEndpoint, *syserr.Error) + UnidirectionalConnect(ctx context.Context) (ConnectedEndpoint, *syserr.Error) // Passcred returns whether or not the SO_PASSCRED socket option is // enabled on this end. @@ -776,7 +777,7 @@ func (e *baseEndpoint) Connected() bool { } // RecvMsg reads data and a control message from the endpoint. -func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (uintptr, uintptr, ControlMessages, bool, *syserr.Error) { +func (e *baseEndpoint) RecvMsg(ctx context.Context, data [][]byte, creds bool, numRights uintptr, peek bool, addr *tcpip.FullAddress) (uintptr, uintptr, ControlMessages, bool, *syserr.Error) { e.Lock() if e.receiver == nil { @@ -802,7 +803,7 @@ func (e *baseEndpoint) RecvMsg(data [][]byte, creds bool, numRights uintptr, pee // SendMsg writes data and a control message to the endpoint's peer. // This method does not block if the data cannot be written. -func (e *baseEndpoint) SendMsg(data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) { +func (e *baseEndpoint) SendMsg(ctx context.Context, data [][]byte, c ControlMessages, to BoundEndpoint) (uintptr, *syserr.Error) { e.Lock() if !e.Connected() { e.Unlock() diff --git a/pkg/sentry/socket/unix/unix.go b/pkg/sentry/socket/unix/unix.go index 58483a279..97db87f3e 100644 --- a/pkg/sentry/socket/unix/unix.go +++ b/pkg/sentry/socket/unix/unix.go @@ -363,7 +363,7 @@ func (s *SocketOperations) Connect(t *kernel.Task, sockaddr []byte, blocking boo defer ep.Release() // Connect the server endpoint. - return s.ep.Connect(ep) + return s.ep.Connect(t, ep) } // Writev implements fs.FileOperations.Write. @@ -372,11 +372,12 @@ func (s *SocketOperations) Write(ctx context.Context, _ *fs.File, src usermem.IO ctrl := control.New(t, s.ep, nil) if src.NumBytes() == 0 { - nInt, err := s.ep.SendMsg([][]byte{}, ctrl, nil) + nInt, err := s.ep.SendMsg(ctx, [][]byte{}, ctrl, nil) return int64(nInt), err.ToError() } return src.CopyInTo(ctx, &EndpointWriter{ + Ctx: ctx, Endpoint: s.ep, Control: ctrl, To: nil, @@ -387,6 +388,7 @@ func (s *SocketOperations) Write(ctx context.Context, _ *fs.File, src usermem.IO // a transport.Endpoint. func (s *SocketOperations) SendMsg(t *kernel.Task, src usermem.IOSequence, to []byte, flags int, haveDeadline bool, deadline ktime.Time, controlMessages socket.ControlMessages) (int, *syserr.Error) { w := EndpointWriter{ + Ctx: t, Endpoint: s.ep, Control: controlMessages.Unix, To: nil, @@ -486,6 +488,7 @@ func (s *SocketOperations) Read(ctx context.Context, _ *fs.File, dst usermem.IOS return 0, nil } return dst.CopyOutFrom(ctx, &EndpointReader{ + Ctx: ctx, Endpoint: s.ep, NumRights: 0, Peek: false, @@ -522,6 +525,7 @@ func (s *SocketOperations) RecvMsg(t *kernel.Task, dst usermem.IOSequence, flags } r := EndpointReader{ + Ctx: t, Endpoint: s.ep, Creds: wantCreds, NumRights: uintptr(numRights), @@ -635,9 +639,9 @@ func (*provider) Socket(t *kernel.Task, stype linux.SockType, protocol int) (*fs var ep transport.Endpoint switch stype { case linux.SOCK_DGRAM: - ep = transport.NewConnectionless() + ep = transport.NewConnectionless(t) case linux.SOCK_SEQPACKET, linux.SOCK_STREAM: - ep = transport.NewConnectioned(stype, t.Kernel()) + ep = transport.NewConnectioned(t, stype, t.Kernel()) default: return nil, syserr.ErrInvalidArgument } @@ -660,7 +664,7 @@ func (*provider) Pair(t *kernel.Task, stype linux.SockType, protocol int) (*fs.F } // Create the endpoints and sockets. - ep1, ep2 := transport.NewPair(stype, t.Kernel()) + ep1, ep2 := transport.NewPair(t, stype, t.Kernel()) s1 := New(t, ep1, stype) s2 := New(t, ep2, stype) diff --git a/pkg/sentry/syscalls/linux/sys_file.go b/pkg/sentry/syscalls/linux/sys_file.go index b20991192..31c26fd5c 100644 --- a/pkg/sentry/syscalls/linux/sys_file.go +++ b/pkg/sentry/syscalls/linux/sys_file.go @@ -2067,7 +2067,7 @@ func MemfdCreate(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.S name = memfdPrefix + name inode := tmpfs.NewMemfdInode(t, allowSeals) - dirent := fs.NewDirent(inode, name) + dirent := fs.NewDirent(t, inode, name) // Per Linux, mm/shmem.c:__shmem_file_setup(), memfd files are set up with // FMODE_READ | FMODE_WRITE. file, err := inode.GetFile(t, dirent, fs.FileFlags{Read: true, Write: true}) diff --git a/pkg/sentry/syscalls/linux/sys_inotify.go b/pkg/sentry/syscalls/linux/sys_inotify.go index 49aff608a..043ecf96c 100644 --- a/pkg/sentry/syscalls/linux/sys_inotify.go +++ b/pkg/sentry/syscalls/linux/sys_inotify.go @@ -35,7 +35,7 @@ func InotifyInit1(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel. return 0, nil, syscall.EINVAL } - dirent := fs.NewDirent(anon.NewInode(t), "inotify") + dirent := fs.NewDirent(t, anon.NewInode(t), "inotify") fileFlags := fs.FileFlags{ Read: true, Write: true, diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go index 588317f4f..67a286212 100644 --- a/runsc/boot/fs.go +++ b/runsc/boot/fs.go @@ -76,7 +76,7 @@ func addOverlay(ctx context.Context, conf *Config, lower *fs.Inode, name string, tmpFS := mustFindFilesystem("tmpfs") if !fs.IsDir(lower.StableAttr) { // Create overlay on top of mount file, e.g. /etc/hostname. - msrc := fs.NewCachingMountSource(tmpFS, upperFlags) + msrc := fs.NewCachingMountSource(ctx, tmpFS, upperFlags) return fs.NewOverlayRootFile(ctx, msrc, lower, upperFlags) } @@ -226,7 +226,7 @@ func mustFindFilesystem(name string) fs.Filesystem { // addSubmountOverlay overlays the inode over a ramfs tree containing the given // paths. func addSubmountOverlay(ctx context.Context, inode *fs.Inode, submounts []string) (*fs.Inode, error) { - msrc := fs.NewPseudoMountSource() + msrc := fs.NewPseudoMountSource(ctx) mountTree, err := ramfs.MakeDirectoryTree(ctx, msrc, submounts) if err != nil { return nil, fmt.Errorf("creating mount tree: %v", err) diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 38425f97d..53e61e43d 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -206,7 +206,9 @@ func New(args Args) (*Loader, error) { // Create VDSO. // // Pass k as the platform since it is savable, unlike the actual platform. - vdso, err := loader.PrepareVDSO(k) + // + // FIXME(b/109889800): Use non-nil context. + vdso, err := loader.PrepareVDSO(nil, k) if err != nil { return nil, fmt.Errorf("creating vdso: %v", err) } -- cgit v1.2.3