Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151179672
D50483.id155974.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
26 KB
Referenced Files
None
Subscribers
None
D50483.id155974.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D50483: Extended errors from kernel
Attached
Detach File
Event Timeline
Log In to Comment