From f050aeeed3462d487a23fcda8c15bfcf87c7a976 Mon Sep 17 00:00:00 2001 From: Lubos Dolezel Date: Thu, 29 Oct 2015 17:27:36 +0100 Subject: [PATCH] Added BSD ioctl translation infrstructure, added mkdir/rmdir and fcntl_nocancel --- src/kernel/emulation/linux/CMakeLists.txt | 2 + src/kernel/emulation/linux/fcntl/fcntl.c | 5 +++ src/kernel/emulation/linux/fcntl/fcntl.h | 1 + src/kernel/emulation/linux/stat/mkdir.c | 20 +++++++++ src/kernel/emulation/linux/stat/mkdir.h | 7 +++ src/kernel/emulation/linux/stat/rmdir.c | 20 +++++++++ src/kernel/emulation/linux/stat/rmdir.h | 7 +++ src/kernel/emulation/linux/syscalls.c | 5 +++ src/kernel/mach_server/client/CMakeLists.txt | 1 + src/kernel/mach_server/client/lkm.c | 42 ++++++++++++++++++ src/kernel/mach_server/client/lkm.h | 8 ++++ src/kernel/mach_server/client/mach_traps.c | 27 +----------- src/lkm/bsd_ioctl.c | 46 +++++++++++++++++--- src/lkm/bsd_ioctl.h | 42 ++++++++++++++++-- src/lkm/traps.c | 12 +++-- 15 files changed, 208 insertions(+), 37 deletions(-) create mode 100644 src/kernel/emulation/linux/stat/mkdir.c create mode 100644 src/kernel/emulation/linux/stat/mkdir.h create mode 100644 src/kernel/emulation/linux/stat/rmdir.c create mode 100644 src/kernel/emulation/linux/stat/rmdir.h create mode 100644 src/kernel/mach_server/client/lkm.c create mode 100644 src/kernel/mach_server/client/lkm.h diff --git a/src/kernel/emulation/linux/CMakeLists.txt b/src/kernel/emulation/linux/CMakeLists.txt index 5f27254d4..4db336984 100644 --- a/src/kernel/emulation/linux/CMakeLists.txt +++ b/src/kernel/emulation/linux/CMakeLists.txt @@ -61,6 +61,8 @@ set(emulation_sources stat/stat.c stat/getfsstat.c stat/statfs.c + stat/mkdir.c + stat/rmdir.c stat/common.c dirent/getdirentries.c time/gettimeofday.c diff --git a/src/kernel/emulation/linux/fcntl/fcntl.c b/src/kernel/emulation/linux/fcntl/fcntl.c index 4ef6fbed0..39c568c40 100644 --- a/src/kernel/emulation/linux/fcntl/fcntl.c +++ b/src/kernel/emulation/linux/fcntl/fcntl.c @@ -25,6 +25,11 @@ extern int sprintf(char *str, const char *format, ...); long sys_readlink(const char* path, char* buf, unsigned long bsize); long sys_fcntl(int fd, int cmd, long arg) +{ + return sys_fcntl_nocancel(fd, cmd, arg); +} + +long sys_fcntl_nocancel(int fd, int cmd, long arg) { int ret, linux_cmd; diff --git a/src/kernel/emulation/linux/fcntl/fcntl.h b/src/kernel/emulation/linux/fcntl/fcntl.h index 0bd233a89..1b7d47e4e 100644 --- a/src/kernel/emulation/linux/fcntl/fcntl.h +++ b/src/kernel/emulation/linux/fcntl/fcntl.h @@ -2,6 +2,7 @@ #define LINUX_FCNTL_H long sys_fcntl(int fd, int cmd, long arg); +long sys_fcntl_nocancel(int fd, int cmd, long arg); enum { LINUX_F_DUPFD = 0, diff --git a/src/kernel/emulation/linux/stat/mkdir.c b/src/kernel/emulation/linux/stat/mkdir.c new file mode 100644 index 000000000..9c8fdd0be --- /dev/null +++ b/src/kernel/emulation/linux/stat/mkdir.c @@ -0,0 +1,20 @@ +#include "mkdir.h" +#include "common.h" +#include "../base.h" +#include "../errno.h" +#include + +long sys_mkdir(const char* path, unsigned int mode) +{ + int ret; + + // TODO: handle case conversion + + ret = LINUX_SYSCALL(__NR_mkdir, path, mode); + + if (ret < 0) + return errno_linux_to_bsd(ret); + + return 0; +} + diff --git a/src/kernel/emulation/linux/stat/mkdir.h b/src/kernel/emulation/linux/stat/mkdir.h new file mode 100644 index 000000000..cd434417e --- /dev/null +++ b/src/kernel/emulation/linux/stat/mkdir.h @@ -0,0 +1,7 @@ +#ifndef LINUX_MKDIR_H +#define LINUX_MKDIR_H + +long sys_mkdir(const char* path, unsigned int mode); + +#endif + diff --git a/src/kernel/emulation/linux/stat/rmdir.c b/src/kernel/emulation/linux/stat/rmdir.c new file mode 100644 index 000000000..0e9787472 --- /dev/null +++ b/src/kernel/emulation/linux/stat/rmdir.c @@ -0,0 +1,20 @@ +#include "rmdir.h" +#include "common.h" +#include "../base.h" +#include "../errno.h" +#include + +long sys_rmdir(const char* path) +{ + int ret; + + // TODO: handle case conversion + + ret = LINUX_SYSCALL(__NR_rmdir, path); + + if (ret < 0) + return errno_linux_to_bsd(ret); + + return 0; +} + diff --git a/src/kernel/emulation/linux/stat/rmdir.h b/src/kernel/emulation/linux/stat/rmdir.h new file mode 100644 index 000000000..45538ee0b --- /dev/null +++ b/src/kernel/emulation/linux/stat/rmdir.h @@ -0,0 +1,7 @@ +#ifndef LINUX_RMDIR_H +#define LINUX_RMDIR_H + +long sys_rmdir(const char* path); + +#endif + diff --git a/src/kernel/emulation/linux/syscalls.c b/src/kernel/emulation/linux/syscalls.c index b7f79dd31..849dd408f 100644 --- a/src/kernel/emulation/linux/syscalls.c +++ b/src/kernel/emulation/linux/syscalls.c @@ -47,6 +47,8 @@ #include "stat/stat.h" #include "stat/lstat.h" #include "stat/statfs.h" +#include "stat/mkdir.h" +#include "stat/rmdir.h" #include "stat/getfsstat.h" #include "time/gettimeofday.h" #include "wqueue/bsdthread_register.h" @@ -84,6 +86,8 @@ void* __bsd_syscall_table[512] = { [121] = sys_writev, [123] = sys_fchown, [124] = sys_fchmod, + [136] = sys_mkdir, + [137] = sys_rmdir, [147] = sys_setsid, [153] = sys_pread, [154] = sys_pwrite, @@ -114,6 +118,7 @@ void* __bsd_syscall_table[512] = { [397] = sys_write_nocancel, [398] = sys_open_nocancel, [399] = sys_close_nocancel, + [406] = sys_fcntl_nocancel, [408] = sys_fsync_nocancel, [411] = sys_readv_nocancel, [412] = sys_writev_nocancel, diff --git a/src/kernel/mach_server/client/CMakeLists.txt b/src/kernel/mach_server/client/CMakeLists.txt index 4686d25ad..3b6365ec2 100644 --- a/src/kernel/mach_server/client/CMakeLists.txt +++ b/src/kernel/mach_server/client/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories("${DARLING_TOP_DIRECTORY}/src/kernel/emulation/linux/ext") set(mach_server_client_sources mach_traps.c mach_time.c + lkm.c ) add_library(mach_server_client OBJECT ${mach_server_client_sources}) diff --git a/src/kernel/mach_server/client/lkm.c b/src/kernel/mach_server/client/lkm.c new file mode 100644 index 000000000..00490f974 --- /dev/null +++ b/src/kernel/mach_server/client/lkm.c @@ -0,0 +1,42 @@ +#include "lkm.h" +#include "../../lkm/api.h" + +int driver_fd; + +void mach_driver_init(void) +{ + if (driver_fd != -1) + close(driver_fd); + + driver_fd = open("/dev/mach", O_RDWR); + if (driver_fd == -1) + { + const char* msg = "Cannot open /dev/mach. Aborting.\nMake sure you have loaded the darling-mach kernel module.\n"; + + write(2, msg, strlen(msg)); + abort(); + } + + if (ioctl(driver_fd, NR_get_api_version, 0) != DARLING_MACH_API_VERSION) + { + const char* msg = "Darling Mach kernel module reports different API level. Aborting.\n"; + + write(2, msg, strlen(msg)); + abort(); + } +} + +extern int __real_ioctl(int fd, int cmd, void* arg); + +// Emulated ioctl implementation +int ioctl(int fd, int cmd, void* arg) +{ + struct bsd_ioctl_args args = { + .fd = fd, + .request = cmd, + .arg = arg + }; + + return __real_ioctl(driver_fd, NR_bsd_ioctl_trap, &args); +} + diff --git a/src/kernel/mach_server/client/lkm.h b/src/kernel/mach_server/client/lkm.h new file mode 100644 index 000000000..01f785190 --- /dev/null +++ b/src/kernel/mach_server/client/lkm.h @@ -0,0 +1,8 @@ +#ifndef _LKM_H +#define _LKM_H + +__attribute__((hidden)) + extern int driver_fd; + +#endif + diff --git a/src/kernel/mach_server/client/mach_traps.c b/src/kernel/mach_server/client/mach_traps.c index bfecc8e3a..f6c96eb29 100644 --- a/src/kernel/mach_server/client/mach_traps.c +++ b/src/kernel/mach_server/client/mach_traps.c @@ -1,3 +1,4 @@ +#define ioctl __real_ioctl #define PRIVATE #include #include @@ -5,34 +6,10 @@ #include #include #include "../../lkm/api.h" +#include "lkm.h" #define UNIMPLEMENTED_TRAP() { char msg[] = "Called unimplemented Mach trap: "; write(2, msg, sizeof(msg)-1); write(2, __FUNCTION__, sizeof(__FUNCTION__)-1); write(2, "\n", 1); } -static int driver_fd = -1; - -void mach_driver_init(void) -{ - if (driver_fd != -1) - close(driver_fd); - - driver_fd = open("/dev/mach", O_RDWR); - if (driver_fd == -1) - { - const char* msg = "Cannot open /dev/mach. Aborting.\nMake sure you have loaded the darling-mach kernel module.\n"; - - write(2, msg, strlen(msg)); - abort(); - } - - if (ioctl(driver_fd, NR_get_api_version, 0) != DARLING_MACH_API_VERSION) - { - const char* msg = "Darling Mach kernel module reports different API level. Aborting.\n"; - - write(2, msg, strlen(msg)); - abort(); - } -} - mach_port_name_t mach_reply_port(void) { return ioctl(driver_fd, NR_mach_reply_port, 0); diff --git a/src/lkm/bsd_ioctl.c b/src/lkm/bsd_ioctl.c index 4a03a2aa3..2884a0f79 100644 --- a/src/lkm/bsd_ioctl.c +++ b/src/lkm/bsd_ioctl.c @@ -18,18 +18,54 @@ */ #include "bsd_ioctl.h" +#include "debug.h" +#include +#include -void bsd_ioctl_xlate_socket(struct bsd_ioctl_args* args) +#define D_TAPE 1 +#define D_DISK 2 +#define D_TTY 3 + +int bsd_ioctl_xlate_socket(struct file* f, struct bsd_ioctl_args* args, long* retval) { - + return bsd_ioctl_xlate_generic(f, args, retval); } -void bsd_ioctl_xlate_tty(struct bsd_ioctl_args* args) +int bsd_ioctl_xlate_tty(struct file* f, struct bsd_ioctl_args* args, long* retval) { - + return bsd_ioctl_xlate_generic(f, args, retval); +} + +int bsd_ioctl_xlate_pts(struct file* f, struct bsd_ioctl_args* args, long* retval) +{ + return bsd_ioctl_xlate_generic(f, args, retval); } -void bsd_ioctl_xlate_pts(struct bsd_ioctl_args* args) +int bsd_ioctl_xlate_generic(struct file* f, struct bsd_ioctl_args* args, long* retval) { + switch (args->request) + { + case BSD_FIODTYPE: + { + char name[60]; + + if (d_path(&f->f_path, name, sizeof(name))) + { + int type; + if (strncmp(name, "/dev/pts", 8) == 0 || strncmp(name, "/dev/tty", 8) == 0) + type = D_TTY; + else if (strncmp(name, "/dev/st", 7) == 0 || strncmp(name, "/dev/nst", 8) == 0) + type = D_TAPE; + else + type = D_DISK; + *retval = type; + + return 1; + } + + break; + } + } + return 0; } diff --git a/src/lkm/bsd_ioctl.h b/src/lkm/bsd_ioctl.h index ab3a3ea86..803d8fd36 100644 --- a/src/lkm/bsd_ioctl.h +++ b/src/lkm/bsd_ioctl.h @@ -20,9 +20,45 @@ #ifndef BSD_IOCTL_H #define BSD_IOCTL_H #include "api.h" +#include -void bsd_ioctl_xlate_socket(struct bsd_ioctl_args* args); -void bsd_ioctl_xlate_tty(struct bsd_ioctl_args* args); -void bsd_ioctl_xlate_pts(struct bsd_ioctl_args* args); +// If only translation of ioctl request number happens, +// retval is untouched and 0 is returned. +// If the ioctl is handled completely differently, retval contains the return +// value to be returned to userspace and function returns non-zero value. + +int bsd_ioctl_xlate_socket(struct file* f, struct bsd_ioctl_args* args, long* retval); +int bsd_ioctl_xlate_tty(struct file* f, struct bsd_ioctl_args* args, long* retval); +int bsd_ioctl_xlate_pts(struct file* f, struct bsd_ioctl_args* args, long* retval); +int bsd_ioctl_xlate_generic(struct file* f, struct bsd_ioctl_args* args, long* retval); + +#define BSD_IOCPARM_MASK 0x1fff +#define BSD_IOCPARM_LEN(x) (((x) >> 16) & BSD_IOCPARM_MASK) +#define BSD_IOCBASECMD(x) ((x) & ~(IBSD_OCPARM_MASK << 16)) +#define BSD_IOCGROUP(x) (((x) >> 8) & 0xff) + +#define BSD_IOCPARM_MAX (BSD_IOCPARM_MASK + 1) +#define BSD_IOC_VOID (uint32_t)0x20000000 +#define BSD_IOC_OUT (uint32_t)0x40000000 +#define BSD_IOC_IN (uint32_t)0x80000000 +#define BSD_IOC_INOUT (BSD_IOC_IN|BSD_IOC_OUT) +#define BSD_IOC_DIRMASK (uint32_t)0xe0000000 + +#define BSD_IOC(inout,group,num,len) \ + (inout | ((len & BSD_IOCPARM_MASK) << 16) | ((group) << 8) | (num)) +#define BSD_IO(g,n) BSD_IOC(BSD_IOC_VOID, (g), (n), 0) +#define BSD_IOR(g,n,t) BSD_IOC(BSD_IOC_OUT, (g), (n), sizeof(t)) +#define BSD_IOW(g,n,t) BSD_IOC(BSD_IOC_IN, (g), (n), sizeof(t)) +#define BSD_IOWR(g,n,t) BSD_IOC(BSD_IOC_INOUT, (g), (n), sizeof(t)) + + +#define BSD_FIOCLEX BSD_IO('f', 1) +#define BSD_FIONCLEX BSD_IO('f', 2) +#define BSD_FIONREAD BSD_IOR('f', 127, int) +#define BSD_FIONBIO BSD_IOW('f', 126, int) +#define BSD_FIOASYNC BSD_IOW('f', 125, int) +#define BSD_FIOSETOWN BSD_IOW('f', 124, int) +#define BSD_FIOGETOWN BSD_IOR('f', 123, int) +#define BSD_FIODTYPE BSD_IOR('f', 122, int) #endif diff --git a/src/lkm/traps.c b/src/lkm/traps.c index ebaa6b30a..edb61d69e 100644 --- a/src/lkm/traps.c +++ b/src/lkm/traps.c @@ -698,6 +698,7 @@ long bsd_ioctl_trap(mach_task_t* task, struct bsd_ioctl_args* in_args) struct file* f; char name[60]; long retval = 0; + int handled; if (copy_from_user(&args, in_args, sizeof(args))) return -EFAULT; @@ -720,13 +721,16 @@ long bsd_ioctl_trap(mach_task_t* task, struct bsd_ioctl_args* in_args) // Perform ioctl translation based on name if (strncmp(name, "socket:", 7) == 0) - bsd_ioctl_xlate_socket(&args); + handled = bsd_ioctl_xlate_socket(f, &args, &retval); else if (strncmp(name, "/dev/tty", 8) == 0) - bsd_ioctl_xlate_tty(&args); + handled = bsd_ioctl_xlate_tty(f, &args, &retval); else if (strncmp(name, "/dev/pts", 8) == 0) - bsd_ioctl_xlate_pts(&args); + handled = bsd_ioctl_xlate_pts(f, &args, &retval); + else + handled = bsd_ioctl_xlate_generic(f, &args, &retval); - retval = f->f_op->unlocked_ioctl(f, args.request, args.arg); + if (!handled) + retval = f->f_op->unlocked_ioctl(f, args.request, args.arg); fput(f); -- 2.51.2