Skip to content

Commit 76ed915

Browse files
benzeajmberg-intel
authored andcommitted
um: Rework syscall handling
Rework syscall handling to be platform independent. Also create a clean split between queueing of syscalls and flushing them out, removing the need to keep state in the code that triggers the syscalls. The code adds syscall_data_len to the global mm_id structure. This will be used later to allow surrounding code to track whether syscalls still need to run and if errors occurred. Signed-off-by: Benjamin Berg <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Johannes Berg <[email protected]>
1 parent 542dc79 commit 76ed915

File tree

16 files changed

+274
-297
lines changed

16 files changed

+274
-297
lines changed

arch/um/include/shared/os.h

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -272,19 +272,15 @@ extern long long os_persistent_clock_emulation(void);
272272
extern long long os_nsecs(void);
273273

274274
/* skas/mem.c */
275-
extern long run_syscall_stub(struct mm_id * mm_idp,
276-
int syscall, unsigned long *args, long expected,
277-
void **addr, int done);
278-
extern long syscall_stub_data(struct mm_id * mm_idp,
279-
unsigned long *data, int data_count,
280-
void **addr, void **stub_addr);
281-
extern int map(struct mm_id * mm_idp, unsigned long virt,
282-
unsigned long len, int prot, int phys_fd,
283-
unsigned long long offset, int done, void **data);
284-
extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
285-
int done, void **data);
286-
extern int protect(struct mm_id * mm_idp, unsigned long addr,
287-
unsigned long len, unsigned int prot, int done, void **data);
275+
int syscall_stub_flush(struct mm_id *mm_idp);
276+
struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp);
277+
278+
void map(struct mm_id *mm_idp, unsigned long virt,
279+
unsigned long len, int prot, int phys_fd,
280+
unsigned long long offset);
281+
void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len);
282+
void protect(struct mm_id *mm_idp, unsigned long addr,
283+
unsigned long len, unsigned int prot);
288284

289285
/* skas/process.c */
290286
extern int is_skas_winch(int pid, int fd, void *data);

arch/um/include/shared/skas/mm_id.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct mm_id {
1313
} u;
1414
unsigned long stack;
1515
int kill;
16+
int syscall_data_len;
1617
};
1718

1819
void __switch_mm(struct mm_id *mm_idp);

arch/um/include/shared/skas/stub-data.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,45 @@
1010

1111
#include <linux/compiler_types.h>
1212
#include <as-layout.h>
13+
#include <sysdep/tls.h>
14+
15+
#define STUB_NEXT_SYSCALL(s) \
16+
((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len))
17+
18+
enum stub_syscall_type {
19+
STUB_SYSCALL_UNSET = 0,
20+
STUB_SYSCALL_MMAP,
21+
STUB_SYSCALL_MUNMAP,
22+
STUB_SYSCALL_MPROTECT,
23+
STUB_SYSCALL_LDT,
24+
};
25+
26+
struct stub_syscall {
27+
union {
28+
struct {
29+
unsigned long addr;
30+
unsigned long length;
31+
unsigned long offset;
32+
int fd;
33+
int prot;
34+
} mem;
35+
struct {
36+
user_desc_t desc;
37+
int func;
38+
} ldt;
39+
};
40+
41+
enum stub_syscall_type syscall;
42+
};
1343

1444
struct stub_data {
1545
unsigned long offset;
1646
int fd;
17-
long parent_err, child_err;
47+
long err, child_err;
1848

49+
int syscall_data_len;
1950
/* 128 leaves enough room for additional fields in the struct */
20-
unsigned char syscall_data[UM_KERN_PAGE_SIZE - 128] __aligned(16);
51+
struct stub_syscall syscall_data[(UM_KERN_PAGE_SIZE - 128) / sizeof(struct stub_syscall)] __aligned(16);
2152

2253
/* Stack for our signal handlers and for calling into . */
2354
unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE);

