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 }