aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/freebsd32/freebsd32_misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/freebsd32/freebsd32_misc.c')
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c227
1 files changed, 157 insertions, 70 deletions
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 67dcaa35cae5..e6aea3acdecd 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Doug Rabson
* All rights reserved.
@@ -27,8 +27,6 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include "opt_ffclock.h"
#include "opt_inet.h"
#include "opt_inet6.h"
@@ -84,6 +82,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysproto.h>
#include <sys/systm.h>
#include <sys/thr.h>
+#include <sys/timerfd.h>
#include <sys/timex.h>
#include <sys/unistd.h>
#include <sys/ucontext.h>
@@ -124,7 +123,20 @@ __FBSDID("$FreeBSD$");
#include <compat/freebsd32/freebsd32_signal.h>
#include <compat/freebsd32/freebsd32_proto.h>
-FEATURE(compat_freebsd_32bit, "Compatible with 32-bit FreeBSD");
+int compat_freebsd_32bit = 1;
+
+static void
+register_compat32_feature(void *arg)
+{
+ if (!compat_freebsd_32bit)
+ return;
+
+ FEATURE_ADD("compat_freebsd32", "Compatible with 32-bit FreeBSD");
+ FEATURE_ADD("compat_freebsd_32bit",
+ "Compatible with 32-bit FreeBSD (legacy feature name)");
+}
+SYSINIT(freebsd32, SI_SUB_EXEC, SI_ORDER_ANY, register_compat32_feature,
+ NULL);
struct ptrace_io_desc32 {
int piod_op;
@@ -133,11 +145,6 @@ struct ptrace_io_desc32 {
uint32_t piod_len;
};
-struct ptrace_sc_ret32 {
- uint32_t sr_retval[2];
- int sr_error;
-};
-
struct ptrace_vm_entry32 {
int pve_entry;
int pve_timestamp;
@@ -240,7 +247,7 @@ freebsd32_wait6(struct thread *td, struct freebsd32_wait6_args *uap)
{
struct __wrusage32 wru32;
struct __wrusage wru, *wrup;
- struct siginfo32 si32;
+ struct __siginfo32 si32;
struct __siginfo si, *sip;
int error, status;
@@ -517,7 +524,7 @@ freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap)
prot |= PROT_EXEC;
#endif
return (kern_mprotect(td, (uintptr_t)PTRIN(uap->addr), uap->len,
- prot));
+ prot, 0));
}
int
@@ -971,6 +978,7 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
struct ptrace_lwpinfo pl;
struct ptrace_vm_entry pve;
struct ptrace_coredump pc;
+ struct ptrace_sc_remote sr;
struct dbreg32 dbreg;
struct fpreg32 fpreg;
struct reg32 reg;
@@ -984,10 +992,13 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
struct ptrace_lwpinfo32 pl;
struct ptrace_vm_entry32 pve;
struct ptrace_coredump32 pc;
+ struct ptrace_sc_remote32 sr;
uint32_t args[nitems(td->td_sa.args)];
struct ptrace_sc_ret32 psr;
struct iovec32 vec;
} r32;
+ syscallarg_t pscr_args[nitems(td->td_sa.args)];
+ u_int pscr_args32[nitems(td->td_sa.args)];
void *addr;
int data, error, i;
@@ -1015,7 +1026,7 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
*/
data = sizeof(r.pl);
if (uap->data < offsetof(struct ptrace_lwpinfo32, pl_siginfo) +
- sizeof(struct siginfo32))
+ sizeof(struct __siginfo32))
data = offsetof(struct ptrace_lwpinfo, pl_siginfo);
break;
case PT_GETREGS:
@@ -1086,6 +1097,28 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
r.pc.pc_limit = PAIR32TO64(off_t, r32.pc.pc_limit);
data = sizeof(r.pc);
break;
+ case PT_SC_REMOTE:
+ if (uap->data != sizeof(r32.sr)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(uap->addr, &r32.sr, uap->data);
+ if (error != 0)
+ break;
+ CP(r32.sr, r.sr, pscr_syscall);
+ CP(r32.sr, r.sr, pscr_nargs);
+ if (r.sr.pscr_nargs > nitems(td->td_sa.args)) {
+ error = EINVAL;
+ break;
+ }
+ error = copyin(PTRIN(r32.sr.pscr_args), pscr_args32,
+ sizeof(u_int) * r32.sr.pscr_nargs);
+ if (error != 0)
+ break;
+ for (i = 0; i < r32.sr.pscr_nargs; i++)
+ pscr_args[i] = pscr_args32[i];
+ r.sr.pscr_args = pscr_args;
+ break;
default:
addr = uap->addr;
break;
@@ -1146,43 +1179,46 @@ freebsd32_ptrace(struct thread *td, struct freebsd32_ptrace_args *uap)
error = copyout(&r32.psr, uap->addr, MIN(uap->data,
sizeof(r32.psr)));
break;
+ case PT_SC_REMOTE:
+ ptrace_sc_ret_to32(&r.sr.pscr_ret, &r32.sr.pscr_ret);
+ error = copyout(&r32.sr.pscr_ret, uap->addr +
+ offsetof(struct ptrace_sc_remote32, pscr_ret),
+ sizeof(r32.psr));
+ break;
}
return (error);
}
int
-freebsd32_copyinuio(struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
+freebsd32_copyinuio(const struct iovec32 *iovp, u_int iovcnt, struct uio **uiop)
{
struct iovec32 iov32;
struct iovec *iov;
struct uio *uio;
- u_int iovlen;
int error, i;
*uiop = NULL;
if (iovcnt > UIO_MAXIOV)
return (EINVAL);
- iovlen = iovcnt * sizeof(struct iovec);
- uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK);
- iov = (struct iovec *)(uio + 1);
+ uio = allocuio(iovcnt);
+ iov = uio->uio_iov;
for (i = 0; i < iovcnt; i++) {
error = copyin(&iovp[i], &iov32, sizeof(struct iovec32));
if (error) {
- free(uio, M_IOV);
+ freeuio(uio);
return (error);
}
iov[i].iov_base = PTRIN(iov32.iov_base);
iov[i].iov_len = iov32.iov_len;
}
- uio->uio_iov = iov;
uio->uio_iovcnt = iovcnt;
uio->uio_segflg = UIO_USERSPACE;
uio->uio_offset = -1;
uio->uio_resid = 0;
for (i = 0; i < iovcnt; i++) {
if (iov->iov_len > INT_MAX - uio->uio_resid) {
- free(uio, M_IOV);
+ freeuio(uio);
return (EINVAL);
}
uio->uio_resid += iov->iov_len;
@@ -1202,7 +1238,7 @@ freebsd32_readv(struct thread *td, struct freebsd32_readv_args *uap)
if (error)
return (error);
error = kern_readv(td, uap->fd, auio);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1216,7 +1252,7 @@ freebsd32_writev(struct thread *td, struct freebsd32_writev_args *uap)
if (error)
return (error);
error = kern_writev(td, uap->fd, auio);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1230,7 +1266,7 @@ freebsd32_preadv(struct thread *td, struct freebsd32_preadv_args *uap)
if (error)
return (error);
error = kern_preadv(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset));
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1244,7 +1280,7 @@ freebsd32_pwritev(struct thread *td, struct freebsd32_pwritev_args *uap)
if (error)
return (error);
error = kern_pwritev(td, uap->fd, auio, PAIR32TO64(off_t,uap->offset));
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -1311,11 +1347,7 @@ freebsd32_copyoutmsghdr(struct msghdr *msg, struct msghdr32 *msg32)
return (error);
}
-#ifndef __mips__
#define FREEBSD32_ALIGNBYTES (sizeof(int) - 1)
-#else
-#define FREEBSD32_ALIGNBYTES (sizeof(long) - 1)
-#endif
#define FREEBSD32_ALIGN(p) \
(((u_long)(p) + FREEBSD32_ALIGNBYTES) & ~FREEBSD32_ALIGNBYTES)
#define FREEBSD32_CMSG_SPACE(l) \
@@ -1535,6 +1567,7 @@ freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
u_int msglen, outlen;
int error;
+ /* Enforce the size limit of the native implementation. */
if (buflen > MCLBYTES)
return (EINVAL);
@@ -1555,35 +1588,39 @@ freebsd32_copyin_control(struct mbuf **mp, caddr_t buf, u_int buflen)
break;
}
cm = (struct cmsghdr *)in1;
- if (cm->cmsg_len < FREEBSD32_ALIGN(sizeof(*cm))) {
+ if (cm->cmsg_len < FREEBSD32_ALIGN(sizeof(*cm)) ||
+ cm->cmsg_len > buflen) {
error = EINVAL;
break;
}
msglen = FREEBSD32_ALIGN(cm->cmsg_len);
- if (msglen > buflen || msglen < cm->cmsg_len) {
+ if (msglen < cm->cmsg_len) {
error = EINVAL;
break;
}
+ /* The native ABI permits the final padding to be omitted. */
+ if (msglen > buflen)
+ msglen = buflen;
buflen -= msglen;
in1 = (char *)in1 + msglen;
outlen += CMSG_ALIGN(sizeof(*cm)) +
CMSG_ALIGN(msglen - FREEBSD32_ALIGN(sizeof(*cm)));
}
- if (error == 0 && outlen > MCLBYTES) {
- /*
- * XXXMJ This implies that the upper limit on 32-bit aligned
- * control messages is less than MCLBYTES, and so we are not
- * perfectly compatible. However, there is no platform
- * guarantee that mbuf clusters larger than MCLBYTES can be
- * allocated.
- */
- error = EINVAL;
- }
if (error != 0)
goto out;
+ /*
+ * Allocate up to MJUMPAGESIZE space for the re-aligned and
+ * re-padded control messages. This allows a full MCLBYTES of
+ * 32-bit sized and aligned messages to fit and avoids an ABI
+ * mismatch with the native implementation.
+ */
m = m_get2(outlen, M_WAITOK, MT_CONTROL, 0);
+ if (m == NULL) {
+ error = EINVAL;
+ goto out;
+ }
m->m_len = outlen;
md = mtod(m, void *);
@@ -2155,13 +2192,13 @@ freebsd32_do_sendfile(struct thread *td,
fdrop(fp, td);
if (uap->sbytes != NULL)
- copyout(&sbytes, uap->sbytes, sizeof(off_t));
+ (void)copyout(&sbytes, uap->sbytes, sizeof(off_t));
out:
if (hdr_uio)
- free(hdr_uio, M_IOV);
+ freeuio(hdr_uio);
if (trl_uio)
- free(trl_uio, M_IOV);
+ freeuio(trl_uio);
return (error);
}
@@ -2256,8 +2293,7 @@ ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap)
struct ostat32 sb32;
int error;
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb);
if (error)
return (error);
copy_ostat(&sb, &sb32);
@@ -2306,7 +2342,7 @@ freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap)
int error;
error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
- &ub, NULL);
+ &ub);
if (error)
return (error);
copy_stat(&ub, &ub32);
@@ -2323,7 +2359,7 @@ ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap)
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
+ UIO_USERSPACE, &sb);
if (error)
return (error);
copy_ostat(&sb, &sb32);
@@ -2441,8 +2477,7 @@ freebsd11_freebsd32_stat(struct thread *td,
struct freebsd11_stat32 sb32;
int error;
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtstat32(&sb, &sb32);
@@ -2477,7 +2512,7 @@ freebsd11_freebsd32_fstatat(struct thread *td,
int error;
error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ &sb);
if (error != 0)
return (error);
error = freebsd11_cvtstat32(&sb, &sb32);
@@ -2495,7 +2530,7 @@ freebsd11_freebsd32_lstat(struct thread *td,
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
+ UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtstat32(&sb, &sb32);
@@ -2567,8 +2602,7 @@ freebsd11_freebsd32_nstat(struct thread *td,
struct nstat32 nsb;
int error;
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtnstat32(&sb, &nsb);
@@ -2586,7 +2620,7 @@ freebsd11_freebsd32_nlstat(struct thread *td,
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
+ UIO_USERSPACE, &sb);
if (error != 0)
return (error);
error = freebsd11_cvtnstat32(&sb, &nsb);
@@ -2638,9 +2672,9 @@ freebsd32___sysctl(struct thread *td, struct freebsd32___sysctl_args *uap)
uap->new, uap->newlen, &j, SCTL_MASK32);
if (error)
return (error);
- if (uap->oldlenp)
- suword32(uap->oldlenp, j);
- return (0);
+ if (uap->oldlenp != NULL && suword32(uap->oldlenp, j) != 0)
+ error = EFAULT;
+ return (error);
}
int
@@ -2663,9 +2697,8 @@ freebsd32___sysctlbyname(struct thread *td,
&oldlen, uap->new, uap->newlen, &rv, SCTL_MASK32, 1);
if (error != 0)
return (error);
- if (uap->oldlenp != NULL)
- error = suword32(uap->oldlenp, rv);
-
+ if (uap->oldlenp != NULL && suword32(uap->oldlenp, rv) != 0)
+ error = EFAULT;
return (error);
}
@@ -2744,7 +2777,7 @@ freebsd32_jail_set(struct thread *td, struct freebsd32_jail_set_args *uap)
if (error)
return (error);
error = kern_jail_set(td, auio, uap->flags);
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -2771,7 +2804,7 @@ freebsd32_jail_get(struct thread *td, struct freebsd32_jail_get_args *uap)
if (error != 0)
break;
}
- free(auio, M_IOV);
+ freeuio(auio);
return (error);
}
@@ -3116,6 +3149,60 @@ freebsd32_ktimer_gettime(struct thread *td,
}
int
+freebsd32_timerfd_gettime(struct thread *td,
+ struct freebsd32_timerfd_gettime_args *uap)
+{
+ struct itimerspec curr_value;
+ struct itimerspec32 curr_value32;
+ int error;
+
+ error = kern_timerfd_gettime(td, uap->fd, &curr_value);
+ if (error == 0) {
+ CP(curr_value, curr_value32, it_value.tv_sec);
+ CP(curr_value, curr_value32, it_value.tv_nsec);
+ CP(curr_value, curr_value32, it_interval.tv_sec);
+ CP(curr_value, curr_value32, it_interval.tv_nsec);
+ error = copyout(&curr_value32, uap->curr_value,
+ sizeof(curr_value32));
+ }
+
+ return (error);
+}
+
+int
+freebsd32_timerfd_settime(struct thread *td,
+ struct freebsd32_timerfd_settime_args *uap)
+{
+ struct itimerspec new_value, old_value;
+ struct itimerspec32 new_value32, old_value32;
+ int error;
+
+ error = copyin(uap->new_value, &new_value32, sizeof(new_value32));
+ if (error != 0)
+ return (error);
+ CP(new_value32, new_value, it_value.tv_sec);
+ CP(new_value32, new_value, it_value.tv_nsec);
+ CP(new_value32, new_value, it_interval.tv_sec);
+ CP(new_value32, new_value, it_interval.tv_nsec);
+ if (uap->old_value == NULL) {
+ error = kern_timerfd_settime(td, uap->fd, uap->flags,
+ &new_value, NULL);
+ } else {
+ error = kern_timerfd_settime(td, uap->fd, uap->flags,
+ &new_value, &old_value);
+ if (error == 0) {
+ CP(old_value, old_value32, it_value.tv_sec);
+ CP(old_value, old_value32, it_value.tv_nsec);
+ CP(old_value, old_value32, it_interval.tv_sec);
+ CP(old_value, old_value32, it_interval.tv_nsec);
+ error = copyout(&old_value32, uap->old_value,
+ sizeof(old_value32));
+ }
+ }
+ return (error);
+}
+
+int
freebsd32_clock_getcpuclockid2(struct thread *td,
struct freebsd32_clock_getcpuclockid2_args *uap)
{
@@ -3184,7 +3271,7 @@ freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap)
}
void
-siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst)
+siginfo_to_siginfo32(const siginfo_t *src, struct __siginfo32 *dst)
{
bzero(dst, sizeof(*dst));
dst->si_signo = src->si_signo;
@@ -3233,7 +3320,7 @@ freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *ua
struct timespec *timeout;
sigset_t set;
ksiginfo_t ksi;
- struct siginfo32 si32;
+ struct __siginfo32 si32;
int error;
if (uap->timeout) {
@@ -3256,7 +3343,7 @@ freebsd32_sigtimedwait(struct thread *td, struct freebsd32_sigtimedwait_args *ua
if (uap->info) {
siginfo_to_siginfo32(&ksi.ksi_info, &si32);
- error = copyout(&si32, uap->info, sizeof(struct siginfo32));
+ error = copyout(&si32, uap->info, sizeof(struct __siginfo32));
}
if (error == 0)
@@ -3271,7 +3358,7 @@ int
freebsd32_sigwaitinfo(struct thread *td, struct freebsd32_sigwaitinfo_args *uap)
{
ksiginfo_t ksi;
- struct siginfo32 si32;
+ struct __siginfo32 si32;
sigset_t set;
int error;
@@ -3285,7 +3372,7 @@ freebsd32_sigwaitinfo(struct thread *td, struct freebsd32_sigwaitinfo_args *uap)
if (uap->info) {
siginfo_to_siginfo32(&ksi.ksi_info, &si32);
- error = copyout(&si32, uap->info, sizeof(struct siginfo32));
+ error = copyout(&si32, uap->info, sizeof(struct __siginfo32));
}
if (error == 0)
td->td_retval[0] = ksi.ksi_signo;
@@ -3450,7 +3537,7 @@ freebsd32_nmount(struct thread *td,
return (error);
error = vfs_donmount(td, flags, auio);
- free(auio, M_IOV);
+ freeuio(auio);
return error;
}
@@ -3525,7 +3612,7 @@ freebsd32_copyout_strings(struct image_params *imgp, uintptr_t *stack_base)
/*
* Install sigcode.
*/
- if (sysent->sv_sigcode_base == 0) {
+ if (!PROC_HAS_SHP(imgp->proc)) {
szsigcode = *sysent->sv_szsigcode;
destp -= szsigcode;
destp = rounddown2(destp, sizeof(uint32_t));
@@ -3855,7 +3942,7 @@ freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap)
int
freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap)
{
- long tmp;
+ intptr_t tmp;
switch (uap->cmd) {
/*