Page MenuHomeFreeBSD

D46193.id151669.diff
No OneTemporary

D46193.id151669.diff

diff --git a/stand/common/load_elf.c b/stand/common/load_elf.c
--- a/stand/common/load_elf.c
+++ b/stand/common/load_elf.c
@@ -545,6 +545,7 @@
Elf_Dyn *dp;
Elf_Addr adp;
Elf_Addr ctors;
+ Elf_Addr kcfi;
int ndp;
int symstrindex;
int symtabindex;
@@ -731,16 +732,28 @@
shdr[ehdr->e_shstrndx].sh_offset, chunk);
if (shstr) {
for (i = 0; i < ehdr->e_shnum; i++) {
- if (strcmp(shstr + shdr[i].sh_name,
- ".ctors") != 0)
- continue;
- ctors = shdr[i].sh_addr;
- file_addmetadata(fp, MODINFOMD_CTORS_ADDR,
- sizeof(ctors), &ctors);
- size = shdr[i].sh_size;
- file_addmetadata(fp, MODINFOMD_CTORS_SIZE,
- sizeof(size), &size);
- break;
+ if (strcmp(shstr + shdr[i].sh_name, ".ctors") ==
+ 0) {
+ ctors = shdr[i].sh_addr;
+ file_addmetadata(fp,
+ MODINFOMD_CTORS_ADDR, sizeof(ctors),
+ &ctors);
+ size = shdr[i].sh_size;
+ file_addmetadata(fp,
+ MODINFOMD_CTORS_SIZE, sizeof(size),
+ &size);
+ }
+ if (strcmp(shstr + shdr[i].sh_name, ".kcfi_traps") ==
+ 0) {
+ kcfi = shdr[i].sh_addr;
+ file_addmetadata(fp,
+ MODINFOMD_CFI_ADDR, sizeof(kcfi),
+ &kcfi);
+ size = shdr[i].sh_size;
+ file_addmetadata(fp,
+ MODINFOMD_CFI_SIZE, sizeof(size),
+ &size);
+ }
}
free(shstr);
}
diff --git a/sys/amd64/amd64/cfi.c b/sys/amd64/amd64/cfi.c
new file mode 100644
--- /dev/null
+++ b/sys/amd64/amd64/cfi.c
@@ -0,0 +1,77 @@
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <machine/cfi.h>
+#include <machine/frame.h>
+#include <machine/cpu.h>
+
+static int
+regoff(int reg)
+{
+#define _MATCH_REG(i, reg) \
+ case i: \
+ return (offsetof(struct trapframe, tf_ ## reg) / \
+ sizeof(register_t))
+ switch (reg) {
+ _MATCH_REG( 0, rax);
+ _MATCH_REG( 1, rcx);
+ _MATCH_REG( 2, rdx);
+ _MATCH_REG( 3, rbx);
+ _MATCH_REG( 4, rsp); /* SIB when mod != 3 */
+ _MATCH_REG( 5, rbp);
+ _MATCH_REG( 6, rsi);
+ _MATCH_REG( 7, rdi);
+ _MATCH_REG( 8, r8); /* REX.R is set */
+ _MATCH_REG( 9, r9);
+ _MATCH_REG(10, r10);
+ _MATCH_REG(11, r11);
+ _MATCH_REG(12, r12);
+ _MATCH_REG(13, r13);
+ _MATCH_REG(14, r14);
+ _MATCH_REG(15, r15);
+ }
+#undef _MATCH_REG
+ return (0);
+}
+
+
+bool
+decode_cfi_frame(struct trapframe *tf, uintptr_t *callee_addr, uint32_t *type)
+{
+ unsigned char buffer[13];
+
+ memcpy(buffer, (unsigned char *)(tf->tf_rip - 12), sizeof(buffer));
+ /*
+ * clang generates following instructions:
+ *
+ * mov $typeid, %reg
+ * add $callee-16, %reg
+ * je .Lcorrect
+ * ud2
+ * .Lcorrect
+ *
+ * What we do is to compare if the previous context is trigger by mov(0xba) and following with one add(0x03),
+ * if it is, we can identified it maybe CFI fault
+ */
+
+ if(buffer[1] != 0xba)
+ return (false);
+
+ if(buffer[7] != 0x03)
+ return (false);
+
+ *type = *((uint32_t *)(buffer + 2));
+
+ // Decode register(prefix & REX.R) | (MODRM.rm(3bit))
+ *callee_addr = ((register_t *)tf)[regoff((((buffer[6] >> 2) & 0x1) << 3) | (buffer[8] & 0x7))];
+ return (true);
+}
+
+void
+post_cfi(struct trapframe *frame)
+{
+ TRAPF_PC(frame) += 2;
+}
+
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -51,6 +51,7 @@
#include <sys/param.h>
#include <sys/asan.h>
#include <sys/bus.h>
+#include <sys/cfi.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
@@ -440,6 +441,14 @@
(void)trap_pfault(frame, false, NULL, NULL);
return;
+ case T_PRIVINFLT:
+ /* Triggered by ud2 with kCFI enabled */
+ #ifdef KCFI
+ if(cfi_handler(frame))
+ return;
+ #endif
+ break;
+
case T_DNA:
if (PCB_USER_FPU(td->td_pcb))
panic("Unregistered use of FPU in kernel");
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -104,6 +104,7 @@
options DEBUGNET # debugnet networking
options NETDUMP # netdump(4) client support
options NETGDB # netgdb(4) client support
+options KCFI
# Make an SMP-capable kernel by default
options SMP # Symmetric MultiProcessor Kernel
@@ -384,3 +385,6 @@
# EFI devices
device efidev # EFI pseudo-device
device efirtc # EFI RTC
+
+options UART_NS8250_EARLY_PORT=0x3fa
+options EARLY_PRINTF=ns8250
diff --git a/sys/amd64/include/cfi.h b/sys/amd64/include/cfi.h
new file mode 100644
--- /dev/null
+++ b/sys/amd64/include/cfi.h
@@ -0,0 +1,14 @@
+#ifndef _MACHINE_CFI_H
+#define _MACHINE_CFI_H
+
+#include <sys/types.h>
+
+
+#include <machine/proc.h>
+#include <machine/reg.h>
+
+
+bool decode_cfi_frame(struct trapframe *, uintptr_t *, uint32_t *);
+void post_cfi(struct trapframe *);
+
+#endif
diff --git a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
--- a/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
+++ b/sys/cddl/contrib/opensolaris/uts/common/dtrace/dtrace.c
@@ -345,21 +345,26 @@
{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
};
-static void
-dtrace_nullop(void)
-{}
+#define DEFINE_NULLOP_HANDLER(name, ...) \
+ static void name(__VA_ARGS__) \
+ { \
+ }
+
+DEFINE_NULLOP_HANDLER(dtrace_provide_handler, void *_1, dtrace_probedesc_t *_2);
+DEFINE_NULLOP_HANDLER(dtrace_provide_module_handler, void *_1, modctl_t *_2);
+DEFINE_NULLOP_HANDLER(dtrace_vpdtid_vp_handler, void *_1, dtrace_id_t _2, void *_3);
static dtrace_pops_t dtrace_provider_ops = {
- .dtps_provide = (void (*)(void *, dtrace_probedesc_t *))dtrace_nullop,
- .dtps_provide_module = (void (*)(void *, modctl_t *))dtrace_nullop,
- .dtps_enable = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
- .dtps_disable = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
- .dtps_suspend = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
- .dtps_resume = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
+ .dtps_provide = dtrace_provide_handler,
+ .dtps_provide_module = dtrace_provide_module_handler,
+ .dtps_enable = dtrace_vpdtid_vp_handler,
+ .dtps_disable = dtrace_vpdtid_vp_handler,
+ .dtps_suspend = dtrace_vpdtid_vp_handler,
+ .dtps_resume = dtrace_vpdtid_vp_handler,
.dtps_getargdesc = NULL,
.dtps_getargval = NULL,
.dtps_usermode = NULL,
- .dtps_destroy = (void (*)(void *, dtrace_id_t, void *))dtrace_nullop,
+ .dtps_destroy = dtrace_vpdtid_vp_handler,
};
static dtrace_id_t dtrace_probeid_begin; /* special BEGIN probe */
@@ -594,7 +599,8 @@
static void dtrace_enabling_provide(dtrace_provider_t *);
static int dtrace_enabling_match(dtrace_enabling_t *, int *);
static void dtrace_enabling_matchall(void);
-static void dtrace_enabling_reap(void);
+static void dtrace_enabling_matchall_task(void *);
+static void dtrace_enabling_reap(void *);
static dtrace_state_t *dtrace_anon_grab(void);
static uint64_t dtrace_helper(int, dtrace_mstate_t *,
dtrace_state_t *, uint64_t, uint64_t);
@@ -8785,21 +8791,21 @@
if (pops->dtps_provide == NULL) {
ASSERT(pops->dtps_provide_module != NULL);
provider->dtpv_pops.dtps_provide =
- (void (*)(void *, dtrace_probedesc_t *))dtrace_nullop;
+ dtrace_provide_handler;
}
if (pops->dtps_provide_module == NULL) {
ASSERT(pops->dtps_provide != NULL);
provider->dtpv_pops.dtps_provide_module =
- (void (*)(void *, modctl_t *))dtrace_nullop;
+ dtrace_provide_module_handler;
}
if (pops->dtps_suspend == NULL) {
ASSERT(pops->dtps_resume == NULL);
provider->dtpv_pops.dtps_suspend =
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop;
+ dtrace_vpdtid_vp_handler;
provider->dtpv_pops.dtps_resume =
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop;
+ dtrace_vpdtid_vp_handler;
}
provider->dtpv_arg = arg;
@@ -8866,8 +8872,7 @@
int i, self = 0, noreap = 0;
dtrace_probe_t *probe, *first = NULL;
- if (old->dtpv_pops.dtps_enable ==
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop) {
+ if (old->dtpv_pops.dtps_enable == dtrace_vpdtid_vp_handler) {
/*
* If DTrace itself is the provider, we're called with locks
* already held.
@@ -9045,8 +9050,7 @@
{
dtrace_provider_t *pvp = (dtrace_provider_t *)id;
- ASSERT(pvp->dtpv_pops.dtps_enable !=
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop);
+ ASSERT(pvp->dtpv_pops.dtps_enable != dtrace_vpdtid_vp_handler);
mutex_enter(&dtrace_provider_lock);
mutex_enter(&dtrace_lock);
@@ -9086,8 +9090,7 @@
/*
* Make sure this isn't the dtrace provider itself.
*/
- ASSERT(prov->dtpv_pops.dtps_enable !=
- (void (*)(void *, dtrace_id_t, void *))dtrace_nullop);
+ ASSERT(prov->dtpv_pops.dtps_enable != dtrace_vpdtid_vp_handler);
mutex_enter(&dtrace_provider_lock);
mutex_enter(&dtrace_lock);
@@ -12992,6 +12995,12 @@
return (0);
}
+static void
+dtrace_enabling_matchall_task(void *arg __unused)
+{
+ dtrace_enabling_matchall();
+}
+
static void
dtrace_enabling_matchall(void)
{
@@ -13119,7 +13128,7 @@
* Called to reap ECBs that are attached to probes from defunct providers.
*/
static void
-dtrace_enabling_reap(void)
+dtrace_enabling_reap(void *args __unused)
{
dtrace_provider_t *prov;
dtrace_probe_t *probe;
@@ -16721,7 +16730,7 @@
}
(void) taskq_dispatch(dtrace_taskq,
- (task_func_t *)dtrace_enabling_matchall, NULL, TQ_SLEEP);
+ dtrace_enabling_matchall_task, NULL, TQ_SLEEP);
mutex_exit(&dtrace_lock);
diff --git a/sys/compat/linuxkpi/common/include/linux/module.h b/sys/compat/linuxkpi/common/include/linux/module.h
--- a/sys/compat/linuxkpi/common/include/linux/module.h
+++ b/sys/compat/linuxkpi/common/include/linux/module.h
@@ -82,9 +82,11 @@
#define SI_SUB_OFED_MODINIT (SI_SUB_ROOT_CONF - 1)
#include <sys/linker.h>
+#include <sys/cfi.h>
static inline void
_module_run(void *arg)
+__NOCFI
{
void (*fn)(void);
#ifdef OFED_DEBUG_INIT
diff --git a/sys/compat/linuxkpi/common/src/linux_shrinker.c b/sys/compat/linuxkpi/common/src/linux_shrinker.c
--- a/sys/compat/linuxkpi/common/src/linux_shrinker.c
+++ b/sys/compat/linuxkpi/common/src/linux_shrinker.c
@@ -92,7 +92,7 @@
}
static void
-linuxkpi_vm_lowmem(void *arg __unused)
+linuxkpi_vm_lowmem(void *arg __unused, int _2 __unused)
{
struct shrinker *s;
diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3895,6 +3895,7 @@
kern/subr_bus_dma.c standard
kern/subr_bufring.c standard
kern/subr_capability.c standard
+kern/subr_cfi.c optional kcfi
kern/subr_clock.c standard
kern/subr_compressor.c standard \
compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd"
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -64,6 +64,7 @@
amd64/amd64/bios.c standard
amd64/amd64/bpf_jit_machdep.c optional bpf_jitter
amd64/amd64/copyout.c standard
+amd64/amd64/cfi.c optional kcfi
amd64/amd64/cpu_switch.S standard
amd64/amd64/db_disasm.c optional ddb
amd64/amd64/db_interface.c optional ddb
diff --git a/sys/conf/kern.mk b/sys/conf/kern.mk
--- a/sys/conf/kern.mk
+++ b/sys/conf/kern.mk
@@ -291,6 +291,10 @@
-fsanitize=thread
.endif
+.if !empty(KCFI_ENABLED)
+SAN_CFLAGS+= -fsanitize=kcfi
+.endif
+
#
# Kernel Memory SANitizer support
#
diff --git a/sys/conf/kern.post.mk b/sys/conf/kern.post.mk
--- a/sys/conf/kern.post.mk
+++ b/sys/conf/kern.post.mk
@@ -37,6 +37,10 @@
MKMODULESENV+= KCSAN_ENABLED="yes"
.endif
+.if !empty(KCFI_ENABLED)
+MKMODULESENV+= KCFI_ENABLED="yes"
+.endif
+
.if defined(GCOV_CFLAGS)
MKMODULESENV+= GCOV_CFLAGS="${GCOV_CFLAGS}"
.endif
@@ -210,11 +214,15 @@
OBJS_DEPEND_GUESS+= offset.inc assym.inc vnode_if.h ${BEFORE_DEPEND:M*.h} \
${MFILES:T:S/.m$/.h/}
+.if !empty(KCFI_ENABLED)
+MAKEOBJOPT= "-s"
+.endif
+
.for mfile in ${MFILES}
# XXX the low quality .m.o rules gnerated by config are normally used
# instead of the .m.c rules here.
-${mfile:T:S/.m$/.c/}: ${mfile}
- ${AWK} -f $S/tools/makeobjops.awk ${mfile} -c
+${mfile:T:S/.m$/.c/}: ${mfile} $S/tools/makeobjops.awk
+ ${AWK} -f $S/tools/makeobjops.awk ${mfile} -c ${MAKEOBJOPT}
${mfile:T:S/.m$/.h/}: ${mfile}
${AWK} -f $S/tools/makeobjops.awk ${mfile} -h
.endfor
diff --git a/sys/conf/kern.pre.mk b/sys/conf/kern.pre.mk
--- a/sys/conf/kern.pre.mk
+++ b/sys/conf/kern.pre.mk
@@ -92,6 +92,7 @@
COMPAT_FREEBSD32_ENABLED!= grep COMPAT_FREEBSD32 opt_global.h || true ; echo
+KCFI_ENABLED!= grep KCFI opt_global.h || true ; echo
KASAN_ENABLED!= grep KASAN opt_global.h || true ; echo
KCSAN_ENABLED!= grep KCSAN opt_global.h || true ; echo
KMSAN_ENABLED!= grep KMSAN opt_global.h || true ; echo
@@ -105,6 +106,10 @@
.endif
.endif
+.if !empty(KCFI_ENABLED)
+MAKEOBJOPT= "-s"
+.endif
+
CFLAGS+= ${GCOV_CFLAGS}
# Put configuration-specific C flags last so that they can override
@@ -149,7 +154,7 @@
NORMAL_S= ${CC:N${CCACHE_BIN}} -c ${ASM_CFLAGS} ${WERROR} ${.IMPSRC}
NORMAL_C_NOWERROR= ${CC} -c ${CFLAGS} ${.IMPSRC}
-NORMAL_M= ${AWK} -f $S/tools/makeobjops.awk ${.IMPSRC} -c ; \
+NORMAL_M= ${AWK} -f $S/tools/makeobjops.awk ${.IMPSRC} -c ${MAKEOBJOPT} ; \
${CC} -c ${CFLAGS} ${WERROR} ${.PREFIX}.c
NORMAL_FW= uudecode -o ${.TARGET} ${.ALLSRC}
diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk
--- a/sys/conf/kmod.mk
+++ b/sys/conf/kmod.mk
@@ -406,6 +406,7 @@
.endfor
.endif
+KCFI_ENABLED= ${KERN_OPTS:MKCFI}
KASAN_ENABLED= ${KERN_OPTS:MKASAN}
KCSAN_ENABLED= ${KERN_OPTS:MKCSAN}
KMSAN_ENABLED= ${KERN_OPTS:MKMSAN}
@@ -435,6 +436,10 @@
${AWK} -f ${SYSDIR}/tools/vnode_if.awk ${SYSDIR}/kern/vnode_if.src -q
.endif
+.if !empty(KCFI_ENABLED)
+MAKEOBJOPT= "-s"
+.endif
+
# Build _if.[ch] from _if.m, and clean them when we're done.
# __MPATH defined in config.mk
_MFILES=${__MPATH:T:O}
@@ -448,7 +453,7 @@
.endif
.endfor # _i
.m.c: ${SYSDIR}/tools/makeobjops.awk
- ${AWK} -f ${SYSDIR}/tools/makeobjops.awk ${.IMPSRC} -c
+ ${AWK} -f ${SYSDIR}/tools/makeobjops.awk ${.IMPSRC} -c ${MAKEOBJOPT}
.m.h: ${SYSDIR}/tools/makeobjops.awk
${AWK} -f ${SYSDIR}/tools/makeobjops.awk ${.IMPSRC} -h
diff --git a/sys/conf/options b/sys/conf/options
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -249,6 +249,7 @@
COVERAGE opt_global.h
KASAN opt_global.h
KCOV
+KCFI opt_global.h
KCSAN opt_global.h
KMSAN opt_global.h
KUBSAN opt_global.h
diff --git a/sys/contrib/openzfs/include/sys/spa.h b/sys/contrib/openzfs/include/sys/spa.h
--- a/sys/contrib/openzfs/include/sys/spa.h
+++ b/sys/contrib/openzfs/include/sys/spa.h
@@ -1210,7 +1210,7 @@
/* Initialization and termination */
extern void spa_init(spa_mode_t mode);
extern void spa_fini(void);
-extern void spa_boot_init(void);
+extern void spa_boot_init(void *);
/* properties */
extern int spa_prop_set(spa_t *spa, nvlist_t *nvp);
diff --git a/sys/contrib/openzfs/module/os/freebsd/spl/spl_vfs.c b/sys/contrib/openzfs/module/os/freebsd/spl/spl_vfs.c
--- a/sys/contrib/openzfs/module/os/freebsd/spl/spl_vfs.c
+++ b/sys/contrib/openzfs/module/os/freebsd/spl/spl_vfs.c
@@ -256,6 +256,12 @@
return (0);
}
+static void
+vrele_task_runner(void *vp)
+{
+ vrele((vnode_t *)vp);
+}
+
/*
* Like vn_rele() except if we are going to call VOP_INACTIVE() then do it
* asynchronously using a taskq. This can avoid deadlocks caused by re-entering
@@ -273,5 +279,5 @@
if (refcount_release_if_not_last(&vp->v_usecount))
return;
VERIFY3U(taskq_dispatch((taskq_t *)taskq,
- (task_func_t *)vrele, vp, TQ_SLEEP), !=, 0);
+ vrele_task_runner, vp, TQ_SLEEP), !=, 0);
}
diff --git a/sys/contrib/openzfs/module/zfs/spa_misc.c b/sys/contrib/openzfs/module/zfs/spa_misc.c
--- a/sys/contrib/openzfs/module/zfs/spa_misc.c
+++ b/sys/contrib/openzfs/module/zfs/spa_misc.c
@@ -2521,7 +2521,7 @@
}
void
-spa_boot_init(void)
+spa_boot_init(void*dummy __unused)
{
spa_config_load();
}
diff --git a/sys/dev/drm2/ttm/ttm_page_alloc.c b/sys/dev/drm2/ttm/ttm_page_alloc.c
--- a/sys/dev/drm2/ttm/ttm_page_alloc.c
+++ b/sys/dev/drm2/ttm/ttm_page_alloc.c
@@ -441,7 +441,7 @@
/**
* Callback for mm to request pool to reduce number of page held.
*/
-static int ttm_pool_mm_shrink(void *arg)
+static int ttm_pool_mm_shrink(void *arg, int _1 __unused)
{
static unsigned int start_pool = 0;
unsigned i;
diff --git a/sys/dev/null/null.c b/sys/dev/null/null.c
--- a/sys/dev/null/null.c
+++ b/sys/dev/null/null.c
@@ -48,6 +48,7 @@
static struct cdev *null_dev;
static struct cdev *zero_dev;
+static d_read_t null_read;
static d_write_t full_write;
static d_write_t null_write;
static d_ioctl_t null_ioctl;
@@ -64,7 +65,7 @@
static struct cdevsw null_cdevsw = {
.d_version = D_VERSION,
- .d_read = (d_read_t *)nullop,
+ .d_read = null_read,
.d_write = null_write,
.d_ioctl = null_ioctl,
.d_name = "null",
@@ -79,6 +80,13 @@
.d_flags = D_MMAP_ANON,
};
+
+static int
+null_read(struct cdev *dev __unused, struct uio *uio __unused, int flags __unused)
+{
+ return (0);
+}
+
/* ARGSUSED */
static int
full_write(struct cdev *dev __unused, struct uio *uio __unused, int flags __unused)
diff --git a/sys/geom/eli/g_eli.c b/sys/geom/eli/g_eli.c
--- a/sys/geom/eli/g_eli.c
+++ b/sys/geom/eli/g_eli.c
@@ -194,7 +194,7 @@
}
static void
-zero_intake_passcache(void *dummy)
+zero_intake_passcache(void *dummy __unused)
{
zero_boot_passcache();
zero_geli_intake_keys();
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -97,6 +97,7 @@
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
+#include <sys/cfi.h>
void mi_startup(void); /* Should be elsewhere */
@@ -255,6 +256,7 @@
*/
void
mi_startup(void)
+__NOCFI
{
struct sysinit *sip;
int last;
diff --git a/sys/kern/kern_conf.c b/sys/kern/kern_conf.c
--- a/sys/kern/kern_conf.c
+++ b/sys/kern/kern_conf.c
@@ -257,41 +257,44 @@
atomic_subtract_rel_long(&dev->si_threadcount, 1);
}
-int
-nullop(void)
-{
-
- return (0);
-}
-
-int
-eopnotsupp(void)
-{
-
- return (EOPNOTSUPP);
-}
+#define DEFINE_ENXIO_HANDLER(name, ...) \
+ static int name(__VA_ARGS__) \
+ { \
+ return (ENXIO); \
+ }
-static int
-enxio(void)
-{
- return (ENXIO);
-}
+#define DEFINE_ENODEV_HANDLER(name, ...) \
+ static int name(__VA_ARGS__) \
+ { \
+ return (ENODEV); \
+ }
-static int
-enodev(void)
-{
- return (ENODEV);
-}
+#define DEFINE_NULLOP_HANDLER(name, ...) \
+ static int \
+ name (__VA_ARGS__) \
+ { \
+ return (0); \
+ }
+DEFINE_ENXIO_HANDLER(dead_open_handler, struct cdev *dev, int oflags, int devtype, struct thread *td);
+DEFINE_ENXIO_HANDLER(dead_close_handler, struct cdev *dev, int fflag, int devtype, struct thread *td);
+DEFINE_ENXIO_HANDLER(dead_read_handler, struct cdev *dev, struct uio *uio, int ioflag);
+DEFINE_ENXIO_HANDLER(dead_write_handler, struct cdev *dev, struct uio *uio, int ioflag);
+DEFINE_ENXIO_HANDLER(dead_ioctl_handler, struct cdev *dev, u_long cmd, caddr_t data,
+ int fflag, struct thread *td);
+DEFINE_ENODEV_HANDLER(dead_poll_handler, struct cdev *dev, int events,
+ struct thread *td);
+DEFINE_ENODEV_HANDLER(dead_mmap_handler, struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
+ int nprot, vm_memattr_t *memattr);
/* Define a dead_cdevsw for use when devices leave unexpectedly. */
-#define dead_open (d_open_t *)enxio
-#define dead_close (d_close_t *)enxio
-#define dead_read (d_read_t *)enxio
-#define dead_write (d_write_t *)enxio
-#define dead_ioctl (d_ioctl_t *)enxio
-#define dead_poll (d_poll_t *)enodev
-#define dead_mmap (d_mmap_t *)enodev
+#define dead_open dead_open_handler
+#define dead_close dead_close_handler
+#define dead_read dead_read_handler
+#define dead_write dead_write_handler
+#define dead_ioctl dead_ioctl_handler
+#define dead_poll dead_poll_handler
+#define dead_mmap dead_mmap_handler
static void
dead_strategy(struct bio *bp)
@@ -300,8 +303,12 @@
biofinish(bp, NULL, ENXIO);
}
-#define dead_kqfilter (d_kqfilter_t *)enxio
-#define dead_mmap_single (d_mmap_single_t *)enodev
+DEFINE_ENXIO_HANDLER(dead_kqfilter_handler, struct cdev *dev, struct knote *kn);
+DEFINE_ENODEV_HANDLER(dead_mmap_single_handler, struct cdev *cdev, vm_ooffset_t *offset,
+ vm_size_t size, struct vm_object **object, int nprot);
+
+#define dead_kqfilter dead_kqfilter_handler
+#define dead_mmap_single dead_mmap_single_handler
static struct cdevsw dead_cdevsw = {
.d_version = D_VERSION,
@@ -320,14 +327,22 @@
/* Default methods if driver does not specify method */
-#define null_open (d_open_t *)nullop
-#define null_close (d_close_t *)nullop
-#define no_read (d_read_t *)enodev
-#define no_write (d_write_t *)enodev
-#define no_ioctl (d_ioctl_t *)enodev
-#define no_mmap (d_mmap_t *)enodev
-#define no_kqfilter (d_kqfilter_t *)enodev
-#define no_mmap_single (d_mmap_single_t *)enodev
+DEFINE_NULLOP_HANDLER(no_open_handler, struct cdev *dev, int oflags, int devtype, struct thread *td);
+DEFINE_NULLOP_HANDLER(no_close_handler, struct cdev *dev, int fflag, int devtype, struct thread *td);
+DEFINE_ENODEV_HANDLER(no_read_handler, struct cdev *dev, struct uio *uio, int ioflag);
+DEFINE_ENODEV_HANDLER(no_write_handler, struct cdev *dev, struct uio *uio, int ioflag);
+DEFINE_ENODEV_HANDLER(no_ioctl_handler, struct cdev *dev, u_long cmd, caddr_t data,
+ int fflag, struct thread *td);
+DEFINE_ENODEV_HANDLER(no_kqfilter_handler, struct cdev *dev, struct knote *kn);
+
+#define null_open (d_open_t *)no_open_handler
+#define null_close (d_close_t *)no_close_handler
+#define no_read (d_read_t *)no_read_handler
+#define no_write (d_write_t *)no_write_handler
+#define no_ioctl (d_ioctl_t *)no_ioctl_handler
+#define no_mmap (d_mmap_t *)dead_mmap_handler
+#define no_kqfilter (d_kqfilter_t *)no_kqfilter_handler
+#define no_mmap_single (d_mmap_single_t *)dead_mmap_single_handler
static void
no_strategy(struct bio *bp)
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
@@ -1475,7 +1475,7 @@
}
static void
-exec_args_kva_lowmem(void *arg __unused)
+exec_args_kva_lowmem(void *arg __unused, int _1 __unused)
{
SLIST_HEAD(, exec_args_kva) head;
struct exec_args_kva *argkva;
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
@@ -71,6 +71,7 @@
#include <sys/sx.h>
#include <sys/sysent.h>
#include <sys/signalvar.h>
+#include <sys/cfi.h>
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
@@ -1113,8 +1114,8 @@
* is called from the MD fork_trampoline() entry point.
*/
void
-fork_exit(void (*callout)(void *, struct trapframe *), void *arg,
- struct trapframe *frame)
+fork_exit(void (*callout)(struct thread *, struct trapframe *), void *arg,
+ struct trapframe *frame) __NOCFI
{
struct proc *p;
struct thread *td;
diff --git a/sys/kern/kern_intr.c b/sys/kern/kern_intr.c
--- a/sys/kern/kern_intr.c
+++ b/sys/kern/kern_intr.c
@@ -51,6 +51,7 @@
#include <sys/random.h>
#include <sys/resourcevar.h>
#include <sys/sched.h>
+#include <sys/cfi.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
@@ -61,6 +62,7 @@
#include <machine/md_var.h>
#include <machine/smp.h>
#include <machine/stdarg.h>
+
#ifdef DDB
#include <ddb/ddb.h>
#include <ddb/db_sym.h>
@@ -1188,6 +1190,7 @@
static void
ithread_execute_handlers(struct proc *p, struct intr_event *ie)
+__NOCFI
{
/* Interrupt handlers should not sleep. */
@@ -1334,7 +1337,7 @@
* o EINVAL: stray interrupt.
*/
int
-intr_event_handle(struct intr_event *ie, struct trapframe *frame)
+intr_event_handle(struct intr_event *ie, struct trapframe *frame) __NOCFI
{
struct intr_handler *ih;
struct trapframe *oldframe;
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -26,11 +26,11 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "opt_ddb.h"
-#include "opt_kld.h"
#include "opt_hwpmc_hooks.h"
+#include "opt_kld.h"
+#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/boottrace.h>
@@ -672,6 +672,10 @@
#ifdef __arm__
lf->exidx_addr = 0;
lf->exidx_size = 0;
+#endif
+#ifdef KCFI
+ lf->kcfi_traps_addr = 0;
+ lf->kcfi_traps_size = 0;
#endif
STAILQ_INIT(&lf->common);
TAILQ_INIT(&lf->modules);
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -47,6 +47,7 @@
#include <sys/linker.h>
#include <sys/sysctl.h>
#include <sys/tslog.h>
+#include <sys/cfi.h>
#include <machine/elf.h>
@@ -359,6 +360,7 @@
static void
link_elf_invoke_cbs(caddr_t addr, size_t size)
+__NOCFI
{
void (**ctor)(void);
size_t i, cnt;
@@ -448,8 +450,8 @@
link_elf_init(void* arg)
{
Elf_Dyn *dp;
- Elf_Addr *ctors_addrp;
- Elf_Size *ctors_sizep;
+ Elf_Addr *addrp;
+ Elf_Size *sizep;
caddr_t modptr, baseptr, sizeptr;
elf_file_t ef;
const char *modname;
@@ -501,15 +503,26 @@
sizeptr = preload_search_info(modptr, MODINFO_SIZE);
if (sizeptr != NULL)
linker_kernel_file->size = *(size_t *)sizeptr;
- ctors_addrp = (Elf_Addr *)preload_search_info(modptr,
+ addrp = (Elf_Addr *)preload_search_info(modptr,
MODINFO_METADATA | MODINFOMD_CTORS_ADDR);
- ctors_sizep = (Elf_Size *)preload_search_info(modptr,
+ sizep = (Elf_Size *)preload_search_info(modptr,
MODINFO_METADATA | MODINFOMD_CTORS_SIZE);
- if (ctors_addrp != NULL && ctors_sizep != NULL) {
+ if (addrp != NULL && sizep != NULL) {
linker_kernel_file->ctors_addr = ef->address +
- *ctors_addrp;
- linker_kernel_file->ctors_size = *ctors_sizep;
+ *addrp;
+ linker_kernel_file->ctors_size = *sizep;
+ }
+#ifdef KCFI
+ addrp = (Elf_Addr *)preload_search_info(modptr,
+ MODINFO_METADATA | MODINFOMD_CFI_ADDR);
+ sizep = (Elf_Size *)preload_search_info(modptr,
+ MODINFO_METADATA | MODINFOMD_CFI_SIZE);
+ if (addrp != NULL && sizep != NULL) {
+ linker_kernel_file->kcfi_traps_addr = ef->address +
+ *addrp;
+ linker_kernel_file->kcfi_traps_size = *sizep;
}
+#endif
}
(void)link_elf_preload_parse_symbols(ef);
@@ -876,6 +889,26 @@
#endif /* __arm__ */
+#ifdef KCFI
+
+static void
+link_elf_locate_kcfi_traps_preload(struct linker_file *lf, caddr_t modptr)
+{
+ Elf_Addr *kcfi_addrp;
+ Elf_Size *kcfi_sizep;
+
+ kcfi_addrp = (Elf_Addr *)preload_search_info(modptr,
+ MODINFO_METADATA | MODINFOMD_CFI_ADDR);
+ kcfi_sizep = (Elf_Size *)preload_search_info(modptr,
+ MODINFO_METADATA | MODINFOMD_CFI_SIZE);
+ if (kcfi_addrp != NULL && kcfi_sizep != NULL) {
+ lf->kcfi_traps_addr = ((elf_file_t)lf)->address + *kcfi_addrp;
+ lf->kcfi_traps_size = *kcfi_sizep;
+ }
+}
+
+#endif /* KCFI */
+
static int
link_elf_link_preload(linker_class_t cls, const char *filename,
linker_file_t *result)
@@ -935,6 +968,10 @@
link_elf_locate_exidx_preload(lf, modptr);
#endif
+#ifdef KCFI
+ link_elf_locate_kcfi_traps_preload(lf, modptr);
+#endif
+
error = parse_dynamic(ef);
if (error == 0)
error = parse_dpcpu(ef);
@@ -1291,11 +1328,18 @@
if (shdr[i].sh_type == SHT_SYMTAB) {
symtabindex = i;
symstrindex = shdr[i].sh_link;
- } else if (shstrs != NULL && shdr[i].sh_name != 0 &&
- strcmp(shstrs + shdr[i].sh_name, ".ctors") == 0) {
- /* Record relocated address and size of .ctors. */
- lf->ctors_addr = mapbase + shdr[i].sh_addr - base_vaddr;
- lf->ctors_size = shdr[i].sh_size;
+ } else if (shstrs != NULL && shdr[i].sh_name != 0) {
+ if (strcmp(shstrs + shdr[i].sh_name, ".ctors") == 0) {
+ /* Record relocated address and size of .ctors. */
+ lf->ctors_addr = mapbase + shdr[i].sh_addr - base_vaddr;
+ lf->ctors_size = shdr[i].sh_size;
+ }
+#ifdef KCFI
+ else if (strcmp(shstrs + shdr[i].sh_name, ".kcfi_traps") == 0) {
+ lf->kcfi_traps_addr = mapbase + shdr[i].sh_addr - base_vaddr;
+ lf->kcfi_traps_size = shdr[i].sh_size;
+ }
+#endif
}
}
if (symtabindex < 0 || symstrindex < 0)
@@ -1636,7 +1680,7 @@
static int
link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
- linker_symval_t *symval, bool see_local)
+ linker_symval_t *symval, bool see_local) __NOCFI
{
elf_file_t ef;
const Elf_Sym *es;
@@ -1669,7 +1713,7 @@
static int
link_elf_debug_symbol_values(linker_file_t lf, c_linker_sym_t sym,
- linker_symval_t *symval)
+ linker_symval_t *symval) __NOCFI
{
elf_file_t ef = (elf_file_t)lf;
const Elf_Sym *es = (const Elf_Sym *)sym;
@@ -1999,7 +2043,7 @@
*/
static int
elf_lookup_ifunc(linker_file_t lf, Elf_Size symidx, int deps __unused,
- Elf_Addr *res)
+ Elf_Addr *res) __NOCFI
{
elf_file_t ef;
const Elf_Sym *symp;
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -43,6 +43,7 @@
#include <sys/rwlock.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
+#include <sys/cfi.h>
#include <machine/elf.h>
@@ -576,7 +577,13 @@
lf->dtors_size = shdr[i].sh_size;
}
}
-
+#ifdef KCFI
+ else if (ef->progtab[pb].name != NULL &&
+ strcmp(ef->progtab[pb].name, ".kcfi_traps") == 0) {
+ lf->kcfi_traps_addr = ef->progtab[pb].addr;
+ lf->kcfi_traps_size = shdr[i].sh_size;
+ }
+#endif
/* Update all symbol values with the offset. */
for (j = 0; j < ef->ddbsymcnt; j++) {
es = &ef->ddbsymtab[j];
@@ -644,6 +651,7 @@
static void
link_elf_invoke_cbs(caddr_t addr, size_t size)
+__NOCFI
{
void (**ctor)(void);
size_t i, cnt;
@@ -1055,6 +1063,7 @@
if (ef->shstrtab != NULL && shdr[i].sh_name != 0) {
ef->progtab[pb].name =
ef->shstrtab + shdr[i].sh_name;
+
if (!strcmp(ef->progtab[pb].name, ".ctors") ||
shdr[i].sh_type == SHT_INIT_ARRAY) {
if (lf->ctors_addr != 0) {
@@ -1081,6 +1090,16 @@
shdr[i].sh_size;
}
}
+#ifdef KCFI
+ else if (
+ !strcmp(ef->progtab[pb].name,
+ ".kcfi_traps")) {
+ lf->kcfi_traps_addr =
+ (caddr_t)mapbase;
+ lf->kcfi_traps_size =
+ shdr[i].sh_size;
+ }
+#endif
} else if (shdr[i].sh_type == SHT_PROGBITS)
ef->progtab[pb].name = "<<PROGBITS>>";
#ifdef __amd64__
@@ -1141,6 +1160,7 @@
error = EINVAL;
goto out;
}
+
/* Initialize the per-cpu area. */
if (ef->progtab[pb].addr != (void *)mapbase &&
!strcmp(ef->progtab[pb].name, DPCPU_SETNAME))
@@ -1515,7 +1535,7 @@
static int
link_elf_symbol_values1(linker_file_t lf, c_linker_sym_t sym,
- linker_symval_t *symval, bool see_local)
+ linker_symval_t *symval, bool see_local) __NOCFI
{
elf_file_t ef;
const Elf_Sym *es;
@@ -1690,6 +1710,7 @@
*/
static int
elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *res)
+__NOCFI
{
elf_file_t ef = (elf_file_t)lf;
Elf_Sym *sym;
diff --git a/sys/kern/subr_cfi.c b/sys/kern/subr_cfi.c
new file mode 100644
--- /dev/null
+++ b/sys/kern/subr_cfi.c
@@ -0,0 +1,114 @@
+#include <sys/cdefs.h>
+
+
+#ifdef _KERNEL
+#include <sys/priv.h>
+#include <sys/cfi.h>
+#include <sys/systm.h>
+#include <sys/kassert.h>
+#include <sys/sysctl.h>
+#include <sys/linker.h>
+#endif
+
+#ifdef _KERNEL
+#include <machine/cpu.h>
+#include <machine/cfi.h>
+#endif
+
+#define CFI_DEBUG_MSG "CFI check failed on PC %p for callee %p and type %x\n"
+
+FEATURE(kcfi, "Kernel control flow integrity");
+
+static SYSCTL_NODE(_debug, OID_AUTO, kcfi, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
+ "KCFI options");
+
+static bool cfi_panic __read_mostly = false;
+SYSCTL_BOOL(_debug_kcfi, OID_AUTO, panic_on_violation, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
+ &cfi_panic, 0, "Panic on KCFI violation");
+
+static bool cfi_disabled __read_mostly = false;
+SYSCTL_BOOL(_debug_kcfi, OID_AUTO, disabled, CTLFLAG_RDTUN | CTLFLAG_NOFETCH,
+ &cfi_disabled, 0, "Disable KCFI message");
+
+#ifdef _KERNEL
+static void
+report_cfi(uintptr_t caller_addr, uintptr_t callee_addr, uint32_t type) {
+ if (cfi_panic)
+ panic(CFI_DEBUG_MSG, (void *)caller_addr, (void *)callee_addr, type);
+ else
+ printf(CFI_DEBUG_MSG, (void *)caller_addr, (void *)callee_addr, type);
+}
+#endif
+
+#ifdef _KERNEL
+static int
+kcfi_lookup_module(linker_file_t lf, void *arg)
+{
+ uintptr_t *module = (uintptr_t *)arg;
+
+ if (lf->address <= (caddr_t)*module &&
+ (lf->address + lf->size) >= (caddr_t)*module) {
+ *module = (uintptr_t) lf;
+ return (1);
+ }
+
+ return (0);
+}
+#endif
+
+#ifdef _KERNEL
+static inline uintptr_t
+cfi_trap_addr(int32_t *addr)
+{
+ return ((uintptr_t)((int32_t)(intptr_t)addr + *addr));
+}
+#endif
+
+#ifdef _KERNEL
+static bool
+is_cfi_exception(uintptr_t address)
+{
+ linker_file_t module;
+ int32_t *trap, *traps_end;
+
+ module = (linker_file_t)address;
+ linker_file_foreach(kcfi_lookup_module, &module);
+
+ if ((uintptr_t)module == address)
+ return (false);
+
+ trap = (int32_t *)(module->kcfi_traps_addr);
+ traps_end = (int32_t *)(module->kcfi_traps_addr +
+ module->kcfi_traps_size);
+
+ if (trap == NULL)
+ return (false);
+
+ for (;trap != traps_end; trap++)
+ if (cfi_trap_addr(trap) == address)
+ return (true);
+
+ return (false);
+}
+#endif
+
+#ifdef _KERNEL
+bool
+cfi_handler(struct trapframe *frame)
+{
+ uintptr_t callee_addr, caller_addr;
+ uint32_t type;
+
+ caller_addr = TRAPF_PC(frame);
+
+ if (decode_cfi_frame(frame, &callee_addr, &type) &&
+ is_cfi_exception((uintptr_t) caller_addr)) {
+ report_cfi(caller_addr, callee_addr, type);
+ /* needs to be platform dependent */
+ post_cfi(frame);
+ return (true);
+ }
+
+ return (false);
+}
+#endif
diff --git a/sys/kern/subr_epoch.c b/sys/kern/subr_epoch.c
--- a/sys/kern/subr_epoch.c
+++ b/sys/kern/subr_epoch.c
@@ -43,6 +43,7 @@
#include <sys/smp.h>
#include <sys/sysctl.h>
#include <sys/turnstile.h>
+#include <sys/cfi.h>
#ifdef EPOCH_TRACE
#include <machine/stdarg.h>
#include <sys/stack.h>
@@ -802,6 +803,7 @@
static void
epoch_call_task(void *arg __unused)
+__NOCFI
{
ck_stack_entry_t *cursor, *head, *next;
ck_epoch_record_t *record;
diff --git a/sys/kern/subr_module.c b/sys/kern/subr_module.c
--- a/sys/kern/subr_module.c
+++ b/sys/kern/subr_module.c
@@ -385,6 +385,14 @@
case MODINFOMD_KEYBUF:
sbuf_cat(sbp, "MODINFOMD_KEYBUF");
break;
+#ifdef KCFI
+ case MODINFOMD_CFI_ADDR:
+ sbuf_cat(sbp, "MODINFOMD_CFI_ADDR");
+ break;
+ case MODINFOMD_CFI_SIZE:
+ sbuf_cat(sbp, "MODINFOMD_CFI_SIZE");
+ break;
+#endif
#ifdef MODINFOMD_SMAP
case MODINFOMD_SMAP:
sbuf_cat(sbp, "MODINFOMD_SMAP");
@@ -455,6 +463,9 @@
break;
case MODINFO_SIZE:
case MODINFO_METADATA | MODINFOMD_CTORS_SIZE:
+#ifdef KCFI
+ case MODINFO_METADATA | MODINFOMD_CFI_SIZE:
+#endif
sbuf_printf(sbp, "%lu", *(u_long *)bptr);
break;
case MODINFO_ADDR:
@@ -464,6 +475,9 @@
case MODINFO_METADATA | MODINFOMD_KERNEND:
case MODINFO_METADATA | MODINFOMD_ENVP:
case MODINFO_METADATA | MODINFOMD_CTORS_ADDR:
+#ifdef KCFI
+ case MODINFO_METADATA | MODINFOMD_CFI_ADDR:
+#endif
#ifdef MODINFOMD_SMAP
case MODINFO_METADATA | MODINFOMD_SMAP:
#endif
diff --git a/sys/kern/subr_pctrie.c b/sys/kern/subr_pctrie.c
--- a/sys/kern/subr_pctrie.c
+++ b/sys/kern/subr_pctrie.c
@@ -49,6 +49,7 @@
#include <sys/cdefs.h>
#include "opt_ddb.h"
+#include <sys/cfi.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
@@ -1159,7 +1160,7 @@
*/
static __always_inline struct pctrie_node *
pctrie_reclaim_prune(struct pctrie_node **pnode, struct pctrie_node *parent,
- pctrie_cb_t callback, int keyoff, void *arg)
+ pctrie_cb_t callback, int keyoff, void *arg) __NOCFI
{
struct pctrie_node *child, *node;
int slot;
@@ -1192,7 +1193,7 @@
*/
static __always_inline struct pctrie_node *
pctrie_reclaim_resume_compound(struct pctrie_node **pnode,
- pctrie_cb_t callback, int keyoff, void *arg)
+ pctrie_cb_t callback, int keyoff, void *arg) __NOCFI
{
struct pctrie_node *parent, *node;
@@ -1212,7 +1213,7 @@
static __always_inline struct pctrie_node *
pctrie_reclaim_begin_compound(struct pctrie_node **pnode,
struct pctrie *ptree,
- pctrie_cb_t callback, int keyoff, void *arg)
+ pctrie_cb_t callback, int keyoff, void *arg) __NOCFI
{
struct pctrie_node *node;
diff --git a/sys/kern/subr_scanf.c b/sys/kern/subr_scanf.c
--- a/sys/kern/subr_scanf.c
+++ b/sys/kern/subr_scanf.c
@@ -39,6 +39,7 @@
#include <sys/ctype.h>
#include <sys/limits.h>
#include <sys/stddef.h>
+#include <sys/cfi.h>
/*
* Note that stdarg.h and the ANSI style va_start macro is used for both
@@ -101,6 +102,7 @@
int
vsscanf(const char *inp, char const *fmt0, va_list ap)
+__NOCFI
{
int inr;
const u_char *fmt = (const u_char *)fmt0;
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
@@ -43,6 +43,7 @@
#include <sys/capsicum.h>
#include <sys/ktr.h>
#include <sys/vmmeter.h>
+#include <sys/cfi.h>
#ifdef KTRACE
#include <sys/uio.h>
#include <sys/ktrace.h>
@@ -50,7 +51,7 @@
#include <security/audit/audit.h>
static inline void
-syscallenter(struct thread *td)
+syscallenter(struct thread *td) __NOCFI
{
struct proc *p;
struct syscall_args *sa;
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -5298,7 +5298,7 @@
/*
* Routine to create and manage a filesystem syncer vnode.
*/
-#define sync_close ((int (*)(struct vop_close_args *))nullop)
+static int sync_close(struct vop_close_args *);
static int sync_fsync(struct vop_fsync_args *);
static int sync_inactive(struct vop_inactive_args *);
static int sync_reclaim(struct vop_reclaim_args *);
@@ -5392,6 +5392,10 @@
vrele(vp);
}
+static int sync_close(struct vop_close_args *args __unused) {
+ return (0);
+}
+
/*
* Do a lazy sync of the filesystem.
*/
diff --git a/sys/net/ifdi_if.m b/sys/net/ifdi_if.m
--- a/sys/net/ifdi_if.m
+++ b/sys/net/ifdi_if.m
@@ -107,7 +107,7 @@
}
static int
- null_priv_ioctl(if_ctx_t _ctx __unused, u_long command, caddr_t *data __unused)
+ null_priv_ioctl(if_ctx_t _ctx __unused, u_long command, caddr_t data __unused)
{
return (ENOTSUP);
}
diff --git a/sys/net/radix.c b/sys/net/radix.c
--- a/sys/net/radix.c
+++ b/sys/net/radix.c
@@ -33,7 +33,8 @@
* Routines to build and maintain radix trees for routing lookups.
*/
#include <sys/param.h>
-#ifdef _KERNEL
+#ifdef _KERNEL
+#include <sys/cfi.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/rmlock.h>
@@ -1056,7 +1057,7 @@
int
rn_walktree(struct radix_head *h, walktree_f_t *f, void *w)
-{
+__NOCFI {
int error;
struct radix_node *base, *next;
struct radix_node *rn = h->rnh_treetop;
diff --git a/sys/net/vnet.c b/sys/net/vnet.c
--- a/sys/net/vnet.c
+++ b/sys/net/vnet.c
@@ -53,6 +53,7 @@
#include <sys/socket.h>
#include <sys/sx.h>
#include <sys/sysctl.h>
+#include <sys/cfi.h>
#include <machine/stdarg.h>
@@ -512,6 +513,7 @@
*/
void
vnet_register_sysinit(void *arg)
+__NOCFI
{
struct vnet_sysinit *vs, *vs2;
struct vnet *vnet;
diff --git a/sys/netinet/ip_reass.c b/sys/netinet/ip_reass.c
--- a/sys/netinet/ip_reass.c
+++ b/sys/netinet/ip_reass.c
@@ -657,7 +657,7 @@
* Drain off all datagram fragments.
*/
static void
-ipreass_drain(void)
+ipreass_drain(void *_1 __unused, int _2 __unused)
{
VNET_ITERATOR_DECL(vnet_iter);
@@ -868,7 +868,7 @@
V_noreass = 0;
} else if (max == 0) {
V_noreass = 1;
- ipreass_drain();
+ ipreass_drain(NULL, 0);
} else if (max == -1) {
V_noreass = 0;
uma_zone_set_max(V_ipq_zone, 0);
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -6825,7 +6825,7 @@
}
static void
-sctp_drain(void)
+sctp_drain(void *_1 __unused, int _2 __unused)
{
struct epoch_tracker et;
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1384,7 +1384,7 @@
}
static void
-tcp_drain(void)
+tcp_drain(void *_1 __unused, int _2 __unused)
{
struct epoch_tracker et;
VNET_ITERATOR_DECL(vnet_iter);
diff --git a/sys/netinet6/frag6.c b/sys/netinet6/frag6.c
--- a/sys/netinet6/frag6.c
+++ b/sys/netinet6/frag6.c
@@ -1078,7 +1078,7 @@
}
void
-frag6_drain(void)
+frag6_drain(void *_1 __unused, int _2 __unused)
{
VNET_ITERATOR_DECL(vnet_iter);
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -414,7 +414,7 @@
void frag6_init(void);
void frag6_destroy(void);
int frag6_input(struct mbuf **, int *, int);
-void frag6_drain(void);
+void frag6_drain(void *, int);
void rip6_init(void);
int rip6_ctloutput(struct socket *, struct sockopt *);
diff --git a/sys/sys/cfi.h b/sys/sys/cfi.h
new file mode 100644
--- /dev/null
+++ b/sys/sys/cfi.h
@@ -0,0 +1,22 @@
+/*
+ */
+#ifndef _SYS_CFI_H_
+#define _SYS_CFI_H_
+
+#ifdef _KERNEL
+
+#include <sys/types.h>
+#include <sys/proc.h>
+
+#ifdef KCFI
+#define __NOCFI __attribute__((__no_sanitize__("kcfi")))
+#else
+#define __NOCFI
+#endif
+
+bool
+cfi_handler(struct trapframe *);
+
+#endif /* _KERNEL */
+
+#endif /* _SYS_CFI_H_ */
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -109,6 +109,11 @@
caddr_t exidx_addr; /* Unwind data index table start */
size_t exidx_size; /* Unwind data index table size */
#endif
+
+#ifdef KCFI
+ caddr_t kcfi_traps_addr; /* KCFI trap table start */
+ size_t kcfi_traps_size; /* KCFI trap table size */
+#endif
};
/*
@@ -251,7 +256,10 @@
#define MODINFOMD_KEYBUF 0x000d /* Crypto key intake buffer */
#define MODINFOMD_FONT 0x000e /* Console font */
#define MODINFOMD_SPLASH 0x000f /* Console splash screen */
-#define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */
+/* No ifdef because we are unable pass the kernel defined preprocessor to lodaer*/
+#define MODINFOMD_CFI_ADDR 0x0010 /* address of .kcfi_traps */
+#define MODINFOMD_CFI_SIZE 0x0020 /* size of .kcfi_traps */
+#define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */
#define MODINFOMD_DEPLIST (0x4001 | MODINFOMD_NOCOPY) /* depends on */
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1154,7 +1154,7 @@
struct session *sess);
int enterthispgrp(struct proc *p, struct pgrp *pgrp);
int fork1(struct thread *, struct fork_req *);
-void fork_exit(void (*)(void *, struct trapframe *), void *,
+void fork_exit(void (*)(struct thread*, struct trapframe *), void *,
struct trapframe *);
void fork_return(struct thread *, struct trapframe *);
int inferior(struct proc *p);
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -144,7 +144,6 @@
int setjmp(struct _jmp_buf *) __returns_twice;
void longjmp(struct _jmp_buf *, int) __dead2;
int dumpstatus(vm_offset_t addr, off_t count);
-int nullop(void);
int eopnotsupp(void);
int ureadc(int, struct uio *);
void hashdestroy(void *, struct malloc_type *, u_long);
diff --git a/sys/tools/makeobjops.awk b/sys/tools/makeobjops.awk
--- a/sys/tools/makeobjops.awk
+++ b/sys/tools/makeobjops.awk
@@ -45,6 +45,7 @@
print " -p use the path component in the source file for destination dir";
print " -l set line width for output files [80]";
print " -d switch on debugging";
+ print " -s generate default function with correct signature when DEFAULT is missed";
exit 1;
}
@@ -291,9 +292,17 @@
firstvar = varnames[1];
- if (default_function == "")
+ if (default_function == "") {
default_function = "kobj_error_method";
+ if (opt_s) {
+ default_function=mname "_error_method";
+ # Generate correct default function for KCFI use
+ # kobj_error_method return ENXIO
+ printc("static " ret " " default_function "(" argument_list ")\n{\n " "return (" ret ") ENXIO;\n}\n");
+ }
+ }
+
# the method description
printh("/** @brief Unique descriptor for the " umname "() method */");
printh("extern struct kobjop_desc " mname "_desc;");
@@ -364,6 +373,7 @@
else if (o == "h") opt_h = 1;
else if (o == "p") opt_p = 1;
else if (o == "d") opt_d = 1;
+ else if (o == "s") opt_s = 1;
else if (o == "l") {
if (length(ARGV[i]) > j) {
opt_l = substr(ARGV[i], j + 1);
diff --git a/sys/tools/vnode_if.awk b/sys/tools/vnode_if.awk
--- a/sys/tools/vnode_if.awk
+++ b/sys/tools/vnode_if.awk
@@ -199,6 +199,7 @@
"#include <sys/signalvar.h>\n" \
"#include <sys/systm.h>\n" \
"#include <sys/vnode.h>\n" \
+ "#include <sys/cfi.h>\n" \
"\n" \
"SDT_PROVIDER_DECLARE(vfs);\n" \
"\n" \
@@ -389,7 +390,7 @@
printc("");
printc("\treturn(" uname "_APV(a->a_" args[0] "->v_op, a));");
printc("}");
- printc("\nint\n" uname "_APV(const struct vop_vector *vop, struct " name "_args *a)");
+ printc("\nint\n" uname "_APV(const struct vop_vector *vop, struct " name "_args *a) __NOCFI");
printc("{");
printc("\tint rc;");
printc("");
diff --git a/sys/ufs/ufs/ufs_dirhash.c b/sys/ufs/ufs/ufs_dirhash.c
--- a/sys/ufs/ufs/ufs_dirhash.c
+++ b/sys/ufs/ufs/ufs_dirhash.c
@@ -98,7 +98,7 @@
doff_t offset);
static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
static int ufsdirhash_recycle(int wanted);
-static void ufsdirhash_lowmem(void);
+static void ufsdirhash_lowmem(void*, int);
static void ufsdirhash_free_locked(struct inode *ip);
static uma_zone_t ufsdirhash_zone;
@@ -1247,7 +1247,7 @@
* Callback that frees some dirhashes when the system is low on virtual memory.
*/
static void
-ufsdirhash_lowmem(void)
+ufsdirhash_lowmem(void *_1 __unused, int _2 __unused)
{
struct dirhash *dh, *dh_temp;
int memfreed, memwanted;

File Metadata

Mime Type
text/plain
Expires
Sat, Apr 4, 8:27 PM (13 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30831699
Default Alt Text
D46193.id151669.diff (44 KB)

Event Timeline