Skip to content

Commit b3d7fe8

Browse files
a-nogikhtorvalds
authored andcommitted
kcov: properly handle subsequent mmap calls
Allocate the kcov buffer during KCOV_MODE_INIT in order to untie mmapping of a kcov instance and the actual coverage collection process. Modify kcov_mmap, so that it can be reliably used any number of times once KCOV_MODE_INIT has succeeded. These changes to the user-facing interface of the tool only weaken the preconditions, so all existing user space code should remain compatible with the new version. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Aleksandr Nogikh <[email protected]> Reviewed-by: Dmitry Vyukov <[email protected]> Reviewed-by: Andrey Konovalov <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Marco Elver <[email protected]> Cc: Sebastian Andrzej Siewior <[email protected]> Cc: Taras Madan <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 17581aa commit b3d7fe8

File tree

1 file changed

+15
-19
lines changed

1 file changed

+15
-19
lines changed

kernel/kcov.c

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -459,37 +459,28 @@ void kcov_task_exit(struct task_struct *t)
459459
static int kcov_mmap(struct file *filep, struct vm_area_struct *vma)
460460
{
461461
int res = 0;
462-
void *area;
463462
struct kcov *kcov = vma->vm_file->private_data;
464463
unsigned long size, off;
465464
struct page *page;
466465
unsigned long flags;
467466

468-
area = vmalloc_user(vma->vm_end - vma->vm_start);
469-
if (!area)
470-
return -ENOMEM;
471-
472467
spin_lock_irqsave(&kcov->lock, flags);
473468
size = kcov->size * sizeof(unsigned long);
474-
if (kcov->mode != KCOV_MODE_INIT || vma->vm_pgoff != 0 ||
469+
if (kcov->area == NULL || vma->vm_pgoff != 0 ||
475470
vma->vm_end - vma->vm_start != size) {
476471
res = -EINVAL;
477472
goto exit;
478473
}
479-
if (!kcov->area) {
480-
kcov->area = area;
481-
vma->vm_flags |= VM_DONTEXPAND;
482-
spin_unlock_irqrestore(&kcov->lock, flags);
483-
for (off = 0; off < size; off += PAGE_SIZE) {
484-
page = vmalloc_to_page(kcov->area + off);
485-
if (vm_insert_page(vma, vma->vm_start + off, page))
486-
WARN_ONCE(1, "vm_insert_page() failed");
487-
}
488-
return 0;
474+
spin_unlock_irqrestore(&kcov->lock, flags);
475+
vma->vm_flags |= VM_DONTEXPAND;
476+
for (off = 0; off < size; off += PAGE_SIZE) {
477+
page = vmalloc_to_page(kcov->area + off);
478+
if (vm_insert_page(vma, vma->vm_start + off, page))
479+
WARN_ONCE(1, "vm_insert_page() failed");
489480
}
481+
return 0;
490482
exit:
491483
spin_unlock_irqrestore(&kcov->lock, flags);
492-
vfree(area);
493484
return res;
494485
}
495486

@@ -674,6 +665,7 @@ static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
674665
unsigned int remote_num_handles;
675666
unsigned long remote_arg_size;
676667
unsigned long size, flags;
668+
void *area;
677669

678670
kcov = filep->private_data;
679671
switch (cmd) {
@@ -683,17 +675,21 @@ static long kcov_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
683675
* Must happen before anything else.
684676
*
685677
* First check the size argument - it must be at least 2
686-
* to hold the current position and one PC. Later we allocate
687-
* size * sizeof(unsigned long) memory, that must not overflow.
678+
* to hold the current position and one PC.
688679
*/
689680
size = arg;
690681
if (size < 2 || size > INT_MAX / sizeof(unsigned long))
691682
return -EINVAL;
683+
area = vmalloc_user(size * sizeof(unsigned long));
684+
if (area == NULL)
685+
return -ENOMEM;
692686
spin_lock_irqsave(&kcov->lock, flags);
693687
if (kcov->mode != KCOV_MODE_DISABLED) {
694688
spin_unlock_irqrestore(&kcov->lock, flags);
689+
vfree(area);
695690
return -EBUSY;
696691
}
692+
kcov->area = area;
697693
kcov->size = size;
698694
kcov->mode = KCOV_MODE_INIT;
699695
spin_unlock_irqrestore(&kcov->lock, flags);

0 commit comments

Comments
 (0)