summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKevin Krakauer <krakauer@google.com>2020-01-08 20:05:02 -0800
committerKevin Krakauer <krakauer@google.com>2020-01-08 20:05:02 -0800
commit06e2366e964e41ade24a699b6fd650512270b975 (patch)
tree7a8a1f9427caedb725ae6804c7c69cb9d606c519
parent0999ae8b34d83a4b2ea8342d0459c8131c35d6e1 (diff)
parentae060a63d9ad1bfb65b84a2ccbaf2893c5a50b76 (diff)
Merge branch 'iptables-write' into iptables-write-input-drop
-rw-r--r--pkg/abi/linux/netfilter.go15
-rw-r--r--pkg/sentry/socket/netfilter/netfilter.go99
-rw-r--r--pkg/sentry/socket/netstack/netstack.go5
-rw-r--r--pkg/tcpip/iptables/iptables.go6
-rw-r--r--pkg/tcpip/iptables/targets.go15
5 files changed, 68 insertions, 72 deletions
diff --git a/pkg/abi/linux/netfilter.go b/pkg/abi/linux/netfilter.go
index 35d66d622..33fcc6c95 100644
--- a/pkg/abi/linux/netfilter.go
+++ b/pkg/abi/linux/netfilter.go
@@ -298,6 +298,7 @@ type IPTReplace struct {
// Entries [0]IPTEntry
}
+// KernelIPTReplace is identical to IPTReplace, but includes the Entries field.
type KernelIPTReplace struct {
IPTReplace
Entries [0]IPTEntry
@@ -306,28 +307,32 @@ type KernelIPTReplace struct {
// SizeOfIPTReplace is the size of an IPTReplace.
const SizeOfIPTReplace = 96
+// ExtensionName holds the name of a netfilter extension.
type ExtensionName [XT_EXTENSION_MAXNAMELEN]byte
// String implements fmt.Stringer.
func (en ExtensionName) String() string {
- return name(en[:])
+ return goString(en[:])
}
+// TableName holds the name of a netfilter table.
type TableName [XT_TABLE_MAXNAMELEN]byte
// String implements fmt.Stringer.
func (tn TableName) String() string {
- return name(tn[:])
+ return goString(tn[:])
}
+// ErrorName holds the name of a netfilter error. These can also hold
+// user-defined chains.
type ErrorName [XT_FUNCTION_MAXNAMELEN]byte
// String implements fmt.Stringer.
-func (fn ErrorName) String() string {
- return name(fn[:])
+func (en ErrorName) String() string {
+ return goString(en[:])
}
-func name(cstring []byte) string {
+func goString(cstring []byte) string {
for i, c := range cstring {
if c == 0 {
return string(cstring[:i])
diff --git a/pkg/sentry/socket/netfilter/netfilter.go b/pkg/sentry/socket/netfilter/netfilter.go
index 3a857ef6d..2fc7aeea3 100644
--- a/pkg/sentry/socket/netfilter/netfilter.go
+++ b/pkg/sentry/socket/netfilter/netfilter.go
@@ -52,7 +52,7 @@ func GetInfo(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr) (linux.IPT
}
// Find the appropriate table.
- table, err := findTable(stack, info.Name.String())
+ table, err := findTable(ep, info.Name)
if err != nil {
return linux.IPTGetinfo{}, err
}
@@ -83,7 +83,7 @@ func GetEntries(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr, outLen
}
// Find the appropriate table.
- table, err := findTable(stack, userEntries.Name.String())
+ table, err := findTable(ep, userEntries.Name)
if err != nil {
return linux.KernelIPTGetEntries{}, err
}
@@ -95,15 +95,19 @@ func GetEntries(t *kernel.Task, stack *stack.Stack, outPtr usermem.Addr, outLen
return linux.KernelIPTGetEntries{}, err
}
if binary.Size(entries) > uintptr(outLen) {
- log.Infof("Insufficient GetEntries output size: %d", uintptr(outLen))
+ log.Warningf("Insufficient GetEntries output size: %d", uintptr(outLen))
return linux.KernelIPTGetEntries{}, syserr.ErrInvalidArgument
}
return entries, nil
}
-func findTable(stack *stack.Stack, tableName string) (iptables.Table, *syserr.Error) {
- table, ok := stack.IPTables().Tables[tableName]
+func findTable(ep tcpip.Endpoint, tablename linux.TableName) (iptables.Table, *syserr.Error) {
+ ipt, err := ep.IPTables()
+ if err != nil {
+ return iptables.Table{}, syserr.FromError(err)
+ }
+ table, ok := ipt.Tables[tablename.String()]
if !ok {
return iptables.Table{}, syserr.ErrInvalidArgument
}
@@ -133,17 +137,17 @@ func FillDefaultIPTables(stack *stack.Stack) {
// format expected by the iptables tool. Linux stores each table as a binary
// blob that can only be traversed by parsing a bit, reading some offsets,
// jumping to those offsets, parsing again, etc.
-func convertNetstackToBinary(name string, table iptables.Table) (linux.KernelIPTGetEntries, metadata, *syserr.Error) {
+func convertNetstackToBinary(tablename string, table iptables.Table) (linux.KernelIPTGetEntries, metadata, *syserr.Error) {
// Return values.
var entries linux.KernelIPTGetEntries
var meta metadata
// The table name has to fit in the struct.
- if linux.XT_TABLE_MAXNAMELEN < len(name) {
- log.Infof("Table name too long.")
+ if linux.XT_TABLE_MAXNAMELEN < len(tablename) {
+ log.Warningf("Table name %q too long.", tablename)
return linux.KernelIPTGetEntries{}, metadata{}, syserr.ErrInvalidArgument
}
- copy(entries.Name[:], name)
+ copy(entries.Name[:], tablename)
for ruleIdx, rule := range table.Rules {
// Is this a chain entry point?
@@ -205,8 +209,8 @@ func marshalTarget(target iptables.Target) []byte {
return marshalStandardTarget(iptables.Accept)
case iptables.UnconditionalDropTarget:
return marshalStandardTarget(iptables.Drop)
- case iptables.PanicTarget:
- return marshalPanicTarget()
+ case iptables.ErrorTarget:
+ return marshalErrorTarget()
default:
panic(fmt.Errorf("unknown target of type %T", target))
}
@@ -225,7 +229,7 @@ func marshalStandardTarget(verdict iptables.Verdict) []byte {
return binary.Marshal(ret, usermem.ByteOrder, target)
}
-func marshalPanicTarget() []byte {
+func marshalErrorTarget() []byte {
// This is an error target named error
target := linux.XTErrorTarget{
Target: linux.XTEntryTarget{
@@ -268,11 +272,12 @@ func translateToStandardVerdict(val int32) (iptables.Verdict, *syserr.Error) {
case -linux.NF_DROP - 1:
return iptables.Drop, nil
case -linux.NF_QUEUE - 1:
- log.Infof("Unsupported iptables verdict QUEUE.")
+ log.Warningf("Unsupported iptables verdict QUEUE.")
case linux.NF_RETURN:
- log.Infof("Unsupported iptables verdict RETURN.")
+ log.Warningf("Unsupported iptables verdict RETURN.")
+ default:
+ log.Warningf("Unknown iptables verdict %d.", val)
}
- log.Infof("Unknown iptables verdict %d.", val)
return iptables.Invalid, syserr.ErrInvalidArgument
}
@@ -283,7 +288,7 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
// Get the basic rules data (struct ipt_replace).
if len(optVal) < linux.SizeOfIPTReplace {
- log.Infof("netfilter.SetEntries: optVal has insufficient size for replace %d", len(optVal))
+ log.Warningf("netfilter.SetEntries: optVal has insufficient size for replace %d", len(optVal))
return syserr.ErrInvalidArgument
}
var replace linux.IPTReplace
@@ -297,7 +302,7 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
case iptables.TablenameFilter:
table = iptables.EmptyFilterTable()
default:
- log.Infof(fmt.Sprintf("We don't yet support writing to the %q table (gvisor.dev/issue/170)", replace.Name.String()))
+ log.Warningf("We don't yet support writing to the %q table (gvisor.dev/issue/170)", replace.Name.String())
return syserr.ErrInvalidArgument
}
@@ -307,7 +312,7 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
for entryIdx := uint32(0); entryIdx < replace.NumEntries; entryIdx++ {
// Get the struct ipt_entry.
if len(optVal) < linux.SizeOfIPTEntry {
- log.Infof("netfilter: optVal has insufficient size for entry %d", len(optVal))
+ log.Warningf("netfilter: optVal has insufficient size for entry %d", len(optVal))
return syserr.ErrInvalidArgument
}
var entry linux.IPTEntry
@@ -323,7 +328,7 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
// filtering. We reject any nonzero IPTIP values for now.
emptyIPTIP := linux.IPTIP{}
if entry.IP != emptyIPTIP {
- log.Infof("netfilter: non-empty struct iptip found")
+ log.Warningf("netfilter: non-empty struct iptip found")
return syserr.ErrInvalidArgument
}
@@ -353,11 +358,11 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
}
}
if ruleIdx := table.BuiltinChains[hk]; ruleIdx == iptables.HookUnset {
- log.Infof("Hook %v is unset.", hk)
+ log.Warningf("Hook %v is unset.", hk)
return syserr.ErrInvalidArgument
}
if ruleIdx := table.Underflows[hk]; ruleIdx == iptables.HookUnset {
- log.Infof("Underflow %v is unset.", hk)
+ log.Warningf("Underflow %v is unset.", hk)
return syserr.ErrInvalidArgument
}
}
@@ -384,7 +389,7 @@ func SetEntries(stack *stack.Stack, optVal []byte) *syserr.Error {
// along with the number of bytes it occupies in optVal.
func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
if len(optVal) < linux.SizeOfXTEntryTarget {
- log.Infof("netfilter: optVal has insufficient size for entry target %d", len(optVal))
+ log.Warningf("netfilter: optVal has insufficient size for entry target %d", len(optVal))
return nil, 0, syserr.ErrInvalidArgument
}
var target linux.XTEntryTarget
@@ -394,14 +399,14 @@ func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
case "":
// Standard target.
if len(optVal) < linux.SizeOfXTStandardTarget {
- log.Infof("netfilter.SetEntries: optVal has insufficient size for standard target %d", len(optVal))
+ log.Warningf("netfilter.SetEntries: optVal has insufficient size for standard target %d", len(optVal))
return nil, 0, syserr.ErrInvalidArgument
}
- var target linux.XTStandardTarget
+ var standardTarget linux.XTStandardTarget
buf = optVal[:linux.SizeOfXTStandardTarget]
- binary.Unmarshal(buf, usermem.ByteOrder, &target)
+ binary.Unmarshal(buf, usermem.ByteOrder, &standardTarget)
- verdict, err := translateToStandardVerdict(target.Verdict)
+ verdict, err := translateToStandardVerdict(standardTarget.Verdict)
if err != nil {
return nil, 0, err
}
@@ -420,9 +425,9 @@ func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
log.Infof("netfilter.SetEntries: optVal has insufficient size for error target %d", len(optVal))
return nil, 0, syserr.ErrInvalidArgument
}
- var target linux.XTErrorTarget
+ var errorTarget linux.XTErrorTarget
buf = optVal[:linux.SizeOfXTErrorTarget]
- binary.Unmarshal(buf, usermem.ByteOrder, &target)
+ binary.Unmarshal(buf, usermem.ByteOrder, &errorTarget)
// Error targets are used in 2 cases:
// * An actual error case. These rules have an error
@@ -431,11 +436,11 @@ func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
// somehow fall through every rule.
// * To mark the start of a user defined chain. These
// rules have an error with the name of the chain.
- switch target.Name.String() {
+ switch errorTarget.Name.String() {
case errorTargetName:
- return iptables.PanicTarget{}, linux.SizeOfXTErrorTarget, nil
+ return iptables.ErrorTarget{}, linux.SizeOfXTErrorTarget, nil
default:
- log.Infof("Unknown error target %q doesn't exist or isn't supported yet.", target.Name.String())
+ log.Infof("Unknown error target %q doesn't exist or isn't supported yet.", errorTarget.Name.String())
return nil, 0, syserr.ErrInvalidArgument
}
}
@@ -445,22 +450,6 @@ func parseTarget(optVal []byte) (iptables.Target, uint32, *syserr.Error) {
return nil, 0, syserr.ErrInvalidArgument
}
-func chainNameFromHook(hook int) string {
- switch hook {
- case linux.NF_INET_PRE_ROUTING:
- return iptables.ChainNamePrerouting
- case linux.NF_INET_LOCAL_IN:
- return iptables.ChainNameInput
- case linux.NF_INET_FORWARD:
- return iptables.ChainNameForward
- case linux.NF_INET_LOCAL_OUT:
- return iptables.ChainNameOutput
- case linux.NF_INET_POST_ROUTING:
- return iptables.ChainNamePostrouting
- }
- panic(fmt.Sprintf("Unknown hook %d does not correspond to a builtin chain"))
-}
-
func hookFromLinux(hook int) iptables.Hook {
switch hook {
case linux.NF_INET_PRE_ROUTING:
@@ -485,7 +474,7 @@ func printReplace(optVal []byte) {
replaceBuf := optVal[:linux.SizeOfIPTReplace]
optVal = optVal[linux.SizeOfIPTReplace:]
binary.Unmarshal(replaceBuf, usermem.ByteOrder, &replace)
- log.Infof("kevin: Replacing table %q: %+v", replace.Name.String(), replace)
+ log.Infof("Replacing table %q: %+v", replace.Name.String(), replace)
// Read in the list of entries at the end of replace.
var totalOffset uint16
@@ -493,33 +482,33 @@ func printReplace(optVal []byte) {
var entry linux.IPTEntry
entryBuf := optVal[:linux.SizeOfIPTEntry]
binary.Unmarshal(entryBuf, usermem.ByteOrder, &entry)
- log.Infof("kevin: Entry %d (total offset %d): %+v", entryIdx, totalOffset, entry)
+ log.Infof("Entry %d (total offset %d): %+v", entryIdx, totalOffset, entry)
totalOffset += entry.NextOffset
if entry.TargetOffset == linux.SizeOfIPTEntry {
- log.Infof("kevin: Entry has no matches.")
+ log.Infof("Entry has no matches.")
} else {
- log.Infof("kevin: Entry has matches.")
+ log.Infof("Entry has matches.")
}
var target linux.XTEntryTarget
targetBuf := optVal[entry.TargetOffset : entry.TargetOffset+linux.SizeOfXTEntryTarget]
binary.Unmarshal(targetBuf, usermem.ByteOrder, &target)
- log.Infof("kevin: Target named %q: %+v", target.Name.String(), target)
+ log.Infof("Target named %q: %+v", target.Name.String(), target)
switch target.Name.String() {
case "":
var standardTarget linux.XTStandardTarget
stBuf := optVal[entry.TargetOffset : entry.TargetOffset+linux.SizeOfXTStandardTarget]
binary.Unmarshal(stBuf, usermem.ByteOrder, &standardTarget)
- log.Infof("kevin: Standard target with verdict %q (%d).", linux.VerdictStrings[standardTarget.Verdict], standardTarget.Verdict)
+ log.Infof("Standard target with verdict %q (%d).", linux.VerdictStrings[standardTarget.Verdict], standardTarget.Verdict)
case errorTargetName:
var errorTarget linux.XTErrorTarget
etBuf := optVal[entry.TargetOffset : entry.TargetOffset+linux.SizeOfXTErrorTarget]
binary.Unmarshal(etBuf, usermem.ByteOrder, &errorTarget)
- log.Infof("kevin: Error target with name %q.", errorTarget.Name.String())
+ log.Infof("Error target with name %q.", errorTarget.Name.String())
default:
- log.Infof("kevin: Unknown target type.")
+ log.Infof("Unknown target type.")
}
optVal = optVal[entry.NextOffset:]
diff --git a/pkg/sentry/socket/netstack/netstack.go b/pkg/sentry/socket/netstack/netstack.go
index 86a8104df..85d5b7424 100644
--- a/pkg/sentry/socket/netstack/netstack.go
+++ b/pkg/sentry/socket/netstack/netstack.go
@@ -1376,10 +1376,7 @@ func (s *SocketOperations) SetSockOpt(t *kernel.Task, level int, name int, optVa
return syserr.ErrNoDevice
}
// Stack must be a netstack stack.
- if err := netfilter.SetEntries(stack.(*Stack).Stack, optVal); err != nil {
- return err
- }
- return nil
+ return netfilter.SetEntries(stack.(*Stack).Stack, optVal)
case linux.IPT_SO_SET_ADD_COUNTERS:
// TODO(gvisor.dev/issue/170): Counter support.
diff --git a/pkg/tcpip/iptables/iptables.go b/pkg/tcpip/iptables/iptables.go
index aff8a680b..91abbbea8 100644
--- a/pkg/tcpip/iptables/iptables.go
+++ b/pkg/tcpip/iptables/iptables.go
@@ -52,7 +52,7 @@ func DefaultTables() IPTables {
Rule{Target: UnconditionalAcceptTarget{}},
Rule{Target: UnconditionalAcceptTarget{}},
Rule{Target: UnconditionalAcceptTarget{}},
- Rule{Target: PanicTarget{}},
+ Rule{Target: ErrorTarget{}},
},
BuiltinChains: map[Hook]int{
Prerouting: 0,
@@ -72,7 +72,7 @@ func DefaultTables() IPTables {
Rules: []Rule{
Rule{Target: UnconditionalAcceptTarget{}},
Rule{Target: UnconditionalAcceptTarget{}},
- Rule{Target: PanicTarget{}},
+ Rule{Target: ErrorTarget{}},
},
BuiltinChains: map[Hook]int{
Prerouting: 0,
@@ -89,7 +89,7 @@ func DefaultTables() IPTables {
Rule{Target: UnconditionalAcceptTarget{}},
Rule{Target: UnconditionalAcceptTarget{}},
Rule{Target: UnconditionalAcceptTarget{}},
- Rule{Target: PanicTarget{}},
+ Rule{Target: ErrorTarget{}},
},
BuiltinChains: map[Hook]int{
Input: 0,
diff --git a/pkg/tcpip/iptables/targets.go b/pkg/tcpip/iptables/targets.go
index cb3ac1aff..8180dcefd 100644
--- a/pkg/tcpip/iptables/targets.go
+++ b/pkg/tcpip/iptables/targets.go
@@ -16,7 +16,10 @@
package iptables
-import "gvisor.dev/gvisor/pkg/tcpip"
+import (
+ "gvisor.dev/gvisor/pkg/log"
+ "gvisor.dev/gvisor/pkg/tcpip"
+)
// UnconditionalAcceptTarget accepts all packets.
type UnconditionalAcceptTarget struct{}
@@ -34,10 +37,12 @@ func (UnconditionalDropTarget) Action(packet tcpip.PacketBuffer) (Verdict, strin
return Drop, ""
}
-// PanicTarget just panics. It represents a target that should be unreachable.
-type PanicTarget struct{}
+// ErrorTarget logs an error and drops the packet. It represents a target that
+// should be unreachable.
+type ErrorTarget struct{}
// Actions implements Target.Action.
-func (PanicTarget) Action(packet tcpip.PacketBuffer) (Verdict, string) {
- panic("PanicTarget triggered.")
+func (ErrorTarget) Action(packet tcpip.PacketBuffer) (Verdict, string) {
+ log.Warningf("ErrorTarget triggered.")
+ return Drop, ""
}