diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/drivers/chan_user.c | 2 | ||||
-rw-r--r-- | arch/um/include/os.h | 2 | ||||
-rw-r--r-- | arch/um/include/sysdep-i386/checksum.h | 74 | ||||
-rw-r--r-- | arch/um/include/sysdep-x86_64/checksum.h | 47 | ||||
-rw-r--r-- | arch/um/os-Linux/Makefile | 10 | ||||
-rw-r--r-- | arch/um/os-Linux/execvp.c | 149 | ||||
-rw-r--r-- | arch/um/os-Linux/helper.c | 14 |
7 files changed, 220 insertions, 78 deletions
diff --git a/arch/um/drivers/chan_user.c b/arch/um/drivers/chan_user.c index 2f880cb167a..0cad3546cb8 100644 --- a/arch/um/drivers/chan_user.c +++ b/arch/um/drivers/chan_user.c @@ -120,7 +120,7 @@ static int winch_thread(void *arg) /* These are synchronization calls between various UML threads on the * host - since they are not different kernel threads, we cannot use * kernel semaphores. We don't use SysV semaphores because they are - * persistant. */ + * persistent. */ count = os_read_file(pipe_fd, &c, sizeof(c)); if(count != sizeof(c)) printk("winch_thread : failed to read synchronization byte, " diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 6516f6dca96..13a86bd383d 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -233,6 +233,8 @@ extern unsigned long __do_user_copy(void *to, const void *from, int n, void (*op)(void *to, const void *from, int n), int *faulted_out); +/* execvp.c */ +extern int execvp_noalloc(char *buf, const char *file, char *const argv[]); /* helper.c */ extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, unsigned long *stack_out); diff --git a/arch/um/include/sysdep-i386/checksum.h b/arch/um/include/sysdep-i386/checksum.h index 052bb061a97..0cb4645cbeb 100644 --- a/arch/um/include/sysdep-i386/checksum.h +++ b/arch/um/include/sysdep-i386/checksum.h @@ -20,8 +20,7 @@ * * it's best to have buff aligned on a 32-bit boundary */ -unsigned int csum_partial(const unsigned char * buff, int len, - unsigned int sum); +__wsum csum_partial(const void *buff, int len, __wsum sum); /* * Note: when you get a NULL pointer exception here this means someone @@ -32,8 +31,8 @@ unsigned int csum_partial(const unsigned char * buff, int len, */ static __inline__ -unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst, - int len, int sum) +__wsum csum_partial_copy_nocheck(const void *src, void *dst, + int len, __wsum sum) { memcpy(dst, src, len); return csum_partial(dst, len, sum); @@ -48,36 +47,25 @@ unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char * */ static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char __user *src, - unsigned char *dst, - int len, int sum, int *err_ptr) +__wsum csum_partial_copy_from_user(const void __user *src, void *dst, + int len, __wsum sum, int *err_ptr) { - if(copy_from_user(dst, src, len)){ + if (copy_from_user(dst, src, len)) { *err_ptr = -EFAULT; - return(-1); + return (__force __wsum)-1; } return csum_partial(dst, len, sum); } /* - * These are the old (and unsafe) way of doing checksums, a warning message - * will be printed if they are used and an exception occurs. - * - * these functions should go away after some time. - */ - -#define csum_partial_copy_fromuser csum_partial_copy_from_user - -/* * This is a version of ip_compute_csum() optimized for IP headers, * which always checksum on 4 octet boundaries. * * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by * Arnt Gulbrandsen. */ -static inline unsigned short ip_fast_csum(unsigned char * iph, - unsigned int ihl) +static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) { unsigned int sum; @@ -105,29 +93,29 @@ static inline unsigned short ip_fast_csum(unsigned char * iph, : "=r" (sum), "=r" (iph), "=r" (ihl) : "1" (iph), "2" (ihl) : "memory"); - return sum; + return (__force __sum16)sum; } /* * Fold a partial checksum */ -static inline unsigned int csum_fold(unsigned int sum) +static inline __sum16 csum_fold(__wsum sum) { __asm__( "addl %1, %0 ;\n" "adcl $0xffff, %0 ;\n" : "=r" (sum) - : "r" (sum << 16), "0" (sum & 0xffff0000) + : "r" ((__force u32)sum << 16), + "0" ((__force u32)sum & 0xffff0000) ); - return (~sum) >> 16; + return (__force __sum16)(~(__force u32)sum >> 16); } -static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, - unsigned long daddr, +static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, - unsigned int sum) + __wsum sum) { __asm__( "addl %1, %0 ;\n" @@ -135,7 +123,7 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, "adcl %3, %0 ;\n" "adcl $0, %0 ;\n" : "=r" (sum) - : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum)); + : "g" (daddr), "g"(saddr), "g"((len + proto) << 8), "0"(sum)); return sum; } @@ -143,11 +131,10 @@ static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, * computes the checksum of the TCP/UDP pseudo-header * returns a 16-bit checksum, already complemented */ -static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, - unsigned int sum) + __wsum sum) { return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); } @@ -157,17 +144,16 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, * in icmp.c */ -static inline unsigned short ip_compute_csum(unsigned char * buff, int len) +static inline __sum16 ip_compute_csum(const void *buff, int len) { return csum_fold (csum_partial(buff, len, 0)); } #define _HAVE_ARCH_IPV6_CSUM -static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, - struct in6_addr *daddr, - __u32 len, - unsigned short proto, - unsigned int sum) +static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, unsigned short proto, + __wsum sum) { __asm__( "addl 0(%1), %0 ;\n" @@ -192,14 +178,14 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, * Copy and checksum to user */ #define HAVE_CSUM_COPY_USER -static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, - unsigned char __user *dst, - int len, int sum, int *err_ptr) +static __inline__ __wsum csum_and_copy_to_user(const void *src, + void __user *dst, + int len, __wsum sum, int *err_ptr) { - if (access_ok(VERIFY_WRITE, dst, len)){ - if(copy_to_user(dst, src, len)){ + if (access_ok(VERIFY_WRITE, dst, len)) { + if (copy_to_user(dst, src, len)) { *err_ptr = -EFAULT; - return(-1); + return (__force __wsum)-1; } return csum_partial(src, len, sum); @@ -208,7 +194,7 @@ static __inline__ unsigned int csum_and_copy_to_user(const unsigned char *src, if (len) *err_ptr = -EFAULT; - return -1; /* invalid checksum */ + return (__force __wsum)-1; /* invalid checksum */ } #endif diff --git a/arch/um/include/sysdep-x86_64/checksum.h b/arch/um/include/sysdep-x86_64/checksum.h index ea97005af69..a5be9031ea8 100644 --- a/arch/um/include/sysdep-x86_64/checksum.h +++ b/arch/um/include/sysdep-x86_64/checksum.h @@ -9,8 +9,7 @@ #include "linux/in6.h" #include "asm/uaccess.h" -extern unsigned csum_partial(const unsigned char *buff, unsigned len, - unsigned sum); +extern __wsum csum_partial(const void *buff, int len, __wsum sum); /* * Note: when you get a NULL pointer exception here this means someone @@ -21,21 +20,21 @@ extern unsigned csum_partial(const unsigned char *buff, unsigned len, */ static __inline__ -unsigned int csum_partial_copy_nocheck(const unsigned char *src, unsigned char *dst, - int len, int sum) +__wsum csum_partial_copy_nocheck(const void *src, void *dst, + int len, __wsum sum) { memcpy(dst, src, len); return(csum_partial(dst, len, sum)); } static __inline__ -unsigned int csum_partial_copy_from_user(const unsigned char *src, - unsigned char *dst, int len, int sum, +__wsum csum_partial_copy_from_user(const void __user *src, + void *dst, int len, __wsum sum, int *err_ptr) { - if(copy_from_user(dst, src, len)){ + if (copy_from_user(dst, src, len)) { *err_ptr = -EFAULT; - return(-1); + return (__force __wsum)-1; } return csum_partial(dst, len, sum); } @@ -48,15 +47,16 @@ unsigned int csum_partial_copy_from_user(const unsigned char *src, * the last step before putting a checksum into a packet. * Make sure not to mix with 64bit checksums. */ -static inline unsigned int csum_fold(unsigned int sum) +static inline __sum16 csum_fold(__wsum sum) { __asm__( " addl %1,%0\n" " adcl $0xffff,%0" : "=r" (sum) - : "r" (sum << 16), "0" (sum & 0xffff0000) + : "r" ((__force u32)sum << 16), + "0" ((__force u32)sum & 0xffff0000) ); - return (~sum) >> 16; + return (__force __sum16)(~(__force u32)sum >> 16); } /** @@ -70,28 +70,27 @@ static inline unsigned int csum_fold(unsigned int sum) * Returns the pseudo header checksum the input data. Result is * 32bit unfolded. */ -static inline unsigned long -csum_tcpudp_nofold(unsigned saddr, unsigned daddr, unsigned short len, - unsigned short proto, unsigned int sum) +static inline __wsum +csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, + unsigned short proto, __wsum sum) { asm(" addl %1, %0\n" " adcl %2, %0\n" " adcl %3, %0\n" " adcl $0, %0\n" : "=r" (sum) - : "g" (daddr), "g" (saddr), "g" ((ntohs(len)<<16)+proto*256), "0" (sum)); - return sum; + : "g" (daddr), "g" (saddr), "g" ((len + proto) << 8), "0" (sum)); + return sum; } /* * computes the checksum of the TCP/UDP pseudo-header * returns a 16-bit checksum, already complemented */ -static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, - unsigned long daddr, - unsigned short len, - unsigned short proto, - unsigned int sum) +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum sum) { return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); } @@ -101,7 +100,7 @@ static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, * iph: ipv4 header * ihl: length of header / 4 */ -static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) +static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) { unsigned int sum; @@ -128,7 +127,7 @@ static inline unsigned short ip_fast_csum(unsigned char *iph, unsigned int ihl) : "=r" (sum), "=r" (iph), "=r" (ihl) : "1" (iph), "2" (ihl) : "memory"); - return(sum); + return (__force __sum16)sum; } static inline unsigned add32_with_carry(unsigned a, unsigned b) @@ -140,6 +139,6 @@ static inline unsigned add32_with_carry(unsigned a, unsigned b) return a; } -extern unsigned short ip_compute_csum(unsigned char * buff, int len); +extern __sum16 ip_compute_csum(const void *buff, int len); #endif diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index b4183929b32..2f8c7946401 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,8 +3,8 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \ - signal.o start_up.o time.o trap.o tty.o uaccess.o umid.o tls.o \ +obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ + sigio.o signal.o start_up.o time.o trap.o tty.o uaccess.o umid.o tls.o \ user_syms.o util.o drivers/ sys-$(SUBARCH)/ obj-$(CONFIG_MODE_SKAS) += skas/ @@ -15,9 +15,9 @@ user-objs-$(CONFIG_MODE_TT) += tt.o obj-$(CONFIG_TTY_LOG) += tty_log.o user-objs-$(CONFIG_TTY_LOG) += tty_log.o -USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \ - process.o sigio.o signal.o start_up.o time.o trap.o tty.o tls.o \ - uaccess.o umid.o util.o +USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ + main.o mem.o process.o sigio.o signal.o start_up.o time.o trap.o tty.o \ + tls.o uaccess.o umid.o util.o CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH) diff --git a/arch/um/os-Linux/execvp.c b/arch/um/os-Linux/execvp.c new file mode 100644 index 00000000000..66e583a4031 --- /dev/null +++ b/arch/um/os-Linux/execvp.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2006 by Paolo Giarrusso - modified from glibc' execvp.c. + Original copyright notice follows: + + Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ +#include <unistd.h> + +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <limits.h> + +#ifndef TEST +#include "um_malloc.h" +#else +#include <stdio.h> +#define um_kmalloc malloc +#endif +#include "os.h" + +/* Execute FILE, searching in the `PATH' environment variable if it contains + no slashes, with arguments ARGV and environment from `environ'. */ +int execvp_noalloc(char *buf, const char *file, char *const argv[]) +{ + if (*file == '\0') { + return -ENOENT; + } + + if (strchr (file, '/') != NULL) { + /* Don't search when it contains a slash. */ + execv(file, argv); + } else { + int got_eacces; + size_t len, pathlen; + char *name, *p; + char *path = getenv("PATH"); + if (path == NULL) + path = ":/bin:/usr/bin"; + + len = strlen(file) + 1; + pathlen = strlen(path); + /* Copy the file name at the top. */ + name = memcpy(buf + pathlen + 1, file, len); + /* And add the slash. */ + *--name = '/'; + + got_eacces = 0; + p = path; + do { + char *startp; + + path = p; + //Let's avoid this GNU extension. + //p = strchrnul (path, ':'); + p = strchr(path, ':'); + if (!p) + p = strchr(path, '\0'); + + if (p == path) + /* Two adjacent colons, or a colon at the beginning or the end + of `PATH' means to search the current directory. */ + startp = name + 1; + else + startp = memcpy(name - (p - path), path, p - path); + + /* Try to execute this name. If it works, execv will not return. */ + execv(startp, argv); + + /* + if (errno == ENOEXEC) { + } + */ + + switch (errno) { + case EACCES: + /* Record the we got a `Permission denied' error. If we end + up finding no executable we can use, we want to diagnose + that we did find one but were denied access. */ + got_eacces = 1; + case ENOENT: + case ESTALE: + case ENOTDIR: + /* Those errors indicate the file is missing or not executable + by us, in which case we want to just try the next path + directory. */ + case ENODEV: + case ETIMEDOUT: + /* Some strange filesystems like AFS return even + stranger error numbers. They cannot reasonably mean + anything else so ignore those, too. */ + case ENOEXEC: + /* We won't go searching for the shell + * if it is not executable - the Linux + * kernel already handles this enough, + * for us. */ + break; + + default: + /* Some other error means we found an executable file, but + something went wrong executing it; return the error to our + caller. */ + return -errno; + } + } while (*p++ != '\0'); + + /* We tried every element and none of them worked. */ + if (got_eacces) + /* At least one failure was due to permissions, so report that + error. */ + return -EACCES; + } + + /* Return the error from the last attempt (probably ENOENT). */ + return -errno; +} +#ifdef TEST +int main(int argc, char**argv) +{ + char buf[PATH_MAX]; + int ret; + argc--; + if (!argc) { + fprintf(stderr, "Not enough arguments\n"); + return 1; + } + argv++; + if (ret = execvp_noalloc(buf, argv[0], argv)) { + errno = -ret; + perror("execvp_noalloc"); + } + return 0; +} +#endif diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index d13299cfa31..c7ad6306e22 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c @@ -8,18 +8,21 @@ #include <unistd.h> #include <errno.h> #include <sched.h> +#include <limits.h> #include <sys/signal.h> #include <sys/wait.h> #include "user.h" #include "kern_util.h" #include "user_util.h" #include "os.h" +#include "um_malloc.h" struct helper_data { void (*pre_exec)(void*); void *pre_data; char **argv; int fd; + char *buf; }; /* Debugging aid, changed only from gdb */ @@ -41,9 +44,8 @@ static int helper_child(void *arg) } if (data->pre_exec != NULL) (*data->pre_exec)(data->pre_data); - execvp(argv[0], argv); - errval = -errno; - printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno); + errval = execvp_noalloc(data->buf, argv[0], argv); + printk("helper_child - execvp of '%s' failed - errno = %d\n", argv[0], -errval); os_write_file(data->fd, &errval, sizeof(errval)); kill(os_getpid(), SIGKILL); return 0; @@ -84,11 +86,13 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, data.pre_data = pre_data; data.argv = argv; data.fd = fds[1]; + data.buf = __cant_sleep() ? um_kmalloc_atomic(PATH_MAX) : + um_kmalloc(PATH_MAX); pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if (pid < 0) { ret = -errno; printk("run_helper : clone failed, errno = %d\n", errno); - goto out_close; + goto out_free2; } close(fds[1]); @@ -109,6 +113,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, CATCH_EINTR(waitpid(pid, NULL, 0)); } +out_free2: + kfree(data.buf); out_close: if (fds[1] != -1) close(fds[1]); |