diff options
Diffstat (limited to 'kernel/bpf/stackmap.c')
| -rw-r--r-- | kernel/bpf/stackmap.c | 20 |
1 files changed, 16 insertions, 4 deletions
diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index 90daf285de03..950ab2f28922 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c | |||
| @@ -44,7 +44,7 @@ static void do_up_read(struct irq_work *entry) | |||
| 44 | struct stack_map_irq_work *work; | 44 | struct stack_map_irq_work *work; |
| 45 | 45 | ||
| 46 | work = container_of(entry, struct stack_map_irq_work, irq_work); | 46 | work = container_of(entry, struct stack_map_irq_work, irq_work); |
| 47 | up_read(work->sem); | 47 | up_read_non_owner(work->sem); |
| 48 | work->sem = NULL; | 48 | work->sem = NULL; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| @@ -180,11 +180,14 @@ static inline int stack_map_parse_build_id(void *page_addr, | |||
| 180 | 180 | ||
| 181 | if (nhdr->n_type == BPF_BUILD_ID && | 181 | if (nhdr->n_type == BPF_BUILD_ID && |
| 182 | nhdr->n_namesz == sizeof("GNU") && | 182 | nhdr->n_namesz == sizeof("GNU") && |
| 183 | nhdr->n_descsz == BPF_BUILD_ID_SIZE) { | 183 | nhdr->n_descsz > 0 && |
| 184 | nhdr->n_descsz <= BPF_BUILD_ID_SIZE) { | ||
| 184 | memcpy(build_id, | 185 | memcpy(build_id, |
| 185 | note_start + note_offs + | 186 | note_start + note_offs + |
| 186 | ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), | 187 | ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), |
| 187 | BPF_BUILD_ID_SIZE); | 188 | nhdr->n_descsz); |
| 189 | memset(build_id + nhdr->n_descsz, 0, | ||
| 190 | BPF_BUILD_ID_SIZE - nhdr->n_descsz); | ||
| 188 | return 0; | 191 | return 0; |
| 189 | } | 192 | } |
| 190 | new_offs = note_offs + sizeof(Elf32_Nhdr) + | 193 | new_offs = note_offs + sizeof(Elf32_Nhdr) + |
| @@ -260,7 +263,7 @@ static int stack_map_get_build_id(struct vm_area_struct *vma, | |||
| 260 | return -EFAULT; /* page not mapped */ | 263 | return -EFAULT; /* page not mapped */ |
| 261 | 264 | ||
| 262 | ret = -EINVAL; | 265 | ret = -EINVAL; |
| 263 | page_addr = page_address(page); | 266 | page_addr = kmap_atomic(page); |
| 264 | ehdr = (Elf32_Ehdr *)page_addr; | 267 | ehdr = (Elf32_Ehdr *)page_addr; |
| 265 | 268 | ||
| 266 | /* compare magic x7f "ELF" */ | 269 | /* compare magic x7f "ELF" */ |
| @@ -276,6 +279,7 @@ static int stack_map_get_build_id(struct vm_area_struct *vma, | |||
| 276 | else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) | 279 | else if (ehdr->e_ident[EI_CLASS] == ELFCLASS64) |
| 277 | ret = stack_map_get_build_id_64(page_addr, build_id); | 280 | ret = stack_map_get_build_id_64(page_addr, build_id); |
| 278 | out: | 281 | out: |
| 282 | kunmap_atomic(page_addr); | ||
| 279 | put_page(page); | 283 | put_page(page); |
| 280 | return ret; | 284 | return ret; |
| 281 | } | 285 | } |
| @@ -310,6 +314,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, | |||
| 310 | for (i = 0; i < trace_nr; i++) { | 314 | for (i = 0; i < trace_nr; i++) { |
| 311 | id_offs[i].status = BPF_STACK_BUILD_ID_IP; | 315 | id_offs[i].status = BPF_STACK_BUILD_ID_IP; |
| 312 | id_offs[i].ip = ips[i]; | 316 | id_offs[i].ip = ips[i]; |
| 317 | memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE); | ||
| 313 | } | 318 | } |
| 314 | return; | 319 | return; |
| 315 | } | 320 | } |
| @@ -320,6 +325,7 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, | |||
| 320 | /* per entry fall back to ips */ | 325 | /* per entry fall back to ips */ |
| 321 | id_offs[i].status = BPF_STACK_BUILD_ID_IP; | 326 | id_offs[i].status = BPF_STACK_BUILD_ID_IP; |
| 322 | id_offs[i].ip = ips[i]; | 327 | id_offs[i].ip = ips[i]; |
| 328 | memset(id_offs[i].build_id, 0, BPF_BUILD_ID_SIZE); | ||
| 323 | continue; | 329 | continue; |
| 324 | } | 330 | } |
| 325 | id_offs[i].offset = (vma->vm_pgoff << PAGE_SHIFT) + ips[i] | 331 | id_offs[i].offset = (vma->vm_pgoff << PAGE_SHIFT) + ips[i] |
| @@ -332,6 +338,12 @@ static void stack_map_get_build_id_offset(struct bpf_stack_build_id *id_offs, | |||
| 332 | } else { | 338 | } else { |
| 333 | work->sem = ¤t->mm->mmap_sem; | 339 | work->sem = ¤t->mm->mmap_sem; |
| 334 | irq_work_queue(&work->irq_work); | 340 | irq_work_queue(&work->irq_work); |
| 341 | /* | ||
| 342 | * The irq_work will release the mmap_sem with | ||
| 343 | * up_read_non_owner(). The rwsem_release() is called | ||
| 344 | * here to release the lock from lockdep's perspective. | ||
| 345 | */ | ||
| 346 | rwsem_release(¤t->mm->mmap_sem.dep_map, 1, _RET_IP_); | ||
| 335 | } | 347 | } |
| 336 | } | 348 | } |
| 337 | 349 | ||
