Date: Mon, 7 Feb 2005 18:26:48 -0500 From: John Baldwin <jhb@FreeBSD.org> To: amd64@FreeBSD.org Cc: ia64@FreeBSD.org Subject: [PATCH] Fixes to the ia32 ABI (and amd64/Linux) Message-ID: <200502071826.48609.jhb@FreeBSD.org>
next in thread | raw e-mail | index | archive | help
Can people test the patch below, it includes various and sundry fixes to the FreeBSD 32 compat ABI (i.e. FreeBSD/i386 binaries on FreeBSD/amd64 and FreeBSD/ia64) and the amd64 Linux/i386 ABI as well. I don't expect it to make anything start working that was broken before, but there shouldn't be any regressions: --- //depot/projects/smpng/sys/amd64/linux32/linux32_machdep.c 2004/10/05 19:15:26 +++ //depot/user/jhb/proc/amd64/linux32/linux32_machdep.c 2005/02/04 16:32:42 @@ -34,6 +34,7 @@ #include <sys/param.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/imgact.h> #include <sys/lock.h> #include <sys/malloc.h> #include <sys/mman.h> @@ -49,6 +50,8 @@ #include <vm/vm.h> #include <vm/pmap.h> +#include <vm/vm_extern.h> +#include <vm/vm_kern.h> #include <vm/vm_map.h> #include <amd64/linux32/linux.h> @@ -89,72 +92,120 @@ return (lsa); } -int -linux_execve(struct thread *td, struct linux_execve_args *args) +/* + * Custom version of exec_copyin_args() so that we can translate + * the pointers. + */ +static int +linux_exec_copyin_args(struct image_args *args, char *fname, + enum uio_seg segflg, char **argv, char **envv) { - struct execve_args ap; - caddr_t sg; + char *argp, *envp; + u_int32_t *p32, arg; + size_t length; int error; - u_int32_t *p32, arg; - char **p, *p64; - int count; + + bzero(args, sizeof(*args)); + if (argv == NULL) + return (EFAULT); - sg = stackgap_init(); - CHECKALTEXIST(td, &sg, args->path); + /* + * Allocate temporary demand zeroed space for argument and + * environment strings + */ + args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX); + if (args->buf == NULL) + return (ENOMEM); + args->begin_argv = args->buf; + args->endp = args->begin_argv; + args->stringspace = ARG_MAX; -#ifdef DEBUG - if (ldebug(execve)) - printf(ARGS(execve, "%s"), args->path); -#endif + args->fname = args->buf + ARG_MAX; - ap.fname = args->path; + /* + * Copy the file name. + */ + error = (segflg == UIO_SYSSPACE) ? + copystr(fname, args->fname, PATH_MAX, &length) : + copyinstr(fname, args->fname, PATH_MAX, &length); + if (error != 0) + return (error); - if (args->argp != NULL) { - count = 0; - p32 = (u_int32_t *)args->argp; - do { - error = copyin(p32++, &arg, sizeof(arg)); - if (error) - return error; - count++; - } while (arg != 0); - p = stackgap_alloc(&sg, count * sizeof(char *)); - ap.argv = p; - p32 = (u_int32_t *)args->argp; - do { - error = copyin(p32++, &arg, sizeof(arg)); - if (error) - return error; - p64 = PTRIN(arg); - error = copyout(&p64, p++, sizeof(p64)); - if (error) - return error; - } while (arg != 0); + /* + * extract arguments first + */ + p32 = (u_int32_t *)argv; + for (;;) { + error = copyin(p32++, &arg, sizeof(arg)); + if (error) + return (error); + if (arg == 0) + break; + argp = PTRIN(arg); + error = copyinstr(argp, args->endp, args->stringspace, &length); + if (error) { + if (error == ENAMETOOLONG) + return (E2BIG); + else + return (error); + } + args->stringspace -= length; + args->endp += length; + args->argc++; } - if (args->envp != NULL) { - count = 0; - p32 = (u_int32_t *)args->envp; - do { + + args->begin_envv = args->endp; + + /* + * extract environment strings + */ + if (envv) { + p32 = (u_int32_t *)envv; + for (;;) { error = copyin(p32++, &arg, sizeof(arg)); if (error) - return error; - count++; - } while (arg != 0); - p = stackgap_alloc(&sg, count * sizeof(char *)); - ap.envv = p; - p32 = (u_int32_t *)args->envp; - do { - error = copyin(p32++, &arg, sizeof(arg)); - if (error) - return error; - p64 = PTRIN(arg); - error = copyout(&p64, p++, sizeof(p64)); - if (error) - return error; - } while (arg != 0); + return (error); + if (arg == 0) + break; + envp = PTRIN(arg); + error = copyinstr(envp, args->endp, args->stringspace, + &length); + if (error) { + if (error == ENAMETOOLONG) + return (E2BIG); + else + return (error); + } + args->stringspace -= length; + args->endp += length; + args->envc++; + } } - return (execve(td, &ap)); + return (0); +} + +int +linux_execve(struct thread *td, struct linux_execve_args *args) +{ + struct image_args eargs; + char *path; + int error; + + LCONVPATHEXIST(td, args->path, &path); + +#ifdef DEBUG + if (ldebug(execve)) + printf(ARGS(execve, "%s"), path); +#endif + + error = linux_exec_copyin_args(&eargs, path, UIO_SYSSPACE, args->argp, + args->envp); + free(path, M_TEMP); + if (error == 0) + error = kern_execve(td, &eargs, NULL); + exec_free_args(&eargs); + return (error); } struct iovec32 { @@ -903,36 +954,20 @@ int linux_nanosleep(struct thread *td, struct linux_nanosleep_args *uap) { - struct timespec ats; + struct timespec rqt, rmt; struct l_timespec ats32; - struct nanosleep_args bsd_args; int error; - caddr_t sg; - caddr_t sarqts, sarmts; - sg = stackgap_init(); error = copyin(uap->rqtp, &ats32, sizeof(ats32)); if (error != 0) return (error); - ats.tv_sec = ats32.tv_sec; - ats.tv_nsec = ats32.tv_nsec; - sarqts = stackgap_alloc(&sg, sizeof(ats)); - error = copyout(&ats, sarqts, sizeof(ats)); - if (error != 0) - return (error); - sarmts = stackgap_alloc(&sg, sizeof(ats)); - bsd_args.rqtp = (void *)sarqts; - bsd_args.rmtp = (void *)sarmts; - error = nanosleep(td, &bsd_args); + rqt.tv_sec = ats32.tv_sec; + rqt.tv_nsec = ats32.tv_nsec; + error = kern_nanosleep(td, &rqt, &rmt); if (uap->rmtp != NULL) { - error = copyin(sarmts, &ats, sizeof(ats)); - if (error != 0) - return (error); - ats32.tv_sec = ats.tv_sec; - ats32.tv_nsec = ats.tv_nsec; + ats32.tv_sec = rmt.tv_sec; + ats32.tv_nsec = rmt.tv_nsec; error = copyout(&ats32, uap->rmtp, sizeof(ats32)); - if (error != 0) - return (error); } return (error); } --- //depot/projects/smpng/sys/amd64/linux32/linux32_sysvec.c 2005/01/31 22:15:49 +++ //depot/user/jhb/proc/amd64/linux32/linux32_sysvec.c 2005/02/04 16:32:42 @@ -744,7 +744,8 @@ exec_linux_imgact_try(struct image_params *imgp) { const char *head = (const char *)imgp->image_header; - int error = -1; + char *rpath; + int error = -1, len; /* * The interpreter for shell scripts run from a linux binary needs @@ -758,12 +759,10 @@ * path is found, use our stringspace to store it. */ if ((error = exec_shell_imgact(imgp)) == 0) { - char *rpath = NULL; - - linux_emul_find(FIRST_THREAD_IN_PROC(imgp->proc), NULL, - imgp->interpreter_name, &rpath, 0); - if (rpath != imgp->interpreter_name) { - int len = strlen(rpath) + 1; + linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc), + imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0); + if (rpath != NULL) { + len = strlen(rpath) + 1; if (len <= MAXSHELLCMDLEN) { memcpy(imgp->interpreter_name, rpath, len); --- //depot/projects/smpng/sys/compat/freebsd32/freebsd32_misc.c 2005/01/31 22:15:49 +++ //depot/user/jhb/proc/compat/freebsd32/freebsd32_misc.c 2005/02/04 16:32:42 @@ -222,65 +222,111 @@ return (error); } -int -freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap) +/* + * Custom version of exec_copyin_args() so that we can translate + * the pointers. + */ +static int +freebsd32_exec_copyin_args(struct image_args *args, char *fname, + enum uio_seg segflg, u_int32_t *argv, u_int32_t *envv) { + char *argp, *envp; + u_int32_t *p32, arg; + size_t length; int error; - caddr_t sg; - struct execve_args ap; - u_int32_t *p32, arg; - char **p, *p64; - int count; + + bzero(args, sizeof(*args)); + if (argv == NULL) + return (EFAULT); + + /* + * Allocate temporary demand zeroed space for argument and + * environment strings + */ + args->buf = (char *) kmem_alloc_wait(exec_map, PATH_MAX + ARG_MAX); + if (args->buf == NULL) + return (ENOMEM); + args->begin_argv = args->buf; + args->endp = args->begin_argv; + args->stringspace = ARG_MAX; + + args->fname = args->buf + ARG_MAX; - sg = stackgap_init(); - ap.fname = uap->fname; + /* + * Copy the file name. + */ + error = (segflg == UIO_SYSSPACE) ? + copystr(fname, args->fname, PATH_MAX, &length) : + copyinstr(fname, args->fname, PATH_MAX, &length); + if (error != 0) + return (error); - if (uap->argv) { - count = 0; - p32 = uap->argv; - do { - error = copyin(p32++, &arg, sizeof(arg)); - if (error) - return error; - count++; - } while (arg != 0); - p = stackgap_alloc(&sg, count * sizeof(char *)); - ap.argv = p; - p32 = uap->argv; - do { - error = copyin(p32++, &arg, sizeof(arg)); - if (error) - return error; - p64 = PTRIN(arg); - error = copyout(&p64, p++, sizeof(p64)); - if (error) - return error; - } while (arg != 0); + /* + * extract arguments first + */ + p32 = argv; + for (;;) { + error = copyin(p32++, &arg, sizeof(arg)); + if (error) + return (error); + if (arg == 0) + break; + argp = PTRIN(arg); + error = copyinstr(argp, args->endp, args->stringspace, &length); + if (error) { + if (error == ENAMETOOLONG) + return (E2BIG); + else + return (error); + } + args->stringspace -= length; + args->endp += length; + args->argc++; } - if (uap->envv) { - count = 0; - p32 = uap->envv; - do { + + args->begin_envv = args->endp; + + /* + * extract environment strings + */ + if (envv) { + p32 = envv; + for (;;) { error = copyin(p32++, &arg, sizeof(arg)); if (error) - return error; - count++; - } while (arg != 0); - p = stackgap_alloc(&sg, count * sizeof(char *)); - ap.envv = p; - p32 = uap->envv; - do { - error = copyin(p32++, &arg, sizeof(arg)); - if (error) - return error; - p64 = PTRIN(arg); - error = copyout(&p64, p++, sizeof(p64)); - if (error) - return error; - } while (arg != 0); + return (error); + if (arg == 0) + break; + envp = PTRIN(arg); + error = copyinstr(envp, args->endp, args->stringspace, + &length); + if (error) { + if (error == ENAMETOOLONG) + return (E2BIG); + else + return (error); + } + args->stringspace -= length; + args->endp += length; + args->envc++; + } } - return execve(td, &ap); + return (0); +} + +int +freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap) +{ + struct image_args eargs; + int error; + + error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE, + uap->argv, uap->envv); + if (error == 0) + error = kern_execve(td, &eargs, NULL); + exec_free_args(&eargs); + return (error); } #ifdef __ia64__ @@ -437,99 +483,63 @@ int freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap) { + struct itimerval itv, oitv, *itvp; + struct itimerval32 i32; int error; - caddr_t sg; - struct itimerval32 *p32, *op32, s32; - struct itimerval *p = NULL, *op = NULL, s; - p32 = uap->itv; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct itimerval)); - uap->itv = (struct itimerval32 *)p; - error = copyin(p32, &s32, sizeof(s32)); + if (uap->itv != NULL) { + error = copyin(uap->itv, &i32, sizeof(i32)); if (error) return (error); - TV_CP(s32, s, it_interval); - TV_CP(s32, s, it_value); - error = copyout(&s, p, sizeof(s)); - if (error) - return (error); - } - op32 = uap->oitv; - if (op32) { - sg = stackgap_init(); - op = stackgap_alloc(&sg, sizeof(struct itimerval)); - uap->oitv = (struct itimerval32 *)op; - } - error = setitimer(td, (struct setitimer_args *) uap); - if (error) + TV_CP(i32, itv, it_interval); + TV_CP(i32, itv, it_value); + itvp = &itv; + } else + itvp = NULL; + error = kern_setitimer(td, uap->which, itvp, &oitv); + if (error || uap->oitv == NULL) return (error); - if (op32) { - error = copyin(op, &s, sizeof(s)); - if (error) - return (error); - TV_CP(s, s32, it_interval); - TV_CP(s, s32, it_value); - error = copyout(&s32, op32, sizeof(s32)); - } - return (error); + TV_CP(oitv, i32, it_interval); + TV_CP(oitv, i32, it_value); + return (copyout(&i32, uap->oitv, sizeof(i32))); } int freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap) { + struct itimerval itv; + struct itimerval32 i32; int error; - caddr_t sg; - struct itimerval32 *p32, s32; - struct itimerval *p = NULL, s; - p32 = uap->itv; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct itimerval)); - uap->itv = (struct itimerval32 *)p; - } - error = getitimer(td, (struct getitimer_args *) uap); - if (error) + error = kern_getitimer(td, uap->which, &itv); + if (error || uap->itv == NULL) return (error); - if (p32) { - error = copyin(p, &s, sizeof(s)); - if (error) - return (error); - TV_CP(s, s32, it_interval); - TV_CP(s, s32, it_value); - error = copyout(&s32, p32, sizeof(s32)); - } - return (error); + TV_CP(itv, i32, it_interval); + TV_CP(itv, i32, it_value); + return (copyout(&i32, uap->itv, sizeof(i32))); } int freebsd32_select(struct thread *td, struct freebsd32_select_args *uap) { + struct timeval32 tv32; + struct timeval tv, *tvp; int error; - caddr_t sg; - struct timeval32 *p32, s32; - struct timeval *p = NULL, s; - p32 = uap->tv; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct timeval)); - uap->tv = (struct timeval32 *)p; - error = copyin(p32, &s32, sizeof(s32)); + if (uap->tv != NULL) { + error = copyin(uap->tv, &tv32, sizeof(tv32)); if (error) return (error); - CP(s32, s, tv_sec); - CP(s32, s, tv_usec); - error = copyout(&s, p, sizeof(s)); - if (error) - return (error); - } + CP(tv32, tv, tv_sec); + CP(tv32, tv, tv_usec); + tvp = &tv; + } else + tvp = NULL; /* * XXX big-endian needs to convert the fd_sets too. + * XXX Do pointers need PTRIN()? */ - return (select(td, (struct select_args *) uap)); + return (kern_select(td, uap->nd, uap->in, uap->ou, uap->ex, tvp)); } struct kevent32 { @@ -799,28 +809,22 @@ int freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap) { + struct timeval32 s32[2]; + struct timeval s[2], *sp; int error; - caddr_t sg; - struct timeval32 *p32, s32[2]; - struct timeval *p = NULL, s[2]; - p32 = uap->tptr; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, 2*sizeof(struct timeval)); - uap->tptr = (struct timeval32 *)p; - error = copyin(p32, s32, sizeof(s32)); + if (uap->tptr != NULL) { + error = copyin(uap->tptr, s32, sizeof(s32)); if (error) return (error); CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_usec); CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_usec); - error = copyout(s, p, sizeof(s)); - if (error) - return (error); - } - return (utimes(td, (struct utimes_args *) uap)); + sp = s; + } else + sp = NULL; + return (kern_utimes(td, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE)); } int @@ -851,7 +855,7 @@ op = stackgap_alloc(&sg, sizeof(struct timeval)); uap->olddelta = (struct timeval32 *)op; } - error = utimes(td, (struct utimes_args *) uap); + error = adjtime(td, (struct adjtime_args *) uap); if (error) return error; if (op32) { @@ -869,28 +873,15 @@ int freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap) { + struct statfs32 s32; + struct statfs s; int error; - caddr_t sg; - struct statfs32 *p32, s32; - struct statfs *p = NULL, s; - p32 = uap->buf; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct statfs)); - uap->buf = (struct statfs32 *)p; - } - error = statfs(td, (struct statfs_args *) uap); + error = kern_statfs(td, uap->path, UIO_USERSPACE, &s); if (error) return (error); - if (p32) { - error = copyin(p, &s, sizeof(s)); - if (error) - return (error); - copy_statfs(&s, &s32); - error = copyout(&s32, p32, sizeof(s32)); - } - return (error); + copy_statfs(&s, &s32); + return (copyout(&s32, uap->buf, sizeof(s32))); } #endif @@ -898,28 +889,15 @@ int freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap) { + struct statfs32 s32; + struct statfs s; int error; - caddr_t sg; - struct statfs32 *p32, s32; - struct statfs *p = NULL, s; - p32 = uap->buf; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct statfs)); - uap->buf = (struct statfs32 *)p; - } - error = fstatfs(td, (struct fstatfs_args *) uap); + error = kern_fstatfs(td, uap->fd, &s); if (error) return (error); - if (p32) { - error = copyin(p, &s, sizeof(s)); - if (error) - return (error); - copy_statfs(&s, &s32); - error = copyout(&s32, p32, sizeof(s32)); - } - return (error); + copy_statfs(&s, &s32); + return (copyout(&s32, uap->buf, sizeof(s32))); } #endif @@ -927,28 +905,18 @@ int freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap) { + struct statfs32 s32; + struct statfs s; + fhandle_t fh; int error; - caddr_t sg; - struct statfs32 *p32, s32; - struct statfs *p = NULL, s; - p32 = uap->buf; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct statfs)); - uap->buf = (struct statfs32 *)p; - } - error = fhstatfs(td, (struct fhstatfs_args *) uap); + if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) + return (error); + error = kern_fhstatfs(td, fh, &s); if (error) return (error); - if (p32) { - error = copyin(p, &s, sizeof(s)); - if (error) - return (error); - copy_statfs(&s, &s32); - error = copyout(&s32, p32, sizeof(s32)); - } - return (error); + copy_statfs(&s, &s32); + return (copyout(&s32, uap->buf, sizeof(s32))); } #endif @@ -1124,20 +1092,8 @@ struct stat sb; struct stat32 sb32; int error; - struct nameidata nd; -#ifdef LOOKUP_SHARED - NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ, - UIO_USERSPACE, uap->path, td); -#else - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - uap->path, td); -#endif - if ((error = namei(&nd)) != 0) - return (error); - error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(nd.ni_vp); + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); copy_stat(&sb, &sb32); @@ -1148,17 +1104,11 @@ int freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap) { - struct file *fp; struct stat ub; struct stat32 ub32; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) - return (error); - mtx_lock(&Giant); - error = fo_stat(fp, &ub, td->td_ucred, td); - mtx_unlock(&Giant); - fdrop(fp, td); + error = kern_fstat(td, uap->fd, &ub); if (error) return (error); copy_stat(&ub, &ub32); @@ -1169,20 +1119,11 @@ int freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap) { - int error; - struct vnode *vp; struct stat sb; struct stat32 sb32; - struct nameidata nd; + int error; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); copy_stat(&sb, &sb32); -- John Baldwin <jhb@FreeBSD.org> <>< http://www.FreeBSD.org/~jhb/ "Power Users Use the Power to Serve" = http://www.FreeBSD.org
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200502071826.48609.jhb>