github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/sys/linux/init_iptables.go (about)

     1  // Copyright 2018 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package linux
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/google/syzkaller/prog"
    10  )
    11  
    12  func (arch *arch) generateIptables(g *prog.Gen, typ prog.Type, dir prog.Dir, old prog.Arg) (
    13  	arg prog.Arg, calls []*prog.Call) {
    14  	return arch.generateNetfilterTable(g, typ, dir, old, true, 5)
    15  }
    16  
    17  func (arch *arch) generateArptables(g *prog.Gen, typ prog.Type, dir prog.Dir, old prog.Arg) (
    18  	arg prog.Arg, calls []*prog.Call) {
    19  	return arch.generateNetfilterTable(g, typ, dir, old, false, 3)
    20  }
    21  
    22  func (arch *arch) generateNetfilterTable(g *prog.Gen, typ prog.Type, dir prog.Dir, old prog.Arg,
    23  	hasUnion bool, hookCount int) (arg prog.Arg, calls []*prog.Call) {
    24  	const (
    25  		hookStart     = 4
    26  		nonHookFields = 7
    27  		unused        = uint64(^uint32(0))
    28  	)
    29  	if old == nil {
    30  		arg = g.GenerateSpecialArg(typ, dir, &calls)
    31  	} else {
    32  		// TODO(dvyukov): try to restore original hook order after mutation
    33  		// instead of assigning brand new offsets.
    34  		arg = prog.CloneArg(old)
    35  		calls = g.MutateArg(arg)
    36  	}
    37  	var tableArg *prog.GroupArg
    38  	if hasUnion {
    39  		tableArg = arg.(*prog.UnionArg).Option.(*prog.GroupArg)
    40  	} else {
    41  		tableArg = arg.(*prog.GroupArg)
    42  	}
    43  	numFileds := nonHookFields + 2*hookCount
    44  	if len(tableArg.Inner) != numFileds {
    45  		panic("wrong number of fields in netfilter table")
    46  	}
    47  	entriesArg := tableArg.Inner[numFileds-1].(*prog.GroupArg)
    48  	if len(entriesArg.Inner) != 2 {
    49  		panic("netfilter entries is expected to have 2 fields")
    50  	}
    51  	entriesArray := entriesArg.Inner[0].(*prog.GroupArg)
    52  	// Collect offsets of entries.
    53  	offsets := make([]uint64, len(entriesArray.Inner))
    54  	var pos uint64
    55  	for i, entryArg := range entriesArray.Inner {
    56  		offsets[i] = pos
    57  		pos += entryArg.Size()
    58  	}
    59  	if pos != entriesArray.Size() {
    60  		panic("netfilter offsets are broken")
    61  	}
    62  	genOffset := func() uint64 {
    63  		if g.Rand().Intn(100) == 0 {
    64  			// Assign the underflow entry once in a while.
    65  			// We have it in underflow hooks, so no point in using it frequently.
    66  			return pos
    67  		}
    68  		return offsets[g.Rand().Intn(len(offsets))]
    69  	}
    70  	// Assign offsets to used hooks.
    71  	for hook := hookStart; hook < hookStart+hookCount; hook++ {
    72  		hookArg := tableArg.Inner[hook].(*prog.ConstArg)
    73  		if hookArg.Type().(*prog.ConstType).Val == unused {
    74  			continue // unused hook
    75  		}
    76  		hookArg.Val = genOffset()
    77  	}
    78  	// Assign offsets to used underflow entries.
    79  	for hook := hookStart + hookCount; hook < hookStart+2*hookCount; hook++ {
    80  		hookArg := tableArg.Inner[hook].(*prog.ConstArg)
    81  		if hookArg.Type().(*prog.ConstType).Val == unused {
    82  			continue // unused hook
    83  		}
    84  		hookArg.Val = pos
    85  	}
    86  	// Now update standard target jump offsets.
    87  	prog.ForeachSubArg(arg, func(arg prog.Arg, _ *prog.ArgCtx) {
    88  		if !strings.HasPrefix(arg.Type().Name(), `xt_target_t["", `) {
    89  			return
    90  		}
    91  		targetArg := arg.(*prog.GroupArg)
    92  		valArg := targetArg.Inner[3].(*prog.ConstArg)
    93  		flagsType, ok := valArg.Type().(*prog.FlagsType)
    94  		if !ok {
    95  			return
    96  		}
    97  		if int64(valArg.Val) < 0 {
    98  			for _, val := range flagsType.Vals {
    99  				if val == valArg.Val {
   100  					return // verdict
   101  				}
   102  			}
   103  		}
   104  		valArg.Val = genOffset()
   105  	})
   106  	return
   107  }
   108  
   109  func (arch *arch) generateEbtables(g *prog.Gen, typ prog.Type, dir prog.Dir, old prog.Arg) (
   110  	arg prog.Arg, calls []*prog.Call) {
   111  	if old == nil {
   112  		arg = g.GenerateSpecialArg(typ, dir, &calls)
   113  	} else {
   114  		// TODO(dvyukov): try to restore original hook order after mutation
   115  		// instead of assigning brand new offsets.
   116  		arg = prog.CloneArg(old)
   117  		calls = g.MutateArg(arg)
   118  	}
   119  	if g.Target().ArgContainsAny(arg) {
   120  		return
   121  	}
   122  	hooksField, entriesField := 4, 7
   123  	if g.Target().PtrSize == 8 {
   124  		// Account for paddings.
   125  		hooksField, entriesField = 5, 9
   126  	}
   127  	tableArg := arg.(*prog.UnionArg).Option.(*prog.GroupArg)
   128  	entriesPtr := tableArg.Inner[entriesField].(*prog.PointerArg)
   129  	if entriesPtr.Res == nil {
   130  		return
   131  	}
   132  	entriesArray := entriesPtr.Res.(*prog.GroupArg)
   133  	offsets := make([]uint64, len(entriesArray.Inner))
   134  	var pos, totalEntries uint64
   135  	for i, entriesArg0 := range entriesArray.Inner {
   136  		entriesArg := entriesArg0.(*prog.GroupArg)
   137  		arrayArg := entriesArg.Inner[len(entriesArg.Inner)-1].(*prog.GroupArg)
   138  		entriesArg.Inner[2].(*prog.ConstArg).Val = totalEntries
   139  		totalEntries += uint64(len(arrayArg.Inner))
   140  		offsets[i] = pos
   141  		pos += entriesArg.Size()
   142  	}
   143  	tableArg.Inner[2].(*prog.ConstArg).Val = totalEntries
   144  	if pos != entriesArray.Size() {
   145  		panic("netfilter offsets are broken")
   146  	}
   147  	// Assign offsets to used hooks.
   148  	validHooks := tableArg.Inner[1].(*prog.ConstArg).Val
   149  	hooksArg := tableArg.Inner[hooksField].(*prog.GroupArg)
   150  	for i, hookArg0 := range hooksArg.Inner {
   151  		hookArg := hookArg0.(*prog.ConstArg)
   152  		if validHooks&(1<<uint(i)) == 0 {
   153  			hookArg.Val = 0
   154  			continue
   155  		}
   156  		addr := g.Target().PhysicalAddr(entriesPtr)
   157  		if len(offsets) != 0 {
   158  			addr += offsets[0]
   159  			offsets = offsets[1:]
   160  		}
   161  		hookArg.Val = addr
   162  	}
   163  	// TODO(dvyukov): assign jump targets for targets.
   164  	return
   165  }
   166  
   167  func (arch *arch) neutralizeEbtables(c *prog.Call) {
   168  	// This is very hacky... just as netfilter interfaces.
   169  	// setsockopt's len argument must be equal to size of ebt_replace + entries size.
   170  	lenArg := c.Args[4].(*prog.ConstArg)
   171  	tablePtr := c.Args[3].(*prog.PointerArg).Res
   172  	if tablePtr == nil {
   173  		return
   174  	}
   175  	tableArg := tablePtr.(*prog.UnionArg).Option.(*prog.GroupArg)
   176  	entriesField := len(tableArg.Inner) - 1
   177  	entriesArg := tableArg.Inner[entriesField].(*prog.PointerArg).Res
   178  	if entriesArg == nil {
   179  		return
   180  	}
   181  	lenArg.Val = tableArg.Size() + entriesArg.Size()
   182  }