summaryrefslogtreecommitdiffstats
path: root/kernel/bpf/stackmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/bpf/stackmap.c')
-rw-r--r--kernel/bpf/stackmap.c20
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);
278out: 281out:
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 = &current->mm->mmap_sem; 339 work->sem = &current->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(&current->mm->mmap_sem.dep_map, 1, _RET_IP_);
335 } 347 }
336} 348}
337 349