Skip to content

Commit d7830d9

Browse files
kerumetogvisor-bot
authored andcommitted
Implement functionality for Nftables GetChain message.
Implemented GetChain message for both regular and base chains. Retrieving information on netdev family chains are still not supported, as well as inet base chains that are hooked onto Ingress and Egress hooks PiperOrigin-RevId: 784663315
1 parent db69f00 commit d7830d9

File tree

7 files changed

+613
-42
lines changed

7 files changed

+613
-42
lines changed

pkg/sentry/socket/netlink/netfilter/protocol.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ func (p *Protocol) ProcessMessage(ctx context.Context, s *netlink.Socket, msg *n
134134
return err.GetError()
135135
}
136136
return nil
137+
case linux.NFT_MSG_GETCHAIN:
138+
nft.Mu.RLock()
139+
defer nft.Mu.RUnlock()
140+
if err := p.getChain(nft, attrs, family, hdr.Flags, ms); err != nil {
141+
log.Debugf("Nftables get chain error: %s", err)
142+
return err.GetError()
143+
}
144+
return nil
137145
default:
138146
log.Debugf("Unsupported message type: %d", msgType)
139147
return syserr.ErrNotSupported
@@ -569,6 +577,89 @@ func (p *Protocol) chainParseHook(chain *nftables.Chain, family stack.AddressFam
569577
return baseChainInfo, nil
570578
}
571579

