Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142276492
D46193.id151673.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
20 KB
Referenced Files
None
Subscribers
None
D46193.id151673.diff
View Options
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,26 @@
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) {
+ 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,
- ".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;
+ ".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,76 @@
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+
+#include <machine/cfi.h>
+#include <machine/cpu.h>
+#include <machine/frame.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
@@ -49,8 +49,10 @@
#include "opt_kdb.h"
#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 +442,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/include/cfi.h b/sys/amd64/include/cfi.h
new file mode 100644
--- /dev/null
+++ b/sys/amd64/include/cfi.h
@@ -0,0 +1,12 @@
+#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/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/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -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
@@ -30,6 +30,7 @@
#include "opt_gdb.h"
#include <sys/param.h>
+#include <sys/cfi.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
@@ -47,7 +48,6 @@
#include <sys/linker.h>
#include <sys/sysctl.h>
#include <sys/tslog.h>
-
#include <machine/elf.h>
#include <net/vnet.h>
@@ -56,6 +56,7 @@
#include <vm/vm.h>
#include <vm/vm_param.h>
+
#ifdef SPARSE_MAPPING
#include <vm/vm_object.h>
#include <vm/vm_kern.h>
@@ -358,7 +359,7 @@
}
static void
-link_elf_invoke_cbs(caddr_t addr, size_t size)
+link_elf_invoke_cbs(caddr_t addr, size_t size) __NOCFI
{
void (**ctor)(void);
size_t i, cnt;
@@ -448,8 +449,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 +502,25 @@
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,
- MODINFO_METADATA | MODINFOMD_CTORS_ADDR);
- ctors_sizep = (Elf_Size *)preload_search_info(modptr,
- MODINFO_METADATA | MODINFOMD_CTORS_SIZE);
- if (ctors_addrp != NULL && ctors_sizep != NULL) {
- linker_kernel_file->ctors_addr = ef->address +
- *ctors_addrp;
- linker_kernel_file->ctors_size = *ctors_sizep;
+ addrp = (Elf_Addr *)preload_search_info(modptr,
+ MODINFO_METADATA | MODINFOMD_CTORS_ADDR);
+ sizep = (Elf_Size *)preload_search_info(modptr,
+ MODINFO_METADATA | MODINFOMD_CTORS_SIZE);
+ if (addrp != NULL && sizep != NULL) {
+ linker_kernel_file->ctors_addr = ef->address + *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 +887,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 +966,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 +1326,22 @@
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 +1682,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 +1715,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 +2045,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
@@ -31,6 +31,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/cfi.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/lock.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];
@@ -643,7 +650,7 @@
}
static void
-link_elf_invoke_cbs(caddr_t addr, size_t size)
+link_elf_invoke_cbs(caddr_t addr, size_t size) __NOCFI
{
void (**ctor)(void);
size_t i, cnt;
@@ -1055,6 +1062,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 +1089,13 @@
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 +1156,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 +1531,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;
@@ -1689,7 +1705,8 @@
* the case that the symbol can be found through the hash table.
*/
static int
-elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps, Elf_Addr *res)
+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,116 @@
+#include <sys/cdefs.h>
+
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <sys/cfi.h>
+#include <sys/kassert.h>
+#include <sys/linker.h>
+#include <sys/priv.h>
+#include <sys/sysctl.h>
+#endif
+
+#ifdef _KERNEL
+#include <machine/cfi.h>
+#include <machine/cpu.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_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/sys/cfi.h b/sys/sys/cfi.h
new file mode 100644
--- /dev/null
+++ b/sys/sys/cfi.h
@@ -0,0 +1,21 @@
+/*
+ */
+#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,6 +256,10 @@
#define MODINFOMD_KEYBUF 0x000d /* Crypto key intake buffer */
#define MODINFOMD_FONT 0x000e /* Console font */
#define MODINFOMD_SPLASH 0x000f /* Console splash screen */
+/* 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 */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Jan 19, 2:13 AM (4 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27727328
Default Alt Text
D46193.id151673.diff (20 KB)
Attached To
Mode
D46193: sys: implement Kernel CFI from clang
Attached
Detach File
Event Timeline
Log In to Comment