Index: arch/amd64/amd64/copy.S =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/amd64/copy.S,v retrieving revision 1.18 diff -u -p -r1.18 copy.S --- arch/amd64/amd64/copy.S 7 Jul 2010 01:13:29 -0000 1.18 +++ arch/amd64/amd64/copy.S 22 Oct 2015 08:26:09 -0000 @@ -42,6 +42,7 @@ #include #include +#include #define GET_CURPCB(reg) \ movq CPUVAR(CURLWP), reg; \ @@ -134,6 +135,7 @@ ENTRY(kcopy) cmpq %rcx,%rax # overlapping? jb 1f # nope, copy forward + SMAP_STAC(kcopy) shrq $3,%rcx # copy by 64-bit words rep movsq @@ -142,6 +144,7 @@ ENTRY(kcopy) andl $7,%ecx # any bytes left? rep movsb + SMAP_CLAC(kcopy) xorq %rax,%rax ret @@ -155,6 +158,7 @@ ENTRY(kcopy) addq %rcx,%rsi std andq $7,%rcx # any fractional bytes? + SMAP_STAC(kcopy_backwards) decq %rdi decq %rsi rep @@ -165,6 +169,7 @@ ENTRY(kcopy) subq $7,%rdi rep movsq + SMAP_CLAC(kcopy_backwards) cld .Lkcopy_end: xorq %rax,%rax @@ -181,6 +186,7 @@ ENTRY(copyout) movq $VM_MAXUSER_ADDRESS,%r8 cmpq %r8,%rdx ja _C_LABEL(copy_efault) # jump if end in kernel space + SMAP_STAC(copyout) .Lcopyout_start: movq %rax,%rcx # length @@ -192,6 +198,7 @@ ENTRY(copyout) rep movsb # copy remaining bytes .Lcopyout_end: + SMAP_CLAC(copyout) xorl %eax,%eax ret DEFERRED_SWITCH_CALL @@ -207,6 +214,7 @@ ENTRY(copyin) movq $VM_MAXUSER_ADDRESS,%r8 cmpq %r8,%rdx ja _C_LABEL(copy_efault) # j if end in kernel space + SMAP_STAC(copyin) .Lcopyin_start: 3: /* bcopy(%rsi, %rdi, %rax); */ @@ -219,6 +227,7 @@ ENTRY(copyin) rep movsb .Lcopyin_end: + SMAP_CLAC(copyin) xorl %eax,%eax ret DEFERRED_SWITCH_CALL @@ -249,6 +258,7 @@ ENTRY(copyoutstr) */ movq $VM_MAXUSER_ADDRESS,%rax subq %rdi,%rax + SMAP_STAC(copyoutstr) jc _C_LABEL(copystr_efault) cmpq %rdx,%rax jae 1f @@ -264,12 +274,14 @@ ENTRY(copyoutstr) testb %al,%al jnz 1b .Lcopyoutstr_end: + SMAP_CLAC(copyoutstr) /* Success -- 0 byte reached. */ decq %rdx xorq %rax,%rax jmp copystr_return 2: /* rdx is zero -- return EFAULT or ENAMETOOLONG. */ + SMAP_CLAC(copyoutstr_error) movq $VM_MAXUSER_ADDRESS,%r11 cmpq %r11,%rdi jae _C_LABEL(copystr_efault) @@ -282,6 +294,7 @@ ENTRY(copyinstr) xchgq %rdi,%rsi movq %rdx,%r8 movq %rcx,%r9 + SMAP_STAC(copyinstr) /* * Get min(%rdx, VM_MAXUSER_ADDRESS-%rsi). @@ -305,11 +318,13 @@ ENTRY(copyinstr) .Lcopyinstr_end: /* Success -- 0 byte reached. */ + SMAP_CLAC(copyinstr) decq %rdx xorq %rax,%rax jmp copystr_return 2: /* edx is zero -- return EFAULT or ENAMETOOLONG. */ + SMAP_CLAC(copyinstr_error) movq $VM_MAXUSER_ADDRESS,%r11 cmpq %r11,%rsi jae _C_LABEL(copystr_efault) @@ -367,7 +382,9 @@ ENTRY(fuword) GET_CURPCB(%rcx) leaq _C_LABEL(fusufailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) + SMAP_STAC(fuword) movl (%rdi),%eax + SMAP_CLAC(fuword) movq $0,PCB_ONFAULT(%rcx) ret DEFERRED_SWITCH_CALL @@ -380,7 +397,9 @@ ENTRY(fusword) GET_CURPCB(%rcx) leaq _C_LABEL(fusufailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) + SMAP_STAC(fusword) movzwl (%rdi),%eax + SMAP_CLAC(fusword) movq $0,PCB_ONFAULT(%rcx) ret DEFERRED_SWITCH_CALL @@ -394,7 +413,9 @@ ENTRY(fuswintr) GET_CURPCB(%rcx) leaq _C_LABEL(fusuintrfailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) + SMAP_STAC(fuswintr) movzwl (%rdi),%eax + SMAP_CLAC(fuswintr) movq $0,PCB_ONFAULT(%rcx) ret @@ -406,7 +427,9 @@ ENTRY(fubyte) GET_CURPCB(%rcx) leaq _C_LABEL(fusufailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) + SMAP_STAC(fubyte) movzbl (%rdi),%eax + SMAP_CLAC(fubyte) movq $0,PCB_ONFAULT(%rcx) ret DEFERRED_SWITCH_CALL @@ -420,8 +443,9 @@ ENTRY(suword) GET_CURPCB(%rcx) leaq _C_LABEL(fusufailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) - + SMAP_STAC(suword) movq %rsi,(%rdi) + SMAP_CLAC(suword) xorq %rax,%rax movq %rax,PCB_ONFAULT(%rcx) ret @@ -436,8 +460,9 @@ ENTRY(susword) GET_CURPCB(%rcx) leaq _C_LABEL(fusufailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) - + SMAP_STAC(susword) movw %si,(%rdi) + SMAP_CLAC(susword) xorq %rax,%rax movq %rax,PCB_ONFAULT(%rcx) ret @@ -452,7 +477,9 @@ ENTRY(suswintr) GET_CURPCB(%rcx) leaq _C_LABEL(fusuintrfailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) + SMAP_STAC(suswintr) movw %si,(%rdi) + SMAP_CLAC(suswintr) xorq %rax,%rax movq %rax,PCB_ONFAULT(%rcx) ret @@ -466,8 +493,9 @@ ENTRY(subyte) GET_CURPCB(%rcx) leaq _C_LABEL(fusufailure)(%rip),%r11 movq %r11,PCB_ONFAULT(%rcx) - + SMAP_STAC(subyte) movb %sil,(%rdi) + SMAP_CLAC(subyte) xorq %rax,%rax movq %rax,PCB_ONFAULT(%rcx) ret @@ -503,6 +531,7 @@ ENTRY(ucas_64) cmpq %r8, %rdi ja _C_LABEL(ucas_fault) movq %rsi, %rax + SMAP_STAC(ucas_64) .Lucas64_start: /* Perform the CAS */ lock @@ -513,6 +542,7 @@ ENTRY(ucas_64) * Set the return values. */ movq %rax, (%rcx) + SMAP_CLAC(ucas_64) xorq %rax, %rax ret DEFERRED_SWITCH_CALL @@ -527,6 +557,7 @@ ENTRY(ucas_32) cmpq %r8, %rdi ja _C_LABEL(ucas_fault) movl %esi, %eax + SMAP_STAC(ucas_32) .Lucas32_start: /* Perform the CAS */ lock @@ -537,6 +568,7 @@ ENTRY(ucas_32) * Set the return values. */ movl %eax, (%rcx) + SMAP_CLAC(ucas_32) xorq %rax, %rax ret DEFERRED_SWITCH_CALL Index: arch/amd64/amd64/db_disasm.c =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/amd64/db_disasm.c,v retrieving revision 1.22 diff -u -p -r1.22 db_disasm.c --- arch/amd64/amd64/db_disasm.c 12 May 2015 23:16:47 -0000 1.22 +++ arch/amd64/amd64/db_disasm.c 22 Oct 2015 08:26:09 -0000 @@ -1317,6 +1317,12 @@ db_disasm(db_addr_t loc, bool altfmt) if (ip->i_extra == (const char *)db_Grp7 && regmodrm == 0xf8) { i_name = "swapgs"; i_mode = 0; + } else if (ip->i_extra == (const char *)db_Grp7 && regmodrm == 0xcb) { + i_name = "stac"; + i_mode = 0; + } else if (ip->i_extra == (const char *)db_Grp7 && regmodrm == 0xca) { + i_name = "clac"; + i_mode = 0; } else { i_name = ((const char * const *)ip->i_extra) [f_reg(rex, regmodrm)]; Index: arch/amd64/amd64/trap.c =================================================================== RCS file: /cvsroot/src/sys/arch/amd64/amd64/trap.c,v retrieving revision 1.80 diff -u -p -r1.80 trap.c --- arch/amd64/amd64/trap.c 27 Feb 2015 15:35:10 -0000 1.80 +++ arch/amd64/amd64/trap.c 22 Oct 2015 08:26:09 -0000 @@ -505,6 +505,31 @@ kernelfault: } cr2 = rcr2(); + + /* PGEX_X will be thrown iff SMEP is enabled and invalid instruction + * fetch from user space was detected */ + if (cr2 <= VM_MAXUSER_ADDRESS && frame->tf_err & PGEX_X) { + /* SMEP protection fired up, user page was tried to be + * executed in the kernel mode */ + panic("user space address %p executed in the supervisor mode", + (void *)cr2); + } + + onfault = onfault_handler(pcb, frame); + + /* PGEX_P will be set if SMAP is enabled and invalid access to user + * space was deteceted. We check here if page-fault occured within + * allowed function. */ + if (cr2 <= VM_MAXUSER_ADDRESS && frame->tf_err & PGEX_P && + onfault_handler(pcb, frame) == NULL) { + if (frame->tf_err & PGEX_W) + panic("user space address %p invalid write in the " + "supervisor mode", (void *)cr2); + else + panic("user space address %p invlid read in the " + "supervisor mode", (void *)cr2); + } + goto faultcommon; case T_PAGEFLT|T_USER: { /* page fault */ Index: arch/i386/i386/copy.S =================================================================== RCS file: /cvsroot/src/sys/arch/i386/i386/copy.S,v retrieving revision 1.23 diff -u -p -r1.23 copy.S --- arch/i386/i386/copy.S 10 Jan 2014 16:47:07 -0000 1.23 +++ arch/i386/i386/copy.S 22 Oct 2015 08:26:19 -0000 @@ -73,6 +73,7 @@ __KERNEL_RCSID(0, "$NetBSD: copy.S,v 1.2 #include #include +#include #define GET_CURPCB(reg) \ movl CPUVAR(CURLWP), reg; \ @@ -168,6 +169,7 @@ ENTRY(kcopy) subl %esi,%eax cmpl %ecx,%eax # overlapping? movl %ecx,%edx + SMAP_STAC(kcopy) jb 1f # nope, copy forward shrl $2,%ecx # copy by 32-bit words @@ -179,6 +181,7 @@ ENTRY(kcopy) rep movsb 0: + SMAP_CLAC(kcopy) popl %edi popl %esi xorl %eax,%eax @@ -187,6 +190,7 @@ ENTRY(kcopy) ALIGN_TEXT 1: addl %ecx,%edi # copy backward addl %ecx,%esi + SMAP_STAC(kcopy_backward) std andl $3,%ecx # any fractional bytes? decl %edi @@ -202,6 +206,7 @@ ENTRY(kcopy) cld .Lkcopy_end: + SMAP_CLAC(kcopy_backward) popl %edi popl %esi xorl %eax,%eax @@ -240,6 +245,7 @@ ENTRY(copyout) ja _C_LABEL(copy_efault) movl %eax,%ecx shrl $2,%ecx + SMAP_STAC(copyout) rep movsl andl $3,%eax @@ -249,6 +255,7 @@ ENTRY(copyout) movsb 1: .Lcopyout_end: + SMAP_CLAC(copyout) popl %edi popl %esi xorl %eax,%eax @@ -282,6 +289,7 @@ ENTRY(copyin) ja _C_LABEL(copy_efault) movl %eax,%ecx shrl $2,%ecx + SMAP_STAC(copyin) rep movsl andl $3,%eax @@ -291,6 +299,7 @@ ENTRY(copyin) movsb 1: .Lcopyin_end: + SMAP_CLAC(copyin) popl %edi popl %esi xorl %eax,%eax @@ -308,12 +317,14 @@ NENTRY(copy_efault) */ /* LINTSTUB: Ignore */ NENTRY(kcopy_fault) + SMAP_CLAC(kcopy_efault) popl %edi popl %esi ret /* LINTSTUB: Ignore */ NENTRY(copy_fault) + SMAP_CLAC(copy_fault) popl %edi popl %esi ret @@ -340,6 +351,7 @@ ENTRY(copyoutstr) movl 12(%esp),%esi # esi = from movl 16(%esp),%edi # edi = to movl 20(%esp),%edx # edx = maxlen + SMAP_STAC(copyoutstr) .Lcopyoutstr_start: 5: /* @@ -391,6 +403,7 @@ ENTRY(copyinstr) movl 12(%esp),%esi # %esi = from movl 16(%esp),%edi # %edi = to movl 20(%esp),%edx # %edx = maxlen + SMAP_STAC(copyinstr) /* * Get min(%edx, VM_MAXUSER_ADDRESS-%esi). @@ -434,6 +447,7 @@ NENTRY(copystr_efault) NENTRY(copystr_fault) copystr_return: /* Set *lencopied and return %eax. */ + SMAP_CLAC(copystr_fault) movl 20(%esp),%ecx subl %edx,%ecx movl 24(%esp),%edx @@ -461,6 +475,7 @@ ENTRY(copystr) movl 16(%esp),%edi # edi = to movl 20(%esp),%edx # edx = maxlen incl %edx + SMAP_STAC(copystr) 1: decl %edx jz 4f @@ -485,7 +500,8 @@ ENTRY(copystr) jz 7f movl %ecx,(%edx) -7: popl %edi +7: SMAP_CLAC(copystr) + popl %edi popl %esi ret @@ -502,7 +518,9 @@ ENTRY(fuword) ja _C_LABEL(fusuaddrfault) GET_CURPCB(%ecx) movl $_C_LABEL(fusufault),PCB_ONFAULT(%ecx) + SMAP_STAC(fuword) movl (%edx),%eax + SMAP_CLAC(fuword) movl $0,PCB_ONFAULT(%ecx) ret DEFERRED_SWITCH_CALL @@ -520,7 +538,9 @@ ENTRY(fusword) ja _C_LABEL(fusuaddrfault) GET_CURPCB(%ecx) movl $_C_LABEL(fusufault),PCB_ONFAULT(%ecx) + SMAP_STAC(fusword) movzwl (%edx),%eax + SMAP_CLAC(fusword) movl $0,PCB_ONFAULT(%ecx) ret DEFERRED_SWITCH_CALL @@ -541,7 +561,9 @@ ENTRY(fuswintr) movl CPUVAR(CURLWP),%ecx movl L_PCB(%ecx),%ecx movl $_C_LABEL(fusubail),PCB_ONFAULT(%ecx) + SMAP_STAC(fuswintr) movzwl (%edx),%eax + SMAP_CLAC(fuswintr) movl $0,PCB_ONFAULT(%ecx) ret @@ -558,7 +580,9 @@ ENTRY(fubyte) ja _C_LABEL(fusuaddrfault) GET_CURPCB(%ecx) movl $_C_LABEL(fusufault),PCB_ONFAULT(%ecx) + SMAP_STAC(fubyte) movzbl (%edx),%eax + SMAP_CLAC(fubyte) movl $0,PCB_ONFAULT(%ecx) ret DEFERRED_SWITCH_CALL @@ -568,6 +592,7 @@ ENTRY(fubyte) */ /* LINTSTUB: Ignore */ NENTRY(fusufault) + SMAP_CLAC(fusufault) movl $0,PCB_ONFAULT(%ecx) movl $-1,%eax ret @@ -579,6 +604,7 @@ NENTRY(fusufault) */ /* LINTSTUB: Ignore */ NENTRY(fusubail) + SMAP_CLAC(fusubail) movl $0,PCB_ONFAULT(%ecx) movl $-1,%eax ret @@ -588,6 +614,7 @@ NENTRY(fusubail) */ /* LINTSTUB: Ignore */ NENTRY(fusuaddrfault) + SMAP_CLAC(fusuaddrfault) movl $-1,%eax ret @@ -605,7 +632,9 @@ ENTRY(suword) GET_CURPCB(%ecx) movl $_C_LABEL(fusufault),PCB_ONFAULT(%ecx) movl 8(%esp),%eax + SMAP_STAC(suword) movl %eax,(%edx) + SMAP_CLAC(suword) xorl %eax,%eax movl %eax,PCB_ONFAULT(%ecx) ret @@ -625,7 +654,9 @@ ENTRY(susword) GET_CURPCB(%ecx) movl $_C_LABEL(fusufault),PCB_ONFAULT(%ecx) movl 8(%esp),%eax + SMAP_STAC(susword) movw %ax,(%edx) + SMAP_CLAC(susword) xorl %eax,%eax movl %eax,PCB_ONFAULT(%ecx) ret @@ -648,7 +679,9 @@ ENTRY(suswintr) movl L_PCB(%ecx),%ecx movl $_C_LABEL(fusubail),PCB_ONFAULT(%ecx) movl 8(%esp),%eax + SMAP_STAC(suswintr) movw %ax,(%edx) + SMAP_CLAC(suswintr) xorl %eax,%eax movl %eax,PCB_ONFAULT(%ecx) ret @@ -667,7 +700,9 @@ ENTRY(subyte) GET_CURPCB(%ecx) movl $_C_LABEL(fusufault),PCB_ONFAULT(%ecx) movb 8(%esp),%al + SMAP_STAC(subyte) movb %al,(%edx) + SMAP_CLAC(subyte) xorl %eax,%eax movl %eax,PCB_ONFAULT(%ecx) ret @@ -689,6 +724,7 @@ ENTRY(ucas_32) /* Label for fault handler */ .Lucas32_start: /* Perform the CAS */ + SMAP_STAC(ucas_32) lock cmpxchgl %ecx, (%edx) .Lucas32_end: @@ -696,6 +732,7 @@ ENTRY(ucas_32) * Note: %eax is "old" value. * Set the return values. */ + SMAP_CLAC(ucas_32) movl 16(%esp), %edx movl %eax, (%edx) xorl %eax, %eax @@ -703,6 +740,7 @@ ENTRY(ucas_32) DEFERRED_SWITCH_CALL NENTRY(ucas_efault) + SMAP_CLAC(ucas_efault) mov $EFAULT, %eax NENTRY(ucas_fault) ret @@ -737,6 +775,7 @@ ENTRY(x86_copyargs) ja _C_LABEL(x86_copyargs_efault) /* There are a maximum of 8 args + 2 for syscall indirect */ cmp $16,%ecx + SMAP_STAC(x86_copyargs) movl (%esi),%eax movl 4(%esi),%ecx movl %eax,(%edx) @@ -747,6 +786,7 @@ ENTRY(x86_copyargs) movl %ecx,12(%edx) ja 2f /* Optimise since most sycalls have <= 4 args */ 1: + SMAP_CLAC(x86_copyargs) popl %esi xorl %eax,%eax ret @@ -772,6 +812,7 @@ NENTRY(x86_copyargs_efault) /* LINTSTUB: Ignore */ NENTRY(x86_copyargs_fault) + SMAP_CLAC(x86_copyargs_fault) popl %esi ret DEFERRED_SWITCH_CALL Index: arch/x86/include/cpu.h =================================================================== RCS file: /cvsroot/src/sys/arch/x86/include/cpu.h,v retrieving revision 1.66 diff -u -p -r1.66 cpu.h --- arch/x86/include/cpu.h 23 Feb 2014 22:38:40 -0000 1.66 +++ arch/x86/include/cpu.h 22 Oct 2015 08:26:21 -0000 @@ -157,12 +157,13 @@ struct cpu_info { uint32_t ci_max_ext_cpuid; /* cpuid.80000000:%eax */ volatile uint32_t ci_lapic_counter; - uint32_t ci_feat_val[5]; /* X86 CPUID feature bits */ + uint32_t ci_feat_val[6]; /* X86 CPUID feature bits */ /* [0] basic features cpuid.1:%edx * [1] basic features cpuid.1:%ecx (CPUID2_xxx bits) * [2] extended features cpuid:80000001:%edx * [3] extended features cpuid:80000001:%ecx * [4] VIA padlock features + * [5] Intel Structured Extended Features */ const struct cpu_functions *ci_func; /* start/stop functions */ Index: arch/x86/include/cpuvar.h =================================================================== RCS file: /cvsroot/src/sys/arch/x86/include/cpuvar.h,v retrieving revision 1.46 diff -u -p -r1.46 cpuvar.h --- arch/x86/include/cpuvar.h 20 Apr 2012 22:23:24 -0000 1.46 +++ arch/x86/include/cpuvar.h 22 Oct 2015 08:26:21 -0000 @@ -125,7 +125,7 @@ void pat_init(struct cpu_info *); extern int cpu_vendor; extern bool x86_mp_online; -extern uint32_t cpu_feature[5]; +extern uint32_t cpu_feature[6]; #endif /* _KERNEL */ Index: arch/x86/include/smap.h =================================================================== RCS file: arch/x86/include/smap.h diff -N arch/x86/include/smap.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ arch/x86/include/smap.h 22 Oct 2015 08:26:21 -0000 @@ -0,0 +1,76 @@ +/* $Id$ */ + +/* + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Mateusz Kocielski. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _X86_SMAP_H_ +#define _X86_SMAP_H_ + +/* + * Following definitions create space for SMAP related instructions + * STAC/CLAC which sets/clears AC flag bit in EFLAGS register. If + * AC is not set and SMAP is turned on, then accessing user space + * memory from supervisor mode will cause page fault. + * + * In order to allow user space access we have to explicit operate + * AC flag in copyin/out etc. We put appropriate NOP instructions + * in functions that will be replaced by patching mechanism if SMAP + * is present. + * + * STAC/CLAC are 3-bytes long, so we have to use 3-bytes of NOPs + * here + */ + +#ifdef i386 +/* + * XXX: Couldn't find better 3-bytes no-op than three nops... + */ + +#define SMAP_INSTR_NOP nop; nop; nop /* 0x90 0x90 0x90 */ +#endif + +#ifdef amd64 +/* + * Intel's documentation recommended 3-bytes long no-op + * instruction is "NOP DWORD ptr [EAX] = 0x0F 0x1F 0x00" + */ + +#define SMAP_INSTR_NOP nopl (%eax) /* 0x0F 0x1F 0x00 */ +#endif + +#define SMAP_STAC(label) \ + .global _C_LABEL(_smap_##label##_stac) ; \ + _C_LABEL(_smap_##label##_stac): ; \ + SMAP_INSTR_NOP +#define SMAP_CLAC(label) \ + .global _C_LABEL(_smap_##label##_clac) ; \ + _C_LABEL(_smap_##label##_clac): ; \ + SMAP_INSTR_NOP + +#endif Index: arch/x86/x86/cpu.c =================================================================== RCS file: /cvsroot/src/sys/arch/x86/x86/cpu.c,v retrieving revision 1.116 diff -u -p -r1.116 cpu.c --- arch/x86/x86/cpu.c 17 Sep 2015 23:48:01 -0000 1.116 +++ arch/x86/x86/cpu.c 22 Oct 2015 08:26:21 -0000 @@ -177,12 +177,13 @@ static void tss_init(struct i386tss *, v static void cpu_init_idle_lwp(struct cpu_info *); -uint32_t cpu_feature[5]; /* X86 CPUID feature bits +uint32_t cpu_feature[6]; /* X86 CPUID feature bits * [0] basic features %edx * [1] basic features %ecx * [2] extended features %edx * [3] extended features %ecx * [4] VIA padlock features + * [5] Intel Structured Extended Feature */ extern char x86_64_doubleflt_stack[]; @@ -556,6 +557,23 @@ cpu_init(struct cpu_info *ci) lcr0(rcr0() | CR0_WP); /* + * If available, enable SMEP (supervisor-mode execution + * protection). This feature allows user pages to be + * protected from execution in supervisor mode. + */ + if (cpu_feature[5] & CPUID_SEF_SMEP) + cr4 |= CR4_SMEP; + + /* + * If available, enable SMAP (supervisor-mode access + * protection). This feature allows user pages to be + * protected from access in supervisor mode. Data can be + * copiedin/out only using dedicated routines. + */ + if (cpu_feature[5] & CPUID_SEF_SMAP) + cr4 |= CR4_SMAP; + + /* * On a P6 or above, enable global TLB caching if the * hardware supports it. */ Index: arch/x86/x86/identcpu.c =================================================================== RCS file: /cvsroot/src/sys/arch/x86/x86/identcpu.c,v retrieving revision 1.48 diff -u -p -r1.48 identcpu.c --- arch/x86/x86/identcpu.c 8 Dec 2014 15:22:47 -0000 1.48 +++ arch/x86/x86/identcpu.c 22 Oct 2015 08:26:21 -0000 @@ -828,6 +828,11 @@ cpu_probe(struct cpu_info *ci) ci->ci_initapicid = (miscbytes >> 24) & 0xff; } + if (cpuid_level >= 7) { + x86_cpuid(7, descs); + ci->ci_feat_val[5] = descs[1]; /* %ebx */ + } + /* * Get the basic information from the extended cpuid leafs. * These were first implemented by amd, but most of the values Index: arch/x86/x86/patch.c =================================================================== RCS file: /cvsroot/src/sys/arch/x86/x86/patch.c,v retrieving revision 1.22 diff -u -p -r1.22 patch.c --- arch/x86/x86/patch.c 15 Nov 2013 08:47:55 -0000 1.22 +++ arch/x86/x86/patch.c 22 Oct 2015 08:26:21 -0000 @@ -80,6 +80,180 @@ extern void *x86_lockpatch[]; extern void *x86_retpatch[]; extern void *atomic_lockpatch[]; +#ifdef amd64 +extern void *_smap_copyin_stac; +extern void *_smap_copyinstr_stac; +extern void *_smap_copyout_stac; +extern void *_smap_copyoutstr_stac; +extern void *_smap_fubyte_stac; +extern void *_smap_fuswintr_stac; +extern void *_smap_fusword_stac; +extern void *_smap_fuword_stac; +extern void *_smap_kcopy_backwards_stac; +extern void *_smap_kcopy_stac; +extern void *_smap_subyte_stac; +extern void *_smap_suswintr_stac; +extern void *_smap_susword_stac; +extern void *_smap_suword_stac; +extern void *_smap_ucas_32_stac; +extern void *_smap_ucas_64_stac; +#endif +#ifdef i386 +extern void *_smap_copyin_stac; +extern void *_smap_copyinstr_stac; +extern void *_smap_copyout_stac; +extern void *_smap_copyoutstr_stac; +extern void *_smap_copystr_stac; +extern void *_smap_fubyte_stac; +extern void *_smap_fuswintr_stac; +extern void *_smap_fusword_stac; +extern void *_smap_fuword_stac; +extern void *_smap_kcopy_backward_stac; +extern void *_smap_kcopy_stac; +extern void *_smap_subyte_stac; +extern void *_smap_suswintr_stac; +extern void *_smap_susword_stac; +extern void *_smap_suword_stac; +extern void *_smap_ucas_32_stac; +extern void *_smap_x86_copyargs_stac; +#endif + +void *smap_stac_patch[] = { +#ifdef amd64 + &_smap_copyin_stac, + &_smap_copyinstr_stac, + &_smap_copyout_stac, + &_smap_copyoutstr_stac, + &_smap_fubyte_stac, + &_smap_fuswintr_stac, + &_smap_fusword_stac, + &_smap_fuword_stac, + &_smap_kcopy_backwards_stac, + &_smap_kcopy_stac, + &_smap_subyte_stac, + &_smap_suswintr_stac, + &_smap_susword_stac, + &_smap_suword_stac, + &_smap_ucas_32_stac, + &_smap_ucas_64_stac, +#endif +#ifdef i386 + &_smap_copyin_stac, + &_smap_copyinstr_stac, + &_smap_copyout_stac, + &_smap_copyoutstr_stac, + &_smap_copystr_stac, + &_smap_fubyte_stac, + &_smap_fuswintr_stac, + &_smap_fusword_stac, + &_smap_fuword_stac, + &_smap_kcopy_backward_stac, + &_smap_kcopy_stac, + &_smap_subyte_stac, + &_smap_suswintr_stac, + &_smap_susword_stac, + &_smap_suword_stac, + &_smap_ucas_32_stac, + &_smap_x86_copyargs_stac, +#endif + NULL +}; + +#ifdef amd64 +extern void *_smap_copyin_clac; +extern void *_smap_copyinstr_clac; +extern void *_smap_copyinstr_error_clac; +extern void *_smap_copyout_clac; +extern void *_smap_copyoutstr_clac; +extern void *_smap_copyoutstr_error_clac; +extern void *_smap_fubyte_clac; +extern void *_smap_fuswintr_clac; +extern void *_smap_fusword_clac; +extern void *_smap_fuword_clac; +extern void *_smap_kcopy_backwards_clac; +extern void *_smap_kcopy_clac; +extern void *_smap_subyte_clac; +extern void *_smap_suswintr_clac; +extern void *_smap_susword_clac; +extern void *_smap_suword_clac; +extern void *_smap_ucas_32_clac; +extern void *_smap_ucas_64_clac; +#endif +#ifdef i386 +extern void *_smap_copy_fault_clac; +extern void *_smap_copyin_clac; +extern void *_smap_copyout_clac; +extern void *_smap_copystr_clac; +extern void *_smap_copystr_fault_clac; +extern void *_smap_fubyte_clac; +extern void *_smap_fusuaddrfault_clac; +extern void *_smap_fusubail_clac; +extern void *_smap_fusufault_clac; +extern void *_smap_fuswintr_clac; +extern void *_smap_fusword_clac; +extern void *_smap_fuword_clac; +extern void *_smap_kcopy_backward_clac; +extern void *_smap_kcopy_clac; +extern void *_smap_kcopy_efault_clac; +extern void *_smap_subyte_clac; +extern void *_smap_suswintr_clac; +extern void *_smap_susword_clac; +extern void *_smap_suword_clac; +extern void *_smap_ucas_32_clac; +extern void *_smap_ucas_efault_clac; +extern void *_smap_x86_copyargs_clac; +extern void *_smap_x86_copyargs_fault_clac; +#endif + +void *smap_clac_patch[] = { +#ifdef amd64 + &_smap_copyin_clac, + &_smap_copyinstr_clac, + &_smap_copyinstr_error_clac, + &_smap_copyout_clac, + &_smap_copyoutstr_clac, + &_smap_copyoutstr_error_clac, + &_smap_fubyte_clac, + &_smap_fuswintr_clac, + &_smap_fusword_clac, + &_smap_fuword_clac, + &_smap_kcopy_backwards_clac, + &_smap_kcopy_clac, + &_smap_subyte_clac, + &_smap_suswintr_clac, + &_smap_susword_clac, + &_smap_suword_clac, + &_smap_ucas_32_clac, + &_smap_ucas_64_clac, +#endif +#ifdef i386 + &_smap_copy_fault_clac, + &_smap_copyin_clac, + &_smap_copyout_clac, + &_smap_copystr_clac, + &_smap_copystr_fault_clac, + &_smap_fubyte_clac, + &_smap_fusuaddrfault_clac, + &_smap_fusubail_clac, + &_smap_fusufault_clac, + &_smap_fuswintr_clac, + &_smap_fusword_clac, + &_smap_fuword_clac, + &_smap_kcopy_backward_clac, + &_smap_kcopy_clac, + &_smap_kcopy_efault_clac, + &_smap_subyte_clac, + &_smap_suswintr_clac, + &_smap_susword_clac, + &_smap_suword_clac, + &_smap_ucas_32_clac, + &_smap_ucas_efault_clac, + &_smap_x86_copyargs_clac, + &_smap_x86_copyargs_fault_clac, +#endif + NULL +}; + #define X86_NOP 0x90 #define X86_REP 0xf3 #define X86_RET 0xc3 @@ -236,6 +410,23 @@ x86_patch(bool early) } } + /* If SMAP is present then patch all prepared nop holes + * with STAC/CLAC instructions. + * + * CLAC = 0x0f, 0x01, 0xca + * STAC = 0x0f, 0x01, 0xcb + */ + if (!early && cpu_feature[5] & CPUID_SEF_SMAP) { + for (i = 0; smap_clac_patch[i] != NULL; i++) { + /* 3-bytes NOP -> CLAC */ + patchbytes(smap_clac_patch[i], 0x0f, 0x01, 0xca); + } + for (i = 0; smap_stac_patch[i] != NULL; i++) { + /* 3-bytes NOP -> STAC */ + patchbytes(smap_stac_patch[i], 0x0f, 0x01, 0xcb); + } + } + /* Write back and invalidate cache, flush pipelines. */ wbinvd(); x86_flush(); Index: modules/examples/Makefile =================================================================== RCS file: /cvsroot/src/sys/modules/examples/Makefile,v retrieving revision 1.1 diff -u -p -r1.1 Makefile --- modules/examples/Makefile 13 May 2015 07:07:36 -0000 1.1 +++ modules/examples/Makefile 22 Oct 2015 08:26:24 -0000 @@ -7,5 +7,6 @@ SUBDIR+= hello SUBDIR+= ping # Needs an additional helper program SUBDIR+= properties SUBDIR+= readhappy +SUBDIR+= smap .include Index: modules/examples/smap/Makefile =================================================================== RCS file: modules/examples/smap/Makefile diff -N modules/examples/smap/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/examples/smap/Makefile 22 Oct 2015 08:26:24 -0000 @@ -0,0 +1,18 @@ +# $NetBSD: Makefile,v 1.1 2015/05/13 07:07:36 pgoyette Exp $ + +.include "../Makefile.inc" + +#S?= /usr/src/sys + +KMOD= smap +SRCS= smap.c + +.include + +# To make use of this module, you'll need to separately build the +# cmd_ping program, with a Makefile similar to +# +# MKMAN= NO +# PROG= cmd_ping +# .include + Index: modules/examples/smap/cmd_smap.c =================================================================== RCS file: modules/examples/smap/cmd_smap.c diff -N modules/examples/smap/cmd_smap.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/examples/smap/cmd_smap.c 22 Oct 2015 08:26:24 -0000 @@ -0,0 +1,162 @@ +/* $Id$ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Mateusz Kocielski. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__RCSID("$Id$"); + +#include +#include +#include +#include +#include +#include +#include + +#include "smap.h" + +#define SMAP_DEV "/dev/smap" + +static int dummy = 0xdead; + +static void +panic(void) +{ + dummy = 0xbabe; +} + +static int +user_confirm(void) +{ + char buf[10]; + + printf("!!! WARNING !!!\n"); + printf("This test will likely cause kernel panic, are you sure to " + "continue?\n"); + for(;;) { + printf("type yes or no: "); + scanf("%9s", &buf); + if (strcasecmp(buf, "yes") == 0) + return 1; + else if (strcasecmp(buf, "no") == 0) + return 0; + } +} + +static void +usage(int status) +{ + (void)fprintf(stderr, "%s [-h] [-c] [-r] [-u]\n", getprogname()); + exit(status); +} + +static void +smap_error() +{ + (void)fprintf(stderr, "SMAP doesn't work - kernel was supposed to " + "panic\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) +{ + int ch, fd; + int call_test, write_test, read_test, usercopy_test, confirm = 1; + + call_test = write_test = read_test = usercopy_test = 0; + + while((ch = getopt(argc, argv, "hcwruN")) != -1) { + switch(ch) { + case 'c': + call_test = 1; + break; + case 'w': + write_test = 1; + break; + case 'r': + read_test = 1; + break; + case 'u': + usercopy_test = 1; + break; + case 'N': + confirm = 0; + break; + case 'h': + usage(EXIT_SUCCESS); + /*NOTREACHED*/ + default: + usage(EXIT_FAILURE); + /*NOTREACHED*/ + } + } + + if (call_test+write_test+read_test+usercopy_test != 1) + usage(EXIT_FAILURE); + + /* confirm read/write/call test as it's likely to cause panic */ + if (usercopy_test != 1 && confirm) { + if (user_confirm() != 1) + exit(EXIT_FAILURE); + } + + if ((fd = open(SMAP_DEV, O_RDWR)) == -1) + err(EXIT_FAILURE, "Cannot open %s", SMAP_DEV); + + if (call_test != 0) { + printf("calling userland address: %p in the supervisor mode", panic); + fflush(stdout); + ioctl(fd, CMD_SMAP_CALL, panic); + smap_error(); + /*NOTREACHED*/ + } else if (read) { + printf("reading userland address: %p in the supervisor mode", dummy); + ioctl(fd, CMD_SMAP_READ, dummy); + smap_error(); + /*NOTREACHED*/ + } else if (write_test) { + printf("writing to userland address: %p in the supervisor mode", + dummy); + ioctl(fd, CMD_SMAP_WRITE, dummy); + smap_error(); + /*NOTREACHED*/ + } else if (usercopy_test) { + printf("not yet.."); + } else { + /* just in case we missed something... */ + assert(/*CONSTCOND*/0 && "impossible"); + } + + if (close(fd) == -1) + err(EXIT_FAILURE, "Cannot close %s", SMAP_DEV); + + return EXIT_SUCCESS; +} Index: modules/examples/smap/smap.c =================================================================== RCS file: modules/examples/smap/smap.c diff -N modules/examples/smap/smap.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/examples/smap/smap.c 22 Oct 2015 08:26:24 -0000 @@ -0,0 +1,181 @@ +/* $NetBSD: smap.c,v 1.1 2015/05/13 07:07:36 pgoyette Exp $ */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Mateusz Kocielski. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: smap.c,v 1.1 2015/05/13 07:07:36 pgoyette Exp $"); + +#include +#include +#include +#include +#include + +#include + +#include "smap.h" + +/* + * This code bases on example ping module. + * + * This module is dedicated to test SMAP/SMEP extensions. Do not load id, + * unless you know what you're doing. Really, don't. It opens serious security + * holes in the kernel. + * + * How does it work? + * + * 1) first of all upon open(2) it checks if CPU has got SMAP or SMEP + * extensions, if they're missing, then it returns EOPNOTSUPP + * 2) if open was sucessful, then user process can call following functions + * with ANY address: + * + * - execute func + * - read from any address + * - write to any address + * - check if all dedicated functions to copy from/to userland work + * properly + * + * To use this device you need to do: + * mknod /dev/smap c 211 0 + */ + +dev_type_open(smap_open); +dev_type_close(smap_close); +dev_type_ioctl(smap_ioctl); + +static struct cdevsw smap_cdevsw = { + .d_open = smap_open, + .d_close = smap_close, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = smap_ioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER +}; + +int +smap_open(dev_t self __unused, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + + return 0; +} + +int +smap_close(dev_t self __unused, int flag __unused, int mode __unused, + struct lwp *l __unused) +{ + return 0; +} + +/* call provided address */ +static int +smap_ioctl_call(void *addr) +{ + void (*func)(void) = addr; + + /* call function, kernel should panic if SMAP is on */ + (void)func(); + + /* we shouldn't be here, but if we survived, then return an error */ + + return EFAULT; +} + +/* read 4-bytes from provided address */ +static int +smap_ioctl_read(void *addr) +{ + volatile uint32_t *p = addr; + volatile uint32_t __unused(rv); + + /* read access should panic if SMAP is on */ + rv = *p; + + /* we shouldn't be here, but if we survived, then return an error */ + return EFAULT; +} + +/* write provided 4-bytes to addess */ +static int +smap_ioctl_write(void *addr, uint32_t what) +{ + volatile uint32_t *p = addr; + + *p = what; + + /* we shouldn't be here, but if we survived, then return an error */ + return EFAULT; +} + +int +smap_ioctl(dev_t self __unused, u_long cmd, void *data, int flag, + struct lwp *l __unused) +{ + switch(cmd) { + case CMD_SMAP_CALL: + return smap_ioctl_call(*(void **)data); + case CMD_SMAP_READ: + return smap_ioctl_read(*(void **)data); + case CMD_SMAP_WRITE: + return smap_ioctl_write(*(void **)data, flag); + default: + return EINVAL; + } + /*NOTREACHED*/ +} + +MODULE(MODULE_CLASS_MISC, smap, NULL); + +static int +smap_modcmd(modcmd_t cmd, void *arg __unused) +{ + /* The major should be verified and changed if needed to avoid + * conflicts with other devices. */ + int cmajor = 211, bmajor = -1; + + switch (cmd) { + case MODULE_CMD_INIT: + if (devsw_attach("smap", NULL, &bmajor, &smap_cdevsw, &cmajor)) + return ENXIO; + return 0; + case MODULE_CMD_FINI: + /* XXX: add counter */ + return 0; + default: + return ENOTTY; + } +} Index: modules/examples/smap/smap.h =================================================================== RCS file: modules/examples/smap/smap.h diff -N modules/examples/smap/smap.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/examples/smap/smap.h 22 Oct 2015 08:26:24 -0000 @@ -0,0 +1,42 @@ +/* $Id */ + +/*- + * Copyright (c) 2015 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Mateusz Kocielski. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SMAP_H_ +#define _SMAP_H_ + +#include + +#define CMD_SMAP_CALL _IO('s', 0) +#define CMD_SMAP_READ _IO('s', 1) +#define CMD_SMAP_WRITE _IO('s', 2) + +#endif /* _SMAP_H_ */