Commit 342528ff authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'uml-for-linus-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux

Pull uml updates from Richard Weinberger:

 - Make stub data pages configurable

 - Make it harder to mix user and kernel code by accident

* tag 'uml-for-linus-6.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/uml/linux:
  um: make stub data pages size tweakable
  um: prevent user code in modules
  um: further clean up user_syms
  um: don't export printf()
  um: hostfs: define our own API boundary
  um: add __weak for exported functions
parents 9f269232 6032aca0
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
#define STUB_START stub_start #define STUB_START stub_start
#define STUB_CODE STUB_START #define STUB_CODE STUB_START
#define STUB_DATA (STUB_CODE + UM_KERN_PAGE_SIZE) #define STUB_DATA (STUB_CODE + UM_KERN_PAGE_SIZE)
#define STUB_END (STUB_DATA + UM_KERN_PAGE_SIZE) #define STUB_DATA_PAGES 1 /* must be a power of two */
#define STUB_END (STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE)
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
......
...@@ -24,11 +24,12 @@ ...@@ -24,11 +24,12 @@
void __attribute__ ((__section__ (".__syscall_stub"))) void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void) stub_clone_handler(void)
{ {
struct stub_data *data = get_stub_page(); struct stub_data *data = get_stub_data();
long err; long err;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
(unsigned long)data + UM_KERN_PAGE_SIZE / 2); (unsigned long)data +
STUB_DATA_PAGES * UM_KERN_PAGE_SIZE / 2);
if (err) { if (err) {
data->parent_err = err; data->parent_err = err;
goto done; goto done;
......
...@@ -21,7 +21,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) ...@@ -21,7 +21,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
unsigned long stack = 0; unsigned long stack = 0;
int ret = -ENOMEM; int ret = -ENOMEM;
stack = get_zeroed_page(GFP_KERNEL); stack = __get_free_pages(GFP_KERNEL | __GFP_ZERO, ilog2(STUB_DATA_PAGES));
if (stack == 0) if (stack == 0)
goto out; goto out;
...@@ -52,7 +52,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) ...@@ -52,7 +52,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
out_free: out_free:
if (to_mm->id.stack != 0) if (to_mm->id.stack != 0)
free_page(to_mm->id.stack); free_pages(to_mm->id.stack, ilog2(STUB_DATA_PAGES));
out: out:
return ret; return ret;
} }
...@@ -74,6 +74,6 @@ void destroy_context(struct mm_struct *mm) ...@@ -74,6 +74,6 @@ void destroy_context(struct mm_struct *mm)
} }
os_kill_ptraced_process(mmu->id.u.pid, 1); os_kill_ptraced_process(mmu->id.u.pid, 1);
free_page(mmu->id.stack); free_pages(mmu->id.stack, ilog2(STUB_DATA_PAGES));
free_ldt(mmu); free_ldt(mmu);
} }
...@@ -326,9 +326,13 @@ int __init linux_main(int argc, char **argv) ...@@ -326,9 +326,13 @@ int __init linux_main(int argc, char **argv)
add_arg(DEFAULT_COMMAND_LINE_CONSOLE); add_arg(DEFAULT_COMMAND_LINE_CONSOLE);
host_task_size = os_get_top_address(); host_task_size = os_get_top_address();
/* reserve two pages for the stubs */ /* reserve a few pages for the stubs (taking care of data alignment) */
host_task_size -= 2 * PAGE_SIZE; /* align the data portion */
stub_start = host_task_size; BUILD_BUG_ON(!is_power_of_2(STUB_DATA_PAGES));
stub_start = (host_task_size - 1) & ~(STUB_DATA_PAGES * PAGE_SIZE - 1);
/* another page for the code portion */
stub_start -= PAGE_SIZE;
host_task_size = stub_start;
/* /*
* TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps * TASK_SIZE needs to be PGDIR_SIZE aligned or else exit_mmap craps
......
...@@ -262,7 +262,7 @@ static int userspace_tramp(void *stack) ...@@ -262,7 +262,7 @@ static int userspace_tramp(void *stack)
if (stack != NULL) { if (stack != NULL) {
fd = phys_mapping(uml_to_phys(stack), &offset); fd = phys_mapping(uml_to_phys(stack), &offset);
addr = mmap((void *) STUB_DATA, addr = mmap((void *) STUB_DATA,
UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fd, offset); MAP_FIXED | MAP_SHARED, fd, offset);
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n", printk(UM_KERN_ERR "mapping segfault stack at 0x%lx failed, errno = %d\n",
...@@ -277,7 +277,7 @@ static int userspace_tramp(void *stack) ...@@ -277,7 +277,7 @@ static int userspace_tramp(void *stack)
(unsigned long) stub_segv_handler - (unsigned long) stub_segv_handler -
(unsigned long) __syscall_stub_start; (unsigned long) __syscall_stub_start;
set_sigstack((void *) STUB_DATA, UM_KERN_PAGE_SIZE); set_sigstack((void *) STUB_DATA, STUB_DATA_PAGES * UM_KERN_PAGE_SIZE);
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO; sa.sa_flags = SA_ONSTACK | SA_NODEFER | SA_SIGINFO;
sa.sa_sigaction = (void *) v; sa.sa_sigaction = (void *) v;
...@@ -515,7 +515,7 @@ static int __init init_thread_regs(void) ...@@ -515,7 +515,7 @@ static int __init init_thread_regs(void)
thread_regs[REGS_IP_INDEX] = STUB_CODE + thread_regs[REGS_IP_INDEX] = STUB_CODE +
(unsigned long) stub_clone_handler - (unsigned long) stub_clone_handler -
(unsigned long) __syscall_stub_start; (unsigned long) __syscall_stub_start;
thread_regs[REGS_SP_INDEX] = STUB_DATA + UM_KERN_PAGE_SIZE - thread_regs[REGS_SP_INDEX] = STUB_DATA + STUB_DATA_PAGES * UM_KERN_PAGE_SIZE -
sizeof(void *); sizeof(void *);
#ifdef __SIGNAL_FRAMESIZE #ifdef __SIGNAL_FRAMESIZE
thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE; thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
......
...@@ -3,112 +3,40 @@ ...@@ -3,112 +3,40 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/module.h>
/* Some of this are builtin function (some are not but could in the future), /*
* so I *must* declare good prototypes for them and then EXPORT them. * This file exports some critical string functions and compiler
* The kernel code uses the macro defined by include/linux/string.h, * built-in functions (where calls are emitted by the compiler
* so I undef macros; the userspace code does not include that and I * itself that we cannot avoid even in kernel code) to modules.
* add an EXPORT for the glibc one. *
* "_user.c" code that previously used exports here such as hostfs
* really should be considered part of the 'hypervisor' and define
* its own API boundary like hostfs does now; don't add exports to
* this file for such cases.
*/ */
#undef strlen
#undef strstr
#undef memcpy
#undef memset
extern size_t strlen(const char *);
extern void *memmove(void *, const void *, size_t);
extern void *memset(void *, int, size_t);
extern int printf(const char *, ...);
/* If it's not defined, the export is included in lib/string.c.*/ /* If it's not defined, the export is included in lib/string.c.*/
#ifdef __HAVE_ARCH_STRSTR #ifdef __HAVE_ARCH_STRSTR
#undef strstr
EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(strstr);
#endif #endif
#ifndef __x86_64__ #ifndef __x86_64__
#undef memcpy
extern void *memcpy(void *, const void *, size_t); extern void *memcpy(void *, const void *, size_t);
EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memcpy);
extern void *memmove(void *, const void *, size_t);
EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(memmove);
#undef memset
extern void *memset(void *, int, size_t);
EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memset);
#endif #endif
EXPORT_SYMBOL(printf);
/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
* However, the modules will use the CRC defined *here*, no matter if it is
* good; so the versions of these symbols will always match
*/
#define EXPORT_SYMBOL_PROTO(sym) \
int sym(void); \
EXPORT_SYMBOL(sym);
extern void readdir64(void) __attribute__((weak));
EXPORT_SYMBOL(readdir64);
extern void truncate64(void) __attribute__((weak));
EXPORT_SYMBOL(truncate64);
#ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA
/* needed for __access_ok() */
EXPORT_SYMBOL(vsyscall_ehdr); EXPORT_SYMBOL(vsyscall_ehdr);
EXPORT_SYMBOL(vsyscall_end); EXPORT_SYMBOL(vsyscall_end);
#endif #endif
EXPORT_SYMBOL_PROTO(__errno_location);
EXPORT_SYMBOL_PROTO(access);
EXPORT_SYMBOL_PROTO(open);
EXPORT_SYMBOL_PROTO(open64);
EXPORT_SYMBOL_PROTO(close);
EXPORT_SYMBOL_PROTO(read);
EXPORT_SYMBOL_PROTO(write);
EXPORT_SYMBOL_PROTO(dup2);
EXPORT_SYMBOL_PROTO(__xstat);
EXPORT_SYMBOL_PROTO(__lxstat);
EXPORT_SYMBOL_PROTO(__lxstat64);
EXPORT_SYMBOL_PROTO(__fxstat64);
EXPORT_SYMBOL_PROTO(lseek);
EXPORT_SYMBOL_PROTO(lseek64);
EXPORT_SYMBOL_PROTO(chown);
EXPORT_SYMBOL_PROTO(fchown);
EXPORT_SYMBOL_PROTO(truncate);
EXPORT_SYMBOL_PROTO(ftruncate64);
EXPORT_SYMBOL_PROTO(utime);
EXPORT_SYMBOL_PROTO(utimes);
EXPORT_SYMBOL_PROTO(futimes);
EXPORT_SYMBOL_PROTO(chmod);
EXPORT_SYMBOL_PROTO(fchmod);
EXPORT_SYMBOL_PROTO(rename);
EXPORT_SYMBOL_PROTO(__xmknod);
EXPORT_SYMBOL_PROTO(symlink);
EXPORT_SYMBOL_PROTO(link);
EXPORT_SYMBOL_PROTO(unlink);
EXPORT_SYMBOL_PROTO(readlink);
EXPORT_SYMBOL_PROTO(mkdir);
EXPORT_SYMBOL_PROTO(rmdir);
EXPORT_SYMBOL_PROTO(opendir);
EXPORT_SYMBOL_PROTO(readdir);
EXPORT_SYMBOL_PROTO(closedir);
EXPORT_SYMBOL_PROTO(seekdir);
EXPORT_SYMBOL_PROTO(telldir);
EXPORT_SYMBOL_PROTO(ioctl);
EXPORT_SYMBOL_PROTO(pread64);
EXPORT_SYMBOL_PROTO(pwrite64);
EXPORT_SYMBOL_PROTO(statfs);
EXPORT_SYMBOL_PROTO(statfs64);
EXPORT_SYMBOL_PROTO(getuid);
EXPORT_SYMBOL_PROTO(fsync);
EXPORT_SYMBOL_PROTO(fdatasync);
EXPORT_SYMBOL_PROTO(lstat64);
EXPORT_SYMBOL_PROTO(fstat64);
EXPORT_SYMBOL_PROTO(mknod);
/* Export symbols used by GCC for the stack protector. */ /* Export symbols used by GCC for the stack protector. */
extern void __stack_smash_handler(void *) __attribute__((weak)); extern void __stack_smash_handler(void *) __attribute__((weak));
EXPORT_SYMBOL(__stack_smash_handler); EXPORT_SYMBOL(__stack_smash_handler);
...@@ -117,6 +45,6 @@ extern long __guard __attribute__((weak)); ...@@ -117,6 +45,6 @@ extern long __guard __attribute__((weak));
EXPORT_SYMBOL(__guard); EXPORT_SYMBOL(__guard);
#ifdef _FORTIFY_SOURCE #ifdef _FORTIFY_SOURCE
extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); extern int __sprintf_chk(char *str, int flag, size_t len, const char *format);
EXPORT_SYMBOL(__sprintf_chk); EXPORT_SYMBOL(__sprintf_chk);
#endif #endif
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
# =========================================================================== # ===========================================================================
USER_SINGLE_OBJS := \ USER_SINGLE_OBJS := \
$(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs))
USER_OBJS += $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) USER_OBJS += $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS))
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS:.o=.%): \ $(USER_OBJS:.o=.%): \
......
...@@ -89,19 +89,19 @@ static inline void remap_stack_and_trap(void) ...@@ -89,19 +89,19 @@ static inline void remap_stack_and_trap(void)
"addl %4,%%ebx ; movl %%eax, (%%ebx) ;" "addl %4,%%ebx ; movl %%eax, (%%ebx) ;"
"int $3" "int $3"
: : : :
"g" (~(UM_KERN_PAGE_SIZE - 1)), "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)),
"g" (STUB_MMAP_NR), "g" (STUB_MMAP_NR),
"g" (UML_STUB_FIELD_FD), "g" (UML_STUB_FIELD_FD),
"g" (UML_STUB_FIELD_OFFSET), "g" (UML_STUB_FIELD_OFFSET),
"g" (UML_STUB_FIELD_CHILD_ERR), "g" (UML_STUB_FIELD_CHILD_ERR),
"c" (UM_KERN_PAGE_SIZE), "c" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE),
"d" (PROT_READ | PROT_WRITE), "d" (PROT_READ | PROT_WRITE),
"S" (MAP_FIXED | MAP_SHARED) "S" (MAP_FIXED | MAP_SHARED)
: :
"memory"); "memory");
} }
static __always_inline void *get_stub_page(void) static __always_inline void *get_stub_data(void)
{ {
unsigned long ret; unsigned long ret;
...@@ -109,7 +109,7 @@ static __always_inline void *get_stub_page(void) ...@@ -109,7 +109,7 @@ static __always_inline void *get_stub_page(void)
"movl %%esp,%0 ;" "movl %%esp,%0 ;"
"andl %1,%0" "andl %1,%0"
: "=a" (ret) : "=a" (ret)
: "g" (~(UM_KERN_PAGE_SIZE - 1))); : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)));
return (void *)ret; return (void *)ret;
} }
......
...@@ -98,18 +98,18 @@ static inline void remap_stack_and_trap(void) ...@@ -98,18 +98,18 @@ static inline void remap_stack_and_trap(void)
"int3" "int3"
: : : :
"g" (STUB_MMAP_NR), "g" (STUB_MMAP_NR),
"g" (~(UM_KERN_PAGE_SIZE - 1)), "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)),
"g" (MAP_FIXED | MAP_SHARED), "g" (MAP_FIXED | MAP_SHARED),
"g" (UML_STUB_FIELD_FD), "g" (UML_STUB_FIELD_FD),
"g" (UML_STUB_FIELD_OFFSET), "g" (UML_STUB_FIELD_OFFSET),
"g" (UML_STUB_FIELD_CHILD_ERR), "g" (UML_STUB_FIELD_CHILD_ERR),
"S" (UM_KERN_PAGE_SIZE), "S" (STUB_DATA_PAGES * UM_KERN_PAGE_SIZE),
"d" (PROT_READ | PROT_WRITE) "d" (PROT_READ | PROT_WRITE)
: :
__syscall_clobber, "r10", "r8", "r9"); __syscall_clobber, "r10", "r8", "r9");
} }
static __always_inline void *get_stub_page(void) static __always_inline void *get_stub_data(void)
{ {
unsigned long ret; unsigned long ret;
...@@ -117,7 +117,7 @@ static __always_inline void *get_stub_page(void) ...@@ -117,7 +117,7 @@ static __always_inline void *get_stub_page(void)
"movq %%rsp,%0 ;" "movq %%rsp,%0 ;"
"andq %1,%0" "andq %1,%0"
: "=a" (ret) : "=a" (ret)
: "g" (~(UM_KERN_PAGE_SIZE - 1))); : "g" (~(STUB_DATA_PAGES * UM_KERN_PAGE_SIZE - 1)));
return (void *)ret; return (void *)ret;
} }
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
void __attribute__ ((__section__ (".__syscall_stub"))) void __attribute__ ((__section__ (".__syscall_stub")))
stub_segv_handler(int sig, siginfo_t *info, void *p) stub_segv_handler(int sig, siginfo_t *info, void *p)
{ {
struct faultinfo *f = get_stub_page(); struct faultinfo *f = get_stub_data();
ucontext_t *uc = p; ucontext_t *uc = p;
GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext); GET_FAULTINFO_FROM_MC(*f, &uc->uc_mcontext);
......
...@@ -123,7 +123,7 @@ obj-$(CONFIG_9P_FS) += 9p/ ...@@ -123,7 +123,7 @@ obj-$(CONFIG_9P_FS) += 9p/
obj-$(CONFIG_AFS_FS) += afs/ obj-$(CONFIG_AFS_FS) += afs/
obj-$(CONFIG_NILFS2_FS) += nilfs2/ obj-$(CONFIG_NILFS2_FS) += nilfs2/
obj-$(CONFIG_BEFS_FS) += befs/ obj-$(CONFIG_BEFS_FS) += befs/
obj-$(CONFIG_HOSTFS) += hostfs/ obj-y += hostfs/
obj-$(CONFIG_CACHEFILES) += cachefiles/ obj-$(CONFIG_CACHEFILES) += cachefiles/
obj-$(CONFIG_DEBUG_FS) += debugfs/ obj-$(CONFIG_DEBUG_FS) += debugfs/
obj-$(CONFIG_TRACING) += tracefs/ obj-$(CONFIG_TRACING) += tracefs/
......
...@@ -3,9 +3,11 @@ ...@@ -3,9 +3,11 @@
# Licensed under the GPL # Licensed under the GPL
# #
hostfs-objs := hostfs_kern.o hostfs_user.o hostfs-objs := hostfs_kern.o
obj-y := hostfs-builtin-$(CONFIG_HOSTFS) += hostfs_user.o hostfs_user_exp.o
obj-y := $(hostfs-builtin-y) $(hostfs-builtin-m)
obj-$(CONFIG_HOSTFS) += hostfs.o obj-$(CONFIG_HOSTFS) += hostfs.o
include $(srctree)/arch/um/scripts/Makefile.rules include $(srctree)/arch/um/scripts/Makefile.rules
#include <linux/module.h>
#include "hostfs.h"
EXPORT_SYMBOL_GPL(stat_file);
EXPORT_SYMBOL_GPL(access_file);
EXPORT_SYMBOL_GPL(open_file);
EXPORT_SYMBOL_GPL(open_dir);
EXPORT_SYMBOL_GPL(seek_dir);
EXPORT_SYMBOL_GPL(read_dir);
EXPORT_SYMBOL_GPL(read_file);
EXPORT_SYMBOL_GPL(write_file);
EXPORT_SYMBOL_GPL(lseek_file);
EXPORT_SYMBOL_GPL(fsync_file);
EXPORT_SYMBOL_GPL(replace_file);
EXPORT_SYMBOL_GPL(close_file);
EXPORT_SYMBOL_GPL(close_dir);
EXPORT_SYMBOL_GPL(file_create);
EXPORT_SYMBOL_GPL(set_attr);
EXPORT_SYMBOL_GPL(make_symlink);
EXPORT_SYMBOL_GPL(unlink_file);
EXPORT_SYMBOL_GPL(do_mkdir);
EXPORT_SYMBOL_GPL(hostfs_do_rmdir);
EXPORT_SYMBOL_GPL(do_mknod);
EXPORT_SYMBOL_GPL(link_file);
EXPORT_SYMBOL_GPL(hostfs_do_readlink);
EXPORT_SYMBOL_GPL(rename_file);
EXPORT_SYMBOL_GPL(rename2_file);
EXPORT_SYMBOL_GPL(do_statfs);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment