Allow creating packet socket bound to any protocol

...even protocols the stack is unaware of.

While I am here, annotate checklocks on stack.packetEndpointList.

PiperOrigin-RevId: 397226754
This commit is contained in:
Ghanan Gowripalan 2021-09-16 20:04:00 -07:00 committed by gVisor bot
parent 85bd3dd9b1
commit b28bd31bb6
5 changed files with 94 additions and 7 deletions

View File

@ -97,6 +97,8 @@ type packetEndpointList struct {
mu sync.RWMutex
// eps is protected by mu, but the contained PacketEndpoint values are not.
//
// +checklocks:mu
eps []PacketEndpoint
}
@ -117,6 +119,12 @@ func (p *packetEndpointList) remove(ep PacketEndpoint) {
}
}
func (p *packetEndpointList) len() int {
p.mu.RLock()
defer p.mu.RUnlock()
return len(p.eps)
}
// forEach calls fn with each endpoints in p while holding the read lock on p.
func (p *packetEndpointList) forEach(fn func(PacketEndpoint)) {
p.mu.RLock()
@ -157,14 +165,8 @@ func newNIC(stack *Stack, id tcpip.NICID, name string, ep LinkEndpoint, ctx NICC
resolutionRequired := ep.Capabilities()&CapabilityResolutionRequired != 0
// Register supported packet and network endpoint protocols.
for _, netProto := range header.Ethertypes {
nic.packetEPs.eps[netProto] = new(packetEndpointList)
}
for _, netProto := range stack.networkProtocols {
netNum := netProto.Number()
nic.packetEPs.eps[netNum] = new(packetEndpointList)
netEP := netProto.NewEndpoint(nic, nic)
nic.networkEndpoints[netNum] = netEP
@ -974,7 +976,8 @@ func (n *nic) registerPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep Pa
eps, ok := n.packetEPs.eps[netProto]
if !ok {
return &tcpip.ErrNotSupported{}
eps = new(packetEndpointList)
n.packetEPs.eps[netProto] = eps
}
eps.add(ep)
@ -990,6 +993,9 @@ func (n *nic) unregisterPacketEndpoint(netProto tcpip.NetworkProtocolNumber, ep
return
}
eps.remove(ep)
if eps.len() == 0 {
delete(n.packetEPs.eps, netProto)
}
}
// isValidForOutgoing returns true if the endpoint can be used to send out a

View File

@ -366,6 +366,10 @@ syscall_test(
test = "//test/syscalls/linux:packet_socket_raw_test",
)
syscall_test(
test = "//test/syscalls/linux:packet_socket_test",
)
syscall_test(
test = "//test/syscalls/linux:partial_bad_buffer_test",
)

View File

@ -7,6 +7,7 @@ package(
exports_files(
[
"packet_socket.cc",
"packet_socket_dgram.cc",
"packet_socket_raw.cc",
"raw_socket.cc",
@ -1480,6 +1481,20 @@ cc_binary(
],
)
cc_binary(
name = "packet_socket_test",
testonly = 1,
srcs = ["packet_socket.cc"],
linkstatic = 1,
deps = [
"//test/util:capability_util",
"//test/util:file_descriptor",
"//test/util:socket_util",
gtest,
"//test/util:test_main",
],
)
cc_binary(
name = "pty_test",
testonly = 1,

View File

@ -0,0 +1,60 @@
// Copyright 2021 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <net/if.h>
#include <netinet/if_ether.h>
#include <limits>
#include "gtest/gtest.h"
#include "test/util/capability_util.h"
#include "test/util/file_descriptor.h"
#include "test/util/socket_util.h"
namespace gvisor {
namespace testing {
namespace {
using ::testing::Combine;
using ::testing::Values;
class PacketSocketTest : public ::testing::TestWithParam<std::tuple<int, int>> {
protected:
void SetUp() override {
if (!ASSERT_NO_ERRNO_AND_VALUE(HavePacketSocketCapability())) {
const auto [type, protocol] = GetParam();
ASSERT_THAT(socket(AF_PACKET, type, htons(protocol)),
SyscallFailsWithErrno(EPERM));
GTEST_SKIP() << "Missing packet socket capability";
}
}
};
TEST_P(PacketSocketTest, Create) {
const auto [type, protocol] = GetParam();
FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_PACKET, type, htons(protocol)));
EXPECT_GE(fd.get(), 0);
}
INSTANTIATE_TEST_SUITE_P(AllPacketSocketTests, PacketSocketTest,
Combine(Values(SOCK_DGRAM, SOCK_RAW),
Values(0, 1, 255, ETH_P_IP, ETH_P_IPV6,
std::numeric_limits<uint16_t>::max())));
} // namespace
} // namespace testing
} // namespace gvisor

View File

@ -17,6 +17,8 @@
#ifndef GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
#define GVISOR_TEST_UTIL_CAPABILITY_UTIL_H_
#include "test/util/posix_error.h"
#if defined(__Fuchsia__)
// Nothing to include.
#elif defined(__linux__)