mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
hostinet: Allow more socket options to have variable-length buffers.
Most of these buffers can be truncated in the Sentry before returning to the application. IP_TOS is a bit funny, since it is interpreted as a 8, 16, or 32-bit int depending on the buffer size, so simple truncation does not work. We allow all sizes to be passed to the host. PiperOrigin-RevId: 513880257
This commit is contained in:
committed by
Ayush Ranjan
parent
35937b7f61
commit
da3c2bbb82
@@ -31,7 +31,7 @@ import (
|
||||
)
|
||||
|
||||
func firstBytePtr(bs []byte) unsafe.Pointer {
|
||||
if bs == nil {
|
||||
if len(bs) == 0 {
|
||||
return nil
|
||||
}
|
||||
return unsafe.Pointer(&bs[0])
|
||||
@@ -222,11 +222,7 @@ func accept4(fd int, addr *byte, addrlen *uint32, flags int) (int, error) {
|
||||
|
||||
func getsockopt(fd int, level, name int, opt []byte) ([]byte, error) {
|
||||
optlen32 := int32(len(opt))
|
||||
var optPtr uintptr
|
||||
if optlen32 > 0 {
|
||||
optPtr = uintptr(firstBytePtr(opt))
|
||||
}
|
||||
_, _, errno := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), optPtr, uintptr(unsafe.Pointer(&optlen32)), 0)
|
||||
_, _, errno := unix.Syscall6(unix.SYS_GETSOCKOPT, uintptr(fd), uintptr(level), uintptr(name), uintptr(firstBytePtr(opt)), uintptr(unsafe.Pointer(&optlen32)), 0)
|
||||
if errno != 0 {
|
||||
return nil, errno
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ var SockOpts = []SockOpt{
|
||||
{linux.SOL_IP, linux.IP_RECVORIGDSTADDR, sizeofInt32, true, true},
|
||||
{linux.SOL_IP, linux.IP_RECVTOS, sizeofInt32, true, true},
|
||||
{linux.SOL_IP, linux.IP_RECVTTL, sizeofInt32, true, true},
|
||||
{linux.SOL_IP, linux.IP_TOS, sizeofInt32, true, true},
|
||||
{linux.SOL_IP, linux.IP_TOS, 0 /* Can be 32, 16, or 8 bits */, true, true},
|
||||
{linux.SOL_IP, linux.IP_TTL, sizeofInt32, true, true},
|
||||
|
||||
{linux.SOL_IPV6, linux.IPV6_MULTICAST_HOPS, sizeofInt32, true, true},
|
||||
@@ -169,9 +169,21 @@ func (s *Socket) GetSockOpt(t *kernel.Task, level, name int, optValAddr hostarch
|
||||
if sockOpt.Size > 0 {
|
||||
// Validate size of input buffer.
|
||||
if uint64(optLen) < sockOpt.Size {
|
||||
// Special case for TCP_INFO. We allow smaller buffers, and
|
||||
// only fill up what we can.
|
||||
if level != linux.SOL_TCP || name != linux.TCP_INFO {
|
||||
// Special case for options that allow smaller buffers.
|
||||
//
|
||||
// To keep the syscall filters simple and restrictive,
|
||||
// we use the full buffer size when calling the host,
|
||||
// but truncate before returning to the application.
|
||||
switch {
|
||||
case level == linux.SOL_TCP && name == linux.TCP_INFO:
|
||||
// Allow smaller buffer.
|
||||
case level == linux.SOL_ICMPV6 && name == linux.ICMPV6_FILTER:
|
||||
// Allow smaller buffer.
|
||||
case level == linux.SOL_IP && name == linux.IP_TTL:
|
||||
// Allow smaller buffer.
|
||||
case level == linux.SOL_IPV6 && name == linux.IPV6_TCLASS:
|
||||
// Allow smaller buffer.
|
||||
default:
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
}
|
||||
@@ -190,9 +202,8 @@ func (s *Socket) GetSockOpt(t *kernel.Task, level, name int, optValAddr hostarch
|
||||
return nil, syserr.FromError(err)
|
||||
}
|
||||
opt = postGetSockOpt(t, level, name, opt)
|
||||
// Special-case for TCP_INFO. We truncate the buffer to whatever size
|
||||
// the user requested.
|
||||
if level == linux.SOL_TCP && name == linux.TCP_INFO && uint64(optLen) < sockOpt.Size {
|
||||
// If option allows a smaller buffer, truncate it to desired size.
|
||||
if uint64(optLen) < sockOpt.Size {
|
||||
opt = opt[:optLen]
|
||||
}
|
||||
optP := primitive.ByteSlice(opt)
|
||||
|
||||
@@ -738,6 +738,7 @@ syscall_test(
|
||||
|
||||
syscall_test(
|
||||
size = "large",
|
||||
add_hostinet = True,
|
||||
container = True,
|
||||
one_sandbox = False,
|
||||
shard_count = most_shards,
|
||||
@@ -746,6 +747,7 @@ syscall_test(
|
||||
|
||||
syscall_test(
|
||||
size = "large",
|
||||
add_hostinet = True,
|
||||
shard_count = most_shards,
|
||||
# Takes too long for TSAN. Creates a lot of TCP sockets.
|
||||
tags = ["nogotsan"],
|
||||
@@ -810,6 +812,7 @@ syscall_test(
|
||||
|
||||
syscall_test(
|
||||
size = "medium",
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_ipv6_udp_unbound_loopback_test",
|
||||
)
|
||||
|
||||
@@ -831,11 +834,13 @@ syscall_test(
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
add_hostinet = True,
|
||||
shard_count = more_shards,
|
||||
test = "//test/syscalls/linux:socket_ip_unbound_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
add_hostinet = True,
|
||||
shard_count = more_shards,
|
||||
test = "//test/syscalls/linux:socket_ipv6_unbound_test",
|
||||
)
|
||||
@@ -862,10 +867,12 @@ syscall_test(
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_blocking_local_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_blocking_ip_test",
|
||||
)
|
||||
|
||||
@@ -875,11 +882,13 @@ syscall_test(
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_non_stream_blocking_udp_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
size = "large",
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_stream_blocking_local_test",
|
||||
)
|
||||
|
||||
@@ -890,11 +899,13 @@ syscall_test(
|
||||
|
||||
syscall_test(
|
||||
size = "medium",
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_stream_local_test",
|
||||
)
|
||||
|
||||
syscall_test(
|
||||
size = "medium",
|
||||
add_hostinet = True,
|
||||
test = "//test/syscalls/linux:socket_stream_nonblock_local_test",
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user