580+
// getChain returns the chain with the given name and table name.
581+
func (p *Protocol) getChain(nft *nftables.NFTables, attrs map[uint16]nlmsg.BytesView, family stack.AddressFamily, msgFlags uint16, ms *nlmsg.MessageSet) *syserr.AnnotatedError {
582+
if (msgFlags & linux.NLM_F_DUMP) != 0 {
583+
// TODO: b/421437663 - Support dump requests for chains.
584+
return syserr.NewAnnotatedError(syserr.ErrNotSupported, fmt.Sprintf("Nftables: Chain dump is not currently supported"))
585+
}
586+
587+
tabNameBytes, ok := attrs[linux.NFTA_CHAIN_TABLE]
588+
if !ok {
589+
return syserr.NewAnnotatedError(syserr.ErrInvalidArgument, fmt.Sprintf("Nftables: NFTA_CHAIN_TABLE attribute is malformed or not found"))
590+
}
591+
592+
tabName := tabNameBytes.String()
593+
tab, err := nft.GetTable(family, tabName, uint32(ms.PortID))
594+
if err != nil {
595+
return err
596+
}
597+
598+
chainNameBytes, ok := attrs[linux.NFTA_CHAIN_NAME]
599+
if !ok {
600+
return syserr.NewAnnotatedError(syserr.ErrInvalidArgument, fmt.Sprintf("Nftables: NFTA_CHAIN_NAME attribute is malformed or not found"))
601+
}
602+
603+
chainName := chainNameBytes.String()
604+
chain, err := tab.GetChain(chainName)
605+
if err != nil {
606+
return err
607+
}
608+
609+
m := ms.AddMessage(linux.NetlinkMessageHeader{
610+
Type: uint16(linux.NFNL_SUBSYS_NFTABLES)<<8 | uint16(linux.NFT_MSG_NEWCHAIN),
611+
})
612+
613+
m.Put(&linux.NetFilterGenMsg{
614+
Family: uint8(family),
615+
Version: uint8(linux.NFNETLINK_V0),
616+
// Unused, set to 0.
617+
ResourceID: uint16(0),
618+
})
619+
m.PutAttrString(linux.NFTA_CHAIN_TABLE, tabName)
620+
m.PutAttrString(linux.NFTA_CHAIN_NAME, chainName)
621+
m.PutAttr(linux.NFTA_CHAIN_HANDLE, primitive.AllocateUint64(chain.GetHandle()))
622+
623+
if chain.IsBaseChain() {
624+
err := getBaseChainHookInfo(chain, family, m)
625+
if err != nil {
626+
return err
627+
}
628+
629+
baseChainInfo := chain.GetBaseChainInfo()
630+
m.PutAttr(linux.NFTA_CHAIN_POLICY, primitive.AllocateUint32(uint32(baseChainInfo.PolicyBoolToValue())))
631+
m.PutAttrString(linux.NFTA_CHAIN_TYPE, baseChainInfo.BcType.String())
632+
}
633+
634+
chainFlags := chain.GetFlags()
635+
if chainFlags != 0 {
636+
m.PutAttr(linux.NFTA_CHAIN_FLAGS, primitive.AllocateUint32(uint32(chainFlags)))
637+
}
638+
639+
m.PutAttr(linux.NFTA_CHAIN_USE, primitive.AllocateUint32(uint32(chain.GetChainUse())))
640+
if chain.HasUserData() {
641+
m.PutAttr(linux.NFTA_CHAIN_USERDATA, primitive.AsByteSlice(chain.GetUserData()))
642+
}
643+
644+
return nil
645+
}
646+
647+
// getBaseChainHookInfo creates a NFTA_CHAIN_HOOK attribute with all the corresponding nested attributes.
648+
func getBaseChainHookInfo(chain *nftables.Chain, family stack.AddressFamily, m *nlmsg.Message) *syserr.AnnotatedError {
649+
baseChainInfo := chain.GetBaseChainInfo()
650+
var nestedAttrs nlmsg.NestedAttr
651+
652+
nestedAttrs.PutAttr(linux.NFTA_HOOK_HOOKNUM, primitive.AllocateUint32(baseChainInfo.LinuxHookNum))
653+
nestedAttrs.PutAttr(linux.NFTA_HOOK_PRIORITY, primitive.AllocateUint32(uint32(baseChainInfo.Priority.GetValue())))
654+
655+
if isNetDevHook(family, baseChainInfo.LinuxHookNum) {
656+
return syserr.NewAnnotatedError(syserr.ErrNotSupported, fmt.Sprintf("Nftables: Netdev basechains or basechains attached to Ingress or Egress are not currently supported for getting"))
657+
}
658+
659+
m.PutNestedAttr(linux.NFTA_CHAIN_HOOK, nestedAttrs)
660+
return nil
661+
}
662+
572663
// isNetDevHook returns whether the given family and hook number represent a netdev hook, or if
573664
// the family is inet and is attempting to attach to Ingress or Egress hooks.
574665
func isNetDevHook(family stack.AddressFamily, hookNum uint32) bool {

pkg/sentry/socket/netlink/nlmsg/message.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,30 @@ func (m *Message) PutAttrString(atype uint16, s string) {
191191
m.putZeros(aligned - l)
192192
}
193193

194+
// PutNestedAttr adds v to the message as a netlink nested attribute.
195+
func (m *Message) PutNestedAttr(atype uint16, v NestedAttr) {
196+
m.PutAttr(atype, primitive.AsByteSlice(v))
197+
}
198+
199+
// NestedAttr represents a nested netlink attribute.
200+
type NestedAttr []byte
201+
202+
// PutAttr adds v to the provided NestedAttr, creating nested attributes.
203+
func (n *NestedAttr) PutAttr(atype uint16, v marshal.Marshallable) {
204+
m := Message{
205+
buf: *n,
206+
}
207+
m.PutAttr(atype, v)
208+
}
209+
210+
// PutAttrString adds s to the provided NestedAttr, creating nested attributes.
211+
func (n *NestedAttr) PutAttrString(atype uint16, s string) {
212+
m := Message{
213+
buf: *n,
214+
}
215+
m.PutAttrString(atype, s)
216+
}
217+
194218
// MessageSet contains a series of netlink messages.
195219
type MessageSet struct {
196220
// Multi indicates that this a multi-part message, to be terminated by

pkg/tcpip/nftables/nftables.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,11 @@ func (c *Chain) SetUserData(data []byte) {
767767
copy(c.userData, data)
768768
}
769769

770+
// HasUserData returns whether the chain has user data.
771+
func (c *Chain) HasUserData() bool {
772+
return c.userData != nil
773+
}
774+
770775
// IsBaseChain returns whether the chain is a base chain.
771776
func (c *Chain) IsBaseChain() bool {
772777
return c.baseChainInfo != nil
@@ -811,6 +816,11 @@ func (c *Chain) SetBaseChainInfo(info *BaseChainInfo) *syserr.AnnotatedError {
811816
return nil
812817
}
813818

819+
// GetChainUse returns the chain use value of the chain.
820+
func (c *Chain) GetChainUse() uint32 {
821+
return c.chainUse
822+
}
823+
814824
// GetComment returns the comment of the chain.
815825
func (c *Chain) GetComment() string {
816826
return c.comment

pkg/tcpip/nftables/nftables_types.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ type Chain struct {
365365
// by the kernel, but rather userspace applications like nft binary.
366366
userData []byte
367367

368+
// TODO: b/421437663 - Increment the chainUse field when a jump or goto
369+
// instruction is encountered.
370+
// From net/netfilter/nf_tables_api.c: nft_data_hold
371+
// chainUse is the number of jump references to this chain.
372+
chainUse uint32
373+
368374
// comment is the optional comment for the table.
369375
comment string
370376
}
@@ -402,6 +408,14 @@ type BaseChainInfo struct {
402408
PolicyDrop bool
403409
}
404410

411+
// PolicyBoolToValue converts the policy drop boolean to a uint8.
412+
func (bc *BaseChainInfo) PolicyBoolToValue() uint8 {
413+
if bc.PolicyDrop {
414+
return uint8(linux.NF_DROP)
415+
}
416+
return uint8(linux.NF_ACCEPT)
417+
}
418+
405419
// NewBaseChainInfo creates a new BaseChainInfo object with the given values.
406420
// The device and policyDrop parameters are optional in the nft binary and
407421
// should be set to empty string and false if not needed.

0 commit comments

Comments
 (0)