github.com/elfadel/cilium@v1.6.12/pkg/datapath/loader/template.go (about) 1 // Copyright 2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package loader 16 17 import ( 18 "fmt" 19 "reflect" 20 21 "github.com/cilium/cilium/common/addressing" 22 "github.com/cilium/cilium/pkg/bpf" 23 "github.com/cilium/cilium/pkg/byteorder" 24 "github.com/cilium/cilium/pkg/datapath" 25 "github.com/cilium/cilium/pkg/identity" 26 "github.com/cilium/cilium/pkg/mac" 27 bpfconfig "github.com/cilium/cilium/pkg/maps/configmap" 28 "github.com/cilium/cilium/pkg/maps/ctmap" 29 "github.com/cilium/cilium/pkg/maps/policymap" 30 ) 31 32 var ( 33 TemplateSecurityID = identity.ReservedIdentityWorld 34 TemplateLxcID = uint16(65535) 35 TemplateMAC = mac.MAC([]byte{0x02, 0x00, 0x60, 0x0D, 0xF0, 0x0D}) 36 TemplateIPv4 = []byte{192, 0, 2, 3} 37 TemplateIPv6 = []byte{0x20, 0x01, 0xdb, 0x8, 0x0b, 0xad, 0xca, 0xfe, 0x60, 0x0d, 0xbe, 0xe2, 0x0b, 0xad, 0xca, 0xfe} 38 39 CallsMapName = "cilium_calls_" 40 elfMapPrefixes = []string{ 41 policymap.MapName, 42 CallsMapName, 43 bpfconfig.MapNamePrefix, 44 } 45 elfCtMapPrefixes = []string{ 46 ctmap.MapNameTCP4, 47 ctmap.MapNameAny4, 48 ctmap.MapNameTCP6, 49 ctmap.MapNameAny6, 50 } 51 ) 52 53 // templateCfg wraps a real configuration from an endpoint to pass through its 54 // configuration of conditional branches in the datapath, but to mock out dummy 55 // values for static data. 56 // 57 // Note that the static data dummy values must be non-zero in every 32-bit 58 // section of the data to ensure that during compilation, the compiler reserves 59 // space in the .data section of the ELF for the value of the data, rather than 60 // generating a reference to the .bss section (which is what it will typically 61 // do if a static integer is initialized to zero). 62 // 63 // Ideally we also statically configure the values used in the template in such 64 // a way that if ever someone managed to inadvertently attach the template 65 // program directly to a device, that there are no unintended consequences such 66 // as allowing traffic to leak out with routable addresses. 67 type templateCfg struct { 68 datapath.EndpointConfiguration 69 stats *SpanStat 70 } 71 72 // GetID returns a uint64, but in practice on the datapath side it is 73 // guaranteed to be 16-bit; it is used to generate map names, so we need to 74 // ensure that the template generates map names that are as long as the longest 75 // possible name, which would be guaranteed with a 5-digit output. 76 // 77 // In practice, attempts to load an endpoint with the ID 65535 will fail which 78 // means that the calling code must approprately substitute the ID in the ELF 79 // prior to load, or it will fail with a relatively obvious error. 80 func (t *templateCfg) GetID() uint64 { 81 return uint64(TemplateLxcID) 82 } 83 84 // StringID returns the string form of the ID returned by GetID(). 85 func (t *templateCfg) StringID() string { 86 return fmt.Sprintf("%d", t.GetID()) 87 } 88 89 // GetIdentity treats the template program as part of the world, so if there's 90 // ever some weird bug that causes the template value here to be used, it will 91 // be in the least privileged security context. 92 func (t *templateCfg) GetIdentity() identity.NumericIdentity { 93 return TemplateSecurityID 94 } 95 96 // GetIdentityLocked is identical to GetIdentity(). This is a temporary 97 // function until WriteEndpointConfig() no longer assumes that the endpoint is 98 // locked. 99 func (t *templateCfg) GetIdentityLocked() identity.NumericIdentity { 100 return TemplateSecurityID 101 } 102 103 // GetNodeMAC returns a well-known dummy MAC address which may be later 104 // substituted in the ELF. 105 func (t *templateCfg) GetNodeMAC() mac.MAC { 106 return TemplateMAC 107 } 108 109 // IPv4Address always returns an IP in the documentation prefix (RFC5737) as 110 // a nonsense address that should typically not be routable. 111 func (t *templateCfg) IPv4Address() addressing.CiliumIPv4 { 112 return addressing.CiliumIPv4(TemplateIPv4) 113 } 114 115 // IPv6Address returns an IP in the documentation prefix (RFC3849) to ensure 116 // that each 32-bit segment of the address is non-zero as per the requirements 117 // described in the structure definition. This can't be guaranteed while using 118 // a more appropriate prefix such as the discard prefix (RFC6666). 119 func (t *templateCfg) IPv6Address() addressing.CiliumIPv6 { 120 return addressing.CiliumIPv6(TemplateIPv6) 121 } 122 123 // wrap takes an endpoint configuration and optional stats tracker and wraps 124 // it inside a templateCfg which hides static data from callers that wish to 125 // generate header files based on the configuration, substituting it for 126 // template data. 127 func wrap(cfg datapath.EndpointConfiguration, stats *SpanStat) *templateCfg { 128 if stats == nil { 129 stats = &SpanStat{} 130 } 131 return &templateCfg{ 132 EndpointConfiguration: cfg, 133 stats: stats, 134 } 135 } 136 137 // elfMapSubstitutions returns the set of map substitutions that must occur in 138 // an ELF template object file to update map references for the specified 139 // endpoint. 140 func elfMapSubstitutions(ep endpoint) map[string]string { 141 result := make(map[string]string) 142 143 epID := uint16(ep.GetID()) 144 for _, name := range elfMapPrefixes { 145 templateStr := bpf.LocalMapName(name, TemplateLxcID) 146 desiredStr := bpf.LocalMapName(name, epID) 147 result[templateStr] = desiredStr 148 } 149 if ep.ConntrackLocalLocked() { 150 for _, name := range elfCtMapPrefixes { 151 templateStr := bpf.LocalMapName(name, TemplateLxcID) 152 desiredStr := bpf.LocalMapName(name, epID) 153 result[templateStr] = desiredStr 154 } 155 } 156 157 result[policymap.CallString(TemplateLxcID)] = policymap.CallString(epID) 158 return result 159 } 160 161 // sliceToU16 converts the input slice of two bytes to a uint16. 162 func sliceToU16(input []byte) uint16 { 163 result := uint16(input[0]) << 8 164 result |= uint16(input[1]) 165 return result 166 } 167 168 // sliceToBe16 converts the input slice of two bytes to a big-endian uint16. 169 func sliceToBe16(input []byte) uint16 { 170 return byteorder.HostToNetwork(sliceToU16(input)).(uint16) 171 } 172 173 // sliceToU32 converts the input slice of four bytes to a uint32. 174 func sliceToU32(input []byte) uint32 { 175 result := uint32(input[0]) << 24 176 result |= uint32(input[1]) << 16 177 result |= uint32(input[2]) << 8 178 result |= uint32(input[3]) 179 return result 180 } 181 182 // sliceToBe32 converts the input slice of four bytes to a big-endian uint32. 183 func sliceToBe32(input []byte) uint32 { 184 return byteorder.HostToNetwork(sliceToU32(input)).(uint32) 185 } 186 187 // elfVariableSubstitutions returns the set of data substitutions that must 188 // occur in an ELF template object file to update static data for the specified 189 // endpoint. 190 func elfVariableSubstitutions(ep endpoint) map[string]uint32 { 191 result := make(map[string]uint32) 192 193 if ipv6 := ep.IPv6Address(); ipv6 != nil { 194 // Corresponds to DEFINE_IPV6() in bpf/lib/utils.h 195 result["LXC_IP_1"] = sliceToBe32(ipv6[0:4]) 196 result["LXC_IP_2"] = sliceToBe32(ipv6[4:8]) 197 result["LXC_IP_3"] = sliceToBe32(ipv6[8:12]) 198 result["LXC_IP_4"] = sliceToBe32(ipv6[12:16]) 199 } 200 if ipv4 := ep.IPv4Address(); ipv4 != nil { 201 result["LXC_IPV4"] = byteorder.HostSliceToNetwork(ipv4, reflect.Uint32).(uint32) 202 } 203 204 mac := ep.GetNodeMAC() 205 result["NODE_MAC_1"] = sliceToBe32(mac[0:4]) 206 result["NODE_MAC_2"] = uint32(sliceToBe16(mac[4:6])) 207 result["LXC_ID"] = uint32(ep.GetID()) 208 identity := ep.GetIdentity().Uint32() 209 result["SECLABEL"] = identity 210 result["SECLABEL_NB"] = byteorder.HostToNetwork(identity).(uint32) 211 212 return result 213 214 } 215 216 // ELFSubstitutions fetches the set of variable and map substitutions that 217 // must be implemented against an ELF template to configure the datapath for 218 // the specified endpoint. 219 func ELFSubstitutions(ep endpoint) (map[string]uint32, map[string]string) { 220 return elfVariableSubstitutions(ep), elfMapSubstitutions(ep) 221 }