- Add a custom version of exec_copyin_args() to deal with the 32-bit

pointers in argv and envv in userland and use that together with
  kern_execve() and exec_free_args() to implement freebsd32_execve()
  without using the stackgap.
- Fix freebsd32_adjtime() to call adjtime() rather than utimes().  Still
  uses stackgap for now.
- Use kern_setitimer(), kern_getitimer(), kern_select(), kern_utimes(),
  kern_statfs(), kern_fstatfs(), kern_fhstatfs(), kern_stat(),
  kern_fstat(), and kern_lstat().

Tested by:	cokane (amd64)
Silence on:	amd64, ia64
This commit is contained in:
John Baldwin 2005-02-18 18:56:04 +00:00
parent 78e436448f
commit 38765a3178

View File

@ -222,65 +222,111 @@ freebsd32_sigaltstack(struct thread *td,
return (error); return (error);
} }
/*
* 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;
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;
/*
* 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);
/*
* 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++;
}
args->begin_envv = args->endp;
/*
* extract environment strings
*/
if (envv) {
p32 = envv;
for (;;) {
error = copyin(p32++, &arg, sizeof(arg));
if (error)
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 (0);
}
int int
freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap) freebsd32_execve(struct thread *td, struct freebsd32_execve_args *uap)
{ {
struct image_args eargs;
int error; int error;
caddr_t sg;
struct execve_args ap;
u_int32_t *p32, arg;
char **p, *p64;
int count;
sg = stackgap_init(); error = freebsd32_exec_copyin_args(&eargs, uap->fname, UIO_USERSPACE,
ap.fname = uap->fname; uap->argv, uap->envv);
if (error == 0)
if (uap->argv) { error = kern_execve(td, &eargs, NULL);
count = 0; exec_free_args(&eargs);
p32 = uap->argv; return (error);
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);
}
if (uap->envv) {
count = 0;
p32 = uap->envv;
do {
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 execve(td, &ap);
} }
#ifdef __ia64__ #ifdef __ia64__
@ -437,99 +483,63 @@ CTASSERT(sizeof(struct itimerval32) == 16);
int int
freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap) freebsd32_setitimer(struct thread *td, struct freebsd32_setitimer_args *uap)
{ {
struct itimerval itv, oitv, *itvp;
struct itimerval32 i32;
int error; int error;
caddr_t sg;
struct itimerval32 *p32, *op32, s32;
struct itimerval *p = NULL, *op = NULL, s;
p32 = uap->itv; if (uap->itv != NULL) {
if (p32) { error = copyin(uap->itv, &i32, sizeof(i32));
sg = stackgap_init();
p = stackgap_alloc(&sg, sizeof(struct itimerval));
uap->itv = (struct itimerval32 *)p;
error = copyin(p32, &s32, sizeof(s32));
if (error) if (error)
return (error); return (error);
TV_CP(s32, s, it_interval); TV_CP(i32, itv, it_interval);
TV_CP(s32, s, it_value); TV_CP(i32, itv, it_value);
error = copyout(&s, p, sizeof(s)); itvp = &itv;
if (error) } else
return (error); itvp = NULL;
} error = kern_setitimer(td, uap->which, itvp, &oitv);
op32 = uap->oitv; if (error || uap->oitv == NULL)
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)
return (error); return (error);
if (op32) { TV_CP(oitv, i32, it_interval);
error = copyin(op, &s, sizeof(s)); TV_CP(oitv, i32, it_value);
if (error) return (copyout(&i32, uap->oitv, sizeof(i32)));
return (error);
TV_CP(s, s32, it_interval);
TV_CP(s, s32, it_value);
error = copyout(&s32, op32, sizeof(s32));
}
return (error);
} }
int int
freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap) freebsd32_getitimer(struct thread *td, struct freebsd32_getitimer_args *uap)
{ {
struct itimerval itv;
struct itimerval32 i32;
int error; int error;
caddr_t sg;
struct itimerval32 *p32, s32;
struct itimerval *p = NULL, s;
p32 = uap->itv; error = kern_getitimer(td, uap->which, &itv);
if (p32) { if (error || uap->itv == NULL)
sg = stackgap_init();
p = stackgap_alloc(&sg, sizeof(struct itimerval));
uap->itv = (struct itimerval32 *)p;
}
error = getitimer(td, (struct getitimer_args *) uap);
if (error)
return (error); return (error);
if (p32) { TV_CP(itv, i32, it_interval);
error = copyin(p, &s, sizeof(s)); TV_CP(itv, i32, it_value);
if (error) return (copyout(&i32, uap->itv, sizeof(i32)));
return (error);
TV_CP(s, s32, it_interval);
TV_CP(s, s32, it_value);
error = copyout(&s32, p32, sizeof(s32));
}
return (error);
} }
int int
freebsd32_select(struct thread *td, struct freebsd32_select_args *uap) freebsd32_select(struct thread *td, struct freebsd32_select_args *uap)
{ {
struct timeval32 tv32;
struct timeval tv, *tvp;
int error; int error;
caddr_t sg;
struct timeval32 *p32, s32;
struct timeval *p = NULL, s;
p32 = uap->tv; if (uap->tv != NULL) {
if (p32) { error = copyin(uap->tv, &tv32, sizeof(tv32));
sg = stackgap_init();
p = stackgap_alloc(&sg, sizeof(struct timeval));
uap->tv = (struct timeval32 *)p;
error = copyin(p32, &s32, sizeof(s32));
if (error) if (error)
return (error); return (error);
CP(s32, s, tv_sec); CP(tv32, tv, tv_sec);
CP(s32, s, tv_usec); CP(tv32, tv, tv_usec);
error = copyout(&s, p, sizeof(s)); tvp = &tv;
if (error) } else
return (error); tvp = NULL;
}
/* /*
* XXX big-endian needs to convert the fd_sets too. * 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 { struct kevent32 {
@ -799,28 +809,22 @@ freebsd32_settimeofday(struct thread *td,
int int
freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap) freebsd32_utimes(struct thread *td, struct freebsd32_utimes_args *uap)
{ {
struct timeval32 s32[2];
struct timeval s[2], *sp;
int error; int error;
caddr_t sg;
struct timeval32 *p32, s32[2];
struct timeval *p = NULL, s[2];
p32 = uap->tptr; if (uap->tptr != NULL) {
if (p32) { error = copyin(uap->tptr, s32, sizeof(s32));
sg = stackgap_init();
p = stackgap_alloc(&sg, 2*sizeof(struct timeval));
uap->tptr = (struct timeval32 *)p;
error = copyin(p32, s32, sizeof(s32));
if (error) if (error)
return (error); return (error);
CP(s32[0], s[0], tv_sec); CP(s32[0], s[0], tv_sec);
CP(s32[0], s[0], tv_usec); CP(s32[0], s[0], tv_usec);
CP(s32[1], s[1], tv_sec); CP(s32[1], s[1], tv_sec);
CP(s32[1], s[1], tv_usec); CP(s32[1], s[1], tv_usec);
error = copyout(s, p, sizeof(s)); sp = s;
if (error) } else
return (error); sp = NULL;
} return (kern_utimes(td, uap->path, UIO_USERSPACE, sp, UIO_SYSSPACE));
return (utimes(td, (struct utimes_args *) uap));
} }
int int
@ -851,7 +855,7 @@ freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
op = stackgap_alloc(&sg, sizeof(struct timeval)); op = stackgap_alloc(&sg, sizeof(struct timeval));
uap->olddelta = (struct timeval32 *)op; uap->olddelta = (struct timeval32 *)op;
} }
error = utimes(td, (struct utimes_args *) uap); error = adjtime(td, (struct adjtime_args *) uap);
if (error) if (error)
return error; return error;
if (op32) { if (op32) {
@ -869,28 +873,15 @@ freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
int int
freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap) freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_args *uap)
{ {
struct statfs32 s32;
struct statfs s;
int error; int error;
caddr_t sg;
struct statfs32 *p32, s32;
struct statfs *p = NULL, s;
p32 = uap->buf; error = kern_statfs(td, uap->path, UIO_USERSPACE, &s);
if (p32) {
sg = stackgap_init();
p = stackgap_alloc(&sg, sizeof(struct statfs));
uap->buf = (struct statfs32 *)p;
}
error = statfs(td, (struct statfs_args *) uap);
if (error) if (error)
return (error); return (error);
if (p32) { copy_statfs(&s, &s32);
error = copyin(p, &s, sizeof(s)); return (copyout(&s32, uap->buf, sizeof(s32)));
if (error)
return (error);
copy_statfs(&s, &s32);
error = copyout(&s32, p32, sizeof(s32));
}
return (error);
} }
#endif #endif
@ -898,28 +889,15 @@ freebsd4_freebsd32_statfs(struct thread *td, struct freebsd4_freebsd32_statfs_ar
int int
freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap) freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_args *uap)
{ {
struct statfs32 s32;
struct statfs s;
int error; int error;
caddr_t sg;
struct statfs32 *p32, s32;
struct statfs *p = NULL, s;
p32 = uap->buf; error = kern_fstatfs(td, uap->fd, &s);
if (p32) {
sg = stackgap_init();
p = stackgap_alloc(&sg, sizeof(struct statfs));
uap->buf = (struct statfs32 *)p;
}
error = fstatfs(td, (struct fstatfs_args *) uap);
if (error) if (error)
return (error); return (error);
if (p32) { copy_statfs(&s, &s32);
error = copyin(p, &s, sizeof(s)); return (copyout(&s32, uap->buf, sizeof(s32)));
if (error)
return (error);
copy_statfs(&s, &s32);
error = copyout(&s32, p32, sizeof(s32));
}
return (error);
} }
#endif #endif
@ -927,28 +905,18 @@ freebsd4_freebsd32_fstatfs(struct thread *td, struct freebsd4_freebsd32_fstatfs_
int int
freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap) freebsd4_freebsd32_fhstatfs(struct thread *td, struct freebsd4_freebsd32_fhstatfs_args *uap)
{ {
struct statfs32 s32;
struct statfs s;
fhandle_t fh;
int error; int error;
caddr_t sg;
struct statfs32 *p32, s32;
struct statfs *p = NULL, s;
p32 = uap->buf; if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
if (p32) { return (error);
sg = stackgap_init(); error = kern_fhstatfs(td, fh, &s);
p = stackgap_alloc(&sg, sizeof(struct statfs));
uap->buf = (struct statfs32 *)p;
}
error = fhstatfs(td, (struct fhstatfs_args *) uap);
if (error) if (error)
return (error); return (error);
if (p32) { copy_statfs(&s, &s32);
error = copyin(p, &s, sizeof(s)); return (copyout(&s32, uap->buf, sizeof(s32)));
if (error)
return (error);
copy_statfs(&s, &s32);
error = copyout(&s32, p32, sizeof(s32));
}
return (error);
} }
#endif #endif
@ -1124,20 +1092,8 @@ freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
struct stat sb; struct stat sb;
struct stat32 sb32; struct stat32 sb32;
int error; int error;
struct nameidata nd;
#ifdef LOOKUP_SHARED error = kern_stat(td, uap->path, UIO_USERSPACE, &sb);
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);
if (error) if (error)
return (error); return (error);
copy_stat(&sb, &sb32); copy_stat(&sb, &sb32);
@ -1148,17 +1104,11 @@ freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
int int
freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap) freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
{ {
struct file *fp;
struct stat ub; struct stat ub;
struct stat32 ub32; struct stat32 ub32;
int error; int error;
if ((error = fget(td, uap->fd, &fp)) != 0) error = kern_fstat(td, uap->fd, &ub);
return (error);
mtx_lock(&Giant);
error = fo_stat(fp, &ub, td->td_ucred, td);
mtx_unlock(&Giant);
fdrop(fp, td);
if (error) if (error)
return (error); return (error);
copy_stat(&ub, &ub32); copy_stat(&ub, &ub32);
@ -1169,20 +1119,11 @@ freebsd32_fstat(struct thread *td, struct freebsd32_fstat_args *uap)
int int
freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap) freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
{ {
int error;
struct vnode *vp;
struct stat sb; struct stat sb;
struct stat32 sb32; struct stat32 sb32;
struct nameidata nd; int error;
NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb);
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);
if (error) if (error)
return (error); return (error);
copy_stat(&sb, &sb32); copy_stat(&sb, &sb32);