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 | ||