Commit 76ed9158 authored by Benjamin Berg's avatar Benjamin Berg Committed by Johannes Berg
Browse files

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: default avatarBenjamin Berg <benjamin@sipsolutions.net>
Link: https://patch.msgid.link/20240703134536.1161108-5-benjamin@sipsolutions.net


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 542dc79f
Loading
Loading
Loading
Loading
+9 −13
Original line number Diff line number Diff line
@@ -272,19 +272,15 @@ extern long long os_persistent_clock_emulation(void);
extern long long os_nsecs(void);

/* skas/mem.c */
extern long run_syscall_stub(struct mm_id * mm_idp,
			     int syscall, unsigned long *args, long expected,
			     void **addr, int done);
extern long syscall_stub_data(struct mm_id * mm_idp,
			      unsigned long *data, int data_count,
			      void **addr, void **stub_addr);
extern int map(struct mm_id * mm_idp, unsigned long virt,
int syscall_stub_flush(struct mm_id *mm_idp);
struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp);

void map(struct mm_id *mm_idp, unsigned long virt,
	 unsigned long len, int prot, int phys_fd,
	       unsigned long long offset, int done, void **data);
extern int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
		 int done, void **data);
extern int protect(struct mm_id * mm_idp, unsigned long addr,
		   unsigned long len, unsigned int prot, int done, void **data);
	 unsigned long long offset);
void unmap(struct mm_id *mm_idp, unsigned long addr, unsigned long len);
void protect(struct mm_id *mm_idp, unsigned long addr,
	     unsigned long len, unsigned int prot);

/* skas/process.c */
extern int is_skas_winch(int pid, int fd, void *data);
+1 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ struct mm_id {
	} u;
	unsigned long stack;
	int kill;
	int syscall_data_len;
};

void __switch_mm(struct mm_id *mm_idp);
+33 −2
Original line number Diff line number Diff line
@@ -10,14 +10,45 @@

#include <linux/compiler_types.h>
#include <as-layout.h>
#include <sysdep/tls.h>

#define STUB_NEXT_SYSCALL(s) \
	((struct stub_syscall *) (((unsigned long) s) + (s)->cmd_len))

enum stub_syscall_type {
	STUB_SYSCALL_UNSET = 0,
	STUB_SYSCALL_MMAP,
	STUB_SYSCALL_MUNMAP,
	STUB_SYSCALL_MPROTECT,
	STUB_SYSCALL_LDT,
};

struct stub_syscall {
	union {
		struct {
			unsigned long addr;
			unsigned long length;
			unsigned long offset;
			int fd;
			int prot;
		} mem;
		struct {
			user_desc_t desc;
			int func;
		} ldt;
	};

	enum stub_syscall_type syscall;
};

struct stub_data {
	unsigned long offset;
	int fd;
	long parent_err, child_err;
	long err, child_err;

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

	/* Stack for our signal handlers and for calling into . */
	unsigned char sigstack[UM_KERN_PAGE_SIZE] __aligned(UM_KERN_PAGE_SIZE);
+8 −0
Original line number Diff line number Diff line
@@ -42,11 +42,19 @@ extern void panic(const char *fmt, ...)
#define printk(...) _printk(__VA_ARGS__)
extern int _printk(const char *fmt, ...)
	__attribute__ ((format (printf, 1, 2)));
extern void print_hex_dump(const char *level, const char *prefix_str,
			   int prefix_type, int rowsize, int groupsize,
			   const void *buf, size_t len, _Bool ascii);
#else
static inline int printk(const char *fmt, ...)
{
	return 0;
}
static inline void print_hex_dump(const char *level, const char *prefix_str,
				  int prefix_type, int rowsize, int groupsize,
				  const void *buf, size_t len, _Bool ascii)
{
}
#endif

extern int in_aton(char *str);
+3 −7
Original line number Diff line number Diff line
@@ -22,15 +22,11 @@

void flush_thread(void)
{
	void *data = NULL;
	int ret;

	arch_flush_thread(&current->thread.arch);

	ret = unmap(&current->mm->context.id, 0, TASK_SIZE, 1, &data);
	if (ret) {
		printk(KERN_ERR "%s - clearing address space failed, err = %d\n",
		       __func__, ret);
	unmap(&current->mm->context.id, 0, TASK_SIZE);
	if (syscall_stub_flush(&current->mm->context.id) < 0) {
		printk(KERN_ERR "%s - clearing address space failed", __func__);
		force_sig(SIGKILL);
	}
	get_safe_registers(current_pt_regs()->regs.gp,
Loading