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 + +#include +#include + +#include +#include +#include + +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 #include #include +#include #include #include #include @@ -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 + + +#include +#include + + +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 +#include 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 #include +#include 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 #include #include +#include #include #include @@ -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 #include #include +#include #include #include #include @@ -61,6 +62,7 @@ #include #include #include + #ifdef DDB #include #include @@ -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 #include "opt_ddb.h" -#include "opt_kld.h" #include "opt_hwpmc_hooks.h" +#include "opt_kld.h" +#include #include #include #include @@ -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 #include #include +#include #include @@ -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 #include #include +#include #include @@ -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 = "<>"; #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 + + +#ifdef _KERNEL +#include +#include +#include +#include +#include +#include +#endif + +#ifdef _KERNEL +#include +#include +#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 #include #include +#include #ifdef EPOCH_TRACE #include #include @@ -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 #include "opt_ddb.h" +#include #include #include #include @@ -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 #include #include +#include /* * 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 #include #include +#include #ifdef KTRACE #include #include @@ -50,7 +51,7 @@ #include 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 -#ifdef _KERNEL +#ifdef _KERNEL +#include #include #include #include @@ -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 #include #include +#include #include @@ -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 +#include + +#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 \n" \ "#include \n" \ "#include \n" \ + "#include \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;