mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
iptables: check revision numbers and support owner matcher v1
This change also replaces use of kernel.Task with a narrower type (IDMapper) in preparation for a follow-up CL. PiperOrigin-RevId: 578387814
This commit is contained in:
committed by
gVisor bot
parent
5f75371657
commit
7f08016fb8
@@ -633,8 +633,8 @@ const (
|
||||
XT_UDP_INV_MASK = 0x03
|
||||
)
|
||||
|
||||
// IPTOwnerInfo holds data for matching packets with owner. It corresponds
|
||||
// to struct ipt_owner_info in libxt_owner.c of iptables binary.
|
||||
// IPTOwnerInfo holds data for matching packets with the owner v0 matcher. It
|
||||
// corresponds to struct ipt_owner_info in libxt_owner.c of iptables binary.
|
||||
//
|
||||
// +marshal
|
||||
type IPTOwnerInfo struct {
|
||||
@@ -661,11 +661,29 @@ type IPTOwnerInfo struct {
|
||||
Invert uint8 `marshal:"unaligned"`
|
||||
}
|
||||
|
||||
// SizeOfIPTOwnerInfo is the size of an XTOwnerMatchInfo.
|
||||
// SizeOfIPTOwnerInfo is the size of an IPTOwnerInfo.
|
||||
const SizeOfIPTOwnerInfo = 34
|
||||
|
||||
// Flags in IPTOwnerInfo.Match. Corresponding constants are in
|
||||
// include/uapi/linux/netfilter/xt_owner.h.
|
||||
// XTOwnerMatchInfo holds data for matching packets with the owner v1 matcher.
|
||||
// It corresponds to struct xt_owner_match_info in
|
||||
// include/uapi/linux/netfilter/xt_owner.h
|
||||
//
|
||||
// +marshal
|
||||
type XTOwnerMatchInfo struct {
|
||||
UIDMin uint32
|
||||
UIDMax uint32
|
||||
GIDMin uint32
|
||||
GIDMax uint32
|
||||
Match uint8
|
||||
Invert uint8
|
||||
_ [2]byte
|
||||
}
|
||||
|
||||
// SizeOfXTOwnerMatchInfo is the size of an XTOwnerMatchInfo.
|
||||
const SizeOfXTOwnerMatchInfo = 20
|
||||
|
||||
// Flags in IPTOwnerInfo.Match and XTOwnerMatchInfo.Match. Corresponding
|
||||
// constants are in include/uapi/linux/netfilter/xt_owner.h.
|
||||
const (
|
||||
// Match the UID of the packet.
|
||||
XT_OWNER_UID = 1 << 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
load("//tools:defs.bzl", "go_library")
|
||||
load("//tools:defs.bzl", "go_library", "go_test")
|
||||
|
||||
package(
|
||||
default_applicable_licenses = ["//:license"],
|
||||
@@ -13,6 +13,7 @@ go_library(
|
||||
"ipv6.go",
|
||||
"netfilter.go",
|
||||
"owner_matcher.go",
|
||||
"owner_matcher_v1.go",
|
||||
"targets.go",
|
||||
"tcp_matcher.go",
|
||||
"udp_matcher.go",
|
||||
@@ -35,3 +36,14 @@ go_library(
|
||||
"//pkg/tcpip/stack",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "netfilter_test",
|
||||
srcs = ["netfilter_test.go"],
|
||||
embedsrcs = ["istio_blob"],
|
||||
library = ":netfilter",
|
||||
deps = [
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/tcpip/stack",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -19,45 +19,65 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/bits"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// matchMaker knows how to (un)marshal the matcher named name().
|
||||
// matchMaker knows how to (un)marshal the matcher named name(). UPDATE THIS
|
||||
type matchMaker interface {
|
||||
// name is the matcher name as stored in the xt_entry_match struct.
|
||||
name() string
|
||||
|
||||
// revision is the match revision as stored in the xt_entry_match
|
||||
// struct.
|
||||
revision() uint8
|
||||
|
||||
// marshal converts from a stack.Matcher to an ABI struct.
|
||||
marshal(matcher matcher) []byte
|
||||
|
||||
// unmarshal converts from the ABI matcher struct to an
|
||||
// stack.Matcher.
|
||||
unmarshal(task *kernel.Task, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error)
|
||||
unmarshal(mapper IDMapper, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error)
|
||||
}
|
||||
|
||||
type matchKey struct {
|
||||
name string
|
||||
revision uint8
|
||||
}
|
||||
|
||||
func key(mm matchMaker) matchKey {
|
||||
return matchKey{
|
||||
name: mm.name(),
|
||||
revision: mm.revision(),
|
||||
}
|
||||
}
|
||||
|
||||
type matcher interface {
|
||||
name() string
|
||||
revision() uint8
|
||||
}
|
||||
|
||||
// matchMakers maps the name of supported matchers to the matchMaker that
|
||||
// marshals and unmarshals it. It is immutable after package initialization.
|
||||
var matchMakers = map[string]matchMaker{}
|
||||
var matchMakers = map[matchKey]matchMaker{}
|
||||
|
||||
// registermatchMaker should be called by match extensions to register them
|
||||
// with the netfilter package.
|
||||
func registerMatchMaker(mm matchMaker) {
|
||||
if _, ok := matchMakers[mm.name()]; ok {
|
||||
panic(fmt.Sprintf("Multiple matches registered with name %q.", mm.name()))
|
||||
if _, ok := matchMakers[key(mm)]; ok {
|
||||
panic(fmt.Sprintf("Multiple matches registered with key %+v.", key(mm)))
|
||||
}
|
||||
matchMakers[mm.name()] = mm
|
||||
matchMakers[key(mm)] = mm
|
||||
}
|
||||
|
||||
func marshalMatcher(mr stack.Matcher) []byte {
|
||||
matcher := mr.(matcher)
|
||||
matchMaker, ok := matchMakers[matcher.name()]
|
||||
key := matchKey{
|
||||
name: matcher.name(),
|
||||
revision: matcher.revision(),
|
||||
}
|
||||
matchMaker, ok := matchMakers[key]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Unknown matcher of type %T.", matcher))
|
||||
}
|
||||
@@ -85,12 +105,16 @@ func marshalEntryMatch(name string, data []byte) []byte {
|
||||
return buf
|
||||
}
|
||||
|
||||
func unmarshalMatcher(task *kernel.Task, match linux.XTEntryMatch, filter stack.IPHeaderFilter, buf []byte) (stack.Matcher, error) {
|
||||
matchMaker, ok := matchMakers[match.Name.String()]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported matcher with name %q", match.Name.String())
|
||||
func unmarshalMatcher(mapper IDMapper, match linux.XTEntryMatch, filter stack.IPHeaderFilter, buf []byte) (stack.Matcher, error) {
|
||||
key := matchKey{
|
||||
name: match.Name.String(),
|
||||
revision: match.Revision,
|
||||
}
|
||||
return matchMaker.unmarshal(task, buf, filter)
|
||||
matchMaker, ok := matchMakers[key]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported matcher with name %q and revision %d", match.Name.String(), match.Revision)
|
||||
}
|
||||
return matchMaker.unmarshal(mapper, buf, filter)
|
||||
}
|
||||
|
||||
// targetMaker knows how to (un)marshal a target. Once registered,
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -126,7 +125,7 @@ func getEntries4(table stack.Table, tablename linux.TableName) (linux.KernelIPTG
|
||||
return entries, info
|
||||
}
|
||||
|
||||
func modifyEntries4(task *kernel.Task, stk *stack.Stack, optVal []byte, replace *linux.IPTReplace, table *stack.Table) (map[uint32]int, *syserr.Error) {
|
||||
func modifyEntries4(mapper IDMapper, stk *stack.Stack, optVal []byte, replace *linux.IPTReplace, table *stack.Table) (map[uint32]int, *syserr.Error) {
|
||||
nflog("set entries: setting entries in table %q", replace.Name.String())
|
||||
|
||||
// Convert input into a list of rules and their offsets.
|
||||
@@ -162,7 +161,7 @@ func modifyEntries4(task *kernel.Task, stk *stack.Stack, optVal []byte, replace
|
||||
nflog("entry doesn't have enough room for its matchers (only %d bytes remain)", len(optVal))
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
matchers, err := parseMatchers(task, filter, optVal[:matchersSize])
|
||||
matchers, err := parseMatchers(mapper, filter, optVal[:matchersSize])
|
||||
if err != nil {
|
||||
nflog("failed to parse matchers: %v", err)
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
|
||||
@@ -18,7 +18,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
@@ -129,7 +128,7 @@ func getEntries6(table stack.Table, tablename linux.TableName) (linux.KernelIP6T
|
||||
return entries, info
|
||||
}
|
||||
|
||||
func modifyEntries6(task *kernel.Task, stk *stack.Stack, optVal []byte, replace *linux.IPTReplace, table *stack.Table) (map[uint32]int, *syserr.Error) {
|
||||
func modifyEntries6(mapper IDMapper, stk *stack.Stack, optVal []byte, replace *linux.IPTReplace, table *stack.Table) (map[uint32]int, *syserr.Error) {
|
||||
nflog("set entries: setting entries in table %q", replace.Name.String())
|
||||
|
||||
// Convert input into a list of rules and their offsets.
|
||||
@@ -165,7 +164,7 @@ func modifyEntries6(task *kernel.Task, stk *stack.Stack, optVal []byte, replace
|
||||
nflog("entry doesn't have enough room for its matchers (only %d bytes remain)", len(optVal))
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
matchers, err := parseMatchers(task, filter, optVal[:matchersSize])
|
||||
matchers, err := parseMatchers(mapper, filter, optVal[:matchersSize])
|
||||
if err != nil {
|
||||
nflog("failed to parse matchers: %v", err)
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
|
||||
Executable
BIN
Binary file not shown.
@@ -26,6 +26,7 @@ import (
|
||||
"gvisor.dev/gvisor/pkg/hostarch"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/syserr"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
@@ -34,7 +35,7 @@ import (
|
||||
// enableLogging controls whether to log the (de)serialization of netfilter
|
||||
// structs between userspace and netstack. These logs are useful when
|
||||
// developing iptables, but can pollute sentry logs otherwise.
|
||||
const enableLogging = false
|
||||
const enableLogging = true
|
||||
|
||||
// nflog logs messages related to the writing and reading of iptables.
|
||||
func nflog(format string, args ...any) {
|
||||
@@ -173,9 +174,15 @@ func setHooksAndUnderflow(info *linux.IPTGetinfo, table stack.Table, offset uint
|
||||
}
|
||||
}
|
||||
|
||||
// An IDMapper maps UIDs and GIDs to KUIDs and KGIDs.
|
||||
type IDMapper interface {
|
||||
MapToKUID(uid auth.UID) auth.KUID
|
||||
MapToKGID(uid auth.GID) auth.KGID
|
||||
}
|
||||
|
||||
// SetEntries sets iptables rules for a single table. See
|
||||
// net/ipv4/netfilter/ip_tables.c:translate_table for reference.
|
||||
func SetEntries(task *kernel.Task, stk *stack.Stack, optVal []byte, ipv6 bool) *syserr.Error {
|
||||
func SetEntries(mapper IDMapper, stk *stack.Stack, optVal []byte, ipv6 bool) *syserr.Error {
|
||||
var replace linux.IPTReplace
|
||||
optVal = replace.UnmarshalBytes(optVal)
|
||||
|
||||
@@ -193,9 +200,9 @@ func SetEntries(task *kernel.Task, stk *stack.Stack, optVal []byte, ipv6 bool) *
|
||||
var err *syserr.Error
|
||||
var offsets map[uint32]int
|
||||
if ipv6 {
|
||||
offsets, err = modifyEntries6(task, stk, optVal, &replace, &table)
|
||||
offsets, err = modifyEntries6(mapper, stk, optVal, &replace, &table)
|
||||
} else {
|
||||
offsets, err = modifyEntries4(task, stk, optVal, &replace, &table)
|
||||
offsets, err = modifyEntries4(mapper, stk, optVal, &replace, &table)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -295,7 +302,7 @@ func SetEntries(task *kernel.Task, stk *stack.Stack, optVal []byte, ipv6 bool) *
|
||||
|
||||
// parseMatchers parses 0 or more matchers from optVal. optVal should contain
|
||||
// only the matchers.
|
||||
func parseMatchers(task *kernel.Task, filter stack.IPHeaderFilter, optVal []byte) ([]stack.Matcher, error) {
|
||||
func parseMatchers(mapper IDMapper, filter stack.IPHeaderFilter, optVal []byte) ([]stack.Matcher, error) {
|
||||
nflog("set entries: parsing matchers of size %d", len(optVal))
|
||||
var matchers []stack.Matcher
|
||||
for len(optVal) > 0 {
|
||||
@@ -318,7 +325,7 @@ func parseMatchers(task *kernel.Task, filter stack.IPHeaderFilter, optVal []byte
|
||||
}
|
||||
|
||||
// Parse the specific matcher.
|
||||
matcher, err := unmarshalMatcher(task, match, filter, optVal[linux.SizeOfXTEntryMatch:match.MatchSize])
|
||||
matcher, err := unmarshalMatcher(mapper, match, filter, optVal[linux.SizeOfXTEntryMatch:match.MatchSize])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create matcher: %v", err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2023 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 netfilter
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"testing"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
// istioBlob is a golden iptables ruleset generated by Istio. It is already in
|
||||
// the format ready to by passed to IPT_SO_SET_REPLACE.
|
||||
//
|
||||
// Updating this requires running Istio, calling IPT_SO_GET_INFO and
|
||||
// IPT_SO_GET_ENTRIES, then stitching the structs up. So be careful when
|
||||
// updating!
|
||||
//
|
||||
//go:embed istio_blob
|
||||
var istioBlob []byte
|
||||
|
||||
// FakeIDMapper implements IDMapper.
|
||||
type FakeIDMapper struct{}
|
||||
|
||||
// MapToKUID implements IDMapper.
|
||||
func (*FakeIDMapper) MapToKUID(auth.UID) auth.KUID {
|
||||
return 0
|
||||
}
|
||||
|
||||
// MapToKGID implements IDMapper.
|
||||
func (*FakeIDMapper) MapToKGID(auth.GID) auth.KGID {
|
||||
return 0
|
||||
}
|
||||
|
||||
// TestIstioBlob tests that we support the iptables ruleset generated by Istio,
|
||||
// i.e. that we can parse the rules and set them in netstack.
|
||||
func TestIstioBlob(t *testing.T) {
|
||||
mapper := FakeIDMapper{}
|
||||
stack := stack.New(stack.Options{})
|
||||
if err := SetEntries(&mapper, stack, istioBlob, false); err != nil {
|
||||
t.Fatalf("failed to set Istio rules, try setting enableLogging and running again: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
@@ -38,6 +37,10 @@ func (ownerMarshaler) name() string {
|
||||
return matcherNameOwner
|
||||
}
|
||||
|
||||
func (ownerMarshaler) revision() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// marshal implements matchMaker.marshal.
|
||||
func (ownerMarshaler) marshal(mr matcher) []byte {
|
||||
matcher := mr.(*OwnerMatcher)
|
||||
@@ -65,7 +68,7 @@ func (ownerMarshaler) marshal(mr matcher) []byte {
|
||||
}
|
||||
|
||||
// unmarshal implements matchMaker.unmarshal.
|
||||
func (ownerMarshaler) unmarshal(task *kernel.Task, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
func (ownerMarshaler) unmarshal(mapper IDMapper, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
if len(buf) < linux.SizeOfIPTOwnerInfo {
|
||||
return nil, fmt.Errorf("buf has insufficient size for owner match: %d", len(buf))
|
||||
}
|
||||
@@ -77,9 +80,8 @@ func (ownerMarshaler) unmarshal(task *kernel.Task, buf []byte, filter stack.IPHe
|
||||
nflog("parsed IPTOwnerInfo: %+v", matchData)
|
||||
|
||||
var owner OwnerMatcher
|
||||
creds := task.Credentials()
|
||||
owner.uid = creds.UserNamespace.MapToKUID(auth.UID(matchData.UID))
|
||||
owner.gid = creds.UserNamespace.MapToKGID(auth.GID(matchData.GID))
|
||||
owner.uid = mapper.MapToKUID(auth.UID(matchData.UID))
|
||||
owner.gid = mapper.MapToKGID(auth.GID(matchData.GID))
|
||||
|
||||
// Check flags.
|
||||
if matchData.Match&linux.XT_OWNER_UID != 0 {
|
||||
@@ -113,6 +115,10 @@ func (*OwnerMatcher) name() string {
|
||||
return matcherNameOwner
|
||||
}
|
||||
|
||||
func (*OwnerMatcher) revision() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Match implements Matcher.Match.
|
||||
func (om *OwnerMatcher) Match(hook stack.Hook, pkt stack.PacketBufferPtr, _, _ string) (bool, bool) {
|
||||
// Support only for OUTPUT chain.
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
// Copyright 2023 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 netfilter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerMatchMaker(ownerMarshalerV1{})
|
||||
}
|
||||
|
||||
// ownerMarshalerV1 implements matchMaker for owner matching.
|
||||
type ownerMarshalerV1 struct{}
|
||||
|
||||
// name implements matchMaker.name.
|
||||
func (ownerMarshalerV1) name() string {
|
||||
return matcherNameOwner
|
||||
}
|
||||
|
||||
func (ownerMarshalerV1) revision() uint8 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// marshal implements matchMaker.marshal.
|
||||
func (ownerMarshalerV1) marshal(mr matcher) []byte {
|
||||
matcher := mr.(*OwnerMatcherV1)
|
||||
ownerInfo := linux.XTOwnerMatchInfo{
|
||||
UIDMin: uint32(matcher.uid),
|
||||
UIDMax: uint32(matcher.uid),
|
||||
GIDMin: uint32(matcher.gid),
|
||||
GIDMax: uint32(matcher.gid),
|
||||
}
|
||||
|
||||
// Support for UID and GID match.
|
||||
if matcher.matchUID {
|
||||
ownerInfo.Match |= linux.XT_OWNER_UID
|
||||
}
|
||||
if matcher.matchGID {
|
||||
ownerInfo.Match |= linux.XT_OWNER_GID
|
||||
}
|
||||
if matcher.invertUID {
|
||||
ownerInfo.Invert |= linux.XT_OWNER_UID
|
||||
}
|
||||
if matcher.invertGID {
|
||||
ownerInfo.Invert |= linux.XT_OWNER_GID
|
||||
}
|
||||
buf := marshal.Marshal(&ownerInfo)
|
||||
return marshalEntryMatch(matcherNameOwner, buf)
|
||||
}
|
||||
|
||||
// unmarshal implements matchMaker.unmarshal.
|
||||
func (ownerMarshalerV1) unmarshal(mapper IDMapper, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
if len(buf) < linux.SizeOfXTOwnerMatchInfo {
|
||||
return nil, fmt.Errorf("buf has insufficient size for owner match: %d", len(buf))
|
||||
}
|
||||
|
||||
// For alignment reasons, the match's total size may
|
||||
// exceed what's strictly necessary to hold matchData.
|
||||
var matchData linux.XTOwnerMatchInfo
|
||||
matchData.UnmarshalUnsafe(buf)
|
||||
nflog("parsed XTOwnerMatchInfo: %+v", matchData)
|
||||
|
||||
if matchData.UIDMin != matchData.UIDMax {
|
||||
nflog("owner v1 doesn't support differing UID min/max")
|
||||
}
|
||||
if matchData.GIDMin != matchData.GIDMax {
|
||||
nflog("owner v1 doesn't support differing GID min/max")
|
||||
}
|
||||
owner := OwnerMatcherV1{
|
||||
uid: mapper.MapToKUID(auth.UID(matchData.UIDMin)),
|
||||
gid: mapper.MapToKGID(auth.GID(matchData.GIDMin)),
|
||||
matchUID: matchData.Match&linux.XT_OWNER_UID != 0,
|
||||
matchGID: matchData.Match&linux.XT_OWNER_GID != 0,
|
||||
invertUID: matchData.Invert&linux.XT_OWNER_UID != 0,
|
||||
invertGID: matchData.Invert&linux.XT_OWNER_GID != 0,
|
||||
}
|
||||
return &owner, nil
|
||||
}
|
||||
|
||||
// OwnerMatcherV1 matches against a UID and/or GID.
|
||||
type OwnerMatcherV1 struct {
|
||||
uid auth.KUID
|
||||
gid auth.KGID
|
||||
matchUID bool
|
||||
matchGID bool
|
||||
invertUID bool
|
||||
invertGID bool
|
||||
}
|
||||
|
||||
// name implements matcher.name.
|
||||
func (*OwnerMatcherV1) name() string {
|
||||
return matcherNameOwner
|
||||
}
|
||||
|
||||
func (*OwnerMatcherV1) revision() uint8 {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Match implements Matcher.Match.
|
||||
func (om *OwnerMatcherV1) Match(hook stack.Hook, pkt stack.PacketBufferPtr, _, _ string) (bool, bool) {
|
||||
// Support only for OUTPUT chain.
|
||||
if hook != stack.Output {
|
||||
return false, true
|
||||
}
|
||||
|
||||
// If the packet owner is not set, drop the packet.
|
||||
if pkt.Owner == nil {
|
||||
return false, true
|
||||
}
|
||||
|
||||
var matches bool
|
||||
// Check for UID match.
|
||||
if om.matchUID {
|
||||
if auth.KUID(pkt.Owner.KUID()) == om.uid {
|
||||
matches = true
|
||||
}
|
||||
if matches == om.invertUID {
|
||||
return false, false
|
||||
}
|
||||
}
|
||||
|
||||
// Check for GID match.
|
||||
if om.matchGID {
|
||||
matches = false
|
||||
if auth.KGID(pkt.Owner.KGID()) == om.gid {
|
||||
matches = true
|
||||
}
|
||||
if matches == om.invertGID {
|
||||
return false, false
|
||||
}
|
||||
}
|
||||
|
||||
return true, false
|
||||
}
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
@@ -38,6 +37,10 @@ func (tcpMarshaler) name() string {
|
||||
return matcherNameTCP
|
||||
}
|
||||
|
||||
func (tcpMarshaler) revision() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// marshal implements matchMaker.marshal.
|
||||
func (tcpMarshaler) marshal(mr matcher) []byte {
|
||||
matcher := mr.(*TCPMatcher)
|
||||
@@ -51,7 +54,7 @@ func (tcpMarshaler) marshal(mr matcher) []byte {
|
||||
}
|
||||
|
||||
// unmarshal implements matchMaker.unmarshal.
|
||||
func (tcpMarshaler) unmarshal(_ *kernel.Task, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
func (tcpMarshaler) unmarshal(_ IDMapper, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
if len(buf) < linux.SizeOfXTTCP {
|
||||
return nil, fmt.Errorf("buf has insufficient size for TCP match: %d", len(buf))
|
||||
}
|
||||
@@ -94,6 +97,10 @@ func (*TCPMatcher) name() string {
|
||||
return matcherNameTCP
|
||||
}
|
||||
|
||||
func (*TCPMatcher) revision() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Match implements Matcher.Match.
|
||||
func (tm *TCPMatcher) Match(hook stack.Hook, pkt stack.PacketBufferPtr, _, _ string) (bool, bool) {
|
||||
switch pkt.NetworkProtocolNumber {
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/marshal"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
)
|
||||
@@ -38,6 +37,10 @@ func (udpMarshaler) name() string {
|
||||
return matcherNameUDP
|
||||
}
|
||||
|
||||
func (udpMarshaler) revision() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// marshal implements matchMaker.marshal.
|
||||
func (udpMarshaler) marshal(mr matcher) []byte {
|
||||
matcher := mr.(*UDPMatcher)
|
||||
@@ -51,7 +54,7 @@ func (udpMarshaler) marshal(mr matcher) []byte {
|
||||
}
|
||||
|
||||
// unmarshal implements matchMaker.unmarshal.
|
||||
func (udpMarshaler) unmarshal(_ *kernel.Task, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
func (udpMarshaler) unmarshal(_ IDMapper, buf []byte, filter stack.IPHeaderFilter) (stack.Matcher, error) {
|
||||
if len(buf) < linux.SizeOfXTUDP {
|
||||
return nil, fmt.Errorf("buf has insufficient size for UDP match: %d", len(buf))
|
||||
}
|
||||
@@ -91,6 +94,10 @@ func (*UDPMatcher) name() string {
|
||||
return matcherNameUDP
|
||||
}
|
||||
|
||||
func (*UDPMatcher) revision() uint8 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Match implements Matcher.Match.
|
||||
func (um *UDPMatcher) Match(hook stack.Hook, pkt stack.PacketBufferPtr, _, _ string) (bool, bool) {
|
||||
switch pkt.NetworkProtocolNumber {
|
||||
|
||||
@@ -2311,7 +2311,7 @@ func setSockOptIPv6(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int
|
||||
return syserr.ErrNoDevice
|
||||
}
|
||||
// Stack must be a netstack stack.
|
||||
return netfilter.SetEntries(t, stk.(*Stack).Stack, optVal, true)
|
||||
return netfilter.SetEntries(t.Credentials().UserNamespace, stk.(*Stack).Stack, optVal, true)
|
||||
|
||||
case linux.IP6T_SO_SET_ADD_COUNTERS:
|
||||
log.Infof("IP6T_SO_SET_ADD_COUNTERS is not supported")
|
||||
@@ -2558,7 +2558,7 @@ func setSockOptIP(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int,
|
||||
return syserr.ErrNoDevice
|
||||
}
|
||||
// Stack must be a netstack stack.
|
||||
return netfilter.SetEntries(t, stk.(*Stack).Stack, optVal, false)
|
||||
return netfilter.SetEntries(t.Credentials().UserNamespace, stk.(*Stack).Stack, optVal, false)
|
||||
|
||||
case linux.IPT_SO_SET_ADD_COUNTERS:
|
||||
log.Infof("IPT_SO_SET_ADD_COUNTERS is not supported")
|
||||
|
||||
Reference in New Issue
Block a user