mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Remove unused rpcinet.
PiperOrigin-RevId: 290198756
This commit is contained in:
committed by
gVisor bot
parent
7a45ae7e67
commit
19b4653147
@@ -18,7 +18,6 @@ go_library(
|
||||
"mounts.go",
|
||||
"net.go",
|
||||
"proc.go",
|
||||
"rpcinet_proc.go",
|
||||
"stat.go",
|
||||
"sys.go",
|
||||
"sys_net.go",
|
||||
@@ -46,7 +45,6 @@ go_library(
|
||||
"//pkg/sentry/limits",
|
||||
"//pkg/sentry/mm",
|
||||
"//pkg/sentry/socket",
|
||||
"//pkg/sentry/socket/rpcinet",
|
||||
"//pkg/sentry/socket/unix",
|
||||
"//pkg/sentry/socket/unix/transport",
|
||||
"//pkg/sentry/usage",
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/proc/seqfile"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
)
|
||||
|
||||
@@ -87,15 +86,9 @@ func New(ctx context.Context, msrc *fs.MountSource, cgroupControllers map[string
|
||||
}
|
||||
|
||||
// Add more contents that need proc to be initialized.
|
||||
p.AddChild(ctx, "net", p.newNetDir(ctx, k, msrc))
|
||||
p.AddChild(ctx, "sys", p.newSysDir(ctx, msrc))
|
||||
|
||||
// If we're using rpcinet we will let it manage /proc/net.
|
||||
if _, ok := p.k.NetworkStack().(*rpcinet.Stack); ok {
|
||||
p.AddChild(ctx, "net", newRPCInetProcNet(ctx, msrc))
|
||||
} else {
|
||||
p.AddChild(ctx, "net", p.newNetDir(ctx, k, msrc))
|
||||
}
|
||||
|
||||
return newProcInode(ctx, p, msrc, fs.SpecialDirectory, nil), nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package proc
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/fsutil"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
// rpcInetInode implements fs.InodeOperations.
|
||||
type rpcInetInode struct {
|
||||
fsutil.SimpleFileInode
|
||||
|
||||
// filepath is the full path of this rpcInetInode.
|
||||
filepath string
|
||||
|
||||
k *kernel.Kernel
|
||||
}
|
||||
|
||||
func newRPCInetInode(ctx context.Context, msrc *fs.MountSource, filepath string, mode linux.FileMode) *fs.Inode {
|
||||
f := &rpcInetInode{
|
||||
SimpleFileInode: *fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermsFromMode(mode), linux.PROC_SUPER_MAGIC),
|
||||
filepath: filepath,
|
||||
k: kernel.KernelFromContext(ctx),
|
||||
}
|
||||
return newProcInode(ctx, f, msrc, fs.SpecialFile, nil)
|
||||
}
|
||||
|
||||
// GetFile implements fs.InodeOperations.GetFile.
|
||||
func (i *rpcInetInode) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlags) (*fs.File, error) {
|
||||
flags.Pread = true
|
||||
flags.Pwrite = true
|
||||
fops := &rpcInetFile{
|
||||
inode: i,
|
||||
}
|
||||
return fs.NewFile(ctx, dirent, flags, fops), nil
|
||||
}
|
||||
|
||||
// rpcInetFile implements fs.FileOperations as RPCs.
|
||||
type rpcInetFile struct {
|
||||
fsutil.FileGenericSeek `state:"nosave"`
|
||||
fsutil.FileNoIoctl `state:"nosave"`
|
||||
fsutil.FileNoMMap `state:"nosave"`
|
||||
fsutil.FileNoSplice `state:"nosave"`
|
||||
fsutil.FileNoopFlush `state:"nosave"`
|
||||
fsutil.FileNoopFsync `state:"nosave"`
|
||||
fsutil.FileNoopRelease `state:"nosave"`
|
||||
fsutil.FileNotDirReaddir `state:"nosave"`
|
||||
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
|
||||
waiter.AlwaysReady `state:"nosave"`
|
||||
|
||||
inode *rpcInetInode
|
||||
}
|
||||
|
||||
// Read implements fs.FileOperations.Read.
|
||||
//
|
||||
// This method can panic if an rpcInetInode was created without an rpcinet
|
||||
// stack.
|
||||
func (f *rpcInetFile) Read(ctx context.Context, file *fs.File, dst usermem.IOSequence, offset int64) (int64, error) {
|
||||
if offset < 0 {
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
s, ok := f.inode.k.NetworkStack().(*rpcinet.Stack)
|
||||
if !ok {
|
||||
panic("Network stack is not a rpcinet.")
|
||||
}
|
||||
|
||||
contents, se := s.RPCReadFile(f.inode.filepath)
|
||||
if se != nil || offset >= int64(len(contents)) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
|
||||
n, err := dst.CopyOut(ctx, contents[offset:])
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
// Write implements fs.FileOperations.Write.
|
||||
//
|
||||
// This method can panic if an rpcInetInode was created without an rpcInet
|
||||
// stack.
|
||||
func (f *rpcInetFile) Write(ctx context.Context, file *fs.File, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
s, ok := f.inode.k.NetworkStack().(*rpcinet.Stack)
|
||||
if !ok {
|
||||
panic("Network stack is not a rpcinet.")
|
||||
}
|
||||
|
||||
if src.NumBytes() == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
b := make([]byte, src.NumBytes(), src.NumBytes())
|
||||
n, err := src.CopyIn(ctx, b)
|
||||
if err != nil {
|
||||
return int64(n), err
|
||||
}
|
||||
|
||||
written, se := s.RPCWriteFile(f.inode.filepath, b)
|
||||
return int64(written), se.ToError()
|
||||
}
|
||||
|
||||
// newRPCInetProcNet will build an inode for /proc/net.
|
||||
func newRPCInetProcNet(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
contents := map[string]*fs.Inode{
|
||||
"arp": newRPCInetInode(ctx, msrc, "/proc/net/arp", 0444),
|
||||
"dev": newRPCInetInode(ctx, msrc, "/proc/net/dev", 0444),
|
||||
"if_inet6": newRPCInetInode(ctx, msrc, "/proc/net/if_inet6", 0444),
|
||||
"ipv6_route": newRPCInetInode(ctx, msrc, "/proc/net/ipv6_route", 0444),
|
||||
"netlink": newRPCInetInode(ctx, msrc, "/proc/net/netlink", 0444),
|
||||
"netstat": newRPCInetInode(ctx, msrc, "/proc/net/netstat", 0444),
|
||||
"packet": newRPCInetInode(ctx, msrc, "/proc/net/packet", 0444),
|
||||
"protocols": newRPCInetInode(ctx, msrc, "/proc/net/protocols", 0444),
|
||||
"psched": newRPCInetInode(ctx, msrc, "/proc/net/psched", 0444),
|
||||
"ptype": newRPCInetInode(ctx, msrc, "/proc/net/ptype", 0444),
|
||||
"route": newRPCInetInode(ctx, msrc, "/proc/net/route", 0444),
|
||||
"tcp": newRPCInetInode(ctx, msrc, "/proc/net/tcp", 0444),
|
||||
"tcp6": newRPCInetInode(ctx, msrc, "/proc/net/tcp6", 0444),
|
||||
"udp": newRPCInetInode(ctx, msrc, "/proc/net/udp", 0444),
|
||||
"udp6": newRPCInetInode(ctx, msrc, "/proc/net/udp6", 0444),
|
||||
}
|
||||
|
||||
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
|
||||
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
|
||||
}
|
||||
|
||||
// newRPCInetProcSysNet will build an inode for /proc/sys/net.
|
||||
func newRPCInetProcSysNet(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
contents := map[string]*fs.Inode{
|
||||
"ipv4": newRPCInetSysNetIPv4Dir(ctx, msrc),
|
||||
"core": newRPCInetSysNetCore(ctx, msrc),
|
||||
}
|
||||
|
||||
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
|
||||
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
|
||||
}
|
||||
|
||||
// newRPCInetSysNetCore builds the /proc/sys/net/core directory.
|
||||
func newRPCInetSysNetCore(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
contents := map[string]*fs.Inode{
|
||||
"default_qdisc": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/default_qdisc", 0444),
|
||||
"message_burst": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/message_burst", 0444),
|
||||
"message_cost": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/message_cost", 0444),
|
||||
"optmem_max": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/optmem_max", 0444),
|
||||
"rmem_default": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/rmem_default", 0444),
|
||||
"rmem_max": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/rmem_max", 0444),
|
||||
"somaxconn": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/somaxconn", 0444),
|
||||
"wmem_default": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/wmem_default", 0444),
|
||||
"wmem_max": newRPCInetInode(ctx, msrc, "/proc/sys/net/core/wmem_max", 0444),
|
||||
}
|
||||
|
||||
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
|
||||
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
|
||||
}
|
||||
|
||||
// newRPCInetSysNetIPv4Dir builds the /proc/sys/net/ipv4 directory.
|
||||
func newRPCInetSysNetIPv4Dir(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
contents := map[string]*fs.Inode{
|
||||
"ip_local_port_range": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_local_port_range", 0444),
|
||||
"ip_local_reserved_ports": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_local_reserved_ports", 0444),
|
||||
"ipfrag_time": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ipfrag_time", 0444),
|
||||
"ip_nonlocal_bind": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_nonlocal_bind", 0444),
|
||||
"ip_no_pmtu_disc": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/ip_no_pmtu_disc", 0444),
|
||||
"tcp_allowed_congestion_control": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_allowed_congestion_control", 0444),
|
||||
"tcp_available_congestion_control": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_available_congestion_control", 0444),
|
||||
"tcp_base_mss": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_base_mss", 0444),
|
||||
"tcp_congestion_control": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_congestion_control", 0644),
|
||||
"tcp_dsack": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_dsack", 0644),
|
||||
"tcp_early_retrans": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_early_retrans", 0644),
|
||||
"tcp_fack": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fack", 0644),
|
||||
"tcp_fastopen": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fastopen", 0644),
|
||||
"tcp_fastopen_key": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fastopen_key", 0444),
|
||||
"tcp_fin_timeout": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_fin_timeout", 0644),
|
||||
"tcp_invalid_ratelimit": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_invalid_ratelimit", 0444),
|
||||
"tcp_keepalive_intvl": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_keepalive_intvl", 0644),
|
||||
"tcp_keepalive_probes": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_keepalive_probes", 0644),
|
||||
"tcp_keepalive_time": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_keepalive_time", 0644),
|
||||
"tcp_mem": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_mem", 0444),
|
||||
"tcp_mtu_probing": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_mtu_probing", 0644),
|
||||
"tcp_no_metrics_save": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_no_metrics_save", 0444),
|
||||
"tcp_probe_interval": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_probe_interval", 0444),
|
||||
"tcp_probe_threshold": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_probe_threshold", 0444),
|
||||
"tcp_retries1": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_retries1", 0644),
|
||||
"tcp_retries2": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_retries2", 0644),
|
||||
"tcp_rfc1337": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_rfc1337", 0444),
|
||||
"tcp_rmem": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_rmem", 0444),
|
||||
"tcp_sack": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_sack", 0644),
|
||||
"tcp_slow_start_after_idle": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_slow_start_after_idle", 0644),
|
||||
"tcp_synack_retries": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_synack_retries", 0644),
|
||||
"tcp_syn_retries": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_syn_retries", 0644),
|
||||
"tcp_timestamps": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_timestamps", 0644),
|
||||
"tcp_wmem": newRPCInetInode(ctx, msrc, "/proc/sys/net/ipv4/tcp_wmem", 0444),
|
||||
}
|
||||
|
||||
d := ramfs.NewDir(ctx, contents, fs.RootOwner, fs.FilePermsFromMode(0555))
|
||||
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/proc/seqfile"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fs/ramfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
@@ -106,16 +105,10 @@ func (p *proc) newVMDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
func (p *proc) newSysDir(ctx context.Context, msrc *fs.MountSource) *fs.Inode {
|
||||
children := map[string]*fs.Inode{
|
||||
"kernel": p.newKernelDir(ctx, msrc),
|
||||
"net": p.newSysNetDir(ctx, msrc),
|
||||
"vm": p.newVMDir(ctx, msrc),
|
||||
}
|
||||
|
||||
// If we're using rpcinet we will let it manage /proc/sys/net.
|
||||
if _, ok := p.k.NetworkStack().(*rpcinet.Stack); ok {
|
||||
children["net"] = newRPCInetProcSysNet(ctx, msrc)
|
||||
} else {
|
||||
children["net"] = p.newSysNetDir(ctx, msrc)
|
||||
}
|
||||
|
||||
d := ramfs.NewDir(ctx, children, fs.RootOwner, fs.FilePermsFromMode(0555))
|
||||
return newProcInode(ctx, d, msrc, fs.SpecialDirectory, nil)
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
load("//tools/go_stateify:defs.bzl", "go_library")
|
||||
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "rpcinet",
|
||||
srcs = [
|
||||
"device.go",
|
||||
"rpcinet.go",
|
||||
"socket.go",
|
||||
"stack.go",
|
||||
"stack_unsafe.go",
|
||||
],
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet",
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
":syscall_rpc_go_proto",
|
||||
"//pkg/abi/linux",
|
||||
"//pkg/binary",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/context",
|
||||
"//pkg/sentry/device",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/fs/fsutil",
|
||||
"//pkg/sentry/inet",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/time",
|
||||
"//pkg/sentry/socket",
|
||||
"//pkg/sentry/socket/hostinet",
|
||||
"//pkg/sentry/socket/rpcinet/conn",
|
||||
"//pkg/sentry/socket/rpcinet/notifier",
|
||||
"//pkg/sentry/unimpl",
|
||||
"//pkg/sentry/usermem",
|
||||
"//pkg/syserr",
|
||||
"//pkg/syserror",
|
||||
"//pkg/tcpip",
|
||||
"//pkg/tcpip/buffer",
|
||||
"//pkg/tcpip/stack",
|
||||
"//pkg/unet",
|
||||
"//pkg/waiter",
|
||||
],
|
||||
)
|
||||
|
||||
proto_library(
|
||||
name = "syscall_rpc_proto",
|
||||
srcs = ["syscall_rpc.proto"],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
cc_proto_library(
|
||||
name = "syscall_rpc_cc_proto",
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
deps = [":syscall_rpc_proto"],
|
||||
)
|
||||
|
||||
go_proto_library(
|
||||
name = "syscall_rpc_go_proto",
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto",
|
||||
proto = ":syscall_rpc_proto",
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
@@ -1,18 +0,0 @@
|
||||
load("//tools/go_stateify:defs.bzl", "go_library")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "conn",
|
||||
srcs = ["conn.go"],
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/conn",
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
deps = [
|
||||
"//pkg/binary",
|
||||
"//pkg/sentry/socket/rpcinet:syscall_rpc_go_proto",
|
||||
"//pkg/sync",
|
||||
"//pkg/syserr",
|
||||
"//pkg/unet",
|
||||
"@com_github_golang_protobuf//proto:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,187 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Package conn is an RPC connection to a syscall RPC server.
|
||||
package conn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
"gvisor.dev/gvisor/pkg/unet"
|
||||
|
||||
pb "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto"
|
||||
)
|
||||
|
||||
type request struct {
|
||||
response []byte
|
||||
ready chan struct{}
|
||||
ignoreResult bool
|
||||
}
|
||||
|
||||
// RPCConnection represents a single RPC connection to a syscall gofer.
|
||||
type RPCConnection struct {
|
||||
// reqID is the ID of the last request and must be accessed atomically.
|
||||
reqID uint64
|
||||
|
||||
sendMu sync.Mutex
|
||||
socket *unet.Socket
|
||||
|
||||
reqMu sync.Mutex
|
||||
requests map[uint64]request
|
||||
}
|
||||
|
||||
// NewRPCConnection initializes a RPC connection to a socket gofer.
|
||||
func NewRPCConnection(s *unet.Socket) *RPCConnection {
|
||||
conn := &RPCConnection{socket: s, requests: map[uint64]request{}}
|
||||
go func() { // S/R-FIXME(b/77962828)
|
||||
var nums [16]byte
|
||||
for {
|
||||
for n := 0; n < len(nums); {
|
||||
nn, err := conn.socket.Read(nums[n:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprint("error reading length from socket rpc gofer: ", err))
|
||||
}
|
||||
n += nn
|
||||
}
|
||||
|
||||
b := make([]byte, binary.LittleEndian.Uint64(nums[:8]))
|
||||
id := binary.LittleEndian.Uint64(nums[8:])
|
||||
|
||||
for n := 0; n < len(b); {
|
||||
nn, err := conn.socket.Read(b[n:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprint("error reading request from socket rpc gofer: ", err))
|
||||
}
|
||||
n += nn
|
||||
}
|
||||
|
||||
conn.reqMu.Lock()
|
||||
r := conn.requests[id]
|
||||
if r.ignoreResult {
|
||||
delete(conn.requests, id)
|
||||
} else {
|
||||
r.response = b
|
||||
conn.requests[id] = r
|
||||
}
|
||||
conn.reqMu.Unlock()
|
||||
close(r.ready)
|
||||
}
|
||||
}()
|
||||
return conn
|
||||
}
|
||||
|
||||
// NewRequest makes a request to the RPC gofer and returns the request ID and a
|
||||
// channel which will be closed once the request completes.
|
||||
func (c *RPCConnection) NewRequest(req pb.SyscallRequest, ignoreResult bool) (uint64, chan struct{}) {
|
||||
b, err := proto.Marshal(&req)
|
||||
if err != nil {
|
||||
panic(fmt.Sprint("invalid proto: ", err))
|
||||
}
|
||||
|
||||
id := atomic.AddUint64(&c.reqID, 1)
|
||||
ch := make(chan struct{})
|
||||
|
||||
c.reqMu.Lock()
|
||||
c.requests[id] = request{ready: ch, ignoreResult: ignoreResult}
|
||||
c.reqMu.Unlock()
|
||||
|
||||
c.sendMu.Lock()
|
||||
defer c.sendMu.Unlock()
|
||||
|
||||
var nums [16]byte
|
||||
binary.LittleEndian.PutUint64(nums[:8], uint64(len(b)))
|
||||
binary.LittleEndian.PutUint64(nums[8:], id)
|
||||
for n := 0; n < len(nums); {
|
||||
nn, err := c.socket.Write(nums[n:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprint("error writing length and ID to socket gofer: ", err))
|
||||
}
|
||||
n += nn
|
||||
}
|
||||
|
||||
for n := 0; n < len(b); {
|
||||
nn, err := c.socket.Write(b[n:])
|
||||
if err != nil {
|
||||
panic(fmt.Sprint("error writing request to socket gofer: ", err))
|
||||
}
|
||||
n += nn
|
||||
}
|
||||
|
||||
return id, ch
|
||||
}
|
||||
|
||||
// RPCReadFile will execute the ReadFile helper RPC method which avoids the
|
||||
// common pattern of open(2), read(2), close(2) by doing all three operations
|
||||
// as a single RPC. It will read the entire file or return EFBIG if the file
|
||||
// was too large.
|
||||
func (c *RPCConnection) RPCReadFile(path string) ([]byte, *syserr.Error) {
|
||||
req := &pb.SyscallRequest_ReadFile{&pb.ReadFileRequest{
|
||||
Path: path,
|
||||
}}
|
||||
|
||||
id, ch := c.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
|
||||
<-ch
|
||||
|
||||
res := c.Request(id).Result.(*pb.SyscallResponse_ReadFile).ReadFile.Result
|
||||
if e, ok := res.(*pb.ReadFileResponse_ErrorNumber); ok {
|
||||
return nil, syserr.FromHost(syscall.Errno(e.ErrorNumber))
|
||||
}
|
||||
|
||||
return res.(*pb.ReadFileResponse_Data).Data, nil
|
||||
}
|
||||
|
||||
// RPCWriteFile will execute the WriteFile helper RPC method which avoids the
|
||||
// common pattern of open(2), write(2), write(2), close(2) by doing all
|
||||
// operations as a single RPC.
|
||||
func (c *RPCConnection) RPCWriteFile(path string, data []byte) (int64, *syserr.Error) {
|
||||
req := &pb.SyscallRequest_WriteFile{&pb.WriteFileRequest{
|
||||
Path: path,
|
||||
Content: data,
|
||||
}}
|
||||
|
||||
id, ch := c.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
|
||||
<-ch
|
||||
|
||||
res := c.Request(id).Result.(*pb.SyscallResponse_WriteFile).WriteFile
|
||||
if e := res.ErrorNumber; e != 0 {
|
||||
return int64(res.Written), syserr.FromHost(syscall.Errno(e))
|
||||
}
|
||||
|
||||
return int64(res.Written), nil
|
||||
}
|
||||
|
||||
// Request retrieves the request corresponding to the given request ID.
|
||||
//
|
||||
// The channel returned by NewRequest must have been closed before Request can
|
||||
// be called. This will happen automatically, do not manually close the
|
||||
// channel.
|
||||
func (c *RPCConnection) Request(id uint64) pb.SyscallResponse {
|
||||
c.reqMu.Lock()
|
||||
r := c.requests[id]
|
||||
delete(c.requests, id)
|
||||
c.reqMu.Unlock()
|
||||
|
||||
var resp pb.SyscallResponse
|
||||
if err := proto.Unmarshal(r.response, &resp); err != nil {
|
||||
panic(fmt.Sprint("invalid proto: ", err))
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package rpcinet
|
||||
|
||||
import "gvisor.dev/gvisor/pkg/sentry/device"
|
||||
|
||||
var socketDevice = device.NewAnonDevice()
|
||||
@@ -1,17 +0,0 @@
|
||||
load("//tools/go_stateify:defs.bzl", "go_library")
|
||||
|
||||
package(licenses = ["notice"])
|
||||
|
||||
go_library(
|
||||
name = "notifier",
|
||||
srcs = ["notifier.go"],
|
||||
importpath = "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/notifier",
|
||||
visibility = ["//:sandbox"],
|
||||
deps = [
|
||||
"//pkg/sentry/socket/rpcinet:syscall_rpc_go_proto",
|
||||
"//pkg/sentry/socket/rpcinet/conn",
|
||||
"//pkg/sync",
|
||||
"//pkg/waiter",
|
||||
"@org_golang_x_sys//unix:go_default_library",
|
||||
],
|
||||
)
|
||||
@@ -1,231 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Package notifier implements an FD notifier implementation over RPC.
|
||||
package notifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/conn"
|
||||
pb "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/waiter"
|
||||
)
|
||||
|
||||
type fdInfo struct {
|
||||
queue *waiter.Queue
|
||||
waiting bool
|
||||
}
|
||||
|
||||
// Notifier holds all the state necessary to issue notifications when IO events
|
||||
// occur in the observed FDs.
|
||||
type Notifier struct {
|
||||
// rpcConn is the connection that is used for sending RPCs.
|
||||
rpcConn *conn.RPCConnection
|
||||
|
||||
// epFD is the epoll file descriptor used to register for io
|
||||
// notifications.
|
||||
epFD uint32
|
||||
|
||||
// mu protects fdMap.
|
||||
mu sync.Mutex
|
||||
|
||||
// fdMap maps file descriptors to their notification queues and waiting
|
||||
// status.
|
||||
fdMap map[uint32]*fdInfo
|
||||
}
|
||||
|
||||
// NewRPCNotifier creates a new notifier object.
|
||||
func NewRPCNotifier(cn *conn.RPCConnection) (*Notifier, error) {
|
||||
id, c := cn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCreate1{&pb.EpollCreate1Request{}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
res := cn.Request(id).Result.(*pb.SyscallResponse_EpollCreate1).EpollCreate1.Result
|
||||
if e, ok := res.(*pb.EpollCreate1Response_ErrorNumber); ok {
|
||||
return nil, syscall.Errno(e.ErrorNumber)
|
||||
}
|
||||
|
||||
w := &Notifier{
|
||||
rpcConn: cn,
|
||||
epFD: res.(*pb.EpollCreate1Response_Fd).Fd,
|
||||
fdMap: make(map[uint32]*fdInfo),
|
||||
}
|
||||
|
||||
go w.waitAndNotify() // S/R-FIXME(b/77962828)
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// waitFD waits on mask for fd. The fdMap mutex must be hold.
|
||||
func (n *Notifier) waitFD(fd uint32, fi *fdInfo, mask waiter.EventMask) error {
|
||||
if !fi.waiting && mask == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
e := pb.EpollEvent{
|
||||
Events: mask.ToLinux() | unix.EPOLLET,
|
||||
Fd: fd,
|
||||
}
|
||||
|
||||
switch {
|
||||
case !fi.waiting && mask != 0:
|
||||
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCtl{&pb.EpollCtlRequest{Epfd: n.epFD, Op: syscall.EPOLL_CTL_ADD, Fd: fd, Event: &e}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
e := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_EpollCtl).EpollCtl.ErrorNumber
|
||||
if e != 0 {
|
||||
return syscall.Errno(e)
|
||||
}
|
||||
|
||||
fi.waiting = true
|
||||
case fi.waiting && mask == 0:
|
||||
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCtl{&pb.EpollCtlRequest{Epfd: n.epFD, Op: syscall.EPOLL_CTL_DEL, Fd: fd}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
n.rpcConn.Request(id)
|
||||
|
||||
fi.waiting = false
|
||||
case fi.waiting && mask != 0:
|
||||
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollCtl{&pb.EpollCtlRequest{Epfd: n.epFD, Op: syscall.EPOLL_CTL_MOD, Fd: fd, Event: &e}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
e := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_EpollCtl).EpollCtl.ErrorNumber
|
||||
if e != 0 {
|
||||
return syscall.Errno(e)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addFD adds an FD to the list of FDs observed by n.
|
||||
func (n *Notifier) addFD(fd uint32, queue *waiter.Queue) {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
// Panic if we're already notifying on this FD.
|
||||
if _, ok := n.fdMap[fd]; ok {
|
||||
panic(fmt.Sprintf("File descriptor %d added twice", fd))
|
||||
}
|
||||
|
||||
// We have nothing to wait for at the moment. Just add it to the map.
|
||||
n.fdMap[fd] = &fdInfo{queue: queue}
|
||||
}
|
||||
|
||||
// updateFD updates the set of events the FD needs to be notified on.
|
||||
func (n *Notifier) updateFD(fd uint32) error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if fi, ok := n.fdMap[fd]; ok {
|
||||
return n.waitFD(fd, fi, fi.queue.Events())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveFD removes an FD from the list of FDs observed by n.
|
||||
func (n *Notifier) removeFD(fd uint32) {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
// Remove from map, then from epoll object.
|
||||
n.waitFD(fd, n.fdMap[fd], 0)
|
||||
delete(n.fdMap, fd)
|
||||
}
|
||||
|
||||
// hasFD returns true if the FD is in the list of observed FDs.
|
||||
func (n *Notifier) hasFD(fd uint32) bool {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
_, ok := n.fdMap[fd]
|
||||
return ok
|
||||
}
|
||||
|
||||
// waitAndNotify loops waiting for io event notifications from the epoll
|
||||
// object. Once notifications arrive, they are dispatched to the
|
||||
// registered queue.
|
||||
func (n *Notifier) waitAndNotify() error {
|
||||
for {
|
||||
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_EpollWait{&pb.EpollWaitRequest{Fd: n.epFD, NumEvents: 100, Msec: -1}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
res := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_EpollWait).EpollWait.Result
|
||||
if e, ok := res.(*pb.EpollWaitResponse_ErrorNumber); ok {
|
||||
err := syscall.Errno(e.ErrorNumber)
|
||||
// NOTE(magi): I don't think epoll_wait can return EAGAIN but I'm being
|
||||
// conseratively careful here since exiting the notification thread
|
||||
// would be really bad.
|
||||
if err == syscall.EINTR || err == syscall.EAGAIN {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
n.mu.Lock()
|
||||
for _, e := range res.(*pb.EpollWaitResponse_Events).Events.Events {
|
||||
if fi, ok := n.fdMap[e.Fd]; ok {
|
||||
fi.queue.Notify(waiter.EventMaskFromLinux(e.Events))
|
||||
}
|
||||
}
|
||||
n.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// AddFD adds an FD to the list of observed FDs.
|
||||
func (n *Notifier) AddFD(fd uint32, queue *waiter.Queue) error {
|
||||
n.addFD(fd, queue)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateFD updates the set of events the FD needs to be notified on.
|
||||
func (n *Notifier) UpdateFD(fd uint32) error {
|
||||
return n.updateFD(fd)
|
||||
}
|
||||
|
||||
// RemoveFD removes an FD from the list of observed FDs.
|
||||
func (n *Notifier) RemoveFD(fd uint32) {
|
||||
n.removeFD(fd)
|
||||
}
|
||||
|
||||
// HasFD returns true if the FD is in the list of observed FDs.
|
||||
//
|
||||
// This should only be used by tests to assert that FDs are correctly
|
||||
// registered.
|
||||
func (n *Notifier) HasFD(fd uint32) bool {
|
||||
return n.hasFD(fd)
|
||||
}
|
||||
|
||||
// NonBlockingPoll polls the given fd in non-blocking fashion. It is used just
|
||||
// to query the FD's current state; this method will block on the RPC response
|
||||
// although the syscall is non-blocking.
|
||||
func (n *Notifier) NonBlockingPoll(fd uint32, mask waiter.EventMask) waiter.EventMask {
|
||||
for {
|
||||
id, c := n.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Poll{&pb.PollRequest{Fd: fd, Events: mask.ToLinux()}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
res := n.rpcConn.Request(id).Result.(*pb.SyscallResponse_Poll).Poll.Result
|
||||
if e, ok := res.(*pb.PollResponse_ErrorNumber); ok {
|
||||
if syscall.Errno(e.ErrorNumber) == syscall.EINTR {
|
||||
continue
|
||||
}
|
||||
return mask
|
||||
}
|
||||
|
||||
return waiter.EventMaskFromLinux(res.(*pb.PollResponse_Events).Events)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// Package rpcinet implements sockets using an RPC for each syscall.
|
||||
package rpcinet
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,177 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package rpcinet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/hostinet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/conn"
|
||||
"gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/notifier"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
"gvisor.dev/gvisor/pkg/unet"
|
||||
)
|
||||
|
||||
// Stack implements inet.Stack for RPC backed sockets.
|
||||
type Stack struct {
|
||||
interfaces map[int32]inet.Interface
|
||||
interfaceAddrs map[int32][]inet.InterfaceAddr
|
||||
routes []inet.Route
|
||||
rpcConn *conn.RPCConnection
|
||||
notifier *notifier.Notifier
|
||||
}
|
||||
|
||||
// NewStack returns a Stack containing the current state of the host network
|
||||
// stack.
|
||||
func NewStack(fd int32) (*Stack, error) {
|
||||
sock, err := unet.NewSocket(int(fd))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stack := &Stack{
|
||||
interfaces: make(map[int32]inet.Interface),
|
||||
interfaceAddrs: make(map[int32][]inet.InterfaceAddr),
|
||||
rpcConn: conn.NewRPCConnection(sock),
|
||||
}
|
||||
|
||||
var e error
|
||||
stack.notifier, e = notifier.NewRPCNotifier(stack.rpcConn)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
links, err := stack.DoNetlinkRouteRequest(syscall.RTM_GETLINK)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("RTM_GETLINK failed: %v", err)
|
||||
}
|
||||
|
||||
addrs, err := stack.DoNetlinkRouteRequest(syscall.RTM_GETADDR)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("RTM_GETADDR failed: %v", err)
|
||||
}
|
||||
|
||||
e = hostinet.ExtractHostInterfaces(links, addrs, stack.interfaces, stack.interfaceAddrs)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
routes, err := stack.DoNetlinkRouteRequest(syscall.RTM_GETROUTE)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("RTM_GETROUTE failed: %v", err)
|
||||
}
|
||||
|
||||
stack.routes, e = hostinet.ExtractHostRoutes(routes)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
return stack, nil
|
||||
}
|
||||
|
||||
// RPCReadFile will execute the ReadFile helper RPC method which avoids the
|
||||
// common pattern of open(2), read(2), close(2) by doing all three operations
|
||||
// as a single RPC. It will read the entire file or return EFBIG if the file
|
||||
// was too large.
|
||||
func (s *Stack) RPCReadFile(path string) ([]byte, *syserr.Error) {
|
||||
return s.rpcConn.RPCReadFile(path)
|
||||
}
|
||||
|
||||
// RPCWriteFile will execute the WriteFile helper RPC method which avoids the
|
||||
// common pattern of open(2), write(2), write(2), close(2) by doing all
|
||||
// operations as a single RPC.
|
||||
func (s *Stack) RPCWriteFile(path string, data []byte) (int64, *syserr.Error) {
|
||||
return s.rpcConn.RPCWriteFile(path, data)
|
||||
}
|
||||
|
||||
// Interfaces implements inet.Stack.Interfaces.
|
||||
func (s *Stack) Interfaces() map[int32]inet.Interface {
|
||||
interfaces := make(map[int32]inet.Interface)
|
||||
for k, v := range s.interfaces {
|
||||
interfaces[k] = v
|
||||
}
|
||||
return interfaces
|
||||
}
|
||||
|
||||
// InterfaceAddrs implements inet.Stack.InterfaceAddrs.
|
||||
func (s *Stack) InterfaceAddrs() map[int32][]inet.InterfaceAddr {
|
||||
addrs := make(map[int32][]inet.InterfaceAddr)
|
||||
for k, v := range s.interfaceAddrs {
|
||||
addrs[k] = append([]inet.InterfaceAddr(nil), v...)
|
||||
}
|
||||
return addrs
|
||||
}
|
||||
|
||||
// SupportsIPv6 implements inet.Stack.SupportsIPv6.
|
||||
func (s *Stack) SupportsIPv6() bool {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
}
|
||||
|
||||
// TCPReceiveBufferSize implements inet.Stack.TCPReceiveBufferSize.
|
||||
func (s *Stack) TCPReceiveBufferSize() (inet.TCPBufferSize, error) {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
}
|
||||
|
||||
// SetTCPReceiveBufferSize implements inet.Stack.SetTCPReceiveBufferSize.
|
||||
func (s *Stack) SetTCPReceiveBufferSize(size inet.TCPBufferSize) error {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
|
||||
}
|
||||
|
||||
// TCPSendBufferSize implements inet.Stack.TCPSendBufferSize.
|
||||
func (s *Stack) TCPSendBufferSize() (inet.TCPBufferSize, error) {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
|
||||
}
|
||||
|
||||
// SetTCPSendBufferSize implements inet.Stack.SetTCPSendBufferSize.
|
||||
func (s *Stack) SetTCPSendBufferSize(size inet.TCPBufferSize) error {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
}
|
||||
|
||||
// TCPSACKEnabled implements inet.Stack.TCPSACKEnabled.
|
||||
func (s *Stack) TCPSACKEnabled() (bool, error) {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
}
|
||||
|
||||
// SetTCPSACKEnabled implements inet.Stack.SetTCPSACKEnabled.
|
||||
func (s *Stack) SetTCPSACKEnabled(enabled bool) error {
|
||||
panic("rpcinet handles procfs directly this method should not be called")
|
||||
}
|
||||
|
||||
// Statistics implements inet.Stack.Statistics.
|
||||
func (s *Stack) Statistics(stat interface{}, arg string) error {
|
||||
return syserr.ErrEndpointOperation.ToError()
|
||||
}
|
||||
|
||||
// RouteTable implements inet.Stack.RouteTable.
|
||||
func (s *Stack) RouteTable() []inet.Route {
|
||||
return append([]inet.Route(nil), s.routes...)
|
||||
}
|
||||
|
||||
// Resume implements inet.Stack.Resume.
|
||||
func (s *Stack) Resume() {}
|
||||
|
||||
// RegisteredEndpoints implements inet.Stack.RegisteredEndpoints.
|
||||
func (s *Stack) RegisteredEndpoints() []stack.TransportEndpoint { return nil }
|
||||
|
||||
// CleanupEndpoints implements inet.Stack.CleanupEndpoints.
|
||||
func (s *Stack) CleanupEndpoints() []stack.TransportEndpoint { return nil }
|
||||
|
||||
// RestoreCleanupEndpoints implements inet.Stack.RestoreCleanupEndpoints.
|
||||
func (s *Stack) RestoreCleanupEndpoints([]stack.TransportEndpoint) {}
|
||||
@@ -1,193 +0,0 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
package rpcinet
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/binary"
|
||||
pb "gvisor.dev/gvisor/pkg/sentry/socket/rpcinet/syscall_rpc_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sentry/usermem"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
)
|
||||
|
||||
// NewNetlinkRouteRequest builds a netlink message for getting the RIB,
|
||||
// the routing information base.
|
||||
func newNetlinkRouteRequest(proto, seq, family int) []byte {
|
||||
rr := &syscall.NetlinkRouteRequest{}
|
||||
rr.Header.Len = uint32(syscall.NLMSG_HDRLEN + syscall.SizeofRtGenmsg)
|
||||
rr.Header.Type = uint16(proto)
|
||||
rr.Header.Flags = syscall.NLM_F_DUMP | syscall.NLM_F_REQUEST
|
||||
rr.Header.Seq = uint32(seq)
|
||||
rr.Data.Family = uint8(family)
|
||||
return netlinkRRtoWireFormat(rr)
|
||||
}
|
||||
|
||||
func netlinkRRtoWireFormat(rr *syscall.NetlinkRouteRequest) []byte {
|
||||
b := make([]byte, rr.Header.Len)
|
||||
*(*uint32)(unsafe.Pointer(&b[0:4][0])) = rr.Header.Len
|
||||
*(*uint16)(unsafe.Pointer(&b[4:6][0])) = rr.Header.Type
|
||||
*(*uint16)(unsafe.Pointer(&b[6:8][0])) = rr.Header.Flags
|
||||
*(*uint32)(unsafe.Pointer(&b[8:12][0])) = rr.Header.Seq
|
||||
*(*uint32)(unsafe.Pointer(&b[12:16][0])) = rr.Header.Pid
|
||||
b[16] = byte(rr.Data.Family)
|
||||
return b
|
||||
}
|
||||
|
||||
func (s *Stack) getNetlinkFd() (uint32, *syserr.Error) {
|
||||
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Socket{&pb.SocketRequest{Family: int64(syscall.AF_NETLINK), Type: int64(syscall.SOCK_RAW | syscall.SOCK_NONBLOCK), Protocol: int64(syscall.NETLINK_ROUTE)}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
res := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Socket).Socket.Result
|
||||
if e, ok := res.(*pb.SocketResponse_ErrorNumber); ok {
|
||||
return 0, syserr.FromHost(syscall.Errno(e.ErrorNumber))
|
||||
}
|
||||
return res.(*pb.SocketResponse_Fd).Fd, nil
|
||||
}
|
||||
|
||||
func (s *Stack) bindNetlinkFd(fd uint32, sockaddr []byte) *syserr.Error {
|
||||
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Bind{&pb.BindRequest{Fd: fd, Address: sockaddr}}}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
if e := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Bind).Bind.ErrorNumber; e != 0 {
|
||||
return syserr.FromHost(syscall.Errno(e))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stack) closeNetlinkFd(fd uint32) {
|
||||
_, _ = s.rpcConn.NewRequest(pb.SyscallRequest{Args: &pb.SyscallRequest_Close{&pb.CloseRequest{Fd: fd}}}, true /* ignoreResult */)
|
||||
}
|
||||
|
||||
func (s *Stack) rpcSendMsg(req *pb.SyscallRequest_Sendmsg) (uint32, *syserr.Error) {
|
||||
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
res := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Sendmsg).Sendmsg.Result
|
||||
if e, ok := res.(*pb.SendmsgResponse_ErrorNumber); ok {
|
||||
return 0, syserr.FromHost(syscall.Errno(e.ErrorNumber))
|
||||
}
|
||||
|
||||
return res.(*pb.SendmsgResponse_Length).Length, nil
|
||||
}
|
||||
|
||||
func (s *Stack) sendMsg(fd uint32, buf []byte, to []byte, flags int) (int, *syserr.Error) {
|
||||
// Whitelist flags.
|
||||
if flags&^(syscall.MSG_DONTWAIT|syscall.MSG_EOR|syscall.MSG_FASTOPEN|syscall.MSG_MORE|syscall.MSG_NOSIGNAL) != 0 {
|
||||
return 0, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
req := &pb.SyscallRequest_Sendmsg{&pb.SendmsgRequest{
|
||||
Fd: fd,
|
||||
Data: buf,
|
||||
Address: to,
|
||||
More: flags&linux.MSG_MORE != 0,
|
||||
EndOfRecord: flags&linux.MSG_EOR != 0,
|
||||
}}
|
||||
|
||||
n, err := s.rpcSendMsg(req)
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
func (s *Stack) rpcRecvMsg(req *pb.SyscallRequest_Recvmsg) (*pb.RecvmsgResponse_ResultPayload, *syserr.Error) {
|
||||
id, c := s.rpcConn.NewRequest(pb.SyscallRequest{Args: req}, false /* ignoreResult */)
|
||||
<-c
|
||||
|
||||
res := s.rpcConn.Request(id).Result.(*pb.SyscallResponse_Recvmsg).Recvmsg.Result
|
||||
if e, ok := res.(*pb.RecvmsgResponse_ErrorNumber); ok {
|
||||
return nil, syserr.FromHost(syscall.Errno(e.ErrorNumber))
|
||||
}
|
||||
|
||||
return res.(*pb.RecvmsgResponse_Payload).Payload, nil
|
||||
}
|
||||
|
||||
func (s *Stack) recvMsg(fd, l, flags uint32) ([]byte, *syserr.Error) {
|
||||
req := &pb.SyscallRequest_Recvmsg{&pb.RecvmsgRequest{
|
||||
Fd: fd,
|
||||
Length: l,
|
||||
Sender: false,
|
||||
Trunc: flags&linux.MSG_TRUNC != 0,
|
||||
Peek: flags&linux.MSG_PEEK != 0,
|
||||
}}
|
||||
|
||||
res, err := s.rpcRecvMsg(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res.Data, nil
|
||||
}
|
||||
|
||||
func (s *Stack) netlinkRequest(proto, family int) ([]byte, error) {
|
||||
fd, err := s.getNetlinkFd()
|
||||
if err != nil {
|
||||
return nil, err.ToError()
|
||||
}
|
||||
defer s.closeNetlinkFd(fd)
|
||||
|
||||
lsa := syscall.SockaddrNetlink{Family: syscall.AF_NETLINK}
|
||||
b := binary.Marshal(nil, usermem.ByteOrder, &lsa)
|
||||
if err := s.bindNetlinkFd(fd, b); err != nil {
|
||||
return nil, err.ToError()
|
||||
}
|
||||
|
||||
wb := newNetlinkRouteRequest(proto, 1, family)
|
||||
_, err = s.sendMsg(fd, wb, b, 0)
|
||||
if err != nil {
|
||||
return nil, err.ToError()
|
||||
}
|
||||
|
||||
var tab []byte
|
||||
done:
|
||||
for {
|
||||
rb, err := s.recvMsg(fd, uint32(syscall.Getpagesize()), 0)
|
||||
nr := len(rb)
|
||||
if err != nil {
|
||||
return nil, err.ToError()
|
||||
}
|
||||
|
||||
if nr < syscall.NLMSG_HDRLEN {
|
||||
return nil, syserr.ErrInvalidArgument.ToError()
|
||||
}
|
||||
|
||||
tab = append(tab, rb...)
|
||||
msgs, e := syscall.ParseNetlinkMessage(rb)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
for _, m := range msgs {
|
||||
if m.Header.Type == syscall.NLMSG_DONE {
|
||||
break done
|
||||
}
|
||||
if m.Header.Type == syscall.NLMSG_ERROR {
|
||||
return nil, syserr.ErrInvalidArgument.ToError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tab, nil
|
||||
}
|
||||
|
||||
// DoNetlinkRouteRequest returns routing information base, also known as RIB,
|
||||
// which consists of network facility information, states and parameters.
|
||||
func (s *Stack) DoNetlinkRouteRequest(req int) ([]syscall.NetlinkMessage, error) {
|
||||
data, err := s.netlinkRequest(req, syscall.AF_UNSPEC)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return syscall.ParseNetlinkMessage(data)
|
||||
}
|
||||
@@ -1,352 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
// package syscall_rpc is a set of networking related system calls that can be
|
||||
// forwarded to a socket gofer.
|
||||
//
|
||||
package syscall_rpc;
|
||||
|
||||
message SendmsgRequest {
|
||||
uint32 fd = 1;
|
||||
bytes data = 2 [ctype = CORD];
|
||||
bytes address = 3;
|
||||
bool more = 4;
|
||||
bool end_of_record = 5;
|
||||
}
|
||||
|
||||
message SendmsgResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
uint32 length = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message IOCtlRequest {
|
||||
uint32 fd = 1;
|
||||
uint32 cmd = 2;
|
||||
bytes arg = 3;
|
||||
}
|
||||
|
||||
message IOCtlResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
bytes value = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message RecvmsgRequest {
|
||||
uint32 fd = 1;
|
||||
uint32 length = 2;
|
||||
bool sender = 3;
|
||||
bool peek = 4;
|
||||
bool trunc = 5;
|
||||
uint32 cmsg_length = 6;
|
||||
}
|
||||
|
||||
message OpenRequest {
|
||||
bytes path = 1;
|
||||
uint32 flags = 2;
|
||||
uint32 mode = 3;
|
||||
}
|
||||
|
||||
message OpenResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
uint32 fd = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ReadRequest {
|
||||
uint32 fd = 1;
|
||||
uint32 length = 2;
|
||||
}
|
||||
|
||||
message ReadResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
bytes data = 2 [ctype = CORD];
|
||||
}
|
||||
}
|
||||
|
||||
message ReadFileRequest {
|
||||
string path = 1;
|
||||
}
|
||||
|
||||
message ReadFileResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
bytes data = 2 [ctype = CORD];
|
||||
}
|
||||
}
|
||||
|
||||
message WriteRequest {
|
||||
uint32 fd = 1;
|
||||
bytes data = 2 [ctype = CORD];
|
||||
}
|
||||
|
||||
message WriteResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
uint32 length = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message WriteFileRequest {
|
||||
string path = 1;
|
||||
bytes content = 2;
|
||||
}
|
||||
|
||||
message WriteFileResponse {
|
||||
uint32 error_number = 1;
|
||||
uint32 written = 2;
|
||||
}
|
||||
|
||||
message AddressResponse {
|
||||
bytes address = 1;
|
||||
uint32 length = 2;
|
||||
}
|
||||
|
||||
message RecvmsgResponse {
|
||||
message ResultPayload {
|
||||
bytes data = 1 [ctype = CORD];
|
||||
AddressResponse address = 2;
|
||||
uint32 length = 3;
|
||||
bytes cmsg_data = 4;
|
||||
}
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
ResultPayload payload = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message BindRequest {
|
||||
uint32 fd = 1;
|
||||
bytes address = 2;
|
||||
}
|
||||
|
||||
message BindResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message AcceptRequest {
|
||||
uint32 fd = 1;
|
||||
bool peer = 2;
|
||||
int64 flags = 3;
|
||||
}
|
||||
|
||||
message AcceptResponse {
|
||||
message ResultPayload {
|
||||
uint32 fd = 1;
|
||||
AddressResponse address = 2;
|
||||
}
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
ResultPayload payload = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message ConnectRequest {
|
||||
uint32 fd = 1;
|
||||
bytes address = 2;
|
||||
}
|
||||
|
||||
message ConnectResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message ListenRequest {
|
||||
uint32 fd = 1;
|
||||
int64 backlog = 2;
|
||||
}
|
||||
|
||||
message ListenResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message ShutdownRequest {
|
||||
uint32 fd = 1;
|
||||
int64 how = 2;
|
||||
}
|
||||
|
||||
message ShutdownResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message CloseRequest {
|
||||
uint32 fd = 1;
|
||||
}
|
||||
|
||||
message CloseResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message GetSockOptRequest {
|
||||
uint32 fd = 1;
|
||||
int64 level = 2;
|
||||
int64 name = 3;
|
||||
uint32 length = 4;
|
||||
}
|
||||
|
||||
message GetSockOptResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
bytes opt = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SetSockOptRequest {
|
||||
uint32 fd = 1;
|
||||
int64 level = 2;
|
||||
int64 name = 3;
|
||||
bytes opt = 4;
|
||||
}
|
||||
|
||||
message SetSockOptResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message GetSockNameRequest {
|
||||
uint32 fd = 1;
|
||||
}
|
||||
|
||||
message GetSockNameResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
AddressResponse address = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message GetPeerNameRequest {
|
||||
uint32 fd = 1;
|
||||
}
|
||||
|
||||
message GetPeerNameResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
AddressResponse address = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SocketRequest {
|
||||
int64 family = 1;
|
||||
int64 type = 2;
|
||||
int64 protocol = 3;
|
||||
}
|
||||
|
||||
message SocketResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
uint32 fd = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message EpollWaitRequest {
|
||||
uint32 fd = 1;
|
||||
uint32 num_events = 2;
|
||||
sint64 msec = 3;
|
||||
}
|
||||
|
||||
message EpollEvent {
|
||||
uint32 fd = 1;
|
||||
uint32 events = 2;
|
||||
}
|
||||
|
||||
message EpollEvents {
|
||||
repeated EpollEvent events = 1;
|
||||
}
|
||||
|
||||
message EpollWaitResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
EpollEvents events = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message EpollCtlRequest {
|
||||
uint32 epfd = 1;
|
||||
int64 op = 2;
|
||||
uint32 fd = 3;
|
||||
EpollEvent event = 4;
|
||||
}
|
||||
|
||||
message EpollCtlResponse {
|
||||
uint32 error_number = 1;
|
||||
}
|
||||
|
||||
message EpollCreate1Request {
|
||||
int64 flag = 1;
|
||||
}
|
||||
|
||||
message EpollCreate1Response {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
uint32 fd = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message PollRequest {
|
||||
uint32 fd = 1;
|
||||
uint32 events = 2;
|
||||
}
|
||||
|
||||
message PollResponse {
|
||||
oneof result {
|
||||
uint32 error_number = 1;
|
||||
uint32 events = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SyscallRequest {
|
||||
oneof args {
|
||||
SocketRequest socket = 1;
|
||||
SendmsgRequest sendmsg = 2;
|
||||
RecvmsgRequest recvmsg = 3;
|
||||
BindRequest bind = 4;
|
||||
AcceptRequest accept = 5;
|
||||
ConnectRequest connect = 6;
|
||||
ListenRequest listen = 7;
|
||||
ShutdownRequest shutdown = 8;
|
||||
CloseRequest close = 9;
|
||||
GetSockOptRequest get_sock_opt = 10;
|
||||
SetSockOptRequest set_sock_opt = 11;
|
||||
GetSockNameRequest get_sock_name = 12;
|
||||
GetPeerNameRequest get_peer_name = 13;
|
||||
EpollWaitRequest epoll_wait = 14;
|
||||
EpollCtlRequest epoll_ctl = 15;
|
||||
EpollCreate1Request epoll_create1 = 16;
|
||||
PollRequest poll = 17;
|
||||
ReadRequest read = 18;
|
||||
WriteRequest write = 19;
|
||||
OpenRequest open = 20;
|
||||
IOCtlRequest ioctl = 21;
|
||||
WriteFileRequest write_file = 22;
|
||||
ReadFileRequest read_file = 23;
|
||||
}
|
||||
}
|
||||
|
||||
message SyscallResponse {
|
||||
oneof result {
|
||||
SocketResponse socket = 1;
|
||||
SendmsgResponse sendmsg = 2;
|
||||
RecvmsgResponse recvmsg = 3;
|
||||
BindResponse bind = 4;
|
||||
AcceptResponse accept = 5;
|
||||
ConnectResponse connect = 6;
|
||||
ListenResponse listen = 7;
|
||||
ShutdownResponse shutdown = 8;
|
||||
CloseResponse close = 9;
|
||||
GetSockOptResponse get_sock_opt = 10;
|
||||
SetSockOptResponse set_sock_opt = 11;
|
||||
GetSockNameResponse get_sock_name = 12;
|
||||
GetPeerNameResponse get_peer_name = 13;
|
||||
EpollWaitResponse epoll_wait = 14;
|
||||
EpollCtlResponse epoll_ctl = 15;
|
||||
EpollCreate1Response epoll_create1 = 16;
|
||||
PollResponse poll = 17;
|
||||
ReadResponse read = 18;
|
||||
WriteResponse write = 19;
|
||||
OpenResponse open = 20;
|
||||
IOCtlResponse ioctl = 21;
|
||||
WriteFileResponse write_file = 22;
|
||||
ReadFileResponse read_file = 23;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user