diff --git a/include/exterr.h b/include/exterr.h new file mode 100644 --- /dev/null +++ b/include/exterr.h @@ -0,0 +1,11 @@ +#ifndef _EXTERR_H_ +#define _EXTERR_H_ + +#include +#include + +__BEGIN_DECLS +int uexterr_gettext(char *buf, size_t bufsz); +__END_DECLS + +#endif diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -159,6 +159,8 @@ ttyname.c \ ttyslot.c \ ualarm.c \ + uexterr_format.c \ + uexterr_gettext.c \ ulimit.c \ uname.c \ unvis-compat.c \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -462,6 +462,7 @@ psiginfo; rtld_get_var; rtld_set_var; + uexterr_gettext; }; FBSDprivate_1.0 { @@ -592,4 +593,5 @@ __fillcontextx2; __getcontextx_size; __makecontext; + __uexterr_format; }; diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c --- a/lib/libc/gen/libc_interposing_table.c +++ b/lib/libc/gen/libc_interposing_table.c @@ -43,6 +43,7 @@ SLOT(spinunlock, __libc_spinunlock_stub), SLOT(map_stacks_exec, __libc_map_stacks_exec), SLOT(distribute_static_tls, __libc_distribute_static_tls), + SLOT(uexterr_gettext, __libc_uexterr_gettext), }; #undef SLOT diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c new file mode 100644 --- /dev/null +++ b/lib/libc/gen/uexterr_format.c @@ -0,0 +1,12 @@ +#include +#include +#include +#include + +int +__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz) +{ + /* XXXKIB */ + strlcpy(buf, ue->msg, bufsz); + return (0); +} diff --git a/lib/libc/gen/uexterr_get.c b/lib/libc/gen/uexterr_get.c new file mode 100644 --- /dev/null +++ b/lib/libc/gen/uexterr_get.c @@ -0,0 +1,10 @@ +#include +#include +#include + +int +__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz) +{ + strlcpy(buf, ue->msg, bufsz); + return (0); +} diff --git a/lib/libc/gen/uexterr_gettext.c b/lib/libc/gen/uexterr_gettext.c new file mode 100644 --- /dev/null +++ b/lib/libc/gen/uexterr_gettext.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include "libc_private.h" + +static struct uexterror uexterr = { + .ver = UEXTERROR_VER, +}; + +static void uexterr_ctr(void) __attribute__((constructor)); +static void +uexterr_ctr(void) +{ + exterrctl(EXTERRCTL_ENABLE, 0, &uexterr); +} + +int +__libc_uexterr_gettext(char *buf, size_t bufsz) +{ + return (__uexterr_format(&uexterr, buf, bufsz)); +} + +int +uexterr_gettext(char *buf, size_t bufsz) +{ + return (((int (*)(char *, size_t)) + __libc_interposing[INTERPOS_uexterr_gettext])(buf, bufsz)); +} diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -251,6 +251,7 @@ INTERPOS_clock_nanosleep, INTERPOS_distribute_static_tls, INTERPOS_pdfork, + INTERPOS_uexterr_gettext, INTERPOS_MAX }; @@ -380,4 +381,8 @@ int __strerror_rl(int errnum, char *strerrbuf, size_t buflen, struct _xlocale *locale); +struct uexterror; +int __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz); +int __libc_uexterr_gettext(char *buf, size_t bufsz); + #endif /* _LIBC_PRIVATE_H_ */ diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map --- a/lib/libsys/Symbol.sys.map +++ b/lib/libsys/Symbol.sys.map @@ -378,6 +378,7 @@ }; FBSD_1.8 { + exterrctl; fchroot; getrlimitusage; kcmp; diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h --- a/lib/libsys/_libsys.h +++ b/lib/libsys/_libsys.h @@ -465,6 +465,7 @@ typedef int (__sys_getrlimitusage_t)(u_int, int, rlim_t *); typedef int (__sys_fchroot_t)(int); typedef int (__sys_setcred_t)(u_int, const struct setcred *, size_t); +typedef int (__sys_exterrctl_t)(u_int, u_int, void *); void __sys_exit(int rval); int __sys_fork(void); @@ -866,6 +867,7 @@ int __sys_getrlimitusage(u_int which, int flags, rlim_t * res); int __sys_fchroot(int fd); int __sys_setcred(u_int flags, const struct setcred * wcred, size_t size); +int __sys_exterrctl(u_int op, u_int flags, void * ptr); __END_DECLS #endif /* __LIBSYS_H_ */ diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map --- a/lib/libsys/syscalls.map +++ b/lib/libsys/syscalls.map @@ -807,4 +807,6 @@ __sys_fchroot; _setcred; __sys_setcred; + _exterrctl; + __sys_exterrctl; }; diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c --- a/lib/libthr/thread/thr_create.c +++ b/lib/libthr/thread/thr_create.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -285,6 +286,9 @@ curthread->attr.stacksize_attr; #endif + curthread->uexterr.ver = UEXTERROR_VER; + exterrctl(EXTERRCTL_ENABLE, 0, &curthread->uexterr); + /* Run the current thread's start routine with argument: */ _pthread_exit(curthread->start_routine(curthread->arg)); diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -576,6 +577,8 @@ /* pthread_set/get_name_np */ char *name; + + struct uexterror uexterr; }; #define THR_SHOULD_GC(thrd) \ diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c --- a/lib/libthr/thread/thr_syscalls.c +++ b/lib/libthr/thread/thr_syscalls.c @@ -66,9 +66,9 @@ */ #include "namespace.h" -#include -#include #include +#include +#include #include #include #include @@ -620,6 +620,15 @@ return (ret); } +static int +__thr_uexterr_gettext(char *buf, size_t bufsz) +{ + struct pthread *curthread; + + curthread = _get_curthread(); + return (__uexterr_format(&curthread->uexterr, buf, bufsz)); +} + void __thr_interpose_libc(void) { @@ -675,6 +684,7 @@ SLOT(fdatasync); SLOT(clock_nanosleep); SLOT(pdfork); + SLOT(uexterr_gettext); #undef SLOT *(__libc_interposing_slot( INTERPOS__pthread_mutex_init_calloc_cb)) = diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -26,6 +26,7 @@ options SCHED_ULE # ULE scheduler options NUMA # Non-Uniform Memory Architecture support options PREEMPTION # Enable kernel thread preemption +options BLOW_KERNEL_WITH_EXTERR options VIMAGE # Subsystem virtualization, e.g. VNET options INET # InterNETworking options INET6 # IPv6 communications protocols diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -510,4 +510,5 @@ #define FREEBSD32_SYS_getrlimitusage 589 #define FREEBSD32_SYS_fchroot 590 #define FREEBSD32_SYS_freebsd32_setcred 591 -#define FREEBSD32_SYS_MAXSYSCALL 592 +#define FREEBSD32_SYS_exterrctl 592 +#define FREEBSD32_SYS_MAXSYSCALL 593 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -597,4 +597,5 @@ "getrlimitusage", /* 589 = getrlimitusage */ "fchroot", /* 590 = fchroot */ "freebsd32_setcred", /* 591 = freebsd32_setcred */ + "exterrctl", /* 592 = exterrctl */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -659,4 +659,5 @@ { .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */ { .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 590 = fchroot */ { .sy_narg = AS(freebsd32_setcred_args), .sy_call = (sy_call_t *)freebsd32_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 591 = freebsd32_setcred */ + { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3386,6 +3386,15 @@ *n_args = 3; break; } + /* exterrctl */ + case 592: { + struct exterrctl_args *p = params; + uarg[a++] = p->op; /* u_int */ + uarg[a++] = p->flags; /* u_int */ + uarg[a++] = (intptr_t)p->ptr; /* void * */ + *n_args = 3; + break; + } default: *n_args = 0; break; @@ -9147,6 +9156,22 @@ break; }; break; + /* exterrctl */ + case 592: + switch (ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "u_int"; + break; + case 2: + p = "userland void *"; + break; + default: + break; + }; + break; default: break; }; @@ -11040,6 +11065,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* exterrctl */ + case 592: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/conf/options b/sys/conf/options --- a/sys/conf/options +++ b/sys/conf/options @@ -53,6 +53,7 @@ DDB_CTF opt_ddb.h DDB_NUMSYM opt_ddb.h EARLY_PRINTF opt_global.h +BLOW_KERNEL_WITH_EXTERR opt_global.h FULL_BUF_TRACKING opt_global.h GDB KDB opt_global.h diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -658,4 +658,5 @@ { .sy_narg = AS(getrlimitusage_args), .sy_call = (sy_call_t *)sys_getrlimitusage, .sy_auevent = AUE_NULL, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 589 = getrlimitusage */ { .sy_narg = AS(fchroot_args), .sy_call = (sy_call_t *)sys_fchroot, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 590 = fchroot */ { .sy_narg = AS(setcred_args), .sy_call = (sy_call_t *)sys_setcred, .sy_auevent = AUE_SETCRED, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 591 = setcred */ + { .sy_narg = AS(exterrctl_args), .sy_call = (sy_call_t *)sys_exterrctl, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 592 = exterrctl */ }; diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -86,9 +86,9 @@ "struct thread KBI td_flags"); _Static_assert(offsetof(struct thread, td_pflags) == 0x114, "struct thread KBI td_pflags"); -_Static_assert(offsetof(struct thread, td_frame) == 0x4b8, +_Static_assert(offsetof(struct thread, td_frame) == 0x4e8, "struct thread KBI td_frame"); -_Static_assert(offsetof(struct thread, td_emuldata) == 0x6c0, +_Static_assert(offsetof(struct thread, td_emuldata) == 0x6f0, "struct thread KBI td_emuldata"); _Static_assert(offsetof(struct proc, p_flag) == 0xb8, "struct proc KBI p_flag"); diff --git a/sys/kern/subr_syscall.c b/sys/kern/subr_syscall.c --- a/sys/kern/subr_syscall.c +++ b/sys/kern/subr_syscall.c @@ -74,6 +74,8 @@ td->td_dbgflags |= TDB_SCE; PROC_UNLOCK(p); } + if ((td->td_pflags2 & TDP2_UEXTERR) != 0) + td->td_pflags2 &= ~TDP2_EXTERR; error = (p->p_sysent->sv_fetch_syscall_args)(td); se = sa->callp; #ifdef KTRACE @@ -207,6 +209,10 @@ PROC_UNLOCK(p); } (p->p_sysent->sv_set_syscall_retval)(td, error); + if ((td->td_pflags2 & (TDP2_EXTERR | TDP2_UEXTERR)) == + (TDP2_EXTERR | TDP2_UEXTERR)) { + exterr_copyout(td); + } } static inline void diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -34,10 +34,10 @@ * SUCH DAMAGE. */ -#include #include "opt_capsicum.h" #include "opt_ktrace.h" +#define EXTERR_CATEGORY EXTERR_CAT_FILEDESC #include #include #include @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -2200,3 +2201,70 @@ return (3); return (kcmp_cmp((uintptr_t)fp1->f_data, (uintptr_t)fp2->f_data)); } + +void +exterr_copyout(struct thread *td) +{ + struct uexterror ue; + int error; + + MPASS((td->td_pflags2 & (TDP2_EXTERR | TDP2_UEXTERR)) == + (TDP2_EXTERR | TDP2_UEXTERR)); + + memset(&ue, 0, sizeof(ue)); + ue.error = td->td_kexterr.error; + ue.cat = td->td_kexterr.cat; + ue.src_line = td->td_kexterr.src_line; + ue.p1 = td->td_kexterr.p1; + ue.p2 = td->td_kexterr.p2; + if (td->td_kexterr.msg != NULL) + strlcpy(ue.msg, td->td_kexterr.msg, sizeof(ue.msg)); + + error = copyout((char *)&ue + __offsetof(struct uexterror, error), + (char *)td->td_exterr_ptr + __offsetof(struct uexterror, error), + sizeof(ue) - __offsetof(struct uexterror, error)); + if (error != 0) + td->td_pflags2 &= ~TDP2_UEXTERR; +} + +int +sys_exterrctl(struct thread *td, struct exterrctl_args *uap) +{ + uint32_t ver; + int error; + + switch (uap->op) { + case EXTERRCTL_ENABLE: + if ((td->td_pflags2 & TDP2_EXTERR) != 0) + return (EBUSY); + error = copyin(uap->ptr, &ver, sizeof(ver)); + if (error != 0) + return (error); + if (ver != UEXTERROR_VER) + return (EINVAL); + td->td_pflags2 |= TDP2_EXTERR; + td->td_exterr_ptr = uap->ptr; + return (0); + case EXTERRCTL_DISABLE: + if ((td->td_pflags2 & TDP2_EXTERR) == 0) + return (EINVAL); + td->td_pflags2 &= ~TDP2_EXTERR; + return (0); + case EXTERRCTL_GETPTR: + if ((td->td_pflags2 & TDP2_EXTERR) == 0) + return (EINVAL); +#ifdef COMPAT_FREEBSD32 + if (SV_PROC_FLAG(td->td_proc, SV_ILP32) != 0) { + uint32_t ptr; + + ptr = (uintptr_t)td->td_exterr_ptr; + error = copyout(&ptr, uap->ptr, sizeof(ptr)); + } else +#endif + error = copyout(td->td_exterr_ptr, uap->ptr, + sizeof(void *)); + return (error); + default: + return (EINVAL); + } +} diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -597,4 +597,5 @@ "getrlimitusage", /* 589 = getrlimitusage */ "fchroot", /* 590 = fchroot */ "setcred", /* 591 = setcred */ + "exterrctl", /* 592 = exterrctl */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3349,5 +3349,11 @@ size_t size ); } - +592 AUE_NULL STD { + int exterrctl( + u_int op, + u_int flags, + _Inout_updates_bytes_opt_(4) void *ptr + ); + } ; vim: syntax=off diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3473,6 +3473,15 @@ *n_args = 3; break; } + /* exterrctl */ + case 592: { + struct exterrctl_args *p = params; + uarg[a++] = p->op; /* u_int */ + uarg[a++] = p->flags; /* u_int */ + uarg[a++] = (intptr_t)p->ptr; /* void * */ + *n_args = 3; + break; + } default: *n_args = 0; break; @@ -9292,6 +9301,22 @@ break; }; break; + /* exterrctl */ + case 592: + switch (ndx) { + case 0: + p = "u_int"; + break; + case 1: + p = "u_int"; + break; + case 2: + p = "userland void *"; + break; + default: + break; + }; + break; default: break; }; @@ -11275,6 +11300,11 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* exterrctl */ + case 592: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/sys/_exterr.h b/sys/sys/_exterr.h new file mode 100644 --- /dev/null +++ b/sys/sys/_exterr.h @@ -0,0 +1,15 @@ +#ifndef _SYS__EXTERR_H_ +#define _SYS__EXTERR_H_ + +#include + +struct kexterr { + int error; + const char *msg; + __uint64_t p1; + __uint64_t p2; + unsigned cat; + unsigned src_line; +}; + +#endif diff --git a/sys/sys/exterr_cat.h b/sys/sys/exterr_cat.h new file mode 100644 --- /dev/null +++ b/sys/sys/exterr_cat.h @@ -0,0 +1,8 @@ +#ifndef _SYS_EXTERR_CAT_H_ +#define _SYS_EXTERR_CAT_H_ + +#define EXTERR_CAT_MMAP 1 +#define EXTERR_CAT_FILEDESC 2 + +#endif + diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h new file mode 100644 --- /dev/null +++ b/sys/sys/exterrvar.h @@ -0,0 +1,58 @@ +#ifndef _SYS_EXTERRVAR_H_ +#define _SYS_EXTERRVAR_H_ + +#include +#include +#include + +struct uexterror { + uint32_t ver; + uint32_t error; + uint32_t cat; + uint32_t src_line; + uint64_t p1; + uint64_t p2; + uint64_t rsrv1[4]; + char msg[128]; +}; + +#define UEXTERROR_VER 0x10010001 + +#define EXTERRCTL_ENABLE 1 +#define EXTERRCTL_DISABLE 2 +#define EXTERRCTL_GETPTR 3 + +#ifdef _KERNEL + +#ifndef EXTERR_CATEGORY +#error "Specify error category before including sys/exterr.h" +#endif + +#ifdef BLOW_KERNEL_WITH_EXTERR +#define SET_ERROR_MSG(mmsg) _Td->td_kexterr.msg = mmsg +#else +#define SET_ERROR_MSG(mmsg) _Td->td_kexterr.msg = NULL +#endif + +#define SET_ERROR2(eerror, mmsg, pp1, pp2) do { \ + struct thread *_Td = curthread; \ + _Td->td_pflags2 |= TDP2_EXTERR; \ + _Td->td_kexterr.error = eerror; \ + _Td->td_kexterr.cat = EXTERR_CATEGORY; \ + SET_ERROR_MSG(mmsg); \ + _Td->td_kexterr.p1 = pp1; \ + _Td->td_kexterr.p2 = pp2; \ + _Td->td_kexterr.src_line = __LINE__; \ +} while (0) +#define SET_ERROR0(eerror, mmsg) SET_ERROR2(eerror, mmsg, 0, 0) +#define SET_ERROR1(eerror, mmsg, pp1) SET_ERROR2(eerror, mmsg, pp1, 0) + +#else /* _KERNEL */ + +__BEGIN_DECLS +int exterrctl(u_int op, u_int flags, void *ptr); +__END_DECLS + +#endif /* _KERNEL */ + +#endif diff --git a/sys/sys/proc.h b/sys/sys/proc.h --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -42,6 +42,7 @@ #ifdef _KERNEL #include #endif +#include #include #ifndef _KERNEL #include @@ -322,6 +323,8 @@ size_t td_vslock_sz; /* (k) amount of vslock-ed space */ struct kcov_info *td_kcov_info; /* (*) Kernel code coverage data */ long td_ucredref; /* (k) references on td_realucred */ + void *td_exterr_ptr; + struct kexterr td_kexterr; #define td_endzero td_sigmask /* Copied during fork1(), thread_create(), or kthread_add(). */ @@ -569,6 +572,8 @@ #define TDP2_COMPAT32RB 0x00000002 /* compat32 ABI for robust lists */ #define TDP2_ACCT 0x00000004 /* Doing accounting */ #define TDP2_SAN_QUIET 0x00000008 /* Disable warnings from K(A|M)SAN */ +#define TDP2_EXTERR 0x00000010 /* Kernel reported ext error */ +#define TDP2_UEXTERR 0x00000020 /* User set ext error reporting ptr */ /* * Reasons that the current thread can not be run yet. diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -528,4 +528,5 @@ #define SYS_getrlimitusage 589 #define SYS_fchroot 590 #define SYS_setcred 591 -#define SYS_MAXSYSCALL 592 +#define SYS_exterrctl 592 +#define SYS_MAXSYSCALL 593 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -433,4 +433,5 @@ kcmp.o \ getrlimitusage.o \ fchroot.o \ - setcred.o + setcred.o \ + exterrctl.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -1886,6 +1886,11 @@ char wcred_l_[PADL_(const struct setcred *)]; const struct setcred * wcred; char wcred_r_[PADR_(const struct setcred *)]; char size_l_[PADL_(size_t)]; size_t size; char size_r_[PADR_(size_t)]; }; +struct exterrctl_args { + char op_l_[PADL_(u_int)]; u_int op; char op_r_[PADR_(u_int)]; + char flags_l_[PADL_(u_int)]; u_int flags; char flags_r_[PADR_(u_int)]; + char ptr_l_[PADL_(void *)]; void * ptr; char ptr_r_[PADR_(void *)]; +}; int sys_exit(struct thread *, struct exit_args *); int sys_fork(struct thread *, struct fork_args *); int sys_read(struct thread *, struct read_args *); @@ -2287,6 +2292,7 @@ int sys_getrlimitusage(struct thread *, struct getrlimitusage_args *); int sys_fchroot(struct thread *, struct fchroot_args *); int sys_setcred(struct thread *, struct setcred_args *); +int sys_exterrctl(struct thread *, struct exterrctl_args *); #ifdef COMPAT_43 @@ -3268,6 +3274,7 @@ #define SYS_AUE_getrlimitusage AUE_NULL #define SYS_AUE_fchroot AUE_NULL #define SYS_AUE_setcred AUE_SETCRED +#define SYS_AUE_exterrctl AUE_NULL #undef PAD_ #undef PADL_ diff --git a/sys/sys/uio.h b/sys/sys/uio.h --- a/sys/sys/uio.h +++ b/sys/sys/uio.h @@ -84,6 +84,7 @@ int copyinuio(const struct iovec *iovp, u_int iovcnt, struct uio **uiop); int copyout_map(struct thread *td, vm_offset_t *addr, size_t sz); int copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz); +void exterr_copyout(struct thread *td); int physcopyin(void *src, vm_paddr_t dst, size_t len); int physcopyout(vm_paddr_t src, void *dst, size_t len); int physcopyin_vlist(struct bus_dma_segment *src, off_t offset, diff --git a/sys/vm/vm_mmap.c b/sys/vm/vm_mmap.c --- a/sys/vm/vm_mmap.c +++ b/sys/vm/vm_mmap.c @@ -40,13 +40,14 @@ * Mapped file (mmap) interface to VM */ -#include #include "opt_hwpmc_hooks.h" #include "opt_vm.h" +#define EXTERR_CATEGORY EXTERR_CAT_MMAP #include #include #include +#include #include #include #include @@ -190,12 +191,16 @@ pos = mrp->mr_pos; check_fp_fn = mrp->mr_check_fp_fn; - if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) + if ((prot & ~(_PROT_ALL | PROT_MAX(_PROT_ALL))) != 0) { + SET_ERROR0(EINVAL, "unknown PROT bits"); return (EINVAL); + } max_prot = PROT_MAX_EXTRACT(prot); prot = PROT_EXTRACT(prot); - if (max_prot != 0 && (max_prot & prot) != prot) + if (max_prot != 0 && (max_prot & prot) != prot) { + SET_ERROR0(ENOTSUP, "prot is not subset of max_prot"); return (ENOTSUP); + } p = td->td_proc;