This is my second official contribution to what I call ELFSEC, it places a 
signature in binaries, in the ELF header to be exact.  This set of patches
are against 6.1 sources not -current.  While I think it's somewhat premature 
to send this in, some people in #openbsd on efnet were very interested in 
seeing this.  The first implementation I shared was this:

http://marc.info/?l=openbsd-misc&m=149336261728884&w=2

Currently this implementation has been limited to amd64, but other 64 bit OS's 
should be able to run this.  There was concern about my use of MD5 HMAC's so I 
took them out.  The ELF header of 32 bit systems is too small to fit SHA256 
checksums, so I'm leaving it out.

A bit more work needs to be done:

1) Right now the binaries have to be compiled with 'LDFLAGS+= -Wl,-zelfsec' in 
/etc/mk.conf but this breaks make build.  I'd love it if someone took me on 
their shoulders for fixing that.  Every ELF binary produced should have an 
ELFSEC ELF
program header.  Please school me!

Two programs exist in userland for this:

1) elfsec - a general purpose utility that can activate elfsec in 
/etc/rc.securelevel, sign an ELF binary (that has an ELFSEC header), and output 
the checksum of an ELF  binary.  It can also work in conjunction with elfsecd 
to sign a user's compiled programs.  It can also write a new key to 
/etc/elfsec/key (only root
visible).

2) elfsecd - is a daemon that listens on the UNIX socket /var/run/elfsecd.  It 
is chrooted in the unprivileged stage and also pledged in all stages.  The 
unprivileged stage checks a redblack tree if a user is authenticated to sign 
their programs, a userlist exists in /etc/elfsec/users, when authenticated it 
passes the
path and the uid of the requester to a root daemon via imsg framework.  The 
root process then signs the binary after lstat'ing it.

Some thoughts:

1) This is good for routers and switches since compiling isn't done on them,
usually.
2) ELFSEC will only check against uid > 0, since there is no point in securing
against the root user when the key is on disk.  Also root could read the key
out of kernel memory, what's 0wned is 0wned.
3) ELFSEC is good for protecting daemons preventing access, and being a bit
noisy in the process.  It is good for users who don't need to compile or import
their malware from external sources to the system.
4) ELFSEC is great for hacking inside the new vmm system.  It keeps a 
developers system clean while concepts are being checked.  This is how I did 
development
in the second round.  Yes patches to ELFSEC existed at OpenBSD 6.0 time.

Anyone want to continue my work?

With high regards (patch follows),
-peter


Index: gnu/usr.bin/binutils-2.17/bfd/elf-bfd.h
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/bfd/elf-bfd.h,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 elf-bfd.h
--- gnu/usr.bin/binutils-2.17/bfd/elf-bfd.h     4 May 2017 19:57:26 -0000       
1.1.1.1
+++ gnu/usr.bin/binutils-2.17/bfd/elf-bfd.h     5 May 2017 09:37:22 -0000
@@ -1340,6 +1340,9 @@ struct elf_obj_tdata
   /* TRUE if output program should be marked to request W^X permission */
   bfd_boolean wxneeded;
 
+  /* TRUE if output program should be marked to run ELFSEC'ed */
+  bfd_boolean elfsec;
+
   /* Symbol version definitions in external objects.  */
   Elf_Internal_Verdef *verdef;
 
Index: gnu/usr.bin/binutils-2.17/bfd/elf.c
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/bfd/elf.c,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 elf.c
--- gnu/usr.bin/binutils-2.17/bfd/elf.c 4 May 2017 19:57:26 -0000       1.1.1.1
+++ gnu/usr.bin/binutils-2.17/bfd/elf.c 5 May 2017 09:37:16 -0000
@@ -1087,6 +1087,7 @@ get_segment_type (unsigned int p_type)
     case PT_GNU_RELRO: pt = "RELRO"; break;
     case PT_OPENBSD_RANDOMIZE: pt = "OPENBSD_RANDOMIZE"; break;
     case PT_OPENBSD_WXNEEDED: pt = "OPENBSD_WXNEEDED"; break;
+    case PT_OPENBSD_ELFSEC: pt = "OPENBSD_ELFSEC"; break;
     case PT_OPENBSD_BOOTDATA: pt = "OPENBSD_BOOTDATA"; break;
     default: pt = NULL; break;
     }
@@ -2617,6 +2618,11 @@ bfd_section_from_phdr (bfd *abfd, Elf_In
       return _bfd_elf_make_section_from_phdr (abfd, hdr, index,
                                              "openbsd_wxneeded");
 
+    case PT_OPENBSD_ELFSEC:
+      return _bfd_elf_make_section_from_phdr (abfd, hdr, index, 
+                                                               
"openbsd_elfsec");
+
+
     default:
       /* Check for any processor-specific program segment types.  */
       bed = get_elf_backend_data (abfd);
@@ -3951,6 +3957,22 @@ map_sections_to_segments (bfd *abfd)
       pm = &m->next;
     }
 
+  if (elf_tdata (abfd)->elfsec)
+    {
+      amt = sizeof (struct elf_segment_map);
+      m = bfd_zalloc (abfd, amt);
+      if (m == NULL)
+       goto error_return;
+      m->next = NULL;
+      m->p_type = PT_OPENBSD_ELFSEC;
+      m->p_flags = 1;
+      m->p_flags_valid = 1;
+
+      *pm = m;
+      pm = &m->next;
+
+    }
+
   /* If there is a .openbsd.randomdata section, throw in a PT_OPENBSD_RANDOMIZE
      segment.  */
   randomdata = bfd_get_section_by_name (abfd, ".openbsd.randomdata");
@@ -4737,6 +4759,13 @@ get_program_header_size (bfd *abfd)
       /* We need a PT_OPENBSD_WXNEEDED segment.  */
       ++segs;
     }
