Skip to content

Commit 51104c1

Browse files
keesshuahkh
authored andcommitted
kunit: test: Add vm_mmap() allocation resource manager
For tests that need to allocate using vm_mmap() (e.g. usercopy and execve), provide the interface to have the allocation tracked by KUnit itself. This requires bringing up a placeholder userspace mm. This combines my earlier attempt at this with Mark Rutland's version[1]. Normally alloc_mm() and arch_pick_mmap_layout() aren't exported for modules, so export these only for KUnit testing. Link: https://lore.kernel.org/lkml/20230321122514.1743889-2-mark.rutland@arm.com/ [1] Co-developed-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: David Gow <davidgow@google.com> Signed-off-by: Kees Cook <kees@kernel.org> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
1 parent 425ae3a commit 51104c1

File tree

5 files changed

+137
-0
lines changed

5 files changed

+137
-0
lines changed

include/kunit/test.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,23 @@ static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp
480480
return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO);
481481
}
482482

483+
/**
484+
* kunit_vm_mmap() - Allocate KUnit-tracked vm_mmap() area
485+
* @test: The test context object.
486+
* @file: struct file pointer to map from, if any
487+
* @addr: desired address, if any
488+
* @len: how many bytes to allocate
489+
* @prot: mmap PROT_* bits
490+
* @flag: mmap flags
491+
* @offset: offset into @file to start mapping from.
492+
*
493+
* See vm_mmap() for more information.
494+
*/
495+
unsigned long kunit_vm_mmap(struct kunit *test, struct file *file,
496+
unsigned long addr, unsigned long len,
497+
unsigned long prot, unsigned long flag,
498+
unsigned long offset);
499+
483500
void kunit_cleanup(struct kunit *test);
484501

485502
void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...);

kernel/fork.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@
115115
#define CREATE_TRACE_POINTS
116116
#include <trace/events/task.h>
117117

118+
#include <kunit/visibility.h>
119+
118120
/*
119121
* Minimum number of threads to boot the kernel
120122
*/
@@ -1334,6 +1336,7 @@ struct mm_struct *mm_alloc(void)
13341336
memset(mm, 0, sizeof(*mm));
13351337
return mm_init(mm, current, current_user_ns());
13361338
}
1339+
EXPORT_SYMBOL_IF_KUNIT(mm_alloc);
13371340

13381341
static inline void __mmput(struct mm_struct *mm)
13391342
{

lib/kunit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ obj-$(CONFIG_KUNIT) += kunit.o
22

33
kunit-objs += test.o \
44
resource.o \
5+
user_alloc.o \
56
static_stub.o \
67
string-stream.o \
78
assert.o \

lib/kunit/user_alloc.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* KUnit userspace memory allocation resource management.
4+
*/
5+
#include <kunit/resource.h>
6+
#include <kunit/test.h>
7+
#include <linux/kthread.h>
8+
#include <linux/mm.h>
9+
10+
struct kunit_vm_mmap_resource {
11+
unsigned long addr;
12+
size_t size;
13+
};
14+
15+
/* vm_mmap() arguments */
16+
struct kunit_vm_mmap_params {
17+
struct file *file;
18+
unsigned long addr;
19+
unsigned long len;
20+
unsigned long prot;
21+
unsigned long flag;
22+
unsigned long offset;
23+
};
24+
25+
/* Create and attach a new mm if it doesn't already exist. */
26+
static int kunit_attach_mm(void)
27+
{
28+
struct mm_struct *mm;
29+
30+
if (current->mm)
31+
return 0;
32+
33+
mm = mm_alloc();
34+
if (!mm)
35+
return -ENOMEM;
36+
37+
/* Define the task size. */
38+
mm->task_size = TASK_SIZE;
39+
40+
/* Make sure we can allocate new VMAs. */
41+
arch_pick_mmap_layout(mm, &current->signal->rlim[RLIMIT_STACK]);
42+
43+
/* Attach the mm. It will be cleaned up when the process dies. */
44+
kthread_use_mm(mm);
45+
46+
return 0;
47+
}
48+
49+
static int kunit_vm_mmap_init(struct kunit_resource *res, void *context)
50+
{
51+
struct kunit_vm_mmap_params *p = context;
52+
struct kunit_vm_mmap_resource vres;
53+
int ret;
54+
55+
ret = kunit_attach_mm();
56+
if (ret)
57+
return ret;
58+
59+
vres.size = p->len;
60+
vres.addr = vm_mmap(p->file, p->addr, p->len, p->prot, p->flag, p->offset);
61+
if (!vres.addr)
62+
return -ENOMEM;
63+
res->data = kmemdup(&vres, sizeof(vres), GFP_KERNEL);
64+
if (!res->data) {
65+
vm_munmap(vres.addr, vres.size);
66+
return -ENOMEM;
67+
}
68+
69+
return 0;
70+
}
71+
72+
static void kunit_vm_mmap_free(struct kunit_resource *res)
73+
{
74+
struct kunit_vm_mmap_resource *vres = res->data;
75+
76+
/*
77+
* Since this is executed from the test monitoring process,
78+
* the test's mm has already been torn down. We don't need
79+
* to run vm_munmap(vres->addr, vres->size), only clean up
80+
* the vres.
81+
*/
82+
83+
kfree(vres);
84+
res->data = NULL;
85+
}
86+
87+
unsigned long kunit_vm_mmap(struct kunit *test, struct file *file,
88+
unsigned long addr, unsigned long len,
89+
unsigned long prot, unsigned long flag,
90+
unsigned long offset)
91+
{
92+
struct kunit_vm_mmap_params params = {
93+
.file = file,
94+
.addr = addr,
95+
.len = len,
96+
.prot = prot,
97+
.flag = flag,
98+
.offset = offset,
99+
};
100+
struct kunit_vm_mmap_resource *vres;
101+
102+
vres = kunit_alloc_resource(test,
103+
kunit_vm_mmap_init,
104+
kunit_vm_mmap_free,
105+
GFP_KERNEL,
106+
&params);
107+
if (vres)
108+
return vres->addr;
109+
return 0;
110+
}
111+
EXPORT_SYMBOL_GPL(kunit_vm_mmap);
112+
113+
MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);

mm/util.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
#include <linux/uaccess.h>
2828

29+
#include <kunit/visibility.h>
30+
2931
#include "internal.h"
3032
#include "swap.h"
3133

@@ -482,6 +484,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm, struct rlimit *rlim_stack)
482484
clear_bit(MMF_TOPDOWN, &mm->flags);
483485
}
484486
#endif
487+
EXPORT_SYMBOL_IF_KUNIT(arch_pick_mmap_layout);
485488

486489
/**
487490
* __account_locked_vm - account locked pages to an mm's locked_vm

0 commit comments

Comments
 (0)