github.com/datadog/cilium@v1.6.12/bpf/probes/raw_main.c (about)

     1  /*
     2   *  Copyright (C) 2017 Authors of Cilium
     3   *
     4   *  This program is free software; you can redistribute it and/or modify
     5   *  it under the terms of the GNU General Public License as published by
     6   *  the Free Software Foundation; either version 2 of the License, or
     7   *  (at your option) any later version.
     8   *
     9   *  This program is distributed in the hope that it will be useful,
    10   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   *  GNU General Public License for more details.
    13   *
    14   *  You should have received a copy of the GNU General Public License
    15   *  along with this program; if not, write to the Free Software
    16   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    17   */
    18  
    19  #include <unistd.h>
    20  #include <stdio.h>
    21  #include <stdint.h>
    22  #include <string.h>
    23  #include <errno.h>
    24  
    25  #include <sys/resource.h>
    26  
    27  #include "raw_insn.h"
    28  
    29  #include "iproute2/bpf_elf.h"
    30  
    31  #define BPF_MAX_FIXUPS	64
    32  #define BPF_MAX_INSNS	(2 * BPF_MAXINSNS)
    33  
    34  #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
    35  
    36  struct bpf_map_fixup {
    37  	int off;
    38  	enum bpf_map_type type;
    39  	uint32_t size_key;
    40  	uint32_t size_val;
    41  	uint32_t flags;
    42  };
    43  
    44  struct bpf_test {
    45  	const char *emits;
    46  	enum bpf_prog_type type;
    47  	enum bpf_attach_type attach_type;
    48  	struct bpf_insn insns[BPF_MAX_INSNS];
    49  	struct bpf_map_fixup fixup_map[BPF_MAX_FIXUPS];
    50  	const char *warn;
    51  };
    52  
    53  static struct bpf_test tests[] = {
    54  #include "raw_probe.t"
    55  };
    56  
    57  static uint64_t bpf_ptr_to_u64(const void *ptr)
    58  {
    59  	return (uint64_t)(unsigned long)ptr;
    60  }
    61  
    62  #ifndef __NR_bpf
    63  # if defined(__i386__)
    64  #  define __NR_bpf 357
    65  # elif defined(__x86_64__)
    66  #  define __NR_bpf 321
    67  # elif defined(__aarch64__)
    68  #  define __NR_bpf 280
    69  # else
    70  #  warning __NR_bpf not defined.
    71  # endif
    72  #endif
    73  
    74  static int bpf(int cmd, union bpf_attr *attr, unsigned int size)
    75  {
    76  #ifdef __NR_bpf
    77  	return syscall(__NR_bpf, cmd, attr, size);
    78  #else
    79  	errno = ENOSYS;
    80  	return -1;
    81  #endif
    82  }
    83  
    84  int bpf_prog_load(enum bpf_prog_type type, enum bpf_attach_type attach_type,
    85  		  const struct bpf_insn *insns, size_t num_insns,
    86  		  const char *license, char *log, size_t size_log)
    87  {
    88  	union bpf_attr attr;
    89  
    90  	memset(&attr, 0, sizeof(attr));
    91  	attr.prog_type = type;
    92  	attr.insns = bpf_ptr_to_u64(insns);
    93  	attr.insn_cnt = num_insns;
    94  	attr.license = bpf_ptr_to_u64(license);
    95  	attr.expected_attach_type = attach_type;
    96  
    97  	if (size_log > 0) {
    98  		attr.log_buf = bpf_ptr_to_u64(log);
    99  		attr.log_size = size_log;
   100  		attr.log_level = 1;
   101  	}
   102  
   103  	return bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
   104  }
   105  
   106  static int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
   107  			  uint32_t size_value, uint32_t max_elem,
   108  			  uint32_t flags)
   109  {
   110  	union bpf_attr attr;
   111  
   112  	memset(&attr, 0, sizeof(attr));
   113  	attr.map_type = type;
   114  	attr.key_size = size_key;
   115  	attr.value_size = size_value;
   116  	attr.max_entries = max_elem;
   117  	attr.map_flags = flags;
   118  
   119  	return bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
   120  }
   121  
   122  static int bpf_test_length(const struct bpf_insn *insn, size_t max)
   123  {
   124  	int len;
   125  
   126  	for (len = max - 1; len > 0; --len)
   127  		if (insn[len].code != 0 || insn[len].imm != 0)
   128  			break;
   129  
   130  	return len + 1;
   131  }
   132  
   133  /* From iproute2/lib/bpf.c */
   134  static void bpf_map_pin_report(const struct bpf_elf_map *pin,
   135  			       const struct bpf_elf_map *obj)
   136  {
   137  	fprintf(stderr, "Map specification differs from pinned file!\n");
   138  
   139  	if (obj->type != pin->type)
   140  		fprintf(stderr, " - Type:         %u (obj) != %u (pin)\n",
   141  			obj->type, pin->type);
   142  	if (obj->size_key != pin->size_key)
   143  		fprintf(stderr, " - Size key:     %u (obj) != %u (pin)\n",
   144  			obj->size_key, pin->size_key);
   145  	if (obj->size_value != pin->size_value)
   146  		fprintf(stderr, " - Size value:   %u (obj) != %u (pin)\n",
   147  			obj->size_value, pin->size_value);
   148  	if (obj->max_elem != pin->max_elem)
   149  		fprintf(stderr, " - Max elems:    %u (obj) != %u (pin)\n",
   150  			obj->max_elem, pin->max_elem);
   151  	if (obj->flags != pin->flags)
   152  		fprintf(stderr, " - Flags:        %#x (obj) != %#x (pin)\n",
   153  			obj->flags, pin->flags);
   154  	if (obj->pinning != pin->pinning)
   155  		fprintf(stderr, " - Pinning:      %#x (obj) != %#x (pin)\n",
   156  			obj->pinning, pin->pinning);
   157  
   158  	fprintf(stderr, "\n");
   159  }
   160  
   161  #ifndef PATH_MAX
   162  #define PATH_MAX 4096
   163  #endif
   164  
   165  /* From iproute2/lib/bpf.c */
   166  static int bpf_map_selfcheck_pinned(int fd, const struct bpf_elf_map *map,
   167  				    int length, enum bpf_prog_type type)
   168  {
   169  	char file[PATH_MAX], buff[4096];
   170  	struct bpf_elf_map tmp = {}, zero = {};
   171  	unsigned int val, owner_type = 0;
   172  	FILE *fp;
   173  
   174  	snprintf(file, sizeof(file), "/proc/%d/fdinfo/%d", getpid(), fd);
   175  
   176  	fp = fopen(file, "r");
   177  	if (!fp) {
   178  		fprintf(stderr, "No procfs support?!\n");
   179  		return -EIO;
   180  	}
   181  
   182  	while (fgets(buff, sizeof(buff), fp)) {
   183  		if (sscanf(buff, "map_type:\t%u", &val) == 1)
   184  			tmp.type = val;
   185  		else if (sscanf(buff, "key_size:\t%u", &val) == 1)
   186  			tmp.size_key = val;
   187  		else if (sscanf(buff, "value_size:\t%u", &val) == 1)
   188  			tmp.size_value = val;
   189  		else if (sscanf(buff, "max_entries:\t%u", &val) == 1)
   190  			tmp.max_elem = val;
   191  		else if (sscanf(buff, "map_flags:\t%i", &val) == 1)
   192  			tmp.flags = val;
   193  		else if (sscanf(buff, "owner_prog_type:\t%i", &val) == 1)
   194  			owner_type = val;
   195  	}
   196  
   197  	fclose(fp);
   198  
   199  	/* The decision to reject this is on kernel side eventually, but
   200  	 * at least give the user a chance to know what's wrong.
   201  	 */
   202  	if (owner_type && owner_type != type)
   203  		fprintf(stderr, "Program array map owner types differ: %u (obj) != %u (pin)\n",
   204  			type, owner_type);
   205  
   206  	if (!memcmp(&tmp, map, length)) {
   207  		return 0;
   208  	} else {
   209  		/* If kernel doesn't have eBPF-related fdinfo, we cannot do much,
   210  		 * so just accept it. We know we do have an eBPF fd and in this
   211  		 * case, everything is 0. It is guaranteed that no such map exists
   212  		 * since map type of 0 is unloadable BPF_MAP_TYPE_UNSPEC.
   213  		 */
   214  		if (!memcmp(&tmp, &zero, length))
   215  			return 0;
   216  
   217  		bpf_map_pin_report(&tmp, map);
   218  		return -EINVAL;
   219  	}
   220  }
   221  
   222  static void bpf_report(const struct bpf_test *test, int success,
   223  		       int debug_mode)
   224  {
   225  	static char bpf_vlog[1U << 17];
   226  	int fd;
   227  
   228  	printf("%s#define %s\n\n", success ? "" : "// ", test->emits);
   229  
   230  	if (!success || debug_mode) {
   231  		printf("#if 0\n");
   232  		printf("%s %s: ", test->emits, success ?
   233  		       "debug output" : "failed due to load error");
   234  
   235  		memset(bpf_vlog, 0, sizeof(bpf_vlog));
   236  		fd = bpf_prog_load(test->type, test->attach_type, test->insns,
   237  				   bpf_test_length(test->insns, ARRAY_SIZE(test->insns)),
   238  				   "GPL", bpf_vlog, sizeof(bpf_vlog));
   239  		printf("%s\n%s", strerror(errno), bpf_vlog);
   240  		printf("#endif\n\n");
   241  		if (fd > 0)
   242  			close(fd);
   243  	}
   244  
   245  	if (!success && test->warn)
   246  		fprintf(stderr, "%s: %s\n", test->emits, test->warn);
   247  }
   248  
   249  static void bpf_run_test(struct bpf_test *test, int debug_mode)
   250  {
   251  	struct bpf_map_fixup *map = test->fixup_map;
   252  	int fd;
   253  
   254  	/* We can use off here as it's never first insns. */
   255  	while (map->off) {
   256  		struct bpf_elf_map elf_map = {
   257  			.type		= map->type,
   258  			.size_key	= map->size_key,
   259  			.size_value	= map->size_val,
   260  			.pinning	= 0,
   261  			.max_elem	= 1,
   262  			.flags		= map->flags,
   263  		};
   264  	  
   265  		fd = bpf_map_create(map->type, map->size_key,
   266  				    map->size_val, 1, map->flags);
   267  		if (fd < 0) {
   268  			if (debug_mode) {
   269  				printf("#if 0\n");
   270  				printf("%s: bpf_map_create(): %s\n",
   271  				       test->emits, strerror(errno));
   272  				printf("#endif\n\n");
   273  			}
   274  			/* We fail in verifier eventually. */
   275  			break;
   276  		}
   277  		
   278  		if (bpf_map_selfcheck_pinned(fd, &elf_map, sizeof elf_map, test->type) != 0)
   279  			break;
   280  
   281  		test->insns[map->off].imm = fd;
   282  		map++;
   283  	}
   284  
   285  	fd = bpf_prog_load(test->type, test->attach_type, test->insns,
   286  			   bpf_test_length(test->insns, ARRAY_SIZE(test->insns)),
   287  			   "GPL", NULL, 0);
   288  	bpf_report(test, fd > 0, debug_mode);
   289  	if (fd > 0)
   290  		close(fd);
   291  }
   292  
   293  int main(int argc, char **argv)
   294  {
   295  	struct rlimit rold, rinf = { RLIM_INFINITY, RLIM_INFINITY };
   296  	int debug_mode = 0;
   297  	int i;
   298  
   299  	if (argc > 1 && !strncmp(argv[argc - 1], "debug", sizeof("debug")))
   300  		debug_mode = 1;
   301  
   302  	getrlimit(RLIMIT_MEMLOCK, &rold);
   303  	setrlimit(RLIMIT_MEMLOCK, &rinf);
   304  
   305  	for (i = 0; i < ARRAY_SIZE(tests); i++)
   306  		bpf_run_test(&tests[i], debug_mode);
   307  
   308  	setrlimit(RLIMIT_MEMLOCK, &rold);
   309  	return 0;
   310  }