Page MenuHomeFreeBSD

D50483.id155974.diff
No OneTemporary

D50483.id155974.diff

diff --git a/include/Makefile b/include/Makefile
--- a/include/Makefile
+++ b/include/Makefile
@@ -17,7 +17,8 @@
INCS= a.out.h ar.h assert.h bitstring.h byteswap.h \
complex.h cpio.h _ctype.h ctype.h \
db.h \
- dirent.h dlfcn.h elf.h elf-hints.h endian.h err.h fmtmsg.h fnmatch.h \
+ dirent.h dlfcn.h elf.h elf-hints.h endian.h err.h exterr.h \
+ fmtmsg.h fnmatch.h \
fstab.h fts.h ftw.h getopt.h glob.h grp.h \
ieeefp.h ifaddrs.h \
inttypes.h iso646.h kenv.h langinfo.h libgen.h limits.h link.h \
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 <sys/cdefs.h>
+#include <sys/exterr_cat.h>
+
+__BEGIN_DECLS
+int uexterr_gettext(char *buf, size_t bufsz);
+__END_DECLS
+
+#endif
diff --git a/include/unistd.h b/include/unistd.h
--- a/include/unistd.h
+++ b/include/unistd.h
@@ -292,6 +292,7 @@
#define _SC_NPROCESSORS_CONF 57
#define _SC_NPROCESSORS_ONLN 58
#define _SC_CPUSET_SIZE 122
+#define _SC_UEXTERR_MAXLEN 123 /* user */
#endif
/* Extensions found in Solaris and Linux. */
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/sysconf.c b/lib/libc/gen/sysconf.c
--- a/lib/libc/gen/sysconf.c
+++ b/lib/libc/gen/sysconf.c
@@ -34,6 +34,7 @@
#include "namespace.h"
#include <sys/param.h>
+#include <sys/exterrvar.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
@@ -602,6 +603,8 @@
return (-1);
return ((long)value);
#endif
+ case _SC_UEXTERR_MAXLEN:
+ return (UEXTERROR_MAXLEN);
default:
errno = EINVAL;
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,21 @@
+#include <sys/types.h>
+#include <sys/exterrvar.h>
+#include <exterr.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
+{
+ if (bufsz > UEXTERROR_MAXLEN)
+ bufsz = UEXTERROR_MAXLEN;
+ if (ue->error == 0) {
+ strlcpy(buf, "No error", bufsz);
+ return (0);
+ }
+ snprintf(buf, bufsz,
+ "errno %d category %u (src line %u) p1 %#jx p2 %#jx %s",
+ ue->error, ue->cat, ue->src_line,
+ (uintmax_t)ue->p1, (uintmax_t)ue->p2, ue->msg);
+ 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 <sys/types.h>
+#include <sys/exterrvar.h>
+#include <exterr.h>
+#include <string.h>
+#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 <sys/types.h>
#include <sys/rtprio.h>
#include <sys/signalvar.h>
+#include <sys/exterrvar.h>
#include <errno.h>
#include <link.h>
#include <stdlib.h>
@@ -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_init.c b/lib/libthr/thread/thr_init.c
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -433,6 +433,9 @@
thread->unwind_stackend = _usrstack;
#endif
+ thread->uexterr.ver = UEXTERROR_VER;
+ exterrctl(EXTERRCTL_ENABLE, EXTERRCTLF_FORCE, &thread->uexterr);
+
/* Others cleared to zero by thr_alloc() */
}
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 <sys/queue.h>
#include <sys/param.h>
#include <sys/cpuset.h>
+#include <sys/exterrvar.h>
#include <machine/atomic.h>
#include <errno.h>
#include <limits.h>
@@ -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 <sys/types.h>
-#include <sys/mman.h>
#include <sys/param.h>
+#include <sys/exterrvar.h>
+#include <sys/mman.h>
#include <sys/select.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
@@ -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.h b/sys/compat/freebsd32/freebsd32.h
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -419,6 +419,7 @@
uint32_t ki_kstack;
uint32_t ki_udata;
uint32_t ki_tdaddr;
+ uint32_t ki_uerrmsg;
uint32_t ki_spareptrs[KI_NSPARE_PTR]; /* spare room for growth */
int ki_sparelongs[KI_NSPARE_LONG];
int ki_sflag;
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_exec.c b/sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -809,6 +809,7 @@
* it that it now has its own resources back
*/
p->p_flag |= P_EXEC;
+ td->td_pflags2 &= ~TDP2_UEXTERR;
if ((p->p_flag2 & P2_NOTRACE_EXEC) == 0)
p->p_flag2 &= ~P2_NOTRACE;
if ((p->p_flag2 & P2_STKGAP_DISABLE_EXEC) == 0)
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -608,7 +608,8 @@
* been preserved.
*/
p2->p_flag |= p1->p_flag & P_SUGID;
- td2->td_pflags |= (td->td_pflags & (TDP_ALTSTACK | TDP_SIGFASTBLOCK));
+ td2->td_pflags |= td->td_pflags & (TDP_ALTSTACK | TDP_SIGFASTBLOCK);
+ td2->td_pflags2 |= td->td_pflags2 & TDP2_UEXTERR;
SESS_LOCK(p1->p_session);
if (p1->p_session->s_ttyvp != NULL && p1->p_flag & P_CONTROLT)
p2->p_flag |= P_CONTROLT;
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -1348,6 +1348,9 @@
thread_unlock(td);
if (preferthread)
PROC_STATUNLOCK(p);
+
+ if ((td->td_pflags & TDP2_UEXTERR) != 0)
+ kp->ki_uerrmsg = td->td_exterr_ptr;
}
/*
@@ -1503,6 +1506,7 @@
PTRTRIM_CP(*ki, *ki32, ki_tdaddr);
CP(*ki, *ki32, ki_sflag);
CP(*ki, *ki32, ki_tdflags);
+ PTRTRIM_CP(*ki, *ki32, ki_uerrmsg);
}
#endif
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,8 @@
PROC_UNLOCK(p);
}
(p->p_sysent->sv_set_syscall_retval)(td, error);
+ if (error != 0 && (td->td_pflags2 & TDP2_UEXTERR) != 0)
+ 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 <sys/cdefs.h>
#include "opt_capsicum.h"
#include "opt_ktrace.h"
+#define EXTERR_CATEGORY EXTERR_CAT_FILEDESC
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
@@ -46,6 +46,7 @@
#include <sys/filio.h>
#include <sys/fcntl.h>
#include <sys/file.h>
+#include <sys/exterrvar.h>
#include <sys/lock.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
@@ -2200,3 +2201,73 @@
return (3);
return (kcmp_cmp((uintptr_t)fp1->f_data, (uintptr_t)fp2->f_data));
}
+
+void
+exterr_copyout(struct thread *td)
+{
+ struct uexterror ue;
+ ksiginfo_t ksi;
+ void *uloc;
+ size_t sz;
+ int error;
+
+ MPASS((td->td_pflags2 & TDP2_UEXTERR) != 0);
+
+ uloc = (char *)td->td_exterr_ptr + __offsetof(struct uexterror,
+ error);
+ if ((td->td_pflags2 & TDP2_EXTERR) == 0) {
+ ue.error = 0;
+ sz = sizeof(ue.error);
+ } else {
+ 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));
+ sz = sizeof(ue) - __offsetof(struct uexterror, error);
+ }
+ error = copyout(&ue.error, uloc, sz);
+ if (error != 0) {
+ td->td_pflags2 &= ~TDP2_UEXTERR;
+ ksiginfo_init_trap(&ksi);
+ ksi.ksi_signo = SIGSEGV;
+ ksi.ksi_code = SEGV_ACCERR;
+ ksi.ksi_addr = uloc;
+ trapsignal(td, &ksi);
+ }
+}
+
+int
+sys_exterrctl(struct thread *td, struct exterrctl_args *uap)
+{
+ uint32_t ver;
+ int error;
+
+ if ((uap->flags & ~(EXTERRCTLF_FORCE)) != 0)
+ return (EINVAL);
+ switch (uap->op) {
+ case EXTERRCTL_ENABLE:
+ if ((td->td_pflags2 & TDP2_UEXTERR) != 0 &&
+ (uap->flags & EXTERRCTLF_FORCE) == 0)
+ return (EBUSY);
+ td->td_pflags2 &= ~TDP2_UEXTERR;
+ error = copyin(uap->ptr, &ver, sizeof(ver));
+ if (error != 0)
+ return (error);
+ if (ver != UEXTERROR_VER)
+ return (EINVAL);
+ td->td_pflags2 |= TDP2_UEXTERR;
+ td->td_exterr_ptr = uap->ptr;
+ return (0);
+ case EXTERRCTL_DISABLE:
+ if ((td->td_pflags2 & TDP2_UEXTERR) == 0)
+ return (EINVAL);
+ td->td_pflags2 &= ~TDP2_UEXTERR;
+ return (0);
+ 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,
+ _In_reads_bytes_(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 <sys/_types.h>
+
+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,63 @@
+#ifndef _SYS_EXTERRVAR_H_
+#define _SYS_EXTERRVAR_H_
+
+#include <sys/_exterr.h>
+#include <sys/exterr_cat.h>
+#include <sys/types.h>
+
+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_MAXLEN 256
+
+#define UEXTERROR_VER 0x10010001
+
+#define EXTERRCTL_ENABLE 1
+#define EXTERRCTL_DISABLE 2
+
+#define EXTERRCTLF_FORCE 0x00000001
+
+#ifdef _KERNEL
+
+#ifndef EXTERR_CATEGORY
+#error "Specify error category before including sys/exterrvar.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; \
+ if ((_Td->td_pflags2 & TDP2_UEXTERR) != 0) { \
+ _Td->td_pflags2 |= TDP2_EXTERR; \
+ _Td->td_kexterr.error = eerror; \
+ _Td->td_kexterr.cat = EXTERR_CATEGORY; \
+ SET_ERROR_MSG(mmsg); \
+ _Td->td_kexterr.p1 = (uintptr_t)pp1; \
+ _Td->td_kexterr.p2 = (uintptr_t)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 <sys/_eventhandler.h>
#endif
+#include <sys/_exterr.h>
#include <sys/condvar.h>
#ifndef _KERNEL
#include <sys/filedesc.h>
@@ -322,6 +323,7 @@
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 */
+ struct kexterr td_kexterr;
#define td_endzero td_sigmask
/* Copied during fork1(), thread_create(), or kthread_add(). */
@@ -341,6 +343,7 @@
void *td_sigblock_ptr; /* (k) uptr for fast sigblock. */
uint32_t td_sigblock_val; /* (k) fast sigblock value read at
td_sigblock_ptr on kern entry */
+ void *td_exterr_ptr;
#define td_endcopy td_pcb
/*
@@ -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/sys/user.h b/sys/sys/user.h
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -86,7 +86,7 @@
*/
#define KI_NSPARE_INT 2
#define KI_NSPARE_LONG 12
-#define KI_NSPARE_PTR 5
+#define KI_NSPARE_PTR 4
#ifndef _KERNEL
#ifndef KINFO_PROC_SIZE
@@ -212,6 +212,7 @@
* That way the spare room from both arrays will remain contiguous.
*/
struct pwddesc *ki_pd; /* pointer to process paths info */
+ void *ki_uerrmsg; /* address of the ext err msg place */
void *ki_spareptrs[KI_NSPARE_PTR]; /* spare room for growth */
long ki_sparelongs[KI_NSPARE_LONG]; /* spare room for growth */
long ki_sflag; /* PS_* flags */
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 <sys/cdefs.h>
#include "opt_hwpmc_hooks.h"
#include "opt_vm.h"
+#define EXTERR_CATEGORY EXTERR_CAT_MMAP
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/capsicum.h>
+#include <sys/exterrvar.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -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;

File Metadata

Mime Type
text/plain
Expires
Tue, Apr 7, 3:29 PM (1 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31039619
Default Alt Text
D50483.id155974.diff (26 KB)

Event Timeline