arch/um/include/shared/user.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,19 @@ extern void panic(const char *fmt, ...)
4242
#define printk(...) _printk(__VA_ARGS__)
4343
extern int _printk(const char *fmt, ...)
4444
__attribute__ ((format (printf, 1, 2)));
45+
extern void print_hex_dump(const char *level, const char *prefix_str,
46+
int prefix_type, int rowsize, int groupsize,
47+
const void *buf, size_t len, _Bool ascii);
4548
#else
4649
static inline int printk(const char *fmt, ...)
4750
{
4851
return 0;
4952
}
53+
static inline void print_hex_dump(const char *level, const char *prefix_str,
54+
int prefix_type, int rowsize, int groupsize,
55+
const void *buf, size_t len, _Bool ascii)
56+
{
57+
}
5058
#endif
5159

5260
extern int in_aton(char *str);

arch/um/kernel/exec.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,11 @@
2222

2323
void flush_thread(void)
2424
{
25-
void *data = NULL;
26-
int ret;
27-
2825
arch_flush_thread(&current->thread.arch);
2926

30-
ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data);
31-
if (ret) {
32-
printk(KERN_ERR "%s - clearing address space failed, err = %d\n",
33-
__func__, ret);
27+
unmap(&current->mm->context.id, 0, TASK_SIZE);
28+
if (syscall_stub_flush(&current->mm->context.id) < 0) {
29+
printk(KERN_ERR "%s - clearing address space failed", __func__);
3430
force_sig(SIGKILL);
3531
}
3632
get_safe_registers(current_pt_regs()->regs.gp,

arch/um/kernel/skas/Makefile

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
44
#
55

6-
obj-y := clone.o mmu.o process.o syscall.o uaccess.o
6+
obj-y := clone.o stub.o mmu.o process.o syscall.o uaccess.o
77

8-
# clone.o is in the stub, so it can't be built with profiling
8+
# clone.o and stub.o are in the stub, so it can't be built with profiling
99
# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
1010
# disable it
1111

1212
CFLAGS_clone.o := $(CFLAGS_NO_HARDENING)
13-
UNPROFILE_OBJS := clone.o
13+
CFLAGS_stub.o := $(CFLAGS_NO_HARDENING)
14+
UNPROFILE_OBJS := clone.o stub.o
1415

1516
KCOV_INSTRUMENT := n
1617

arch/um/kernel/skas/clone.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ stub_clone_handler(void)
3333
sizeof(data->syscall_data) / 2 -
3434
sizeof(void *));
3535
if (err) {
36-
data->parent_err = err;
36+
data->err = err;
3737
goto done;
3838
}
3939

arch/um/kernel/skas/stub.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Copyright (C) 2021 Benjamin Berg <[email protected]>
4+
*/
5+
6+
#include <sysdep/stub.h>
7+
8+
static __always_inline int syscall_handler(struct stub_data *d)
9+
{
10+
int i;
11+
unsigned long res;
12+
13+
for (i = 0; i < d->syscall_data_len; i++) {
14+
struct stub_syscall *sc = &d->syscall_data[i];
15+
16+
switch (sc->syscall) {
17+
case STUB_SYSCALL_MMAP:
18+
res = stub_syscall6(STUB_MMAP_NR,
19+
sc->mem.addr, sc->mem.length,
20+
sc->mem.prot,
21+
MAP_SHARED | MAP_FIXED,
22+
sc->mem.fd, sc->mem.offset);
23+
if (res != sc->mem.addr) {
24+
d->err = res;
25+
d->syscall_data_len = i;
26+
return -1;
27+
}
28+
break;
29+
case STUB_SYSCALL_MUNMAP:
30+
res = stub_syscall2(__NR_munmap,
31+
sc->mem.addr, sc->mem.length);
32+
if (res) {
33+
d->err = res;
34+
d->syscall_data_len = i;
35+
return -1;
36+
}
37+
break;
38+
case STUB_SYSCALL_MPROTECT:
39+
res = stub_syscall3(__NR_mprotect,
40+
sc->mem.addr, sc->mem.length,
41+
sc->mem.prot);
42+
if (res) {
43+
d->err = res;
44+
d->syscall_data_len = i;
45+
return -1;
46+
}
47+
break;
48+
case STUB_SYSCALL_LDT:
49+
res = stub_syscall3(__NR_modify_ldt, sc->ldt.func,
50+
(unsigned long) &sc->ldt.desc,
51+
sizeof(sc->ldt.desc));
52+
/* We only write, so the expected result is zero */
53+
if (res) {
54+
d->err = res;
55+
d->syscall_data_len = i;
56+
return -1;
57+
}
58+
break;
59+
default:
60+
d->err = -95; /* EOPNOTSUPP */
61+
d->syscall_data_len = i;
62+
return -1;
63+
}
64+
}
65+
66+
d->err = 0;
67+
d->syscall_data_len = 0;
68+
69+
return 0;
70+
}
71+
72+
void __section(".__syscall_stub")
73+
stub_syscall_handler(void)
74+
{
75+
struct stub_data *d = get_stub_data();
76+
77+
syscall_handler(d);
78+
79+
trap_myself();
80+
}

arch/um/kernel/tlb.c

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,19 @@ static int do_ops(struct host_vm_change *hvc, int end,
7171
switch (op->type) {
7272
case MMAP:
7373
if (hvc->userspace)
74-
ret = map(&hvc->mm->context.id, op->u.mmap.addr,
75-
op->u.mmap.len, op->u.mmap.prot,
76-
op->u.mmap.fd,
77-
op->u.mmap.offset, finished,
78-
&hvc->data);
74+
map(&hvc->mm->context.id, op->u.mmap.addr,
75+
op->u.mmap.len, op->u.mmap.prot,
76+
op->u.mmap.fd,
77+
op->u.mmap.offset);
7978
else
8079
map_memory(op->u.mmap.addr, op->u.mmap.offset,
8180
op->u.mmap.len, 1, 1, 1);
8281
break;
8382
case MUNMAP:
8483
if (hvc->userspace)
85-
ret = unmap(&hvc->mm->context.id,
86-
op->u.munmap.addr,
87-
op->u.munmap.len, finished,
88-
&hvc->data);
84+
unmap(&hvc->mm->context.id,
85+
op->u.munmap.addr,
86+
op->u.munmap.len);
8987
else
9088
ret = os_unmap_memory(
9189
(void *) op->u.munmap.addr,
@@ -94,11 +92,10 @@ static int do_ops(struct host_vm_change *hvc, int end,
9492
break;
9593
case MPROTECT:
9694
if (hvc->userspace)
97-
ret = protect(&hvc->mm->context.id,
98-
op->u.mprotect.addr,
99-
op->u.mprotect.len,
100-
op->u.mprotect.prot,
101-
finished, &hvc->data);
95+
protect(&hvc->mm->context.id,
96+
op->u.mprotect.addr,
97+
op->u.mprotect.len,
98+
op->u.mprotect.prot);
10299
else
103100
ret = os_protect_memory(
104101
(void *) op->u.mprotect.addr,
@@ -113,6 +110,9 @@ static int do_ops(struct host_vm_change *hvc, int end,
113110
}
114111
}
115112

113+
if (hvc->userspace && finished)
114+
ret = syscall_stub_flush(&hvc->mm->context.id);
115+
116116
if (ret == -ENOMEM)
117117
report_enomem();
118118

@@ -461,7 +461,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
461461
pmd_t *pmd;
462462
pte_t *pte;
463463
struct mm_struct *mm = vma->vm_mm;
464-
void *flush = NULL;
465464
int r, w, x, prot, err = 0;
466465
struct mm_id *mm_id;
467466

@@ -504,14 +503,13 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
504503
int fd;
505504

506505
fd = phys_mapping(pte_val(*pte) & PAGE_MASK, &offset);
507-
err = map(mm_id, address, PAGE_SIZE, prot, fd, offset,
508-
1, &flush);
509-
}
510-
else err = unmap(mm_id, address, PAGE_SIZE, 1, &flush);
511-
}
512-
else if (pte_newprot(*pte))
513-
err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
506+
map(mm_id, address, PAGE_SIZE, prot, fd, offset);
507+
} else
508+
unmap(mm_id, address, PAGE_SIZE);
509+
} else if (pte_newprot(*pte))
510+
protect(mm_id, address, PAGE_SIZE, prot);
514511

512+
err = syscall_stub_flush(mm_id);
515513
if (err) {
516514
if (err == -ENOMEM)
517515
report_enomem();

0 commit comments

Comments
 (0)