LCOV - code coverage report
Current view: top level - kernel/bpf - stackmap.c (source / functions) Hit Total Coverage
Test: Real Lines: 4 241 1.7 %
Date: 2020-10-17 15:46:16 Functions: 0 19 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /* Copyright (c) 2016 Facebook
       3                 :            :  */
       4                 :            : #include <linux/bpf.h>
       5                 :            : #include <linux/jhash.h>
       6                 :            : #include <linux/filter.h>
       7                 :            : #include <linux/stacktrace.h>
       8                 :            : #include <linux/perf_event.h>
       9                 :            : #include <linux/elf.h>
      10                 :            : #include <linux/pagemap.h>
      11                 :            : #include <linux/irq_work.h>
      12                 :            : #include "percpu_freelist.h"
      13                 :            : 
      14                 :            : #define STACK_CREATE_FLAG_MASK                                  \
      15                 :            :         (BPF_F_NUMA_NODE | BPF_F_RDONLY | BPF_F_WRONLY |        \
      16                 :            :          BPF_F_STACK_BUILD_ID)
      17                 :            : 
      18                 :            : struct stack_map_bucket {
      19                 :            :         struct pcpu_freelist_node fnode;
      20                 :            :         u32 hash;
      21                 :            :         u32 nr;
      22                 :            :         u64 data[];
      23                 :            : };
      24                 :            : 
      25                 :            : struct bpf_stack_map {
      26                 :            :         struct bpf_map map;
      27                 :            :         void *elems;
      28                 :            :         struct pcpu_freelist freelist;
      29                 :            :         u32 n_buckets;
      30                 :            :         struct stack_map_bucket *buckets[];
      31                 :            : };
      32                 :            : 
      33                 :            : /* irq_work to run up_read() for build_id lookup in nmi context */
      34                 :            : struct stack_map_irq_work {
      35                 :            :         struct irq_work irq_work;
      36                 :            :         struct rw_semaphore *sem;
      37                 :            : };
      38                 :            : 
      39                 :          0 : static void do_up_read(struct irq_work *entry)
      40                 :            : {
      41                 :            :         struct stack_map_irq_work *work;
      42                 :            : 
      43                 :            :         work = container_of(entry, struct stack_map_irq_work, irq_work);
      44                 :          0 :         up_read_non_owner(work->sem);
      45                 :          0 :         work->sem = NULL;
      46                 :          0 : }
      47                 :            : 
      48                 :            : static DEFINE_PER_CPU(struct stack_map_irq_work, up_read_work);
      49                 :            : 
      50                 :          0 : static inline bool stack_map_use_build_id(struct bpf_map *map)
      51                 :            : {
      52                 :          0 :         return (map->map_flags & BPF_F_STACK_BUILD_ID);
      53                 :            : }
      54                 :            : 
      55                 :          0 : static inline int stack_map_data_size(struct bpf_map *map)
      56                 :            : {
      57                 :          0 :         return stack_map_use_build_id(map) ?
      58                 :            :                 sizeof(struct bpf_stack_build_id) : sizeof(u64);
      59                 :            : }
      60                 :            : 
      61                 :          0 : static int prealloc_elems_and_freelist(struct bpf_stack_map *smap)
      62                 :            : {
      63                 :          0 :         u32 elem_size = sizeof(struct stack_map_bucket) + smap->map.value_size;
      64                 :            :         int err;
      65                 :            : 
      66                 :          0 :         smap->elems = bpf_map_area_alloc(elem_size * smap->map.max_entries,
      67                 :            :                                          smap->map.numa_node);
      68                 :          0 :         if (!smap->elems)
      69                 :            :                 return -ENOMEM;
      70                 :            : 
      71                 :          0 :         err = pcpu_freelist_init(&smap->freelist);
      72                 :          0 :         if (err)
      73                 :            :                 goto free_elems;
      74                 :            : 
      75                 :          0 :         pcpu_freelist_populate(&smap->freelist, smap->elems, elem_size,
      76                 :            :                                smap->map.max_entries);
      77                 :          0 :         return 0;
      78                 :            : 
      79                 :            : free_elems:
      80                 :          0 :         bpf_map_area_free(smap->elems);
      81                 :          0 :         return err;
      82                 :            : }
      83                 :            : 
      84                 :            : /* Called from syscall */
      85                 :          0 : static struct bpf_map *stack_map_alloc(union bpf_attr *attr)
      86                 :            : {
      87                 :          0 :         u32 value_size = attr->value_size;
      88                 :            :         struct bpf_stack_map *smap;
      89                 :            :         struct bpf_map_memory mem;
      90                 :            :         u64 cost, n_buckets;
      91                 :            :         int err;
      92                 :            : 
      93                 :          0 :         if (!capable(CAP_SYS_ADMIN))
      94                 :            :                 return ERR_PTR(-EPERM);
      95                 :            : 
      96                 :          0 :         if (attr->map_flags & ~STACK_CREATE_FLAG_MASK)
      97                 :            :                 return ERR_PTR(-EINVAL);
      98                 :            : 
      99                 :            :         /* check sanity of attributes */
     100                 :          0 :         if (attr->max_entries == 0 || attr->key_size != 4 ||
     101                 :          0 :             value_size < 8 || value_size % 8)
     102                 :            :                 return ERR_PTR(-EINVAL);
     103                 :            : 
     104                 :            :         BUILD_BUG_ON(sizeof(struct bpf_stack_build_id) % sizeof(u64));
     105                 :          0 :         if (attr->map_flags & BPF_F_STACK_BUILD_ID) {
     106                 :          0 :                 if (value_size % sizeof(struct bpf_stack_build_id) ||
     107                 :          0 :                     value_size / sizeof(struct bpf_stack_build_id)
     108                 :          0 :                     > sysctl_perf_event_max_stack)
     109                 :            :                         return ERR_PTR(-EINVAL);
     110                 :          0 :         } else if (value_size / 8 > sysctl_perf_event_max_stack)
     111                 :            :                 return ERR_PTR(-EINVAL);
     112                 :            : 
     113                 :            :         /* hash table size must be power of 2 */
     114                 :          0 :         n_buckets = roundup_pow_of_two(attr->max_entries);
     115                 :            : 
     116                 :          0 :         cost = n_buckets * sizeof(struct stack_map_bucket *) + sizeof(*smap);
     117                 :          0 :         cost += n_buckets * (value_size + sizeof(struct stack_map_bucket));
     118                 :          0 :         err = bpf_map_charge_init(&mem, cost);
     119                 :          0 :         if (err)
     120                 :          0 :                 return ERR_PTR(err);
     121                 :            : 
     122                 :          0 :         smap = bpf_map_area_alloc(cost, bpf_map_attr_numa_node(attr));
     123                 :          0 :         if (!smap) {
     124                 :          0 :                 bpf_map_charge_finish(&mem);
     125                 :          0 :                 return ERR_PTR(-ENOMEM);
     126                 :            :         }
     127                 :            : 
     128                 :          0 :         bpf_map_init_from_attr(&smap->map, attr);
     129                 :          0 :         smap->map.value_size = value_size;
     130                 :          0 :         smap->n_buckets = n_buckets;
     131                 :            : 
     132                 :          0 :         err = get_callchain_buffers(sysctl_perf_event_max_stack);
     133                 :          0 :         if (err)
     134                 :            :                 goto free_charge;
     135                 :            : 
     136                 :          0 :         err = prealloc_elems_and_freelist(smap);
     137                 :          0 :         if (err)
     138                 :            :                 goto put_buffers;
     139                 :            : 
     140                 :          0 :         bpf_map_charge_move(&smap->map.memory, &mem);
     141                 :            : 
     142                 :          0 :         return &smap->map;
     143                 :            : 
     144                 :            : put_buffers:
     145                 :          0 :         put_callchain_buffers();
     146                 :            : free_charge:
     147                 :          0 :         bpf_map_charge_finish(&mem);
     148                 :          0 :         bpf_map_area_free(smap);
     149                 :          0 :         return ERR_PTR(err);
     150                 :            : }
     151                 :            : 
     152                 :            : #define BPF_BUILD_ID 3
     153                 :            : /*
     154                 :            :  * Parse build id from the note segment. This logic can be shared between
     155                 :            :  * 32-bit and 64-bit system, because Elf32_Nhdr and Elf64_Nhdr are
     156                 :            :  * identical.
     157                 :            :  */
     158                 :          0 : static inline int stack_map_parse_build_id(void *page_addr,
     159                 :            :                                            unsigned char *build_id,
     160                 :            :                                            void *note_start,
     161                 :            :                                            Elf32_Word note_size)
     162                 :            : {
     163                 :            :         Elf32_Word note_offs = 0, new_offs;
     164                 :            : 
     165                 :            :         /* check for overflow */
     166                 :          0 :         if (note_start < page_addr || note_start + note_size < note_start)
     167                 :            :                 return -EINVAL;
     168                 :            : 
     169                 :            :         /* only supports note that fits in the first page */
     170                 :          0 :         if (note_start + note_size > page_addr + PAGE_SIZE)
     171                 :            :                 return -EINVAL;
     172                 :            : 
     173                 :          0 :         while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
     174                 :          0 :                 Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
     175                 :            : 
     176                 :          0 :                 if (nhdr->n_type == BPF_BUILD_ID &&
     177                 :          0 :                     nhdr->n_namesz == sizeof("GNU") &&
     178                 :          0 :                     nhdr->n_descsz > 0 &&
     179                 :            :                     nhdr->n_descsz <= BPF_BUILD_ID_SIZE) {
     180                 :          0 :                         memcpy(build_id,
     181                 :            :                                note_start + note_offs +
     182                 :          0 :                                ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr),
     183                 :            :                                nhdr->n_descsz);
     184                 :          0 :                         memset(build_id + nhdr->n_descsz, 0,
     185                 :            :                                BPF_BUILD_ID_SIZE - nhdr->n_descsz);
     186                 :          0 :                         return 0;
     187                 :            :                 }
     188                 :          0 :                 new_offs = note_offs + sizeof(Elf32_Nhdr) +
     189                 :          0 :                         ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
     190                 :          0 :                 if (new_offs <= note_offs)  /* overflow */
     191                 :            :                         break;
     192                 :            :                 note_offs = new_offs;
     193                 :            :         }
     194                 :            :         return -EINVAL;
     195                 :            : }
     196                 :            : 
     197                 :            : /* Parse build ID from 32-bit ELF */
     198                 :          0 : static int stack_map_get_build_id_32(void *page_addr,
     199                 :            :                                      unsigned char *build_id)
     200                 :            : {
     201                 :            :         Elf32_Ehdr *ehdr = (Elf32_Ehdr *)page_addr;
     202                 :            :         Elf32_Phdr *phdr;
     203                 :            :         int i;
     204                 :            : 
     205                 :            :         /* only supports phdr that fits in one page */
     206                 :          0 :         if (ehdr->e_phnum >
     207                 :            :             (PAGE_SIZE - sizeof(Elf32_Ehdr)) / sizeof(Elf32_Phdr))
     208                 :            :                 return -EINVAL;
     209                 :            : 
     210                 :          0 :         phdr = (Elf32_Phdr *)(page_addr + sizeof(Elf32_Ehdr));
     211                 :            : 
     212                 :          0 :         for (i = 0; i < ehdr->e_phnum; ++i)
     213                 :          0 :                 if (phdr[i].p_type == PT_NOTE)
     214                 :          0 :                         return stack_map_parse_build_id(page_addr, build_id,
     215                 :          0 :                                         page_addr + phdr[i].p_offset,
     216                 :          0 :                                         phdr[i].p_filesz);
     217                 :            :         return -EINVAL;
     218                 :            : }
     219                 :            : 
     220                 :            : /* Parse build ID from 64-bit ELF */
     221                 :          0 : static int stack_map_get_build_id_64(void *page_addr,
     222                 :            :                                      unsigned char *build_id)
     223                 :            : {
     224                 :            :         Elf64_Ehdr *ehdr = (Elf64_Ehdr *)page_addr;
     225                 :            :         Elf64_Phdr *phdr;
     226                 :            :         int i;
     227                 :            : 
     228                 :            :         /* only supports phdr that fits in one page */
     229                 :          0 :         if (ehdr->e_phnum >
     230                 :            :             (PAGE_SIZE - sizeof(Elf64_Ehdr)) / sizeof(Elf64_Phdr))
     231                 :            :                 return -EINVAL;
     232                 :            : 
     233                 :          0 :         phdr = (Elf64_Phdr *)(page_addr + sizeof(Elf64_Ehdr));
     234                 :            : 
     235                 :          0 :         for (i = 0; i < ehdr->e_phnum; ++i)
     236                 :          0 :                 if (phdr[i].p_type == PT_NOTE)
     237                 :          0 :                         return stack_map_parse_build_id(page_addr, build_id,
     238                 :          0 :                                         page_addr + phdr[i].p_offset,
     239                 :          0 :                                         phdr[i].p_filesz);
     240                 :            :         return -EINVAL;
     241                 :            : }
     242                 :            : 
     243                 :            : /* Parse build ID of ELF file mapped to vma */
     244                 :          0 : static int stack_map_get_build_id(struct vm_area_struct *vma,
     245                 :            :                                   unsigned char *build_id)
     246                 :            : {
     247                 :            :         Elf32_Ehdr *ehdr;
     248                 :            :         struct page *page;
     249                 :            :         void *page_addr;
     250                 :            :         int ret;
     251                 :            : 
     252                 :            :         /* only works for page backed storage  */
     253                 :          0 :         if (!vma->vm_file)
     254                 :            :                 return -EINVAL;
     255                 :            : 
     256                 :          0 :         page = find_get_page(vma->vm_file->f_mapping, 0);
     257                 :          0 :         if (!page)
     258                 :            :                 return -EFAULT; /* page not mapped */
     259                 :            : 
     260                 :            :         ret = -EINVAL;
     261                 :          0 :         page_addr = kmap_atomic(page);
     262                 :            :         ehdr = (Elf32_Ehdr *)page_addr;
     263                 :            : 
     264                 :            :         /* compare magic x7f "ELF" */
     265                 :          0 :         if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0)
     266                 :            :                 goto out;
     267                 :            : 
     268                 :            :         /* only support executable file and shared object file */
     269                 :          0 :         if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN)
     270                 :            :                 goto out;
     271                 :            : 
     272                 :          0 :         if (ehdr->e_ident[EI_CLASS] == ELFCLASS32)
     273                 :          0 :                 ret = stack_map_get_build_id_32(page_addr, build_id);
     274                 :          0 :         else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
     275                 :          0 :                 ret = stack_map_get_build_id_64(page_addr, build_id);
     276                 :            : out:
     277                 :            :         kunmap_atomic(page_addr);
     278                 :          0 :         put_page(page);
     279                 :          0 :         return ret;
     280                 :            : }
     281                 :            : 
     282                 :          0 : static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs,
     283                 :            :                                           u64 *ips, u32 trace_nr, bool user)
     284                 :            : {
     285                 :            :         int i;
     286                 :            :         struct vm_area_struct *vma;
     287                 :            :         bool irq_work_busy = false;
     288                 :            :         struct stack_map_irq_work *work = NULL;
     289                 :            : 
     290                 :          0 :         if (irqs_disabled()) {
     291                 :          0 :                 work = this_cpu_ptr(&up_read_work);
     292                 :          0 :                 if (work->irq_work.flags & IRQ_WORK_BUSY)
     293                 :            :                         /* cannot queue more up_read, fallback */
     294                 :            :                         irq_work_busy = true;
     295                 :            :         }
     296                 :            : 
     297                 :            :         /*
     298                 :            :          * We cannot do up_read() when the irq is disabled, because of
     299                 :            :          * risk to deadlock with rq_lock. To do build_id lookup when the
     300                 :            :          * irqs are disabled, we need to run up_read() in irq_work. We use
     301                 :            :          * a percpu variable to do the irq_work. If the irq_work is
     302                 :            :          * already used by another lookup, we fall back to report ips.
     303                 :            :          *
     304                 :            :          * Same fallback is used for kernel stack (!user) on a stackmap
     305                 :            :          * with build_id.
     306                 :            :          */
     307                 :          0 :         if (!user || !current || !current->mm || irq_work_busy ||
     308                 :          0 :             down_read_trylock(&current->mm->mmap_sem) == 0) {
     309                 :            :                 /* cannot access current->mm, fall back to ips */
     310                 :          0 :                 for (i = 0; i < trace_nr; i++) {
     311                 :          0 :                         id_offs[i].status = BPF_STACK_BUILD_ID_IP;
     312                 :          0 :                         id_offs[i].ip = ips[i];
     313                 :          0 :                         memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE);
     314                 :            :                 }
     315                 :          0 :                 return;
     316                 :            :         }
     317                 :            : 
     318                 :          0 :         for (i = 0; i < trace_nr; i++) {
     319                 :          0 :                 vma = find_vma(current->mm, ips[i]);
     320                 :          0 :                 if (!vma || stack_map_get_build_id(vma, id_offs[i].build_id)) {
     321                 :            :                         /* per entry fall back to ips */
     322                 :          0 :                         id_offs[i].status = BPF_STACK_BUILD_ID_IP;
     323                 :          0 :                         id_offs[i].ip = ips[i];
     324                 :          0 :                         memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE);
     325                 :          0 :                         continue;
     326                 :            :                 }
     327                 :          0 :                 id_offs[i].offset = (vma->vm_pgoff << PAGE_SHIFT) + ips[i]
     328                 :          0 :                         - vma->vm_start;
     329                 :          0 :                 id_offs[i].status = BPF_STACK_BUILD_ID_VALID;
     330                 :            :         }
     331                 :            : 
     332                 :          0 :         if (!work) {
     333                 :          0 :                 up_read(&current->mm->mmap_sem);
     334                 :            :         } else {
     335                 :          0 :                 work->sem = &current->mm->mmap_sem;
     336                 :          0 :                 irq_work_queue(&work->irq_work);
     337                 :            :                 /*
     338                 :            :                  * The irq_work will release the mmap_sem with
     339                 :            :                  * up_read_non_owner(). The rwsem_release() is called
     340                 :            :                  * here to release the lock from lockdep's perspective.
     341                 :            :                  */
     342                 :            :                 rwsem_release(&current->mm->mmap_sem.dep_map, 1, _RET_IP_);
     343                 :            :         }
     344                 :            : }
     345                 :            : 
     346                 :          0 : BPF_CALL_3(bpf_get_stackid, struct pt_regs *, regs, struct bpf_map *, map,
     347                 :            :            u64, flags)
     348                 :            : {
     349                 :            :         struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
     350                 :            :         struct perf_callchain_entry *trace;
     351                 :            :         struct stack_map_bucket *bucket, *new_bucket, *old_bucket;
     352                 :          0 :         u32 max_depth = map->value_size / stack_map_data_size(map);
     353                 :            :         /* stack_map_alloc() checks that max_depth <= sysctl_perf_event_max_stack */
     354                 :          0 :         u32 init_nr = sysctl_perf_event_max_stack - max_depth;
     355                 :          0 :         u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
     356                 :            :         u32 hash, id, trace_nr, trace_len;
     357                 :          0 :         bool user = flags & BPF_F_USER_STACK;
     358                 :          0 :         bool kernel = !user;
     359                 :            :         u64 *ips;
     360                 :            :         bool hash_matches;
     361                 :            : 
     362                 :          0 :         if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
     363                 :            :                                BPF_F_FAST_STACK_CMP | BPF_F_REUSE_STACKID)))
     364                 :            :                 return -EINVAL;
     365                 :            : 
     366                 :          0 :         trace = get_perf_callchain(regs, init_nr, kernel, user,
     367                 :            :                                    sysctl_perf_event_max_stack, false, false);
     368                 :            : 
     369                 :          0 :         if (unlikely(!trace))
     370                 :            :                 /* couldn't fetch the stack trace */
     371                 :            :                 return -EFAULT;
     372                 :            : 
     373                 :            :         /* get_perf_callchain() guarantees that trace->nr >= init_nr
     374                 :            :          * and trace-nr <= sysctl_perf_event_max_stack, so trace_nr <= max_depth
     375                 :            :          */
     376                 :          0 :         trace_nr = trace->nr - init_nr;
     377                 :            : 
     378                 :          0 :         if (trace_nr <= skip)
     379                 :            :                 /* skipping more than usable stack trace */
     380                 :            :                 return -EFAULT;
     381                 :            : 
     382                 :          0 :         trace_nr -= skip;
     383                 :          0 :         trace_len = trace_nr * sizeof(u64);
     384                 :          0 :         ips = trace->ip + skip + init_nr;
     385                 :          0 :         hash = jhash2((u32 *)ips, trace_len / sizeof(u32), 0);
     386                 :          0 :         id = hash & (smap->n_buckets - 1);
     387                 :          0 :         bucket = READ_ONCE(smap->buckets[id]);
     388                 :            : 
     389                 :          0 :         hash_matches = bucket && bucket->hash == hash;
     390                 :            :         /* fast cmp */
     391                 :          0 :         if (hash_matches && flags & BPF_F_FAST_STACK_CMP)
     392                 :          0 :                 return id;
     393                 :            : 
     394                 :          0 :         if (stack_map_use_build_id(map)) {
     395                 :            :                 /* for build_id+offset, pop a bucket before slow cmp */
     396                 :          0 :                 new_bucket = (struct stack_map_bucket *)
     397                 :          0 :                         pcpu_freelist_pop(&smap->freelist);
     398                 :          0 :                 if (unlikely(!new_bucket))
     399                 :            :                         return -ENOMEM;
     400                 :          0 :                 new_bucket->nr = trace_nr;
     401                 :          0 :                 stack_map_get_build_id_offset(
     402                 :          0 :                         (struct bpf_stack_build_id *)new_bucket->data,
     403                 :            :                         ips, trace_nr, user);
     404                 :          0 :                 trace_len = trace_nr * sizeof(struct bpf_stack_build_id);
     405                 :          0 :                 if (hash_matches && bucket->nr == trace_nr &&
     406                 :          0 :                     memcmp(bucket->data, new_bucket->data, trace_len) == 0) {
     407                 :          0 :                         pcpu_freelist_push(&smap->freelist, &new_bucket->fnode);
     408                 :          0 :                         return id;
     409                 :            :                 }
     410                 :          0 :                 if (bucket && !(flags & BPF_F_REUSE_STACKID)) {
     411                 :          0 :                         pcpu_freelist_push(&smap->freelist, &new_bucket->fnode);
     412                 :            :                         return -EEXIST;
     413                 :            :                 }
     414                 :            :         } else {
     415                 :          0 :                 if (hash_matches && bucket->nr == trace_nr &&
     416                 :          0 :                     memcmp(bucket->data, ips, trace_len) == 0)
     417                 :          0 :                         return id;
     418                 :          0 :                 if (bucket && !(flags & BPF_F_REUSE_STACKID))
     419                 :            :                         return -EEXIST;
     420                 :            : 
     421                 :          0 :                 new_bucket = (struct stack_map_bucket *)
     422                 :          0 :                         pcpu_freelist_pop(&smap->freelist);
     423                 :          0 :                 if (unlikely(!new_bucket))
     424                 :            :                         return -ENOMEM;
     425                 :          0 :                 memcpy(new_bucket->data, ips, trace_len);
     426                 :            :         }
     427                 :            : 
     428                 :          0 :         new_bucket->hash = hash;
     429                 :          0 :         new_bucket->nr = trace_nr;
     430                 :            : 
     431                 :          0 :         old_bucket = xchg(&smap->buckets[id], new_bucket);
     432                 :          0 :         if (old_bucket)
     433                 :          0 :                 pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
     434                 :          0 :         return id;
     435                 :            : }
     436                 :            : 
     437                 :            : const struct bpf_func_proto bpf_get_stackid_proto = {
     438                 :            :         .func           = bpf_get_stackid,
     439                 :            :         .gpl_only       = true,
     440                 :            :         .ret_type       = RET_INTEGER,
     441                 :            :         .arg1_type      = ARG_PTR_TO_CTX,
     442                 :            :         .arg2_type      = ARG_CONST_MAP_PTR,
     443                 :            :         .arg3_type      = ARG_ANYTHING,
     444                 :            : };
     445                 :            : 
     446                 :          0 : BPF_CALL_4(bpf_get_stack, struct pt_regs *, regs, void *, buf, u32, size,
     447                 :            :            u64, flags)
     448                 :            : {
     449                 :            :         u32 init_nr, trace_nr, copy_len, elem_size, num_elem;
     450                 :          0 :         bool user_build_id = flags & BPF_F_USER_BUILD_ID;
     451                 :          0 :         u32 skip = flags & BPF_F_SKIP_FIELD_MASK;
     452                 :          0 :         bool user = flags & BPF_F_USER_STACK;
     453                 :            :         struct perf_callchain_entry *trace;
     454                 :          0 :         bool kernel = !user;
     455                 :            :         int err = -EINVAL;
     456                 :            :         u64 *ips;
     457                 :            : 
     458                 :          0 :         if (unlikely(flags & ~(BPF_F_SKIP_FIELD_MASK | BPF_F_USER_STACK |
     459                 :            :                                BPF_F_USER_BUILD_ID)))
     460                 :            :                 goto clear;
     461                 :          0 :         if (kernel && user_build_id)
     462                 :            :                 goto clear;
     463                 :            : 
     464                 :          0 :         elem_size = (user && user_build_id) ? sizeof(struct bpf_stack_build_id)
     465                 :          0 :                                             : sizeof(u64);
     466                 :          0 :         if (unlikely(size % elem_size))
     467                 :            :                 goto clear;
     468                 :            : 
     469                 :          0 :         num_elem = size / elem_size;
     470                 :          0 :         if (sysctl_perf_event_max_stack < num_elem)
     471                 :            :                 init_nr = 0;
     472                 :            :         else
     473                 :          0 :                 init_nr = sysctl_perf_event_max_stack - num_elem;
     474                 :          0 :         trace = get_perf_callchain(regs, init_nr, kernel, user,
     475                 :            :                                    sysctl_perf_event_max_stack, false, false);
     476                 :          0 :         if (unlikely(!trace))
     477                 :            :                 goto err_fault;
     478                 :            : 
     479                 :          0 :         trace_nr = trace->nr - init_nr;
     480                 :          0 :         if (trace_nr < skip)
     481                 :            :                 goto err_fault;
     482                 :            : 
     483                 :          0 :         trace_nr -= skip;
     484                 :          0 :         trace_nr = (trace_nr <= num_elem) ? trace_nr : num_elem;
     485                 :          0 :         copy_len = trace_nr * elem_size;
     486                 :          0 :         ips = trace->ip + skip + init_nr;
     487                 :          0 :         if (user && user_build_id)
     488                 :          0 :                 stack_map_get_build_id_offset(buf, ips, trace_nr, user);
     489                 :            :         else
     490                 :          0 :                 memcpy(buf, ips, copy_len);
     491                 :            : 
     492                 :          0 :         if (size > copy_len)
     493                 :          0 :                 memset(buf + copy_len, 0, size - copy_len);
     494                 :          0 :         return copy_len;
     495                 :            : 
     496                 :            : err_fault:
     497                 :            :         err = -EFAULT;
     498                 :            : clear:
     499                 :          0 :         memset(buf, 0, size);
     500                 :          0 :         return err;
     501                 :            : }
     502                 :            : 
     503                 :            : const struct bpf_func_proto bpf_get_stack_proto = {
     504                 :            :         .func           = bpf_get_stack,
     505                 :            :         .gpl_only       = true,
     506                 :            :         .ret_type       = RET_INTEGER,
     507                 :            :         .arg1_type      = ARG_PTR_TO_CTX,
     508                 :            :         .arg2_type      = ARG_PTR_TO_UNINIT_MEM,
     509                 :            :         .arg3_type      = ARG_CONST_SIZE_OR_ZERO,
     510                 :            :         .arg4_type      = ARG_ANYTHING,
     511                 :            : };
     512                 :            : 
     513                 :            : /* Called from eBPF program */
     514                 :          0 : static void *stack_map_lookup_elem(struct bpf_map *map, void *key)
     515                 :            : {
     516                 :          0 :         return ERR_PTR(-EOPNOTSUPP);
     517                 :            : }
     518                 :            : 
     519                 :            : /* Called from syscall */
     520                 :          0 : int bpf_stackmap_copy(struct bpf_map *map, void *key, void *value)
     521                 :            : {
     522                 :            :         struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
     523                 :            :         struct stack_map_bucket *bucket, *old_bucket;
     524                 :          0 :         u32 id = *(u32 *)key, trace_len;
     525                 :            : 
     526                 :          0 :         if (unlikely(id >= smap->n_buckets))
     527                 :            :                 return -ENOENT;
     528                 :            : 
     529                 :          0 :         bucket = xchg(&smap->buckets[id], NULL);
     530                 :          0 :         if (!bucket)
     531                 :            :                 return -ENOENT;
     532                 :            : 
     533                 :          0 :         trace_len = bucket->nr * stack_map_data_size(map);
     534                 :          0 :         memcpy(value, bucket->data, trace_len);
     535                 :          0 :         memset(value + trace_len, 0, map->value_size - trace_len);
     536                 :            : 
     537                 :          0 :         old_bucket = xchg(&smap->buckets[id], bucket);
     538                 :          0 :         if (old_bucket)
     539                 :          0 :                 pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
     540                 :            :         return 0;
     541                 :            : }
     542                 :            : 
     543                 :          0 : static int stack_map_get_next_key(struct bpf_map *map, void *key,
     544                 :            :                                   void *next_key)
     545                 :            : {
     546                 :            :         struct bpf_stack_map *smap = container_of(map,
     547                 :            :                                                   struct bpf_stack_map, map);
     548                 :            :         u32 id;
     549                 :            : 
     550                 :            :         WARN_ON_ONCE(!rcu_read_lock_held());
     551                 :            : 
     552                 :          0 :         if (!key) {
     553                 :            :                 id = 0;
     554                 :            :         } else {
     555                 :          0 :                 id = *(u32 *)key;
     556                 :          0 :                 if (id >= smap->n_buckets || !smap->buckets[id])
     557                 :            :                         id = 0;
     558                 :            :                 else
     559                 :          0 :                         id++;
     560                 :            :         }
     561                 :            : 
     562                 :          0 :         while (id < smap->n_buckets && !smap->buckets[id])
     563                 :          0 :                 id++;
     564                 :            : 
     565                 :          0 :         if (id >= smap->n_buckets)
     566                 :            :                 return -ENOENT;
     567                 :            : 
     568                 :          0 :         *(u32 *)next_key = id;
     569                 :          0 :         return 0;
     570                 :            : }
     571                 :            : 
     572                 :          0 : static int stack_map_update_elem(struct bpf_map *map, void *key, void *value,
     573                 :            :                                  u64 map_flags)
     574                 :            : {
     575                 :          0 :         return -EINVAL;
     576                 :            : }
     577                 :            : 
     578                 :            : /* Called from syscall or from eBPF program */
     579                 :          0 : static int stack_map_delete_elem(struct bpf_map *map, void *key)
     580                 :            : {
     581                 :            :         struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
     582                 :            :         struct stack_map_bucket *old_bucket;
     583                 :          0 :         u32 id = *(u32 *)key;
     584                 :            : 
     585                 :          0 :         if (unlikely(id >= smap->n_buckets))
     586                 :            :                 return -E2BIG;
     587                 :            : 
     588                 :          0 :         old_bucket = xchg(&smap->buckets[id], NULL);
     589                 :          0 :         if (old_bucket) {
     590                 :          0 :                 pcpu_freelist_push(&smap->freelist, &old_bucket->fnode);
     591                 :          0 :                 return 0;
     592                 :            :         } else {
     593                 :            :                 return -ENOENT;
     594                 :            :         }
     595                 :            : }
     596                 :            : 
     597                 :            : /* Called when map->refcnt goes to zero, either from workqueue or from syscall */
     598                 :          0 : static void stack_map_free(struct bpf_map *map)
     599                 :            : {
     600                 :            :         struct bpf_stack_map *smap = container_of(map, struct bpf_stack_map, map);
     601                 :            : 
     602                 :            :         /* wait for bpf programs to complete before freeing stack map */
     603                 :          0 :         synchronize_rcu();
     604                 :            : 
     605                 :          0 :         bpf_map_area_free(smap->elems);
     606                 :          0 :         pcpu_freelist_destroy(&smap->freelist);
     607                 :          0 :         bpf_map_area_free(smap);
     608                 :          0 :         put_callchain_buffers();
     609                 :          0 : }
     610                 :            : 
     611                 :            : const struct bpf_map_ops stack_trace_map_ops = {
     612                 :            :         .map_alloc = stack_map_alloc,
     613                 :            :         .map_free = stack_map_free,
     614                 :            :         .map_get_next_key = stack_map_get_next_key,
     615                 :            :         .map_lookup_elem = stack_map_lookup_elem,
     616                 :            :         .map_update_elem = stack_map_update_elem,
     617                 :            :         .map_delete_elem = stack_map_delete_elem,
     618                 :            :         .map_check_btf = map_check_no_btf,
     619                 :            : };
     620                 :            : 
     621                 :          3 : static int __init stack_map_init(void)
     622                 :            : {
     623                 :            :         int cpu;
     624                 :            :         struct stack_map_irq_work *work;
     625                 :            : 
     626                 :          3 :         for_each_possible_cpu(cpu) {
     627                 :          3 :                 work = per_cpu_ptr(&up_read_work, cpu);
     628                 :            :                 init_irq_work(&work->irq_work, do_up_read);
     629                 :            :         }
     630                 :          3 :         return 0;
     631                 :            : }
     632                 :            : subsys_initcall(stack_map_init);
    

Generated by: LCOV version 1.14