+
+  if (elf_tdata (abfd)->elfsec)
+               {
+                       /* We need a PT_OPENBSD_ELFSEC segment. */
+                       ++segs;
+               }
+
 
   for (s = abfd->sections; s != NULL; s = s->next)
     {
Index: gnu/usr.bin/binutils-2.17/bfd/elflink.c
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/bfd/elflink.c,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 elflink.c
--- gnu/usr.bin/binutils-2.17/bfd/elflink.c     4 May 2017 19:57:26 -0000       
1.1.1.1
+++ gnu/usr.bin/binutils-2.17/bfd/elflink.c     5 May 2017 09:37:11 -0000
@@ -4977,6 +4977,7 @@ bfd_elf_size_dynamic_sections (bfd *outp
 
   elf_tdata (output_bfd)->relro = info->relro;
   elf_tdata (output_bfd)->wxneeded = info->wxneeded;
+  elf_tdata (output_bfd)->elfsec = info->elfsec;
   elf_tdata (output_bfd)->executable = info->executable;
   if (info->execstack)
     elf_tdata (output_bfd)->stack_flags = PF_R | PF_W | PF_X;
Index: gnu/usr.bin/binutils-2.17/binutils/readelf.c
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/binutils/readelf.c,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 readelf.c
--- gnu/usr.bin/binutils-2.17/binutils/readelf.c        4 May 2017 19:57:27 
-0000       1.1.1.1
+++ gnu/usr.bin/binutils-2.17/binutils/readelf.c        5 May 2017 09:37:00 
-0000
@@ -2391,6 +2391,8 @@ get_segment_type (unsigned long p_type)
                        return "OPENBSD_RANDOMIZE";
     case PT_OPENBSD_WXNEEDED:
                        return "OPENBSD_WXNEEDED";
+    case PT_OPENBSD_ELFSEC:
+                       return "OPENBSD_ELFSEC";
     case PT_OPENBSD_BOOTDATA:
                        return "OPENBSD_BOOTDATA";
 
Index: gnu/usr.bin/binutils-2.17/include/bfdlink.h
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/include/bfdlink.h,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 bfdlink.h
--- gnu/usr.bin/binutils-2.17/include/bfdlink.h 4 May 2017 19:57:29 -0000       
1.1.1.1
+++ gnu/usr.bin/binutils-2.17/include/bfdlink.h 5 May 2017 09:36:28 -0000
@@ -267,6 +267,9 @@ struct bfd_link_info
   /* TRUE if output program should be marked to request W^X permission */
   unsigned int wxneeded: 1;
 
+  /* TRUE if output program should be ELFSEC'ed */
+  unsigned int elfsec: 1;
+
   /* TRUE if ok to have version with no definition.  */
   unsigned int allow_undefined_version: 1;
 
Index: gnu/usr.bin/binutils-2.17/include/elf/common.h
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/include/elf/common.h,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 common.h
--- gnu/usr.bin/binutils-2.17/include/elf/common.h      4 May 2017 19:57:29 
-0000       1.1.1.1
+++ gnu/usr.bin/binutils-2.17/include/elf/common.h      5 May 2017 09:36:14 
-0000
@@ -308,6 +308,7 @@
 
 #define PT_OPENBSD_RANDOMIZE   0x65a3dbe6 /* Fill with random data. */
 #define PT_OPENBSD_WXNEEDED    0x65a3dbe7 /* Program does W^X violations */
+#define PT_OPENBSD_ELFSEC      0x65a3dbe8 /* Program does ELFSEC */
 #define PT_OPENBSD_BOOTDATA    0x65a41be6 /* Section for boot arguments */
 
 /* Program segment permissions, in program header p_flags field.  */
Index: gnu/usr.bin/binutils-2.17/ld/ld.texinfo
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/ld/ld.texinfo,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 ld.texinfo
--- gnu/usr.bin/binutils-2.17/ld/ld.texinfo     4 May 2017 19:57:30 -0000       
1.1.1.1
+++ gnu/usr.bin/binutils-2.17/ld/ld.texinfo     5 May 2017 09:35:49 -0000
@@ -1019,6 +1019,10 @@ Marks the executable with a @code{PT_OPE
 indicating it is expected to perform W^X violating operations later
 (such as calling mprotect(2) or mmap(2) with both PROT_WRITE and PROT_EXEC).
 
+@item elfsec
+Marks the executable with a @code{PT_OPENBSD_ELFSEC} program header,
+indicating it is expected to perform ELFSEC'ed operations later.
+
 @end table
 
 Other keywords are ignored for Solaris compatibility.  
Index: gnu/usr.bin/binutils-2.17/ld/ldgram.y
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/ld/ldgram.y,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 ldgram.y
--- gnu/usr.bin/binutils-2.17/ld/ldgram.y       4 May 2017 19:57:30 -0000       
1.1.1.1
+++ gnu/usr.bin/binutils-2.17/ld/ldgram.y       5 May 2017 09:35:41 -0000
@@ -1095,6 +1095,8 @@ phdr_type:
                            $$ = exp_intop (0x65a3dbe6);
                          else if (strcmp (s, "PT_OPENBSD_WXNEEDED") == 0)
                            $$ = exp_intop (0x65a3dbe7);
+                         else if (strcmp (s, "PT_OPENBSD_ELFSEC") == 0)
+                           $$ = exp_intop (0x65a3dbe8);
                          else if (strcmp (s, "PT_OPENBSD_BOOTDATA") == 0)
                            $$ = exp_intop (0x65a41be6);
                          else
Index: gnu/usr.bin/binutils-2.17/ld/emultempl/elf32.em
===================================================================
RCS file: /var/cvsroot/src/src/gnu/usr.bin/binutils-2.17/ld/emultempl/elf32.em,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 elf32.em
--- gnu/usr.bin/binutils-2.17/ld/emultempl/elf32.em     4 May 2017 19:57:30 
-0000       1.1.1.1
+++ gnu/usr.bin/binutils-2.17/ld/emultempl/elf32.em     5 May 2017 09:36:03 
-0000
@@ -2186,6 +2186,8 @@ cat >>e${EMULATION_NAME}.c <<EOF
        link_info.relro = FALSE;
       else if (strcmp (optarg, "wxneeded") == 0)
        link_info.wxneeded = TRUE;
+      else if (strcmp (optarg, "elfsec") == 0)
+       link_info.elfsec = TRUE;
       else if (strcmp (optarg, "notext") == 0)
        link_info.allow_textrel = TRUE;
       else if (strcmp (optarg, "text") == 0)
Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /var/cvsroot/src/src/lib/libc/sys/Makefile.inc,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 Makefile.inc
--- lib/libc/sys/Makefile.inc   4 May 2017 19:58:33 -0000       1.1.1.1
+++ lib/libc/sys/Makefile.inc   5 May 2017 09:35:24 -0000
@@ -45,7 +45,7 @@ ASM=  __semctl.o __syscall.o __thrsigdive
        bind.o chdir.o chflags.o chflagsat.o chmod.o chown.o chroot.o \
        clock_getres.o clock_gettime.o clock_settime.o \
        dup.o dup2.o dup3.o \
-       execve.o \
+       elfsec.o execve.o \
        faccessat.o fchdir.o fchflags.o fchmod.o fchmodat.o fchown.o \
        fchownat.o fhopen.o fhstat.o fhstatfs.o \
        flock.o fpathconf.o fstat.o fstatat.o fstatfs.o \
Index: sbin/Makefile
===================================================================
RCS file: /var/cvsroot/src/src/sbin/Makefile,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 Makefile
--- sbin/Makefile       4 May 2017 19:58:53 -0000       1.1.1.1
+++ sbin/Makefile       4 May 2017 20:11:40 -0000
@@ -1,7 +1,7 @@
 #      $OpenBSD: Makefile,v 1.105 2016/09/17 18:37:01 florian Exp $
 
 SUBDIR=        atactl badsect bioctl clri dhclient \
-       disklabel dmesg dump dumpfs fdisk fsck fsck_ext2fs fsck_ffs  \
+       disklabel dmesg dump dumpfs fdisk elfsec fsck fsck_ext2fs fsck_ffs  \
        fsck_msdos fsdb fsirand growfs ifconfig iked init ipsecctl  \
        isakmpd kbd ldattach mknod mount \
        mount_cd9660 mount_ext2fs mount_ffs mount_msdos \
Index: sbin/elfsec/Makefile
===================================================================
RCS file: sbin/elfsec/Makefile
diff -N sbin/elfsec/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sbin/elfsec/Makefile        4 May 2017 20:11:33 -0000
@@ -0,0 +1,15 @@
+# Makefile
+
+SRCS= elfsec.c elf.c key.c
+PROG= elfsec  
+
+LDFLAGS+= -static -g -Wall 
+LDADD= -lssl -lcrypto
+CFLAGS+= -g -Wall    
+
+NOMAN=1
+
+BINDIR=/sbin
+
+.include <bsd.prog.mk>
+
Index: sbin/elfsec/elf.c
===================================================================
RCS file: sbin/elfsec/elf.c
diff -N sbin/elfsec/elf.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sbin/elfsec/elf.c   4 May 2017 20:11:33 -0000
@@ -0,0 +1,180 @@
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <sys/stat.h>
+#include <sys/exec_elf.h>
+#include <sys/elfsec.h>
+#include <sys/mman.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <errno.h>
+
+#include <elfsec.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+int elfheader_offset(char *);
+int elfheader_sign(char *, char *, int);
+
+
+int
+elfheader_sign(char *file, char *sign, int size)
+{
+       struct stat sb;
+       int ofd, fd, i;
+       char *map;      
+       char signfile[PATH_MAX];
+       Elf64_Ehdr *elfhdr;
+       Elf64_Phdr *phdr, *pphdr;
+       ELFSEChdr *elfsec_hdr;
+
+       fd = open(file, O_RDWR, 0755);
+       if (fd < 0) {
+               perror("open");
+               return -1;
+       }
+
+       if (fstat(fd, &sb) < 0) {
+               perror("fstat");
+               close(fd);
+               return -1;
+       }
+
+       if (sb.st_size <= sizeof(Elf64_Ehdr)) {
+               close(fd);
+               return -1;
+       }
+
+
+       map = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, 
MAP_PRIVATE|MAP_FILE, fd, 0);
+       if (map == MAP_FAILED) {
+               perror("mmap");
+               close(fd);
+               return -1;
+       }
+
+       elfhdr = (Elf64_Ehdr *)map;     
+
+#if DEBUG
+       printf("e_phoff = %ld\n", elfhdr->e_phoff);
+       printf("e_phnum = %ld\n", elfhdr->e_phnum);
+       
+       printf("num * sizeof(Elf64_Phdr) = %d\n", elfhdr->e_phnum * 
sizeof(Elf64_Phdr));
+#endif
+
+       phdr = (Elf64_Phdr *)((void *)(map + elfhdr->e_phoff));
+       if (memcmp(elfhdr->e_ident, ELFMAG, SELFMAG) != 0 || 
+               sb.st_size < sizeof(*elfhdr) + (elfhdr->e_phnum * 
sizeof(*phdr))) {
+               fprintf(stderr, "size violation\n");
+               close(fd);
+               munmap(map, sb.st_size);
+               return -1;
+       }
+
+       for (i = 0; i < elfhdr->e_phnum; i++) {
+               pphdr = &phdr[i];
+               if (pphdr->p_type == PT_OPENBSD_ELFSEC) {
+                       elfsec_hdr = (ELFSEChdr *)pphdr;                        
        
+                       memcpy(elfsec_hdr->hmac, sign, size);
+                       break;
+               }
+       }
+       
+       if (i >= elfhdr->e_phnum) {
+               fprintf(stderr, "no ELFSEC header found, not modifying.\n");
+               close(fd);
+               munmap(map, sb.st_size);
+               return -1;
+       }
+
+       strlcpy(signfile, "/tmp/signfile.XXXXXXXXX", sizeof(signfile));
+       if ((ofd = open(signfile, O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
+               perror("open");
+               close(fd);
+               munmap(map, sb.st_size);
+               return -1;
+       }
+               
+       for (i = 0; i < sb.st_size; i++) {
+               if (write(ofd, (char *)&map[i], 1) < 0) {
+                       perror("write");
+                       close(fd);
+                       munmap(map, sb.st_size);
+                       return -1;
+               }
+       }
+               
+       close(ofd);
+
+       munmap(map, sb.st_size);
+       close(fd);
+
+       if (rename(signfile, file) < 0) {
+               perror("rename");
+               return -1;
+       }
+               
+       if (chown(file, sb.st_uid, sb.st_gid) <  0) {
+               perror("chown");
+               return -1;
+       }
+
+       if (chmod(file, sb.st_mode) < 0) {      
+               perror("chmod");
+               return -1;
+       }
+       
+       return (0);
+}
+
+
+int
+elfheader_offset(char *file)
+{
+       struct stat sb;
+       int fd;
+       int num, offset;
+       char *map;      
+       Elf64_Ehdr *elfhdr;
+
+       fd = open(file, O_RDONLY, 0);
+       if (fd < 0) {
+               perror("open");
+               return -1;
+       }
+
+       if (fstat(fd, &sb) < 0) {
+               perror("fstat");
+               close(fd);
+               return -1;
+       }
+
+       if (sb.st_size < sizeof(*elfhdr)) {
+               close(fd);
+               return -1;
+       }
+
+       map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (map == MAP_FAILED) {
+               perror("mmap");
+               close(fd);
+               return -1;
+       }
+
+
+       elfhdr = (Elf64_Ehdr *)map;     
+
+       num = elfhdr->e_phnum;
+       offset = elfhdr->e_phoff;
+
+       close(fd);
+       munmap(map, sb.st_size);
+       
+       return (num * sizeof(Elf64_Phdr) + offset);
+}
Index: sbin/elfsec/elfsec.c
===================================================================
RCS file: sbin/elfsec/elfsec.c
diff -N sbin/elfsec/elfsec.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sbin/elfsec/elfsec.c        4 May 2017 20:11:33 -0000
@@ -0,0 +1,284 @@
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <sys/socket.h>
+#include <sys/exec_elf.h>
+#include <sys/elfsec.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include <elfsec.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+void usage(void);
+int activate(void);
+int check(char *);
+int sign(char *);
+int usersign(char *);
+int newkey(void);
+
+
+extern int readkey(char *, char *, int);
+extern int writekey(char *, char *, int);
+extern int elfheader_offset(char *);
+extern int elfheader_sign(char *, char *, int);
+
+
+
+struct tabp {
+       char *command;
+       int (*func)(void *);
+} tab[] = {
+       { "activate", (int (*)(void *))activate},
+       { "check", (int (*)(void *))check },
+       { "sign", (int (*)(void *))sign },
+       { "newkey", (int (*)(void *))newkey },
+       { "usersign", (int (*)(void *))usersign },
+       { NULL, NULL }
+};
+       
+struct ess {
+        int len;
+        uid_t uid;
+        char path[PATH_MAX];
+};
+
+
+int
+main(int argc, char *argv[])
+{
+       struct tabp *pt;
+
+       for (pt = &tab[0]; pt->command != NULL; pt++) {
+               if (argv[1]) {
+                       if (strcmp(pt->command, argv[1]) == 0) {
+                               pt->func(argv[2]);
+                               break;
+                       }
+               }
+       }
+
+       if (pt->command == NULL) {
+               usage();
+       }
+
+       exit(0);
+}
+
+int 
+activate(void)
+{
+       char key[32];
+
+       if (readkey("/etc/elfsec/key", (char *)&key, sizeof(key)) < 0) {
+               exit(1);
+       }
+       
+       if (elfsec(key, sizeof(key)) < 0) {
+               exit(1);
+       }
+
+       return 0;
+}
+
+int 
+check(char *path)
+{
+       HMAC_CTX ctx;
+       struct stat sb;
+       char sbuf[512];
+       char key[32];
+       char shabuf[32];
+       int offset = 0;
+       int fd, i, len;
+
+       if ((offset = elfheader_offset(path)) < 0) {
+               exit(1);
+       }
+
+       if (readkey("/etc/elfsec/key", (char *)&key, sizeof(key)) < 0) {
+               exit(1);
+       }
+       
+       fd = open(path, O_RDONLY, 0);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+
+       if (lseek(fd, offset, SEEK_SET)  < 0) {
+               perror("lseek");
+               exit(1);
+       }
+
+       if (fstat(fd, &sb) < 0) {
+               perror("fstat");
+               exit(1);
+       }
+
+
+       HMAC_CTX_init(&ctx);
+ 
+       HMAC_Init(&ctx, key, sizeof(key), EVP_sha256());
+ 
+       for (i = offset; i < sb.st_size; i += 512) {
+               len = read(fd, sbuf, sizeof(sbuf));
+
+               if (len == 0)
+                       break;
+               HMAC_Update(&ctx, sbuf, len);
+       }
+       close(fd);
+
+       i = sizeof(shabuf);
+       HMAC_Final(&ctx, shabuf, &i);
+
+       printf("elfsec check(%s): ", path);
+       for (i = 0; i < sizeof(shabuf); i++) {
+               printf("%02x", shabuf[i] & 0xff);
+       }
+       printf("\n");
+
+       return 0;
+}
+
+
+int 
+sign(char *path)
+{
+       HMAC_CTX ctx;
+       struct stat sb;
+       char sbuf[512];
+       char key[32];
+       char shabuf[32];
+       int offset = 0;
+       int fd, i, len;
+
+       if ((offset = elfheader_offset(path)) < 0) {
+               exit(1);
+       }
+
+       if (readkey("/etc/elfsec/key", (char *)&key, sizeof(key)) < 0) {
+               exit(1);
+       }
+       
+       fd = open(path, O_RDONLY, 0);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+
+       if (lseek(fd, offset, SEEK_SET)  < 0) {
+               perror("lseek");
+               exit(1);
+       }
+
+       if (fstat(fd, &sb) < 0) {
+               perror("fstat");
+               exit(1);
+       }
+
+
+       HMAC_CTX_init(&ctx);
+ 
+       HMAC_Init(&ctx, key, sizeof(key), EVP_sha256());
+ 
+       for (i = offset; i < sb.st_size; i += 512) {
+               len = read(fd, sbuf, sizeof(sbuf));
+
+               if (len == 0)
+                       break;
+               HMAC_Update(&ctx, sbuf, len);
+       }
+       close(fd);
+
+       i = sizeof(shabuf);
+       HMAC_Final(&ctx, shabuf, &i);
+
+       printf("signing %s\t", path);
+
+       if (elfheader_sign(path, shabuf, sizeof(shabuf)) < 0) {
+                       printf("failed!\n");
+                        exit(1);
+       }
+
+       printf("done.\n");
+       
+       return 0;
+}
+
+int 
+newkey(void)
+{
+       char key[32];
+
+       arc4random_buf(&key, sizeof(key));
+       if (writekey("/etc/elfsec/key", key, sizeof(key)) < 0) {
+               exit(1);
+       }
+
+       return 0; 
+
+}
+
+int
+usersign(char *path)
+{
+       char fullpath[PATH_MAX];
+       struct sockaddr_un sun;
+       struct ess elfsec;
+       int so;
+
+       if (realpath(path, (char *)&fullpath) == NULL) {
+               perror("realpath");
+               return -1;
+       }
+
+       so = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (so < 0) {
+               perror("socket");
+               return -1;
+       }
+
+       memset(&sun, 0, sizeof(sun));
+       strlcpy((char *)&sun.sun_path, "/var/run/elfsecd", 
sizeof(sun.sun_path));
+       sun.sun_family = AF_LOCAL;
+
+       if (connect(so, (struct sockaddr *)&sun, sizeof(struct sockaddr_un)) < 
0) {
+               perror("connect");
+               return -1;
+       }
+
+       memset(&elfsec, 0, sizeof(elfsec));     
+       
+       strlcpy(elfsec.path, fullpath, sizeof(elfsec.path) - 1);
+       elfsec.len = strlen(elfsec.path);
+
+       send(so, (char *)&elfsec, sizeof(struct ess), 0);       
+
+       close(so);
+
+       return 0;
+}
+
+void
+usage(void)
+{
+       fprintf(stderr, "elfsec [command] [argument]\n");
+       fprintf(stderr, "       activate\n");
+       fprintf(stderr, "       check path\n");
+       fprintf(stderr, "       sign path\n");
+       fprintf(stderr, "       usersign path\n");
+       fprintf(stderr, "       newkey\n");
+
+       exit(1);
+}
Index: sbin/elfsec/key.c
===================================================================
RCS file: sbin/elfsec/key.c
diff -N sbin/elfsec/key.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sbin/elfsec/key.c   4 May 2017 20:11:33 -0000
@@ -0,0 +1,77 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <netdb.h>
+#include <resolv.h>
+
+int readkey(char *, char *, int);
+int writekey(char *, char *, int);
+
+int
+readkey(char *path, char *key, int len)
+{
+       char buf[512];  
+       FILE *f;
+
+       f = fopen(path, "r");
+       if (f == NULL) {
+               perror("fopen");
+               return -1;
+       }
+
+       if (fgets(buf, sizeof(buf), f) == NULL) {
+               perror("fgets");
+               fclose(f);
+               return -1;
+       }
+
+       fclose(f);
+
+       buf[sizeof(buf) - 1] = '\0';
+
+       if (b64_pton(buf, key, len) < 0) {
+               perror("b64_pton");
+               fclose(f);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int
+writekey(char *path, char *key, int len)
+{
+       int fd;
+       int buflen;
+       char buf[512];
+
+       if ((buflen = b64_ntop(key, len, (char *)&buf, sizeof(buf))) < 0) {
+               perror("b64_ntop");
+               return -1;
+       }
+
+       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+       if (fd < 0) {
+               perror("open");
+               return -1;
+       }
+
+
+       if (write(fd, buf, buflen) != buflen) {
+               perror("write");
+               close(fd);
+               unlink(path);
+               return -1;
+       }
+               
+       close(fd);
+
+       return 0;
+}
Index: sys/conf/files
===================================================================
RCS file: /var/cvsroot/src/src/sys/conf/files,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 files
--- sys/conf/files      4 May 2017 19:58:24 -0000       1.1.1.1
+++ sys/conf/files      5 May 2017 09:35:05 -0000
@@ -645,6 +645,7 @@ file isofs/udf/udf_vnops.c          udf
 file kern/clock_subr.c
 file kern/exec_conf.c
 file kern/exec_elf.c
+file kern/exec_elfsec.c
 file kern/exec_script.c
 file kern/exec_subr.c
 file kern/init_main.c
Index: sys/kern/exec_elf.c
===================================================================
RCS file: /var/cvsroot/src/src/sys/kern/exec_elf.c,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 exec_elf.c
--- sys/kern/exec_elf.c 4 May 2017 19:58:28 -0000       1.1.1.1
+++ sys/kern/exec_elf.c 5 May 2017 09:49:55 -0000
@@ -85,6 +85,7 @@
 #include <sys/signalvar.h>
 #include <sys/stat.h>
 #include <sys/pledge.h>
+#include <sys/elfsec.h>
 
 #include <sys/mman.h>
 
@@ -93,6 +94,12 @@
 #include <machine/reg.h>
 #include <machine/exec.h>
 
+#include <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/hmac.h>
+
+
 int    elf_load_file(struct proc *, char *, struct exec_package *,
            struct elf_args *);
 int    elf_check_header(Elf_Ehdr *);
@@ -511,12 +518,18 @@ int
 exec_elf_makecmds(struct proc *p, struct exec_package *epp)
 {
        Elf_Ehdr *eh = epp->ep_hdr;
-       Elf_Phdr *ph, *pp, *base_ph = NULL;
+       Elf_Phdr *ph, *ph2, *pp, *base_ph = NULL;
        Elf_Addr phdr = 0, exe_base = 0;
+       ELFSEChdr *eshdr;
        int error, i, has_phdr = 0;
        char *interp = NULL;
-       u_long phsize;
+       u_long phsize, phsize2;
        size_t randomizequota = ELF_RANDOMIZE_LIMIT;
+       struct elfsec es;
+       int visited_elfsec = 0;
+       struct nameidata esndp;
+       struct vnode *esvp;
+       struct vattr esvap;
 
        if (epp->ep_hdrvalid < sizeof(Elf_Ehdr))
                return (ENOEXEC);
@@ -703,6 +716,106 @@ exec_elf_makecmds(struct proc *p, struct
                            ph[i].p_memsz, ph[i].p_vaddr + exe_base, NULLVP, 0, 
0);
                        break;
 
+#if defined(__amd64__)
+               case PT_OPENBSD_ELFSEC:
+                       /* is elfsec active? if not break */
+                       if (elfsecactive == 0) {
+                               break;
+                       }
+
+                       /*
+                        * are we superuser?  if yes break.
+                        * since root knows the secret key, there is no point
+                        * in proceeding further with ELFSEC...
+                        */
+       
+                       if (suser(p, 0) == 0)
+                               break;
+
+                       /*
+                        * we are now active and a daemon/user
+                        * now we make sure that someone doesn't create
+                        * several ELFSEC sections to throw us into limbo
+                        * once is enough.
+                        */
+                       
+                       if (visited_elfsec == 1)
+                               break;
+
+                       visited_elfsec = 1;
+
+
+                       NDINIT(&esndp, LOOKUP, FOLLOW, UIO_SYSSPACE, 
epp->ep_ndp->ni_dirp, p);
+                       esndp.ni_pledge = PLEDGE_RPATH;
+                       if ((error = namei(&esndp)) != 0) {
+                               printf("elfsec debug: namei %d\n", error);
+                               goto bad;
+                       }
+                       esvp = esndp.ni_vp;
+
+                       if (esvp->v_type != VREG) {
+                               error = EACCES;
+                               VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+                               goto bad;
+                       }
+
+                       if ((error = VOP_GETATTR(esvp, epp->ep_vap, p->p_ucred, 
p)) != 0) {
+                               printf("elfsec debug: VOP_GETATTR %d\n", error);
+                               VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+                               goto bad;
+                       }
+
+                       if (esvp->v_mount->mnt_flag & MNT_NOEXEC) {
+                               error = EACCES;
+                               VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+                               goto bad;
+                       }
+
+                       if ((error = VOP_ACCESS(esvp, VREAD, p->p_ucred, p)) != 
0) {
+                               printf("elfsec debug: VOP_ACCESS %d\n", error);
+                               VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+                               goto bad;
+                       }
+
+                       if ((error = VOP_GETATTR(esvp, &esvap, p->p_ucred, p)) 
!= 0) {
+                               printf("elfsec debug: VOP_GETATTR %d\n", error);
+                               VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+                               goto bad;
+                       }
+
+                       es.es_filesize = esvap.va_size;
+                       es.es_offset = eh->e_phoff + phsize;
+
+                       HMAC_SHA256_Init(&es.ctx, elfseckey, sizeof(elfseckey));
+
+                       ph2 = mallocarray(1, es.es_filesize - es.es_offset, 
M_TEMP, M_WAITOK);
+                       phsize2 = es.es_filesize - es.es_offset;
+                       
+                       error = elf_read_from(p, esvp, es.es_offset, ph2, 
phsize2);
+                       if (error != 0) {
+                               printf("elfsec debug: elf_read_from %d\n", 
error);
+                               VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+                               free(ph2, M_TEMP, phsize2);
+                               goto bad;
+                       }
+
+                       HMAC_SHA256_Update(&es.ctx, (u_int8_t *)ph2, phsize2);
+
+                       memset(&es.digest, 0, sizeof(es.digest));
+                       HMAC_SHA256_Final(es.digest, &es.ctx);
+                       free(ph2, M_TEMP, phsize2);
+
+                       VOP_CLOSE(esvp, FREAD, p->p_ucred, p);
+
+                       /* now compare the elfsechdr with the checksum */
+                       eshdr = (ELFSEChdr *)pp;
+                       if (memcmp(eshdr->hmac, es.digest, 
SHA256_DIGEST_LENGTH) != 0) {
+                               printf("ELFSEC violation!  Not executing binary 
(%s) for uid %u\n", epp->ep_ndp->ni_dirp, p->p_ucred->cr_uid);
+                               goto bad;
+                       }
+                       break;
+#endif /* __amd64__ */
+
                default:
                        /*
                         * Not fatal, we don't need to understand everything
@@ -710,6 +823,11 @@ exec_elf_makecmds(struct proc *p, struct
                         */
                        break;
                }
+       }
+
+       if (elfsecactive == 1 && visited_elfsec == 0 && suser(p, 0) != 0) {
+               printf("ELFSEC violation!  Not executing binary (%s) for uid 
%u\n", epp->ep_ndp->ni_dirp, p->p_ucred->cr_uid);
+               goto bad;
        }
 
        phdr += exe_base;
Index: sys/kern/exec_elfsec.c
===================================================================
RCS file: sys/kern/exec_elfsec.c
diff -N sys/kern/exec_elfsec.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/kern/exec_elfsec.c      5 May 2017 09:34:47 -0000
@@ -0,0 +1,49 @@
+/* exec_elfsec.c - $Id$ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/proc.h>
+
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+
+#include <sys/exec_elf.h>
+#include <sys/elfsec.h>
+
+
+int elfsecactive = 0;
+char elfseckey[32];
+
+int
+sys_elfsec(struct proc *p, void *v, register_t *retval)
+{
+       struct sys_elfsec_args /* {
+               syscallarg(char *) buf;
+               syscallarg(size_t) nbyte;
+       } */ *uap = v;
+
+       char *key;
+       size_t size;
+       int error;
+
+       if (securelevel > 0)
+               return (EPERM);
+
+       if ((error = suser(p, 0)) != 0)
+               return (error);
+
+        key = SCARG(uap, buf);
+        size = SCARG(uap, nbyte);
+
+       if (size != sizeof(elfseckey)) 
+               return (EINVAL);
+
+       if ((error = copyin(key, &elfseckey, sizeof(elfseckey))) != 0)
+               return (error);
+
+       elfsecactive = 1;
+       printf("elfsec active\n");
+
+       return (0);
+}
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /var/cvsroot/src/src/sys/kern/init_sysent.c,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 init_sysent.c
--- sys/kern/init_sysent.c      4 May 2017 19:58:28 -0000       1.1.1.1
+++ sys/kern/init_sysent.c      5 May 2017 09:34:41 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: init_sysent.c,v 1.186 2016/09/26 16:43:58 jca Exp $   */
+/*     $OpenBSD$       */
 
 /*
  * System call switch table.
@@ -751,5 +751,7 @@ struct sysent sysent[] = {
            sys___set_tcb },                    /* 329 = __set_tcb */
        { 0, 0, SY_NOLOCK | 0,
            sys___get_tcb },                    /* 330 = __get_tcb */
+       { 2, s(struct sys_elfsec_args), 0,
+           sys_elfsec },                       /* 331 = elfsec */
 };
 
Index: sys/kern/syscalls.c
===================================================================
RCS file: /var/cvsroot/src/src/sys/kern/syscalls.c,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 syscalls.c
--- sys/kern/syscalls.c 4 May 2017 19:58:28 -0000       1.1.1.1
+++ sys/kern/syscalls.c 5 May 2017 09:34:34 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscalls.c,v 1.185 2016/09/26 16:43:58 jca Exp $      */
+/*     $OpenBSD$       */
 
 /*
  * System call names.
@@ -393,4 +393,5 @@ char *syscallnames[] = {
        "#328 (obsolete __tfork51)",            /* 328 = obsolete __tfork51 */
        "__set_tcb",                    /* 329 = __set_tcb */
        "__get_tcb",                    /* 330 = __get_tcb */
+       "elfsec",                       /* 331 = elfsec */
 };
Index: sys/kern/syscalls.master
===================================================================
RCS file: /var/cvsroot/src/src/sys/kern/syscalls.master,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 syscalls.master
--- sys/kern/syscalls.master    4 May 2017 19:58:28 -0000       1.1.1.1
+++ sys/kern/syscalls.master    5 May 2017 09:34:28 -0000
@@ -563,3 +563,4 @@
 328    OBSOL           __tfork51
 329    STD NOLOCK      { void sys___set_tcb(void *tcb); }
 330    STD NOLOCK      { void *sys___get_tcb(void); }
+331    STD             { int sys_elfsec(char *buf, size_t nbyte); }
Index: sys/sys/elfsec.h
===================================================================
RCS file: sys/sys/elfsec.h
diff -N sys/sys/elfsec.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ sys/sys/elfsec.h    5 May 2017 09:34:08 -0000
@@ -0,0 +1,62 @@
+#ifndef _ELFSEC_H
+#define _ELFSEC_H
+
+/* 
+ * Copyright (c) 2017 Peter J. Philipp
+ * All rights reserved.
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <crypto/md5.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+#include <crypto/hmac.h>
+
+extern int elfsecactive;
+extern char elfseckey[32];
+
+struct elfsec {
+       u_long es_offset;
+       u_long es_filesize;
+       char es_buf[512];
+       HMAC_SHA256_CTX ctx;
+       int i;  
+       char digest[SHA256_DIGEST_LENGTH];
+};
+       
+
+typedef struct {
+       Elf64_Half      p_type;         /* entry type */
+       Elf64_Half      p_flags;        /* flags */
+       Elf64_Off       p_offset;       /* offset */
+
+       char            hmac[32];       /* 32 bytes for SHA256 HMAC */
+       Elf64_Xword     p_align;        /* memory & file alignment */
+} ELFSEChdr;
+
+
+#endif /* _ELFSEC_H */
Index: sys/sys/exec_elf.h
===================================================================
RCS file: /var/cvsroot/src/src/sys/sys/exec_elf.h,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 exec_elf.h
--- sys/sys/exec_elf.h  4 May 2017 19:58:30 -0000       1.1.1.1
+++ sys/sys/exec_elf.h  5 May 2017 09:33:59 -0000
@@ -433,6 +433,7 @@ typedef struct {
 
 #define PT_OPENBSD_RANDOMIZE   0x65a3dbe6      /* fill with random data */
 #define PT_OPENBSD_WXNEEDED    0x65a3dbe7      /* program performs W^X 
violations */
+#define PT_OPENBSD_ELFSEC      0x65a3dbe8      /* program does ELFSEC */
 #define PT_OPENBSD_BOOTDATA    0x65a41be6      /* section for boot arguments */
 
 /* Segment flags - p_flags */
Index: sys/sys/syscall.h
===================================================================
RCS file: /var/cvsroot/src/src/sys/sys/syscall.h,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 syscall.h
--- sys/sys/syscall.h   4 May 2017 19:58:30 -0000       1.1.1.1
+++ sys/sys/syscall.h   5 May 2017 09:33:51 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscall.h,v 1.184 2016/09/26 16:43:58 jca Exp $       */
+/*     $OpenBSD$       */
 
 /*
  * System call numbers.
@@ -700,4 +700,7 @@
 /* syscall: "__get_tcb" ret: "void *" args: */
 #define        SYS___get_tcb   330
 
-#define        SYS_MAXSYSCALL  331
+/* syscall: "elfsec" ret: "int" args: "char *" "size_t" */
+#define        SYS_elfsec      331
+
+#define        SYS_MAXSYSCALL  332
Index: sys/sys/syscallargs.h
===================================================================
RCS file: /var/cvsroot/src/src/sys/sys/syscallargs.h,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 syscallargs.h
--- sys/sys/syscallargs.h       4 May 2017 19:58:30 -0000       1.1.1.1
+++ sys/sys/syscallargs.h       5 May 2017 09:33:46 -0000
@@ -1,4 +1,4 @@
-/*     $OpenBSD: syscallargs.h,v 1.187 2016/09/26 16:43:58 jca Exp $   */
+/*     $OpenBSD$       */
 
 /*
  * System call argument lists.
@@ -1093,6 +1093,11 @@ struct sys___set_tcb_args {
        syscallarg(void *) tcb;
 };
 
+struct sys_elfsec_args {
+       syscallarg(char *) buf;
+       syscallarg(size_t) nbyte;
+};
+
 /*
  * System call prototypes.
  */
@@ -1341,3 +1346,4 @@ int       sys_symlinkat(struct proc *, void *,
 int    sys_unlinkat(struct proc *, void *, register_t *);
 int    sys___set_tcb(struct proc *, void *, register_t *);
 int    sys___get_tcb(struct proc *, void *, register_t *);
+int    sys_elfsec(struct proc *, void *, register_t *);
Index: usr.sbin/Makefile
===================================================================
RCS file: /var/cvsroot/src/src/usr.sbin/Makefile,v
retrieving revision 1.1.1.1
diff -u -p -u -r1.1.1.1 Makefile
--- usr.sbin/Makefile   4 May 2017 19:59:00 -0000       1.1.1.1
+++ usr.sbin/Makefile   4 May 2017 20:12:01 -0000
@@ -5,8 +5,8 @@
 SUBDIR=        ac accton acme-client acpidump adduser amd apm apmd arp \
        authpf bgpctl bgpd bind chroot config cron crunchgen dev_mkdb \
        dhcpd dhcrelay dhcrelay6 dvmrpctl dvmrpd edquota eeprom eigrpd eigrpctl 
\
-       fdformat ftp-proxy gpioctl hostapd hostctl hotplugd httpd identd \
-       ifstated ikectl inetd installboot iostat iscsictl iscsid kgmon \
+       elfsecd fdformat ftp-proxy gpioctl hostapd hostctl hotplugd httpd  \
+       identd ifstated ikectl inetd installboot iostat iscsictl iscsid kgmon \
        kvm_mkdb ldapd ldapctl ldomctl ldomd ldpd ldpctl lpr makefs \
        mailwrapper map-mbone memconfig mksuncd mkuboot mopd mrinfo \
        mrouted mtrace mtree ndp netgroup_mkdb \
Index: usr.sbin/elfsecd/Makefile
===================================================================
RCS file: usr.sbin/elfsecd/Makefile
diff -N usr.sbin/elfsecd/Makefile
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/elfsecd/Makefile   4 May 2017 20:11:51 -0000
@@ -0,0 +1,10 @@
+SRCS=elf.c key.c elfsecd.c
+PROG=elfsecd
+
+LDADD= -lutil -lcrypto -lssl
+
+NOMAN=1
+BINDIR=/usr/sbin
+
+
+.include <bsd.prog.mk>
Index: usr.sbin/elfsecd/elf.c
===================================================================
RCS file: usr.sbin/elfsecd/elf.c
diff -N usr.sbin/elfsecd/elf.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/elfsecd/elf.c      4 May 2017 20:11:51 -0000
@@ -0,0 +1,180 @@
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <sys/stat.h>
+#include <sys/exec_elf.h>
+#include <sys/elfsec.h>
+#include <sys/mman.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <errno.h>
+
+#include <elfsec.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+int elfheader_offset(char *);
+int elfheader_sign(char *, char *, int);
+
+
+int
+elfheader_sign(char *file, char *sign, int size)
+{
+       struct stat sb;
+       int ofd, fd, i;
+       char *map;      
+       char signfile[PATH_MAX];
+       Elf64_Ehdr *elfhdr;
+       Elf64_Phdr *phdr, *pphdr;
+       ELFSEChdr *elfsec_hdr;
+
+       fd = open(file, O_RDWR, 0755);
+       if (fd < 0) {
+               perror("open");
+               return -1;
+       }
+
+       if (fstat(fd, &sb) < 0) {
+               perror("fstat");
+               close(fd);
+               return -1;
+       }
+
+       if (sb.st_size <= sizeof(Elf64_Ehdr)) {
+               close(fd);
+               return -1;
+       }
+
+
+       map = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, 
MAP_PRIVATE|MAP_FILE, fd, 0);
+       if (map == MAP_FAILED) {
+               perror("mmap");
+               close(fd);
+               return -1;
+       }
+
+       elfhdr = (Elf64_Ehdr *)map;     
+
+#if DEBUG
+       printf("e_phoff = %ld\n", elfhdr->e_phoff);
+       printf("e_phnum = %ld\n", elfhdr->e_phnum);
+       
+       printf("num * sizeof(Elf64_Phdr) = %d\n", elfhdr->e_phnum * 
sizeof(Elf64_Phdr));
+#endif
+
+       phdr = (Elf64_Phdr *)((void *)(map + elfhdr->e_phoff));
+       if (memcmp(elfhdr->e_ident, ELFMAG, SELFMAG) != 0 || 
+               sb.st_size < sizeof(*elfhdr) + (elfhdr->e_phnum * 
sizeof(*phdr))) {
+               fprintf(stderr, "size violation\n");
+               close(fd);
+               munmap(map, sb.st_size);
+               return -1;
+       }
+
+       for (i = 0; i < elfhdr->e_phnum; i++) {
+               pphdr = &phdr[i];
+               if (pphdr->p_type == PT_OPENBSD_ELFSEC) {
+                       elfsec_hdr = (ELFSEChdr *)pphdr;                        
        
+                       memcpy(elfsec_hdr->hmac, sign, size);
+                       break;
+               }
+       }
+       
+       if (i >= elfhdr->e_phnum) {
+               fprintf(stderr, "no ELFSEC header found, not modifying.\n");
+               close(fd);
+               munmap(map, sb.st_size);
+               return -1;
+       }
+
+       strlcpy(signfile, "/tmp/signfile.XXXXXXXXX", sizeof(signfile));
+       if ((ofd = open(signfile, O_WRONLY | O_CREAT | O_TRUNC, 0700)) < 0) {
+               perror("open");
+               close(fd);
+               munmap(map, sb.st_size);
+               return -1;
+       }
+               
+       for (i = 0; i < sb.st_size; i++) {
+               if (write(ofd, (char *)&map[i], 1) < 0) {
+                       perror("write");
+                       close(fd);
+                       munmap(map, sb.st_size);
+                       return -1;
+               }
+       }
+               
+       close(ofd);
+
+       munmap(map, sb.st_size);
+       close(fd);
+
+       if (rename(signfile, file) < 0) {
+               perror("rename");
+               return -1;
+       }
+               
+       if (chown(file, sb.st_uid, sb.st_gid) <  0) {
+               perror("chown");
+               return -1;
+       }
+
+       if (chmod(file, sb.st_mode) < 0) {      
+               perror("chmod");
+               return -1;
+       }
+       
+       return (0);
+}
+
+
+int
+elfheader_offset(char *file)
+{
+       struct stat sb;
+       int fd;
+       int num, offset;
+       char *map;      
+       Elf64_Ehdr *elfhdr;
+
+       fd = open(file, O_RDONLY, 0);
+       if (fd < 0) {
+               perror("open");
+               return -1;
+       }
+
+       if (fstat(fd, &sb) < 0) {
+               perror("fstat");
+               close(fd);
+               return -1;
+       }
+
+       if (sb.st_size < sizeof(*elfhdr)) {
+               close(fd);
+               return -1;
+       }
+
+       map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       if (map == MAP_FAILED) {
+               perror("mmap");
+               close(fd);
+               return -1;
+       }
+
+
+       elfhdr = (Elf64_Ehdr *)map;     
+
+       num = elfhdr->e_phnum;
+       offset = elfhdr->e_phoff;
+
+       close(fd);
+       munmap(map, sb.st_size);
+       
+       return (num * sizeof(Elf64_Phdr) + offset);
+}
Index: usr.sbin/elfsecd/elfsecd.c
===================================================================
RCS file: usr.sbin/elfsecd/elfsecd.c
diff -N usr.sbin/elfsecd/elfsecd.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/elfsecd/elfsecd.c  4 May 2017 20:11:51 -0000
@@ -0,0 +1,486 @@
+/* 
+ * Copyright (c) 2017 Peter J. Philipp
+ * All rights reserved.
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ * 
+ */
+
+/* 
+ * We need a daemon that will sign a users programs, so accept a PATHNAME
+ * on a UNIX socket and check through an access list, when acceptable then
+ * sign the users program with the root owned part..
+ */
+
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <sys/queue.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/pledge.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <sys/tree.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <imsg.h>
+#include <pwd.h>
+#include <signal.h>
+#include <errno.h>
+#include <ctype.h>
+#include <syslog.h>
+
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+
+
+#define        WELLKNOWNSOCKET         "/var/run/elfsecd"
+#define                USERLIST                "/etc/elfsec/users"
+#define                IMSG_PARENTFD           0
+#define                IMSG_CHILDFD            1
+
+struct ess {
+       int len;
+       uid_t uid;
+       char path[PATH_MAX];
+};
+
+struct node {
+        RB_ENTRY(node) entry;
+        uid_t uid;
+};
+
+
+void imsg_dispatch(struct imsgbuf *, char *);
+void onchld(int);
+void onalrm(int);
+int child_main(struct imsgbuf *);
+int parent_main(struct imsgbuf *);
+int uidcmp(struct node *, struct node *);
+
+extern int elfheader_offset(char *);
+extern int elfheader_sign(char *, char *, int);
+extern int readkey(char *, char *, int);
+
+
+
+/* intcmp - compare uid's */
+
+int
+uidcmp(struct node *e1, struct node *e2)
+{
+        return (e1->uid < e2->uid ? -1 : e1->uid > e2->uid);
+}
+
+RB_HEAD(uidtree, node) head = RB_INITIALIZER(&head);
+RB_GENERATE(uidtree, node, entry, uidcmp)
+
+
+
+/*
+ * onchld - signal handler 
+ */
+
+void
+onchld(int sig)
+{
+       pid_t pid;
+       int status;
+
+       while ((pid = waitpid(-1, &status, WNOHANG)) > 0);
+}
+
+void
+onalrm(int sig)
+{
+       return;
+}
+
+
+extern int errno;
+
+
+int
+main(int argc, char *argv[])
+{
+       int imsg_fds[2];
+       struct imsgbuf child_ibuf, parent_ibuf;
+       uid_t euid;
+
+       euid = geteuid();
+       if (euid != 0) {
+               fprintf(stderr, "this program must be started as root\n");
+               exit(1);
+       }
+
+       openlog("elfsecd", LOG_PID|LOG_NDELAY, LOG_DAEMON);
+
+       if (daemon(0,0) < 0) {
+               perror("daemon");
+               exit(1);
+       }
+
+       syslog(LOG_INFO, "starting up");
+
+       signal(SIGCHLD, onchld);
+
+       if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) < 0) {
+               perror("socketpair");
+               exit(1);
+       }
+
+       switch(fork()) {
+       case -1:
+               perror("fork");
+               exit(1);
+       case 0:
+               close(imsg_fds[IMSG_PARENTFD]);
+               imsg_init(&child_ibuf, imsg_fds[IMSG_CHILDFD]);
+               exit(child_main(&child_ibuf));          
+
+       default:
+               close(imsg_fds[IMSG_CHILDFD]);
+               imsg_init(&parent_ibuf, imsg_fds[IMSG_PARENTFD]);               
+               exit(parent_main(&parent_ibuf));        
+       }
+               
+       /* NOTREACHED */        
+}
+
+int
+parent_main(struct imsgbuf *ibuf) 
+{
+       char key[32];
+       fd_set rset;
+       int sel;
+
+       if (pledge("stdio rpath wpath cpath id unix chown fattr", NULL) < 0) {
+               perror("pledge");
+               exit(1);
+       }
+
+       if (readkey("/etc/elfsec/key", (char *)&key, sizeof(key)) < 0) {
+               syslog(LOG_ERR, "can't read elfsec key");
+               exit(1);
+       }
+       
+       for (;;) {
+               FD_ZERO(&rset);
+               FD_SET(ibuf->fd, &rset);        
+               
+               sel = select(ibuf->fd + 1, &rset, NULL, NULL, NULL);
+               if (sel == 0) {
+                       continue;
+               }
+               if (sel == -1) {
+                       perror("select");
+                       continue;
+               }
+
+               if (FD_ISSET(ibuf->fd, &rset)) {
+                       imsg_dispatch(ibuf, key);
+               }
+       }
+       /* NOTREACHED */
+}
+
+void
+imsg_dispatch(struct imsgbuf *ibuf, char *key)
+{
+       HMAC_CTX ctx;
+       char sbuf[512];
+       char shabuf[32];
+       struct imsg imsg;
+       ssize_t n, datalen;
+       struct ess elfsec;
+       struct stat sb;
+       int i, fd, len;
+       int offset = 0;
+
+       if (((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) || n == 0) {
+                       return;
+       }
+               
+       for (;;) {
+               if ((n = imsg_get(ibuf, &imsg)) == -1) {
+                       return;
+               }
+               if (n == 0)
+                       return;
+
+               datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+
+               if (datalen < sizeof(struct ess))
+                       return;
+               
+               memcpy(&elfsec, imsg.data, sizeof(struct ess));
+               imsg_free(&imsg);
+
+               elfsec.path[PATH_MAX - 1] = '\0';
+               if (lstat(elfsec.path, &sb) < 0) {
+                       perror("lstat");
+                       continue;
+               }
+               if (! S_ISREG(sb.st_mode)) {
+                       syslog(LOG_ERR, "path %s is not a regular file!, 
abort", elfsec.path);
+                       continue;
+               }
+       
+               if (sb.st_uid != elfsec.uid) {
+                       syslog(LOG_ERR, "path %s is not owned by uid %d", 
elfsec.path, elfsec.uid);
+                       continue;
+               }
+
+               syslog(LOG_INFO, "signing '%s' for uid %u", elfsec.path, 
elfsec.uid);
+
+               if ((offset = elfheader_offset(elfsec.path)) < 0) {
+                       continue;
+               }
+
+               fd = open(elfsec.path, O_RDONLY, 0);
+               if (fd < 0) {
+                       syslog(LOG_ERR, "open: %m");
+                       continue;
+               }
+
+               if (lseek(fd, offset, SEEK_SET) < 0) {
+                       syslog(LOG_ERR, "lseek: %m");
+                       continue;
+               }
+
+               if (fstat(fd, &sb) < 0) {
+                       syslog(LOG_ERR, "fstat: %m");
+                       continue;
+               }
+
+               HMAC_CTX_init(&ctx);
+               HMAC_Init(&ctx, key, 32, EVP_sha256());
+ 
+               for (i = offset; i < sb.st_size; i += 512) {
+                       len = read(fd, sbuf, sizeof(sbuf));
+       
+                       if (len == 0)
+                               break;
+
+                       HMAC_Update(&ctx, sbuf, len);
+               }
+
+               close(fd);
+
+               i = sizeof(shabuf);
+               HMAC_Final(&ctx, shabuf, &i);
+
+               if (elfheader_sign(elfsec.path, shabuf, sizeof(shabuf)) < 0) {
+                       syslog(LOG_ERR, "signing '%s' failed", elfsec.path);
+               }
+       }
+
+       /* NOTREACHED */
+}
+
+
+
+int
+child_main(struct imsgbuf *ibuf)
+{
+       FILE *f;
+       char buf[512];
+       char *p;
+       struct sockaddr_un sun;
+       struct passwd *pw, *opw;
+       struct ess elfsec;
+       struct node *node, find;
+       int ss, n, len;
+       int so, slen, sel;
+       fd_set rset;
+       uid_t euid, uid;
+       gid_t egid;
+
+
+       
+       f = fopen(USERLIST, "r");
+       if (f != NULL) {
+               while (fgets(buf, sizeof(buf), f) != NULL) {
+                       p = &buf[0];
+                       while (isspace(*p++));
+               
+                       if (*p == '#')
+                               continue;
+
+                       len = strlen(buf);
+                       if (buf[len - 1] == '\n')
+                               len--;
+                       if (buf[len - 1] == '\r')
+                               len--;
+                       buf[len] = '\0';
+                       
+                       pw = getpwnam(buf);
+                       if (pw == NULL)
+                               continue;
+                       
+                       node = calloc(1, sizeof(struct node));
+                       if (node == NULL) {
+                               perror("calloc");
+                               exit(1);
+                       }
+                       node->uid = pw->pw_uid; 
+
+                       RB_INSERT(uidtree, &head, node);
+               }       
+               fclose(f);
+       }
+
+       so = socket(AF_LOCAL, SOCK_STREAM, 0);
+       if (so < 0) {
+               perror("socket");
+               return 1;
+       }
+
+       if (unlink(WELLKNOWNSOCKET) < 0) {
+               perror("unlink");
+       }
+
+       memset(&sun, 0, sizeof(sun));
+       strlcpy((char *)&sun.sun_path, WELLKNOWNSOCKET, sizeof(sun.sun_path));
+       //sun.sun_len = strlen(WELLKNOWNSOCKET);
+       sun.sun_family = AF_LOCAL;
+
+       if (bind(so, (struct sockaddr *)&sun, sizeof(struct sockaddr_un)) < 0) {
+               perror("bind");
+               return 1;
+       }
+
+       if (chmod(WELLKNOWNSOCKET, 0666) < 0)
+               perror("chmod");
+
+
+       pw = getpwnam("_elfsec");
+       if (pw == NULL) {
+               syslog(LOG_ERR, "no such user _elfsec");
+               return 1;
+       }
+
+       if (chroot(pw->pw_dir) < 0) {
+               perror("chroot");
+               exit(1);
+       }
+
+       chdir("/");
+
+       if (pledge("stdio unix id fattr proc getpw", NULL) < 0) {
+               perror("pledge");
+               return 1;
+       }
+
+       if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) {
+               perror("setresgid");
+               return 1;
+       }
+       if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) {
+               perror("setresuid");
+               return 1;
+       }
+
+       memset(&sun, 0, sizeof(struct sockaddr_un));
+
+       signal(SIGALRM, onalrm);
+
+       listen(so, 5);
+
+       for (;;) {
+               FD_ZERO(&rset);
+               FD_SET(so, &rset);      
+               
+               sel = select(so + 1, &rset, NULL, NULL, NULL);
+               if (sel == 0) {
+                       /* hunh!? */
+                       continue;
+               }
+               if (sel == -1) {
+                       perror("select");
+                       continue;
+               }
+       
+               if (FD_ISSET(so, &rset)) {
+                       slen = sizeof(struct sockaddr_un);
+                       ss = accept(so, (struct sockaddr *)&sun, &slen);
+                       if (ss < 0) {
+                               perror("accept");
+                               continue;
+                       }
+
+                       switch(uid = fork()) {
+                       case 0:
+                               close(so);
+                               alarm(10);
+                               if (recvfrom(ss, (char *)&elfsec, sizeof(struct 
ess), MSG_WAITALL, (struct sockaddr *)&sun, &slen) < 0) {
+                                       perror("recvfrom");
+                                       close(ss);
+                                       exit(1);
+                               }       
+                               alarm(0);
+
+                               if (getpeereid(ss, &euid, &egid) < 0) {
+                                       perror("getpeereid");
+                                       close(ss);
+                                       exit(1);
+                               }
+
+                               memset(&find, 0, sizeof(struct node));
+                               find.uid = euid;
+
+                               if (euid != 0 && RB_FIND(uidtree, &head, &find) 
== NULL) {
+                                       syslog(LOG_INFO, "uid %u access not 
allowed", euid);
+                                       exit(1);
+                               }
+                                       
+
+                               elfsec.uid = euid;
+                               imsg_compose(ibuf, 0, 0, 0, -1, &elfsec, 
sizeof(struct ess));
+                               n = msgbuf_write(&ibuf->w);
+                               if (n < 0) {
+                                       perror("msg_write");    
+                               }
+
+                               close(ss);
+                               exit(0);
+                       case -1:
+                               perror("fork");
+                               continue;
+                       default:
+                               close(ss);
+                               continue;       
+                       }
+               }
+       }
+
+       /* NOTREACHED */
+
+}
Index: usr.sbin/elfsecd/key.c
===================================================================
RCS file: usr.sbin/elfsecd/key.c
diff -N usr.sbin/elfsecd/key.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ usr.sbin/elfsecd/key.c      4 May 2017 20:11:51 -0000
@@ -0,0 +1,77 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <netdb.h>
+#include <resolv.h>
+
+int readkey(char *, char *, int);
+int writekey(char *, char *, int);
+
+int
+readkey(char *path, char *key, int len)
+{
+       char buf[512];  
+       FILE *f;
+
+       f = fopen(path, "r");
+       if (f == NULL) {
+               perror("fopen");
+               return -1;
+       }
+
+       if (fgets(buf, sizeof(buf), f) == NULL) {
+               perror("fgets");
+               fclose(f);
+               return -1;
+       }
+
+       fclose(f);
+
+       buf[sizeof(buf) - 1] = '\0';
+
+       if (b64_pton(buf, key, len) < 0) {
+               perror("b64_pton");
+               fclose(f);
+               return -1;
+       }
+
+       return 0;
+}
+
+
+int
+writekey(char *path, char *key, int len)
+{
+       int fd;
+       int buflen;
+       char buf[512];
+
+       if ((buflen = b64_ntop(key, len, (char *)&buf, sizeof(buf))) < 0) {
+               perror("b64_ntop");
+               return -1;
+       }
+
+       fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0600);
+       if (fd < 0) {
+               perror("open");
+               return -1;
+       }
+
+
+       if (write(fd, buf, buflen) != buflen) {
+               perror("write");
+               close(fd);
+               unlink(path);
+               return -1;
+       }
+               
+       close(fd);
+
+       return 0;
+}

Reply via email to