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  }