Commit 21dc2e6c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml

Pull UML updates from Richard Weinberger:

 - remove hppfs ("HonePot ProcFS")

 - initial support for musl libc

 - uaccess cleanup

 - random cleanups and bug fixes all over the place

* 'for-linus-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: (21 commits)
  um: Don't pollute kernel namespace with uapi
  um: Include sys/types.h for makedev(), major(), minor()
  um: Do not use stdin and stdout identifiers for struct members
  um: Do not use __ptr_t type for stack_t's .ss pointer
  um: Fix mconsole dependency
  um: Handle tracehook_report_syscall_entry() result
  um: Remove copy&paste code from init.h
  um: Stop abusing __KERNEL__
  um: Catch unprotected user memory access
  um: Fix warning in setup_signal_stack_si()
  um: Rework uaccess code
  um: Add uaccess.h to ldt.c
  um: Add uaccess.h to syscalls_64.c
  um: Add asm/elf.h to vma.c
  um: Cleanup mem_32/64.c headers
  um: Remove hppfs
  um: Move syscall() declaration into os.h
  um: kernel: ksyms: Export symbol syscall() for fixing modpost issue
  um/os-Linux: Use char[] for syscall_stub declarations
  um: Use char[] for linker script address declarations
  ...
parents b779157d da028d5e
...@@ -44,23 +44,9 @@ config HOSTFS ...@@ -44,23 +44,9 @@ config HOSTFS
If you'd like to be able to work with files stored on the host, If you'd like to be able to work with files stored on the host,
say Y or M here; otherwise say N. say Y or M here; otherwise say N.
config HPPFS
tristate "HoneyPot ProcFS"
depends on PROC_FS
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
Its purpose is to allow a UML to appear to be a physical machine
by removing or changing anything in /proc which gives away the
identity of a UML.
See <http://user-mode-linux.sf.net/old/hppfs.html> for more information.
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
config MCONSOLE config MCONSOLE
bool "Management console" bool "Management console"
depends on PROC_FS
default y default y
help help
The user mode linux management console is a low-level interface to The user mode linux management console is a low-level interface to
......
...@@ -68,9 +68,10 @@ KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \ ...@@ -68,9 +68,10 @@ KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ \
KBUILD_AFLAGS += $(ARCH_INCLUDE) KBUILD_AFLAGS += $(ARCH_INCLUDE)
USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -D__KERNEL__,,\ USER_CFLAGS = $(patsubst $(KERNEL_DEFINES),,$(patsubst -I%,,$(KBUILD_CFLAGS))) \
$(patsubst -I%,,$(KBUILD_CFLAGS)))) $(ARCH_INCLUDE) $(MODE_INCLUDE) \ $(ARCH_INCLUDE) $(MODE_INCLUDE) $(filter -I%,$(CFLAGS)) \
$(filter -I%,$(CFLAGS)) -D_FILE_OFFSET_BITS=64 -idirafter include -D_FILE_OFFSET_BITS=64 -idirafter include \
-D__KERNEL__ -D__UM_HOST__
#This will adjust *FLAGS accordingly to the platform. #This will adjust *FLAGS accordingly to the platform.
include $(ARCH_DIR)/Makefile-os-$(OS) include $(ARCH_DIR)/Makefile-os-$(OS)
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
#include <os.h> #include <os.h>
struct dog_data { struct dog_data {
int stdin; int stdin_fd;
int stdout; int stdout_fd;
int close_me[2]; int close_me[2];
}; };
...@@ -18,11 +18,11 @@ static void pre_exec(void *d) ...@@ -18,11 +18,11 @@ static void pre_exec(void *d)
{ {
struct dog_data *data = d; struct dog_data *data = d;
dup2(data->stdin, 0); dup2(data->stdin_fd, 0);
dup2(data->stdout, 1); dup2(data->stdout_fd, 1);
dup2(data->stdout, 2); dup2(data->stdout_fd, 2);
close(data->stdin); close(data->stdin_fd);
close(data->stdout); close(data->stdout_fd);
close(data->close_me[0]); close(data->close_me[0]);
close(data->close_me[1]); close(data->close_me[1]);
} }
...@@ -49,8 +49,8 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) ...@@ -49,8 +49,8 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock)
goto out_close_in; goto out_close_in;
} }
data.stdin = out_fds[0]; data.stdin_fd = out_fds[0];
data.stdout = in_fds[1]; data.stdout_fd = in_fds[1];
data.close_me[0] = out_fds[1]; data.close_me[0] = out_fds[1];
data.close_me[1] = in_fds[0]; data.close_me[1] = in_fds[0];
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#ifndef __MCONSOLE_H__ #ifndef __MCONSOLE_H__
#define __MCONSOLE_H__ #define __MCONSOLE_H__
#ifndef __KERNEL__ #ifdef __UM_HOST__
#include <stdint.h> #include <stdint.h>
#define u32 uint32_t #define u32 uint32_t
#endif #endif
......
...@@ -166,7 +166,7 @@ int net_sendto(int fd, void *buf, int len, void *to, int sock_len) ...@@ -166,7 +166,7 @@ int net_sendto(int fd, void *buf, int len, void *to, int sock_len)
struct change_pre_exec_data { struct change_pre_exec_data {
int close_me; int close_me;
int stdout; int stdout_fd;
}; };
static void change_pre_exec(void *arg) static void change_pre_exec(void *arg)
...@@ -174,7 +174,7 @@ static void change_pre_exec(void *arg) ...@@ -174,7 +174,7 @@ static void change_pre_exec(void *arg)
struct change_pre_exec_data *data = arg; struct change_pre_exec_data *data = arg;
close(data->close_me); close(data->close_me);
dup2(data->stdout, 1); dup2(data->stdout_fd, 1);
} }
static int change_tramp(char **argv, char *output, int output_len) static int change_tramp(char **argv, char *output, int output_len)
...@@ -189,7 +189,7 @@ static int change_tramp(char **argv, char *output, int output_len) ...@@ -189,7 +189,7 @@ static int change_tramp(char **argv, char *output, int output_len)
return err; return err;
} }
pe_data.close_me = fds[0]; pe_data.close_me = fds[0];
pe_data.stdout = fds[1]; pe_data.stdout_fd = fds[1];
pid = run_helper(change_pre_exec, &pe_data, argv); pid = run_helper(change_pre_exec, &pe_data, argv);
if (pid > 0) /* Avoid hang as we won't get data in failure case. */ if (pid > 0) /* Avoid hang as we won't get data in failure case. */
......
...@@ -55,8 +55,8 @@ static int set_up_tty(int fd) ...@@ -55,8 +55,8 @@ static int set_up_tty(int fd)
} }
struct slip_pre_exec_data { struct slip_pre_exec_data {
int stdin; int stdin_fd;
int stdout; int stdout_fd;
int close_me; int close_me;
}; };
...@@ -64,9 +64,9 @@ static void slip_pre_exec(void *arg) ...@@ -64,9 +64,9 @@ static void slip_pre_exec(void *arg)
{ {
struct slip_pre_exec_data *data = arg; struct slip_pre_exec_data *data = arg;
if (data->stdin >= 0) if (data->stdin_fd >= 0)
dup2(data->stdin, 0); dup2(data->stdin_fd, 0);
dup2(data->stdout, 1); dup2(data->stdout_fd, 1);
if (data->close_me >= 0) if (data->close_me >= 0)
close(data->close_me); close(data->close_me);
} }
...@@ -85,8 +85,8 @@ static int slip_tramp(char **argv, int fd) ...@@ -85,8 +85,8 @@ static int slip_tramp(char **argv, int fd)
} }
err = 0; err = 0;
pe_data.stdin = fd; pe_data.stdin_fd = fd;
pe_data.stdout = fds[1]; pe_data.stdout_fd = fds[1];
pe_data.close_me = fds[0]; pe_data.close_me = fds[0];
err = run_helper(slip_pre_exec, &pe_data, argv); err = run_helper(slip_pre_exec, &pe_data, argv);
if (err < 0) if (err < 0)
......
...@@ -20,18 +20,18 @@ static int slirp_user_init(void *data, void *dev) ...@@ -20,18 +20,18 @@ static int slirp_user_init(void *data, void *dev)
} }
struct slirp_pre_exec_data { struct slirp_pre_exec_data {
int stdin; int stdin_fd;
int stdout; int stdout_fd;
}; };
static void slirp_pre_exec(void *arg) static void slirp_pre_exec(void *arg)
{ {
struct slirp_pre_exec_data *data = arg; struct slirp_pre_exec_data *data = arg;
if (data->stdin != -1) if (data->stdin_fd != -1)
dup2(data->stdin, 0); dup2(data->stdin_fd, 0);
if (data->stdout != -1) if (data->stdout_fd != -1)
dup2(data->stdout, 1); dup2(data->stdout_fd, 1);
} }
static int slirp_tramp(char **argv, int fd) static int slirp_tramp(char **argv, int fd)
...@@ -39,8 +39,8 @@ static int slirp_tramp(char **argv, int fd) ...@@ -39,8 +39,8 @@ static int slirp_tramp(char **argv, int fd)
struct slirp_pre_exec_data pe_data; struct slirp_pre_exec_data pe_data;
int pid; int pid;
pe_data.stdin = fd; pe_data.stdin_fd = fd;
pe_data.stdout = fd; pe_data.stdout_fd = fd;
pid = run_helper(slirp_pre_exec, &pe_data, argv); pid = run_helper(slirp_pre_exec, &pe_data, argv);
return pid; return pid;
......
...@@ -21,7 +21,6 @@ generic-y += param.h ...@@ -21,7 +21,6 @@ generic-y += param.h
generic-y += pci.h generic-y += pci.h
generic-y += percpu.h generic-y += percpu.h
generic-y += preempt.h generic-y += preempt.h
generic-y += sections.h
generic-y += switch_to.h generic-y += switch_to.h
generic-y += topology.h generic-y += topology.h
generic-y += trace_clock.h generic-y += trace_clock.h
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <asm/ptrace-abi.h>
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
struct pt_regs { struct pt_regs {
...@@ -37,7 +36,7 @@ extern int putreg(struct task_struct *child, int regno, unsigned long value); ...@@ -37,7 +36,7 @@ extern int putreg(struct task_struct *child, int regno, unsigned long value);
extern int arch_copy_tls(struct task_struct *new); extern int arch_copy_tls(struct task_struct *new);
extern void clear_flushed_tls(struct task_struct *task); extern void clear_flushed_tls(struct task_struct *task);
extern void syscall_trace_enter(struct pt_regs *regs); extern int syscall_trace_enter(struct pt_regs *regs);
extern void syscall_trace_leave(struct pt_regs *regs); extern void syscall_trace_leave(struct pt_regs *regs);
#endif #endif
......
#ifndef __UM_SECTIONS_H
#define __UM_SECTIONS_H
#include <asm-generic/sections.h>
extern char __binary_start[];
extern char __syscall_stub_start[], __syscall_stub_end[];
#endif
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <asm/types.h> #include <asm/types.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/uaccess.h> #include <asm/segment.h>
struct thread_info { struct thread_info {
struct task_struct *task; /* main task structure */ struct task_struct *task; /* main task structure */
......
/* /*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com) * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Copyright (C) 2015 Richard Weinberger (richard@nod.at)
* Licensed under the GPL * Licensed under the GPL
*/ */
#ifndef __UM_UACCESS_H #ifndef __UM_UACCESS_H
#define __UM_UACCESS_H #define __UM_UACCESS_H
/* thread_info has a mm_segment_t in it, so put the definition up here */ #include <asm/thread_info.h>
typedef struct {
unsigned long seg;
} mm_segment_t;
#include <linux/thread_info.h>
#include <linux/errno.h>
#include <asm/processor.h>
#include <asm/elf.h> #include <asm/elf.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
/*
* The fs value determines whether argument validity checking should be
* performed or not. If get_fs() == USER_DS, checking is performed, with
* get_fs() == KERNEL_DS, checking is bypassed.
*
* For historical reasons, these macros are grossly misnamed.
*/
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
#define USER_DS MAKE_MM_SEG(TASK_SIZE)
#define get_ds() (KERNEL_DS)
#define get_fs() (current_thread_info()->addr_limit)
#define set_fs(x) (current_thread_info()->addr_limit = (x))
#define segment_eq(a, b) ((a).seg == (b).seg)
#define __under_task_size(addr, size) \ #define __under_task_size(addr, size) \
(((unsigned long) (addr) < TASK_SIZE) && \ (((unsigned long) (addr) < TASK_SIZE) && \
(((unsigned long) (addr) + (size)) < TASK_SIZE)) (((unsigned long) (addr) + (size)) < TASK_SIZE))
#define __access_ok_vsyscall(type, addr, size) \ #define __access_ok_vsyscall(addr, size) \
((type == VERIFY_READ) && \ (((unsigned long) (addr) >= FIXADDR_USER_START) && \
((unsigned long) (addr) >= FIXADDR_USER_START) && \
((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \
((unsigned long) (addr) + (size) >= (unsigned long)(addr))) ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))
#define __addr_range_nowrap(addr, size) \ #define __addr_range_nowrap(addr, size) \
((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) ((unsigned long) (addr) <= ((unsigned long) (addr) + (size)))
#define access_ok(type, addr, size) \ extern long __copy_from_user(void *to, const void __user *from, unsigned long n);
(__addr_range_nowrap(addr, size) && \ extern long __copy_to_user(void __user *to, const void *from, unsigned long n);
(__under_task_size(addr, size) || \ extern long __strncpy_from_user(char *dst, const char __user *src, long count);
__access_ok_vsyscall(type, addr, size) || \ extern long __strnlen_user(const void __user *str, long len);
segment_eq(get_fs(), KERNEL_DS))) extern unsigned long __clear_user(void __user *mem, unsigned long len);
static inline int __access_ok(unsigned long addr, unsigned long size);
extern int copy_from_user(void *to, const void __user *from, int n);
extern int copy_to_user(void __user *to, const void *from, int n); /* Teach asm-generic/uaccess.h that we have C functions for these. */
#define __access_ok __access_ok
/* #define __clear_user __clear_user
* strncpy_from_user: - Copy a NUL terminated string from userspace. #define __copy_to_user __copy_to_user
* @dst: Destination address, in kernel space. This buffer must be at #define __copy_from_user __copy_from_user
* least @count bytes long. #define __strnlen_user __strnlen_user
* @src: Source address, in user space. #define __strncpy_from_user __strncpy_from_user
* @count: Maximum number of bytes to copy, including the trailing NUL.
*
* Copies a NUL-terminated string from userspace to kernel space.
*
* On success, returns the length of the string (not including the trailing
* NUL).
*
* If access to userspace fails, returns -EFAULT (some data may have been
* copied).
*
* If @count is smaller than the length of the string, copies @count bytes
* and returns @count.
*/
extern int strncpy_from_user(char *dst, const char __user *src, int count);
/*
* __clear_user: - Zero a block of memory in user space, with less checking.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
* Zero a block of memory in user space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
extern int __clear_user(void __user *mem, int len);
/*
* clear_user: - Zero a block of memory in user space.
* @to: Destination address, in user space.
* @n: Number of bytes to zero.
*
* Zero a block of memory in user space.
*
* Returns number of bytes that could not be cleared.
* On success, this will be zero.
*/
extern int clear_user(void __user *mem, int len);
/*
* strlen_user: - Get the size of a string in user space.
* @str: The string to measure.
* @n: The maximum valid length
*
* Get the size of a NUL-terminated string in user space.
*
* Returns the size of the string INCLUDING the terminating NUL.
* On exception, returns 0.
* If the string is too long, returns a value greater than @n.
*/
extern int strnlen_user(const void __user *str, int len);
#define __copy_from_user(to, from, n) copy_from_user(to, from, n)
#define __copy_to_user(to, from, n) copy_to_user(to, from, n)
#define __copy_to_user_inatomic __copy_to_user #define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user #define __copy_from_user_inatomic __copy_from_user
#define __get_user(x, ptr) \ #include <asm-generic/uaccess.h>
({ \
const __typeof__(*(ptr)) __user *__private_ptr = (ptr); \
__typeof__(x) __private_val; \
int __private_ret = -EFAULT; \
(x) = (__typeof__(*(__private_ptr)))0; \
if (__copy_from_user((__force void *)&__private_val, (__private_ptr),\
sizeof(*(__private_ptr))) == 0) { \
(x) = (__typeof__(*(__private_ptr))) __private_val; \
__private_ret = 0; \
} \
__private_ret; \
})
#define get_user(x, ptr) \
({ \
const __typeof__((*(ptr))) __user *private_ptr = (ptr); \
(access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \
__get_user(x, private_ptr) : ((x) = (__typeof__(*ptr))0, -EFAULT)); \
})
#define __put_user(x, ptr) \
({ \
__typeof__(*(ptr)) __user *__private_ptr = ptr; \
__typeof__(*(__private_ptr)) __private_val; \
int __private_ret = -EFAULT; \
__private_val = (__typeof__(*(__private_ptr))) (x); \
if (__copy_to_user((__private_ptr), &__private_val, \
sizeof(*(__private_ptr))) == 0) { \
__private_ret = 0; \
} \
__private_ret; \
})
#define put_user(x, ptr) \
({ \
__typeof__(*(ptr)) __user *private_ptr = (ptr); \
(access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \
__put_user(x, private_ptr) : -EFAULT); \
})
#define strlen_user(str) strnlen_user(str, ~0U >> 1)
struct exception_table_entry static inline int __access_ok(unsigned long addr, unsigned long size)
{ {
unsigned long insn; return __addr_range_nowrap(addr, size) &&
unsigned long fixup; (__under_task_size(addr, size) ||
}; __access_ok_vsyscall(addr, size) ||
segment_eq(get_fs(), KERNEL_DS));
}
#endif #endif
...@@ -40,28 +40,8 @@ ...@@ -40,28 +40,8 @@
typedef int (*initcall_t)(void); typedef int (*initcall_t)(void);
typedef void (*exitcall_t)(void); typedef void (*exitcall_t)(void);
#ifndef __KERNEL__
#ifndef __section
# define __section(S) __attribute__ ((__section__(#S)))
#endif
#if __GNUC__ == 3
#if __GNUC_MINOR__ >= 3
# define __used __attribute__((__used__))
#else
# define __used __attribute__((__unused__))
#endif
#else
#if __GNUC__ == 4
# define __used __attribute__((__used__))
#endif
#endif
#else
#include <linux/compiler.h> #include <linux/compiler.h>
#endif
/* These are for everybody (although not all archs will actually /* These are for everybody (although not all archs will actually
discard it in modules) */ discard it in modules) */
#define __init __section(.init.text) #define __init __section(.init.text)
...@@ -131,7 +111,7 @@ extern struct uml_param __uml_setup_start, __uml_setup_end; ...@@ -131,7 +111,7 @@ extern struct uml_param __uml_setup_start, __uml_setup_end;
#define __uml_postsetup_call __used __section(.uml.postsetup.init) #define __uml_postsetup_call __used __section(.uml.postsetup.init)
#define __uml_exit_call __used __section(.uml.exitcall.exit) #define __uml_exit_call __used __section(.uml.exitcall.exit)
#ifndef __KERNEL__ #ifdef __UM_HOST__
#define __define_initcall(level,fn) \ #define __define_initcall(level,fn) \
static initcall_t __initcall_##fn __used \ static initcall_t __initcall_##fn __used \
......
...@@ -301,4 +301,6 @@ extern int get_pty(void); ...@@ -301,4 +301,6 @@ extern int get_pty(void);
/* sys-$ARCH/task_size.c */ /* sys-$ARCH/task_size.c */
extern unsigned long os_get_top_address(void); extern unsigned long os_get_top_address(void);
long syscall(long number, ...);
#endif #endif
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
/* This is to get size_t */ /* This is to get size_t */
#ifdef __KERNEL__ #ifndef __UM_HOST__
#include <linux/types.h> #include <linux/types.h>
#else #else
#include <stddef.h> #include <stddef.h>
......
...@@ -42,3 +42,5 @@ EXPORT_SYMBOL(os_makedev); ...@@ -42,3 +42,5 @@ EXPORT_SYMBOL(os_makedev);
EXPORT_SYMBOL(add_sigio_fd); EXPORT_SYMBOL(add_sigio_fd);
EXPORT_SYMBOL(ignore_sigio_fd); EXPORT_SYMBOL(ignore_sigio_fd);
EXPORT_SYMBOL(sigio_broken); EXPORT_SYMBOL(sigio_broken);
EXPORT_SYMBOL(syscall);
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/pfn.h> #include <linux/pfn.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/sections.h>
#include <as-layout.h> #include <as-layout.h>
#include <init.h> #include <init.h>
#include <kern.h> #include <kern.h>
...@@ -55,8 +56,6 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len, ...@@ -55,8 +56,6 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
} }
} }
extern int __syscall_stub_start;
/** /**
* setup_physmem() - Setup physical memory for UML * setup_physmem() - Setup physical memory for UML
* @start: Start address of the physical kernel memory, * @start: Start address of the physical kernel memory,
...@@ -110,8 +109,8 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end, ...@@ -110,8 +109,8 @@ void __init setup_physmem(unsigned long start, unsigned long reserve_end,
* Special kludge - This page will be mapped in to userspace processes * Special kludge - This page will be mapped in to userspace processes
* from physmem_fd, so it needs to be written out there. * from physmem_fd, so it needs to be written out there.
*/ */
os_seek_file(physmem_fd, __pa(&__syscall_stub_start)); os_seek_file(physmem_fd, __pa(__syscall_stub_start));
os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE); os_write_file(physmem_fd, __syscall_stub_start, PAGE_SIZE);
os_fsync_file(physmem_fd); os_fsync_file(physmem_fd);
bootmap_size = init_bootmem(pfn, pfn + delta); bootmap_size = init_bootmem(pfn, pfn + delta);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/tracehook.h> #include <linux/tracehook.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ptrace-abi.h>
void user_enable_single_step(struct task_struct *child) void user_enable_single_step(struct task_struct *child)
{ {
...@@ -131,7 +132,7 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs, ...@@ -131,7 +132,7 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and * XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check * PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
*/ */
void syscall_trace_enter(struct pt_regs *regs) int syscall_trace_enter(struct pt_regs *regs)
{ {
audit_syscall_entry(UPT_SYSCALL_NR(&regs->regs), audit_syscall_entry(UPT_SYSCALL_NR(&regs->regs),
UPT_SYSCALL_ARG1(&regs->regs), UPT_SYSCALL_ARG1(&regs->regs),
...@@ -140,9 +141,9 @@ void syscall_trace_enter(struct pt_regs *regs) ...@@ -140,9 +141,9 @@ void syscall_trace_enter(struct pt_regs *regs)
UPT_SYSCALL_ARG4(&regs->regs)); UPT_SYSCALL_ARG4(&regs->regs));
if (!test_thread_flag(TIF_SYSCALL_TRACE)) if (!test_thread_flag(TIF_SYSCALL_TRACE))
return; return 0;
tracehook_report_syscall_entry(regs); return tracehook_report_syscall_entry(regs);
} }
void syscall_trace_leave(struct pt_regs *regs) void syscall_trace_leave(struct pt_regs *regs)
......
...@@ -8,12 +8,11 @@ ...@@ -8,12 +8,11 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/pgtable.h> #include <asm/pgtable.h>
#include <asm/sections.h>
#include <as-layout.h> #include <as-layout.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
extern int __syscall_stub_start;
static int init_stub_pte(struct mm_struct *mm, unsigned long proc, static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
unsigned long kernel) unsigned long kernel)
{ {
...@@ -93,7 +92,7 @@ void uml_setup_stubs(struct mm_struct *mm) ...@@ -93,7 +92,7 @@ void uml_setup_stubs(struct mm_struct *mm)
int err, ret; int err, ret;
ret = init_stub_pte(mm, STUB_CODE, ret = init_stub_pte(mm, STUB_CODE,
(unsigned long) &__syscall_stub_start); (unsigned long) __syscall_stub_start);
if (ret) if (ret)
goto out; goto out;
...@@ -101,7 +100,7 @@ void uml_setup_stubs(struct mm_struct *mm) ...@@ -101,7 +100,7 @@ void uml_setup_stubs(struct mm_struct *mm)
if (ret) if (ret)
goto out; goto out;
mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); mm->context.stub_pages[0] = virt_to_page(__syscall_stub_start);
mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack); mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);
/* dup_mmap already holds mmap_sem */ /* dup_mmap already holds mmap_sem */
......
...@@ -18,7 +18,10 @@ void handle_syscall(struct uml_pt_regs *r) ...@@ -18,7 +18,10 @@ void handle_syscall(struct uml_pt_regs *r)
long result; long result;
int syscall; int syscall;
syscall_trace_enter(regs); if (syscall_trace_enter(regs)) {
result = -ENOSYS;
goto out;
}
/* /*
* This should go in the declaration of syscall, but when I do that, * This should go in the declaration of syscall, but when I do that,
...@@ -34,6 +37,7 @@ void handle_syscall(struct uml_pt_regs *r) ...@@ -34,6 +37,7 @@ void handle_syscall(struct uml_pt_regs *r)
result = -ENOSYS; result = -ENOSYS;
else result = EXECUTE_SYSCALL(syscall, regs); else result = EXECUTE_SYSCALL(syscall, regs);
out:
PT_REGS_SET_SYSCALL_RETURN(regs, result); PT_REGS_SET_SYSCALL_RETURN(regs, result);
syscall_trace_leave(regs); syscall_trace_leave(regs);
......
...@@ -87,10 +87,10 @@ static int do_op_one_page(unsigned long addr, int len, int is_write, ...@@ -87,10 +87,10 @@ static int do_op_one_page(unsigned long addr, int len, int is_write,
return n; return n;
} }
static int buffer_op(unsigned long addr, int len, int is_write, static long buffer_op(unsigned long addr, int len, int is_write,
int (*op)(unsigned long, int, void *), void *arg) int (*op)(unsigned long, int, void *), void *arg)
{ {
int size, remain, n; long size, remain, n;
size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
remain = len; remain = len;
...@@ -139,18 +139,16 @@ static int copy_chunk_from_user(unsigned long from, int len, void *arg) ...@@ -139,18 +139,16 @@ static int copy_chunk_from_user(unsigned long from, int len, void *arg)
return 0; return 0;
} }
int copy_from_user(void *to, const void __user *from, int n) long __copy_from_user(void *to, const void __user *from, unsigned long n)
{ {
if (segment_eq(get_fs(), KERNEL_DS)) { if (segment_eq(get_fs(), KERNEL_DS)) {
memcpy(to, (__force void*)from, n); memcpy(to, (__force void*)from, n);
return 0; return 0;
} }
return access_ok(VERIFY_READ, from, n) ? return buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to);
buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
n;
} }
EXPORT_SYMBOL(copy_from_user); EXPORT_SYMBOL(__copy_from_user);
static int copy_chunk_to_user(unsigned long to, int len, void *arg) static int copy_chunk_to_user(unsigned long to, int len, void *arg)
{ {
...@@ -161,18 +159,16 @@ static int copy_chunk_to_user(unsigned long to, int len, void *arg) ...@@ -161,18 +159,16 @@ static int copy_chunk_to_user(unsigned long to, int len, void *arg)
return 0; return 0;
} }
int copy_to_user(void __user *to, const void *from, int n) long __copy_to_user(void __user *to, const void *from, unsigned long n)
{ {
if (segment_eq(get_fs(), KERNEL_DS)) { if (segment_eq(get_fs(), KERNEL_DS)) {
memcpy((__force void *) to, from, n); memcpy((__force void *) to, from, n);
return 0; return 0;
} }
return access_ok(VERIFY_WRITE, to, n) ? return buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from);
buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
n;
} }
EXPORT_SYMBOL(copy_to_user); EXPORT_SYMBOL(__copy_to_user);
static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
{ {
...@@ -188,9 +184,9 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) ...@@ -188,9 +184,9 @@ static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
return 0; return 0;
} }
int strncpy_from_user(char *dst, const char __user *src, int count) long __strncpy_from_user(char *dst, const char __user *src, long count)
{ {
int n; long n;
char *ptr = dst; char *ptr = dst;
if (segment_eq(get_fs(), KERNEL_DS)) { if (segment_eq(get_fs(), KERNEL_DS)) {
...@@ -198,16 +194,13 @@ int strncpy_from_user(char *dst, const char __user *src, int count) ...@@ -198,16 +194,13 @@ int strncpy_from_user(char *dst, const char __user *src, int count)
return strnlen(dst, count); return strnlen(dst, count);
} }
if (!access_ok(VERIFY_READ, src, 1))
return -EFAULT;
n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
&ptr); &ptr);
if (n != 0) if (n != 0)
return -EFAULT; return -EFAULT;
return strnlen(dst, count); return strnlen(dst, count);
} }
EXPORT_SYMBOL(strncpy_from_user); EXPORT_SYMBOL(__strncpy_from_user);
static int clear_chunk(unsigned long addr, int len, void *unused) static int clear_chunk(unsigned long addr, int len, void *unused)
{ {
...@@ -215,22 +208,16 @@ static int clear_chunk(unsigned long addr, int len, void *unused) ...@@ -215,22 +208,16 @@ static int clear_chunk(unsigned long addr, int len, void *unused)
return 0; return 0;
} }
int __clear_user(void __user *mem, int len) unsigned long __clear_user(void __user *mem, unsigned long len)
{
return buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL);
}
int clear_user(void __user *mem, int len)
{ {
if (segment_eq(get_fs(), KERNEL_DS)) { if (segment_eq(get_fs(), KERNEL_DS)) {
memset((__force void*)mem, 0, len); memset((__force void*)mem, 0, len);
return 0; return 0;
} }
return access_ok(VERIFY_WRITE, mem, len) ? return buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL);
buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len;
} }
EXPORT_SYMBOL(clear_user); EXPORT_SYMBOL(__clear_user);
static int strnlen_chunk(unsigned long str, int len, void *arg) static int strnlen_chunk(unsigned long str, int len, void *arg)
{ {
...@@ -244,7 +231,7 @@ static int strnlen_chunk(unsigned long str, int len, void *arg) ...@@ -244,7 +231,7 @@ static int strnlen_chunk(unsigned long str, int len, void *arg)
return 0; return 0;
} }
int strnlen_user(const void __user *str, int len) long __strnlen_user(const void __user *str, long len)
{ {
int count = 0, n; int count = 0, n;
...@@ -256,4 +243,4 @@ int strnlen_user(const void __user *str, int len) ...@@ -256,4 +243,4 @@ int strnlen_user(const void __user *str, int len)
return count + 1; return count + 1;
return 0; return 0;
} }
EXPORT_SYMBOL(strnlen_user); EXPORT_SYMBOL(__strnlen_user);
...@@ -220,6 +220,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, ...@@ -220,6 +220,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
show_regs(container_of(regs, struct pt_regs, regs)); show_regs(container_of(regs, struct pt_regs, regs));
panic("Segfault with no mm"); panic("Segfault with no mm");
} }
else if (!is_user && address < TASK_SIZE) {
show_regs(container_of(regs, struct pt_regs, regs));
panic("Kernel tried to access user memory at addr 0x%lx, ip 0x%lx",
address, ip);
}
if (SEGV_IS_FIXABLE(&fi)) if (SEGV_IS_FIXABLE(&fi))
err = handle_page_fault(address, ip, is_write, is_user, err = handle_page_fault(address, ip, is_write, is_user,
......
...@@ -248,8 +248,6 @@ EXPORT_SYMBOL(end_iomem); ...@@ -248,8 +248,6 @@ EXPORT_SYMBOL(end_iomem);
#define MIN_VMALLOC (32 * 1024 * 1024) #define MIN_VMALLOC (32 * 1024 * 1024)
extern char __binary_start;
int __init linux_main(int argc, char **argv) int __init linux_main(int argc, char **argv)
{ {
unsigned long avail, diff; unsigned long avail, diff;
...@@ -294,7 +292,7 @@ int __init linux_main(int argc, char **argv) ...@@ -294,7 +292,7 @@ int __init linux_main(int argc, char **argv)
physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end); physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
} }
uml_physmem = (unsigned long) &__binary_start & PAGE_MASK; uml_physmem = (unsigned long) __binary_start & PAGE_MASK;
/* Reserve up to 4M after the current brk */ /* Reserve up to 4M after the current brk */
uml_reserved = ROUND_4M(brk_start) + (1 << 22); uml_reserved = ROUND_4M(brk_start) + (1 << 22);
......
...@@ -47,7 +47,7 @@ static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, ...@@ -47,7 +47,7 @@ static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
} }
struct tuntap_pre_exec_data { struct tuntap_pre_exec_data {
int stdout; int stdout_fd;
int close_me; int close_me;
}; };
...@@ -55,7 +55,7 @@ static void tuntap_pre_exec(void *arg) ...@@ -55,7 +55,7 @@ static void tuntap_pre_exec(void *arg)
{ {
struct tuntap_pre_exec_data *data = arg; struct tuntap_pre_exec_data *data = arg;
dup2(data->stdout, 1); dup2(data->stdout_fd, 1);
close(data->close_me); close(data->close_me);
} }
...@@ -74,7 +74,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, ...@@ -74,7 +74,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
sprintf(version_buf, "%d", UML_NET_VERSION); sprintf(version_buf, "%d", UML_NET_VERSION);
data.stdout = remote; data.stdout_fd = remote;
data.close_me = me; data.close_me = me;
pid = run_helper(tuntap_pre_exec, &data, argv); pid = run_helper(tuntap_pre_exec, &data, argv);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/types.h>
#include <os.h> #include <os.h>
static void copy_stat(struct uml_stat *dst, const struct stat64 *src) static void copy_stat(struct uml_stat *dst, const struct stat64 *src)
......
...@@ -112,9 +112,11 @@ void timer_init(void) ...@@ -112,9 +112,11 @@ void timer_init(void)
void set_sigstack(void *sig_stack, int size) void set_sigstack(void *sig_stack, int size)
{ {
stack_t stack = ((stack_t) { .ss_flags = 0, stack_t stack = {
.ss_sp = (__ptr_t) sig_stack, .ss_flags = 0,
.ss_size = size - sizeof(void *) }); .ss_sp = sig_stack,
.ss_size = size - sizeof(void *)
};
if (sigaltstack(&stack, NULL) != 0) if (sigaltstack(&stack, NULL) != 0)
panic("enabling signal stack failed, errno = %d\n", errno); panic("enabling signal stack failed, errno = %d\n", errno);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <sysdep/ptrace.h> #include <sysdep/ptrace.h>
#include <sysdep/stub.h> #include <sysdep/stub.h>
extern unsigned long batch_syscall_stub, __syscall_stub_start; extern char batch_syscall_stub[], __syscall_stub_start[];
extern void wait_stub_done(int pid); extern void wait_stub_done(int pid);
...@@ -38,8 +38,8 @@ static int __init init_syscall_regs(void) ...@@ -38,8 +38,8 @@ static int __init init_syscall_regs(void)
{ {
get_safe_registers(syscall_regs, NULL); get_safe_registers(syscall_regs, NULL);
syscall_regs[REGS_IP_INDEX] = STUB_CODE + syscall_regs[REGS_IP_INDEX] = STUB_CODE +
((unsigned long) &batch_syscall_stub - ((unsigned long) batch_syscall_stub -
(unsigned long) &__syscall_stub_start); (unsigned long) __syscall_stub_start);
return 0; return 0;
} }
......
...@@ -174,7 +174,7 @@ static void handle_trap(int pid, struct uml_pt_regs *regs, ...@@ -174,7 +174,7 @@ static void handle_trap(int pid, struct uml_pt_regs *regs,
handle_syscall(regs); handle_syscall(regs);
} }
extern int __syscall_stub_start; extern char __syscall_stub_start[];
static int userspace_tramp(void *stack) static int userspace_tramp(void *stack)
{ {
...@@ -197,7 +197,7 @@ static int userspace_tramp(void *stack) ...@@ -197,7 +197,7 @@ static int userspace_tramp(void *stack)
* This has a pte, but it can't be mapped in with the usual * This has a pte, but it can't be mapped in with the usual
* tlb_flush mechanism because this is part of that mechanism * tlb_flush mechanism because this is part of that mechanism
*/ */
fd = phys_mapping(to_phys(&__syscall_stub_start), &offset); fd = phys_mapping(to_phys(__syscall_stub_start), &offset);
addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE, addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset); PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
if (addr == MAP_FAILED) { if (addr == MAP_FAILED) {
...@@ -223,7 +223,7 @@ static int userspace_tramp(void *stack) ...@@ -223,7 +223,7 @@ static int userspace_tramp(void *stack)
unsigned long v = STUB_CODE + unsigned long v = STUB_CODE +
(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, UM_KERN_PAGE_SIZE);
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
...@@ -447,7 +447,7 @@ static int __init init_thread_regs(void) ...@@ -447,7 +447,7 @@ static int __init init_thread_regs(void)
/* Set parent's instruction pointer to start of clone-stub */ /* Set parent's instruction pointer to start of clone-stub */
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 + UM_KERN_PAGE_SIZE -
sizeof(void *); sizeof(void *);
#ifdef __SIGNAL_FRAMESIZE #ifdef __SIGNAL_FRAMESIZE
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/uaccess.h>
/* /*
* computes the checksum of a memory block at buff, length len, * computes the checksum of a memory block at buff, length len,
......
...@@ -200,8 +200,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ...@@ -200,8 +200,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef struct user_i387_struct elf_fpregset_t; typedef struct user_i387_struct elf_fpregset_t;
#define task_pt_regs(t) (&(t)->thread.regs)
struct task_struct; struct task_struct;
extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu); extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
......
...@@ -28,6 +28,8 @@ static inline void rep_nop(void) ...@@ -28,6 +28,8 @@ static inline void rep_nop(void)
#define cpu_relax() rep_nop() #define cpu_relax() rep_nop()
#define cpu_relax_lowlatency() cpu_relax() #define cpu_relax_lowlatency() cpu_relax()
#define task_pt_regs(t) (&(t)->thread.regs)
#include <asm/processor-generic.h> #include <asm/processor-generic.h>
#endif #endif
...@@ -7,4 +7,12 @@ extern int host_gdt_entry_tls_min; ...@@ -7,4 +7,12 @@ extern int host_gdt_entry_tls_min;
#define GDT_ENTRY_TLS_MIN host_gdt_entry_tls_min #define GDT_ENTRY_TLS_MIN host_gdt_entry_tls_min
#define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1) #define GDT_ENTRY_TLS_MAX (GDT_ENTRY_TLS_MIN + GDT_ENTRY_TLS_ENTRIES - 1)
typedef struct {
unsigned long seg;
} mm_segment_t;
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(~0UL)
#define USER_DS MAKE_MM_SEG(TASK_SIZE)
#endif #endif
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
......
...@@ -7,8 +7,7 @@ ...@@ -7,8 +7,7 @@
*/ */
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/page.h> #include <asm/elf.h>
#include <asm/mman.h>
static struct vm_area_struct gate_vma; static struct vm_area_struct gate_vma;
......
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/page.h> #include <asm/elf.h>
#include <asm/mman.h>
const char *arch_vma_name(struct vm_area_struct *vma) const char *arch_vma_name(struct vm_area_struct *vma)
{ {
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ptrace-abi.h>
#include <skas.h> #include <skas.h>
extern int arch_switch_tls(struct task_struct *to); extern int arch_switch_tls(struct task_struct *to);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#define __FRAME_OFFSETS #define __FRAME_OFFSETS
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ptrace-abi.h>
/* /*
* determines which flags the user has access to. * determines which flags the user has access to.
......
#ifndef _SYSDEP_TLS_H #ifndef _SYSDEP_TLS_H
#define _SYSDEP_TLS_H #define _SYSDEP_TLS_H
# ifndef __KERNEL__ #ifdef __UM_HOST__
/* Change name to avoid conflicts with the original one from <asm/ldt.h>, which /* Change name to avoid conflicts with the original one from <asm/ldt.h>, which
* may be named user_desc (but in 2.4 and in header matching its API was named * may be named user_desc (but in 2.4 and in header matching its API was named
...@@ -22,11 +22,11 @@ typedef struct um_dup_user_desc { ...@@ -22,11 +22,11 @@ typedef struct um_dup_user_desc {
#endif #endif
} user_desc_t; } user_desc_t;
# else /* __KERNEL__ */ #else /* __UM_HOST__ */
typedef struct user_desc user_desc_t; typedef struct user_desc user_desc_t;
# endif /* __KERNEL__ */ #endif /* __UM_HOST__ */
extern int os_set_thread_area(user_desc_t *info, int pid); extern int os_set_thread_area(user_desc_t *info, int pid);
extern int os_get_thread_area(user_desc_t *info, int pid); extern int os_get_thread_area(user_desc_t *info, int pid);
......
...@@ -541,7 +541,8 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig, ...@@ -541,7 +541,8 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
*/ */
/* x86-64 should always use SA_RESTORER. */ /* x86-64 should always use SA_RESTORER. */
if (ksig->ka.sa.sa_flags & SA_RESTORER) if (ksig->ka.sa.sa_flags & SA_RESTORER)
err |= __put_user(ksig->ka.sa.sa_restorer, &frame->pretcode); err |= __put_user((void *)ksig->ka.sa.sa_restorer,
&frame->pretcode);
else else
/* could use a vstub here */ /* could use a vstub here */
return err; return err;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h>
#include <asm/prctl.h> /* XXX This should get the constants from libc */ #include <asm/prctl.h> /* XXX This should get the constants from libc */
#include <os.h> #include <os.h>
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/ptrace-abi.h>
#include <os.h> #include <os.h>
#include <skas.h> #include <skas.h>
#include <sysdep/tls.h> #include <sysdep/tls.h>
......
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/ptrace-abi.h>
void clear_flushed_tls(struct task_struct *task) void clear_flushed_tls(struct task_struct *task)
{ {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <asm/page.h> #include <asm/page.h>
#include <asm/elf.h>
#include <linux/init.h> #include <linux/init.h>
static unsigned int __read_mostly vdso_enabled = 1; static unsigned int __read_mostly vdso_enabled = 1;
......
...@@ -115,7 +115,6 @@ obj-$(CONFIG_AFS_FS) += afs/ ...@@ -115,7 +115,6 @@ 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-$(CONFIG_HOSTFS) += hostfs/
obj-$(CONFIG_HPPFS) += hppfs/
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/
......
#
# Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
# Licensed under the GPL
#
obj-$(CONFIG_HPPFS) += hppfs.o
/*
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <linux/ctype.h>
#include <linux/dcache.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/statfs.h>
#include <linux/types.h>
#include <linux/pid_namespace.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
#include <os.h>
static struct inode *get_inode(struct super_block *, struct dentry *);
struct hppfs_data {
struct list_head list;
char contents[PAGE_SIZE - sizeof(struct list_head)];
};
struct hppfs_private {
struct file *proc_file;
int host_fd;
loff_t len;
struct hppfs_data *contents;
};
struct hppfs_inode_info {
struct dentry *proc_dentry;
struct inode vfs_inode;
};
static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode)
{
return container_of(inode, struct hppfs_inode_info, vfs_inode);
}
#define HPPFS_SUPER_MAGIC 0xb00000ee
static const struct super_operations hppfs_sbops;
static int is_pid(struct dentry *dentry)
{
struct super_block *sb;
int i;
sb = dentry->d_sb;
if (dentry->d_parent != sb->s_root)
return 0;
for (i = 0; i < dentry->d_name.len; i++) {
if (!isdigit(dentry->d_name.name[i]))
return 0;
}
return 1;
}
static char *dentry_name(struct dentry *dentry, int extra)
{
struct dentry *parent;
char *root, *name;
const char *seg_name;
int len, seg_len, root_len;
len = 0;
parent = dentry;
while (parent->d_parent != parent) {
if (is_pid(parent))
len += strlen("pid") + 1;
else len += parent->d_name.len + 1;
parent = parent->d_parent;
}
root = "proc";
root_len = strlen(root);
len += root_len;
name = kmalloc(len + extra + 1, GFP_KERNEL);
if (name == NULL)
return NULL;
name[len] = '\0';
parent = dentry;
while (parent->d_parent != parent) {
if (is_pid(parent)) {
seg_name = "pid";
seg_len = strlen(seg_name);
}
else {
seg_name = parent->d_name.name;
seg_len = parent->d_name.len;
}
len -= seg_len + 1;
name[len] = '/';
memcpy(&name[len + 1], seg_name, seg_len);
parent = parent->d_parent;
}
memcpy(name, root, root_len);
return name;
}
static int file_removed(struct dentry *dentry, const char *file)
{
char *host_file;
int extra, fd;
extra = 0;
if (file != NULL)
extra += strlen(file) + 1;
host_file = dentry_name(dentry, extra + strlen("/remove"));
if (host_file == NULL) {
printk(KERN_ERR "file_removed : allocation failed\n");
return -ENOMEM;
}
if (file != NULL) {
strcat(host_file, "/");
strcat(host_file, file);
}
strcat(host_file, "/remove");
fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
kfree(host_file);
if (fd > 0) {
os_close_file(fd);
return 1;
}
return 0;
}
static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry,
unsigned int flags)
{
struct dentry *proc_dentry, *parent;
struct qstr *name = &dentry->d_name;
struct inode *inode;
int err, deleted;
deleted = file_removed(dentry, NULL);
if (deleted < 0)
return ERR_PTR(deleted);
else if (deleted)
return ERR_PTR(-ENOENT);
parent = HPPFS_I(ino)->proc_dentry;
mutex_lock(&d_inode(parent)->i_mutex);
proc_dentry = lookup_one_len(name->name, parent, name->len);
mutex_unlock(&d_inode(parent)->i_mutex);
if (IS_ERR(proc_dentry))
return proc_dentry;
err = -ENOMEM;
inode = get_inode(ino->i_sb, proc_dentry);
if (!inode)
goto out;
d_add(dentry, inode);
return NULL;
out:
return ERR_PTR(err);
}
static const struct inode_operations hppfs_file_iops = {
};
static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count,
loff_t *ppos, int is_user)
{
ssize_t (*read)(struct file *, char __user *, size_t, loff_t *);
ssize_t n;
read = file_inode(file)->i_fop->read;
if (!is_user)
set_fs(KERNEL_DS);
n = (*read)(file, buf, count, &file->f_pos);
if (!is_user)
set_fs(USER_DS);
if (ppos)
*ppos = file->f_pos;
return n;
}
static ssize_t hppfs_read_file(int fd, char __user *buf, ssize_t count)
{
ssize_t n;
int cur, err;
char *new_buf;
n = -ENOMEM;
new_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (new_buf == NULL) {
printk(KERN_ERR "hppfs_read_file : kmalloc failed\n");
goto out;
}
n = 0;
while (count > 0) {
cur = min_t(ssize_t, count, PAGE_SIZE);
err = os_read_file(fd, new_buf, cur);
if (err < 0) {
printk(KERN_ERR "hppfs_read : read failed, "
"errno = %d\n", err);
n = err;
goto out_free;
} else if (err == 0)
break;
if (copy_to_user(buf, new_buf, err)) {
n = -EFAULT;
goto out_free;
}
n += err;
count -= err;
}
out_free:
kfree(new_buf);
out:
return n;
}
static ssize_t hppfs_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
struct hppfs_private *hppfs = file->private_data;
struct hppfs_data *data;
loff_t off;
int err;
if (hppfs->contents != NULL) {
int rem;
if (*ppos >= hppfs->len)
return 0;
data = hppfs->contents;
off = *ppos;
while (off >= sizeof(data->contents)) {
data = list_entry(data->list.next, struct hppfs_data,
list);
off -= sizeof(data->contents);
}
if (off + count > hppfs->len)
count = hppfs->len - off;
rem = copy_to_user(buf, &data->contents[off], count);
*ppos += count - rem;
if (rem > 0)
return -EFAULT;
} else if (hppfs->host_fd != -1) {
err = os_seek_file(hppfs->host_fd, *ppos);
if (err) {
printk(KERN_ERR "hppfs_read : seek failed, "
"errno = %d\n", err);
return err;
}
err = hppfs_read_file(hppfs->host_fd, buf, count);
if (err < 0) {
printk(KERN_ERR "hppfs_read: read failed: %d\n", err);
return err;
}
count = err;
if (count > 0)
*ppos += count;
}
else count = read_proc(hppfs->proc_file, buf, count, ppos, 1);
return count;
}
static ssize_t hppfs_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
struct hppfs_private *data = file->private_data;
struct file *proc_file = data->proc_file;
ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *);
write = file_inode(proc_file)->i_fop->write;
return (*write)(proc_file, buf, len, ppos);
}
static int open_host_sock(char *host_file, int *filter_out)
{
char *end;
int fd;
end = &host_file[strlen(host_file)];
strcpy(end, "/rw");
*filter_out = 1;
fd = os_connect_socket(host_file);
if (fd > 0)
return fd;
strcpy(end, "/r");
*filter_out = 0;
fd = os_connect_socket(host_file);
return fd;
}
static void free_contents(struct hppfs_data *head)
{
struct hppfs_data *data;
struct list_head *ele, *next;
if (head == NULL)
return;
list_for_each_safe(ele, next, &head->list) {
data = list_entry(ele, struct hppfs_data, list);
kfree(data);
}
kfree(head);
}
static struct hppfs_data *hppfs_get_data(int fd, int filter,
struct file *proc_file,
struct file *hppfs_file,
loff_t *size_out)
{
struct hppfs_data *data, *new, *head;
int n, err;
err = -ENOMEM;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL) {
printk(KERN_ERR "hppfs_get_data : head allocation failed\n");
goto failed;
}
INIT_LIST_HEAD(&data->list);
head = data;
*size_out = 0;
if (filter) {
while ((n = read_proc(proc_file, data->contents,
sizeof(data->contents), NULL, 0)) > 0)
os_write_file(fd, data->contents, n);
err = os_shutdown_socket(fd, 0, 1);
if (err) {
printk(KERN_ERR "hppfs_get_data : failed to shut down "
"socket\n");
goto failed_free;
}
}
while (1) {
n = os_read_file(fd, data->contents, sizeof(data->contents));
if (n < 0) {
err = n;
printk(KERN_ERR "hppfs_get_data : read failed, "
"errno = %d\n", err);
goto failed_free;
} else if (n == 0)
break;
*size_out += n;
if (n < sizeof(data->contents))
break;
new = kmalloc(sizeof(*data), GFP_KERNEL);
if (new == 0) {
printk(KERN_ERR "hppfs_get_data : data allocation "
"failed\n");
err = -ENOMEM;
goto failed_free;
}
INIT_LIST_HEAD(&new->list);
list_add(&new->list, &data->list);
data = new;
}
return head;
failed_free:
free_contents(head);
failed:
return ERR_PTR(err);
}
static struct hppfs_private *hppfs_data(void)
{
struct hppfs_private *data;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (data == NULL)
return data;
*data = ((struct hppfs_private ) { .host_fd = -1,
.len = -1,
.contents = NULL } );
return data;
}
static int file_mode(int fmode)
{
if (fmode == (FMODE_READ | FMODE_WRITE))
return O_RDWR;
if (fmode == FMODE_READ)
return O_RDONLY;
if (fmode == FMODE_WRITE)
return O_WRONLY;
return 0;
}
static int hppfs_open(struct inode *inode, struct file *file)
{
const struct cred *cred = file->f_cred;
struct hppfs_private *data;
struct path path;
char *host_file;
int err, fd, type, filter;
err = -ENOMEM;
data = hppfs_data();
if (data == NULL)
goto out;
host_file = dentry_name(file->f_path.dentry, strlen("/rw"));
if (host_file == NULL)
goto out_free2;
path.mnt = inode->i_sb->s_fs_info;
path.dentry = HPPFS_I(inode)->proc_dentry;
data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred);
err = PTR_ERR(data->proc_file);
if (IS_ERR(data->proc_file))
goto out_free1;
type = os_file_type(host_file);
if (type == OS_TYPE_FILE) {
fd = os_open_file(host_file, of_read(OPENFLAGS()), 0);
if (fd >= 0)
data->host_fd = fd;
else
printk(KERN_ERR "hppfs_open : failed to open '%s', "
"errno = %d\n", host_file, -fd);
data->contents = NULL;
} else if (type == OS_TYPE_DIR) {
fd = open_host_sock(host_file, &filter);
if (fd > 0) {
data->contents = hppfs_get_data(fd, filter,
data->proc_file,
file, &data->len);
if (!IS_ERR(data->contents))
data->host_fd = fd;
} else
printk(KERN_ERR "hppfs_open : failed to open a socket "
"in '%s', errno = %d\n", host_file, -fd);
}
kfree(host_file);
file->private_data = data;
return 0;
out_free1:
kfree(host_file);
out_free2:
free_contents(data->contents);
kfree(data);
out:
return err;
}
static int hppfs_dir_open(struct inode *inode, struct file *file)
{
const struct cred *cred = file->f_cred;
struct hppfs_private *data;
struct path path;
int err;
err = -ENOMEM;
data = hppfs_data();
if (data == NULL)
goto out;
path.mnt = inode->i_sb->s_fs_info;
path.dentry = HPPFS_I(inode)->proc_dentry;
data->proc_file = dentry_open(&path, file_mode(file->f_mode), cred);
err = PTR_ERR(data->proc_file);
if (IS_ERR(data->proc_file))
goto out_free;
file->private_data = data;
return 0;
out_free:
kfree(data);
out:
return err;
}
static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
{
struct hppfs_private *data = file->private_data;
struct file *proc_file = data->proc_file;
loff_t (*llseek)(struct file *, loff_t, int);
loff_t ret;
llseek = file_inode(proc_file)->i_fop->llseek;
if (llseek != NULL) {
ret = (*llseek)(proc_file, off, where);
if (ret < 0)
return ret;
}
return default_llseek(file, off, where);
}
static int hppfs_release(struct inode *inode, struct file *file)
{
struct hppfs_private *data = file->private_data;
struct file *proc_file = data->proc_file;
if (proc_file)
fput(proc_file);
kfree(data);
return 0;
}
static const struct file_operations hppfs_file_fops = {
.owner = NULL,
.llseek = hppfs_llseek,
.read = hppfs_read,
.write = hppfs_write,
.open = hppfs_open,
.release = hppfs_release,
};
struct hppfs_dirent {
struct dir_context ctx;
struct dir_context *caller;
struct dentry *dentry;
};
static int hppfs_filldir(struct dir_context *ctx, const char *name, int size,
loff_t offset, u64 inode, unsigned int type)
{
struct hppfs_dirent *dirent =
container_of(ctx, struct hppfs_dirent, ctx);
if (file_removed(dirent->dentry, name))
return 0;
dirent->caller->pos = dirent->ctx.pos;
return !dir_emit(dirent->caller, name, size, inode, type);
}
static int hppfs_readdir(struct file *file, struct dir_context *ctx)
{
struct hppfs_private *data = file->private_data;
struct file *proc_file = data->proc_file;
struct hppfs_dirent d = {
.ctx.actor = hppfs_filldir,
.caller = ctx,
.dentry = file->f_path.dentry
};
int err;
proc_file->f_pos = ctx->pos;
err = iterate_dir(proc_file, &d.ctx);
ctx->pos = d.ctx.pos;
return err;
}
static const struct file_operations hppfs_dir_fops = {
.owner = NULL,
.iterate = hppfs_readdir,
.open = hppfs_dir_open,
.llseek = default_llseek,
.release = hppfs_release,
};
static int hppfs_statfs(struct dentry *dentry, struct kstatfs *sf)
{
sf->f_blocks = 0;
sf->f_bfree = 0;
sf->f_bavail = 0;
sf->f_files = 0;
sf->f_ffree = 0;
sf->f_type = HPPFS_SUPER_MAGIC;
return 0;
}
static struct inode *hppfs_alloc_inode(struct super_block *sb)
{
struct hppfs_inode_info *hi;
hi = kmalloc(sizeof(*hi), GFP_KERNEL);
if (!hi)
return NULL;
hi->proc_dentry = NULL;
inode_init_once(&hi->vfs_inode);
return &hi->vfs_inode;
}
void hppfs_evict_inode(struct inode *ino)
{
clear_inode(ino);
dput(HPPFS_I(ino)->proc_dentry);
mntput(ino->i_sb->s_fs_info);
}
static void hppfs_i_callback(struct rcu_head *head)
{
struct inode *inode = container_of(head, struct inode, i_rcu);
kfree(HPPFS_I(inode));
}
static void hppfs_destroy_inode(struct inode *inode)
{
call_rcu(&inode->i_rcu, hppfs_i_callback);
}
static const struct super_operations hppfs_sbops = {
.alloc_inode = hppfs_alloc_inode,
.destroy_inode = hppfs_destroy_inode,
.evict_inode = hppfs_evict_inode,
.statfs = hppfs_statfs,
};
static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
int buflen)
{
struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry;
return d_inode(proc_dentry)->i_op->readlink(proc_dentry, buffer,
buflen);
}
static const char *hppfs_follow_link(struct dentry *dentry, void **cookie)
{
struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry;
return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, cookie);
}
static void hppfs_put_link(struct inode *inode, void *cookie)
{
struct inode *proc_inode = d_inode(HPPFS_I(inode)->proc_dentry);
if (proc_inode->i_op->put_link)
proc_inode->i_op->put_link(proc_inode, cookie);
}
static const struct inode_operations hppfs_dir_iops = {
.lookup = hppfs_lookup,
};
static const struct inode_operations hppfs_link_iops = {
.readlink = hppfs_readlink,
.follow_link = hppfs_follow_link,
.put_link = hppfs_put_link,
};
static struct inode *get_inode(struct super_block *sb, struct dentry *dentry)
{
struct inode *proc_ino = d_inode(dentry);
struct inode *inode = new_inode(sb);
if (!inode) {
dput(dentry);
return NULL;
}
if (d_is_dir(dentry)) {
inode->i_op = &hppfs_dir_iops;
inode->i_fop = &hppfs_dir_fops;
} else if (d_is_symlink(dentry)) {
inode->i_op = &hppfs_link_iops;
inode->i_fop = &hppfs_file_fops;
} else {
inode->i_op = &hppfs_file_iops;
inode->i_fop = &hppfs_file_fops;
}
HPPFS_I(inode)->proc_dentry = dentry;
inode->i_uid = proc_ino->i_uid;
inode->i_gid = proc_ino->i_gid;
inode->i_atime = proc_ino->i_atime;
inode->i_mtime = proc_ino->i_mtime;
inode->i_ctime = proc_ino->i_ctime;
inode->i_ino = proc_ino->i_ino;
inode->i_mode = proc_ino->i_mode;
set_nlink(inode, proc_ino->i_nlink);
inode->i_size = proc_ino->i_size;
inode->i_blocks = proc_ino->i_blocks;
return inode;
}
static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
{
struct inode *root_inode;
struct vfsmount *proc_mnt;
int err = -ENOENT;
proc_mnt = mntget(task_active_pid_ns(current)->proc_mnt);
if (IS_ERR(proc_mnt))
goto out;
sb->s_blocksize = 1024;
sb->s_blocksize_bits = 10;
sb->s_magic = HPPFS_SUPER_MAGIC;
sb->s_op = &hppfs_sbops;
sb->s_fs_info = proc_mnt;
err = -ENOMEM;
root_inode = get_inode(sb, dget(proc_mnt->mnt_root));
sb->s_root = d_make_root(root_inode);
if (!sb->s_root)
goto out_mntput;
return 0;
out_mntput:
mntput(proc_mnt);
out:
return(err);
}
static struct dentry *hppfs_read_super(struct file_system_type *type,
int flags, const char *dev_name,
void *data)
{
return mount_nodev(type, flags, data, hppfs_fill_super);
}
static struct file_system_type hppfs_type = {
.owner = THIS_MODULE,
.name = "hppfs",
.mount = hppfs_read_super,
.kill_sb = kill_anon_super,
.fs_flags = 0,
};
MODULE_ALIAS_FS("hppfs");
static int __init init_hppfs(void)
{
return register_filesystem(&hppfs_type);
}
static void __exit exit_hppfs(void)
{
unregister_filesystem(&hppfs_type);
}
module_init(init_hppfs)
module_exit(exit_hppfs)
MODULE_LICENSE("GPL");
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