On Fri, Jul 24, 2009 at 03:49:53PM +0200, Ed Schouten wrote:
> * Jeremie Le Hen <jere...@le-hen.org> wrote:
> > On Fri, Jul 24, 2009 at 01:56:49PM +0200, Ed Schouten wrote:
> > > * Jeremie Le Hen <jere...@le-hen.org> wrote:
> > > > On Fri, Jul 24, 2009 at 11:18:42AM +0300, Kostik Belousov wrote:
> > > > > On Fri, Jul 24, 2009 at 09:34:51AM +0200, Jeremie Le Hen wrote:
> > > > > > Hi Ed,
> > > > > > 
> > > > > > Sorry for the late reply.
> > > > > > 
> > > > > > On Sat, May 09, 2009 at 02:13:13PM +0200, Ed Schouten wrote:
> > > > > > > We probably could. I think I discussed this with Robert Watson 
> > > > > > > some time
> > > > > > > ago and we could use things like ELF hints. But still, that 
> > > > > > > doesn't
> > > > > > > prevent us from reaching this limitation later on.
> > > > > > 
> > > > > > Can you elaborate a little?  Are you talking about elf-hints.h?
> > > > > > I don't see where we can get randomness from it.
> > > > > 
> > > > > The thing is called ELF auxillary information vector. It is used to
> > > > > supply some useful information for interpreter from the kernel,
> > > > > see include/machine/elf.h for AT_* entries.
> > > > 
> > > > Ah ok, so the idea is to generate a new hint, for instance AT_RANDOM,
> > > > generated at link time, that will be used to fill the canary at exec(2)
> > > > time?
> > > 
> > > Very short answer: yes!
> > 
> > Ok thanks.  But this would make stack protection useless for local
> > attacks on suid binaries that are world-readable since the attacker
> > could read the ELF aux vector and compute the canary.  
> 
> Wait wait wait. It seems you were only partially right (and Kostik
> corrected you):
> 
> We could add AT_RANDOM, but this value will be filled in by the kernel
> when starting the process. This means the random value is not stored in
> the binary.

Below is the prototype that seems to work for me both with patched and
old rtld on i386. Patch also contains bits for amd64 that I did not
tested yet. All other arches are not buildable for now.

Patch completely eliminates sysctl syscalls from the rtld and libc
startup. Without the patch, a single run of /bin/ls did 6 sysctls,
with the patch, no sysctls is queried at all.

diff --git a/lib/libc/gen/__getosreldate.c b/lib/libc/gen/__getosreldate.c
index 69aac07..6a4e5ea 100644
--- a/lib/libc/gen/__getosreldate.c
+++ b/lib/libc/gen/__getosreldate.c
@@ -29,6 +29,8 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/sysctl.h>
+#include <errno.h>
+#include <link.h>
 
 /*
  * This is private to libc.  It is intended for wrapping syscall stubs in order
@@ -49,7 +51,15 @@ __getosreldate(void)
 
        if (osreldate != 0)
                return (osreldate);
-       
+
+       if (_rtld_aux_info != NULL)
+               error = _rtld_aux_info(AT_OSRELDATE, &osreldate,
+                   sizeof(osreldate));
+       else
+               error = ENOSYS;
+       if (error == 0 && osreldate != 0)
+               return (osreldate);
+
        oid[0] = CTL_KERN;
        oid[1] = KERN_OSRELDATE;
        osrel = 0;
diff --git a/lib/libc/gen/getpagesize.c b/lib/libc/gen/getpagesize.c
index d796b9d..b8f0ec1 100644
--- a/lib/libc/gen/getpagesize.c
+++ b/lib/libc/gen/getpagesize.c
@@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/sysctl.h>
 
+#include <errno.h>
+#include <link.h>
 #include <unistd.h>
 
 /*
@@ -52,13 +54,23 @@ getpagesize()
        int mib[2]; 
        static int value;
        size_t size;
+       int error;
+
+       if (value != 0)
+               return (value);
+
+       if (_rtld_aux_info != NULL)
+               error = _rtld_aux_info(AT_PAGESZ, &value, sizeof(value));
+       else
+               error = ENOSYS;
+       if (error == 0 && value != 0)
+               return (value);
+
+       mib[0] = CTL_HW;
+       mib[1] = HW_PAGESIZE;
+       size = sizeof value;
+       if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
+               return (-1);
 
-       if (!value) {
-               mib[0] = CTL_HW;
-               mib[1] = HW_PAGESIZE;
-               size = sizeof value;
-               if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
-                       return (-1);
-       }
        return (value);
 }
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index 270d641..e479abe 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -179,6 +179,7 @@ __FBSDID("$FreeBSD$");
 
 #include <errno.h>
 #include <limits.h>
+#include <link.h>
 #include <pthread.h>
 #include <sched.h>
 #include <stdarg.h>
@@ -4769,7 +4770,10 @@ malloc_init_hard(void)
        unsigned i;
        int linklen;
        char buf[PATH_MAX + 1];
+       int mib[2];
+       size_t len;
        const char *opts;
+       int error;
 
        malloc_mutex_lock(&init_lock);
        if (malloc_initialized) {
@@ -4782,10 +4786,11 @@ malloc_init_hard(void)
        }
 
        /* Get number of CPUs. */
-       {
-               int mib[2];
-               size_t len;
-
+       if (_rtld_aux_info != NULL)
+               error = _rtld_aux_info(AT_NCPUS, &ncpus, sizeof(ncpus));
+       else
+               error = ENOSYS;
+       if (error != 0 || ncpus == 0) {
                mib[0] = CTL_HW;
                mib[1] = HW_NCPU;
                len = sizeof(ncpus);
diff --git a/lib/libc/sys/stack_protector.c b/lib/libc/sys/stack_protector.c
index 63beebc..571f63c 100644
--- a/lib/libc/sys/stack_protector.c
+++ b/lib/libc/sys/stack_protector.c
@@ -34,6 +34,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/sysctl.h>
 #include <sys/types.h>
+#include <errno.h>
+#include <link.h>
 #include <signal.h>
 #include <string.h>
 #include <syslog.h>
@@ -54,9 +56,17 @@ __guard_setup(void)
 {
        int mib[2];
        size_t len;
+       int error;
 
        if (__stack_chk_guard[0] != 0)
                return;
+       if (_rtld_aux_info != NULL)
+               error = _rtld_aux_info(AT_CANARY, __stack_chk_guard,
+                   sizeof(__stack_chk_guard));
+       else
+               error = ENOSYS;
+       if (error == 0 && __stack_chk_guard[0] != 0)
+               return;
 
        mib[0] = CTL_KERN;
        mib[1] = KERN_ARND;
diff --git a/libexec/rtld-elf/Symbol.map b/libexec/rtld-elf/Symbol.map
index ce1e3e5..f45f955 100644
--- a/libexec/rtld-elf/Symbol.map
+++ b/libexec/rtld-elf/Symbol.map
@@ -24,4 +24,5 @@ FBSDprivate_1.0 {
     _rtld_free_tls;
     _rtld_atfork_pre;
     _rtld_atfork_post;
+    _rtld_aux_info;
 };
diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c
index 8a32adf..a510884 100644
--- a/libexec/rtld-elf/amd64/reloc.c
+++ b/libexec/rtld-elf/amd64/reloc.c
@@ -113,7 +113,7 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, bool early)
 {
        const Elf_Rela *relalim;
        const Elf_Rela *rela;
@@ -125,9 +125,13 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
         * The dynamic loader may be called from a thread, we have
         * limited amounts of stack available so we cannot use alloca().
         */
-       cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-       if (cache == MAP_FAILED)
+       if (early)
            cache = NULL;
+       else {
+           cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
+           if (cache == MAP_FAILED)
+               cache = NULL;
+       }
 
        relalim = (const Elf_Rela *) ((caddr_t) obj->rela + obj->relasize);
        for (rela = obj->rela;  rela < relalim;  rela++) {
diff --git a/libexec/rtld-elf/i386/reloc.c b/libexec/rtld-elf/i386/reloc.c
index ec83bff..2913d78 100644
--- a/libexec/rtld-elf/i386/reloc.c
+++ b/libexec/rtld-elf/i386/reloc.c
@@ -114,7 +114,7 @@ init_pltgot(Obj_Entry *obj)
 
 /* Process the non-PLT relocations. */
 int
-reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
+reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, bool early)
 {
        const Elf_Rel *rellim;
        const Elf_Rel *rel;
@@ -126,9 +126,13 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld)
         * The dynamic loader may be called from a thread, we have
         * limited amounts of stack available so we cannot use alloca().
         */
-       cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
-       if (cache == MAP_FAILED)
+       if (early)
            cache = NULL;
+       else {
+           cache = mmap(NULL, bytes, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0);
+           if (cache == MAP_FAILED)
+               cache = NULL;
+       }
 
        rellim = (const Elf_Rel *) ((caddr_t) obj->rel + obj->relsize);
        for (rel = obj->rel;  rel < rellim;  rel++) {
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 721fe89..75a1c69 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -40,6 +40,7 @@
 #include <sys/mount.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/sysctl.h>
 #include <sys/uio.h>
 #include <sys/utsname.h>
 #include <sys/ktrace.h>
@@ -84,6 +85,9 @@ typedef struct Struct_DoneList {
  */
 static const char *basename(const char *);
 static void die(void) __dead2;
+static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **,
+    const Elf_Dyn **);
+static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *);
 static void digest_dynamic(Obj_Entry *, int);
 static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
 static Obj_Entry *dlcheck(void *);
@@ -97,7 +101,7 @@ static char *find_library(const char *, const Obj_Entry *);
 static const char *gethints(void);
 static void init_dag(Obj_Entry *);
 static void init_dag1(Obj_Entry *, Obj_Entry *, DoneList *);
-static void init_rtld(caddr_t);
+static void init_rtld(caddr_t, Elf_Auxinfo **);
 static void initlist_add_neededs(Needed_Entry *, Objlist *);
 static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *);
 static bool is_exported(const Elf_Sym *);
@@ -116,7 +120,7 @@ static void objlist_push_head(Objlist *, Obj_Entry *);
 static void objlist_push_tail(Objlist *, Obj_Entry *);
 static void objlist_remove(Objlist *, Obj_Entry *);
 static void *path_enumerate(const char *, path_enum_proc, void *);
-static int relocate_objects(Obj_Entry *, bool, Obj_Entry *);
+static int relocate_objects(Obj_Entry *, bool, Obj_Entry *, bool early);
 static int rtld_dirname(const char *, char *);
 static int rtld_dirname_abs(const char *, char *);
 static void rtld_exit(void);
@@ -188,6 +192,9 @@ extern Elf_Dyn _DYNAMIC;
 #define        RTLD_IS_DYNAMIC()       (&_DYNAMIC != NULL)
 #endif
 
+static int pagesize, osreldate, canary_len, ncpus;
+static char *canary;
+
 /*
  * These are the functions the dynamic linker exports to application
  * programs.  They are the only symbols the dynamic linker is willing
@@ -214,6 +221,7 @@ static func_ptr_type exports[] = {
     (func_ptr_type) &dl_iterate_phdr,
     (func_ptr_type) &_rtld_atfork_pre,
     (func_ptr_type) &_rtld_atfork_post,
+    (func_ptr_type) &_rtld_aux_info,
     NULL
 };
 
@@ -350,7 +358,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry 
**objp)
 
     /* Initialize and relocate ourselves. */
     assert(aux_info[AT_BASE] != NULL);
-    init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr);
+    init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr, aux_info);
 
     __progname = obj_rtld.path;
     argv0 = argv[0] != NULL ? argv[0] : "(null)";
@@ -519,7 +527,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry 
**objp)
     allocate_initial_tls(obj_list);
 
     if (relocate_objects(obj_main,
-       ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld) == -1)
+       ld_bind_now != NULL && *ld_bind_now != '\0', &obj_rtld, false) == -1)
        die();
 
     dbg("doing copy relocations");
@@ -736,14 +744,16 @@ die(void)
  * information in its Obj_Entry structure.
  */
 static void
-digest_dynamic(Obj_Entry *obj, int early)
+digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
+    const Elf_Dyn **dyn_soname)
 {
     const Elf_Dyn *dynp;
     Needed_Entry **needed_tail = &obj->needed;
-    const Elf_Dyn *dyn_rpath = NULL;
-    const Elf_Dyn *dyn_soname = NULL;
     int plttype = DT_REL;
 
+    *dyn_rpath = NULL;
+    *dyn_soname = NULL;
+
     obj->bind_now = false;
     for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
        switch (dynp->d_tag) {
@@ -867,11 +877,11 @@ digest_dynamic(Obj_Entry *obj, int early)
             * We have to wait until later to process this, because we
             * might not have gotten the address of the string table yet.
             */
-           dyn_rpath = dynp;
+           *dyn_rpath = dynp;
            break;
 
        case DT_SONAME:
-           dyn_soname = dynp;
+           *dyn_soname = dynp;
            break;
 
        case DT_INIT:
@@ -958,6 +968,12 @@ digest_dynamic(Obj_Entry *obj, int early)
        obj->pltrelasize = obj->pltrelsize;
        obj->pltrelsize = 0;
     }
+}
+
+static void
+digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
+    const Elf_Dyn *dyn_soname)
+{
 
     if (obj->z_origin && obj->origin_path == NULL) {
        obj->origin_path = xmalloc(PATH_MAX);
@@ -975,6 +991,16 @@ digest_dynamic(Obj_Entry *obj, int early)
        object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
 }
 
+static void
+digest_dynamic(Obj_Entry *obj, int early)
+{
+       const Elf_Dyn *dyn_rpath;
+       const Elf_Dyn *dyn_soname;
+
+       digest_dynamic1(obj, early, &dyn_rpath, &dyn_soname);
+       digest_dynamic2(obj, dyn_rpath, dyn_soname);
+}
+
 /*
  * Process a shared object's program header.  This is used only for the
  * main program, when the kernel has already loaded the main program
@@ -1301,9 +1327,11 @@ init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp)
  * this function is to relocate the dynamic linker.
  */
 static void
-init_rtld(caddr_t mapbase)
+init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info)
 {
     Obj_Entry objtmp;  /* Temporary rtld object */
+    const Elf_Dyn *dyn_rpath;
+    const Elf_Dyn *dyn_soname;
 
     /*
      * Conjure up an Obj_Entry structure for the dynamic linker.
@@ -1320,27 +1348,38 @@ init_rtld(caddr_t mapbase)
 #endif
     if (RTLD_IS_DYNAMIC()) {
        objtmp.dynamic = rtld_dynamic(&objtmp);
-       digest_dynamic(&objtmp, 1);
+       digest_dynamic1(&objtmp, 1, &dyn_rpath, &dyn_soname);
        assert(objtmp.needed == NULL);
 #if !defined(__mips__)
        /* MIPS and SH{3,5} have a bogus DT_TEXTREL. */
        assert(!objtmp.textrel);
 #endif
-
        /*
         * Temporarily put the dynamic linker entry into the object list, so
         * that symbols can be found.
         */
 
-       relocate_objects(&objtmp, true, &objtmp);
+       relocate_objects(&objtmp, true, &objtmp, true);
     }
-
     /* Initialize the object list. */
     obj_tail = &obj_list;
 
     /* Now that non-local variables can be accesses, copy out obj_rtld. */
     memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld));
 
+    if (aux_info[AT_PAGESZ] != NULL)
+           pagesize = aux_info[AT_PAGESZ]->a_un.a_val;
+    if (aux_info[AT_OSRELDATE] != NULL)
+           osreldate = aux_info[AT_OSRELDATE]->a_un.a_val;
+    if (aux_info[AT_CANARY] != NULL && aux_info[AT_CANARYLEN] != NULL) {
+           canary = aux_info[AT_CANARY]->a_un.a_ptr;
+           canary_len = aux_info[AT_CANARYLEN]->a_un.a_val;
+    }
+    if (aux_info[AT_NCPUS] != NULL)
+           ncpus = aux_info[AT_NCPUS]->a_un.a_val;
+
+    digest_dynamic2(&obj_rtld, dyn_rpath, dyn_soname);
+
     /* Replace the path with a dynamically allocated copy. */
     obj_rtld.path = xstrdup(PATH_RTLD);
 
@@ -1745,7 +1784,8 @@ objlist_remove(Objlist *list, Obj_Entry *obj)
  * or -1 on failure.
  */
 static int
-relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj)
+relocate_objects(Obj_Entry *first, bool bind_now, Obj_Entry *rtldobj,
+    bool early)
 {
     Obj_Entry *obj;
 
@@ -1770,7 +1810,7 @@ relocate_objects(Obj_Entry *first, bool bind_now, 
Obj_Entry *rtldobj)
        }
 
        /* Process the non-PLT relocations. */
-       if (reloc_non_plt(obj, rtldobj))
+       if (reloc_non_plt(obj, rtldobj, early))
                return -1;
 
        if (obj->textrel) {     /* Re-protected the text segment. */
@@ -2022,7 +2062,8 @@ dlopen(const char *name, int mode)
            if (result != -1 && ld_tracing)
                goto trace;
            if (result == -1 ||
-             (relocate_objects(obj, mode == RTLD_NOW, &obj_rtld)) == -1) {
+               (relocate_objects(obj, mode == RTLD_NOW, &obj_rtld, false))
+                   == -1) {
                obj->dl_refcount--;
                unref_dag(obj);
                if (obj->refcount == 0)
@@ -3611,3 +3652,110 @@ fetch_ventry(const Obj_Entry *obj, unsigned long symnum)
     }
     return NULL;
 }
+
+static int
+__getosreldate(void)
+{
+       static int osreldate;
+       size_t len;
+       int oid[2];
+       int error, osrel;
+
+       oid[0] = CTL_KERN;
+       oid[1] = KERN_OSRELDATE;
+       osrel = 0;
+       len = sizeof(osrel);
+       error = sysctl(oid, 2, &osrel, &len, NULL, 0);
+       if (error == 0 && osrel > 0 && len == sizeof(osrel))
+               osreldate = osrel;
+       return (osreldate);
+}
+
+static int
+__getpagesize(void)
+{
+       int mib[2];
+       static int value;
+       size_t size;
+
+       mib[0] = CTL_HW;
+       mib[1] = HW_PAGESIZE;
+       size = sizeof value;
+       if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
+               return (-1);
+
+       return (value);
+}
+
+static int
+__getncpus(void)
+{
+       int mib[2];
+       size_t len;
+       int n;
+
+       mib[0] = CTL_HW;
+       mib[1] = HW_NCPU;
+       len = sizeof(ncpus);
+       if (sysctl(mib, 2, &n, &len, (void *) 0, 0) == -1)
+               n = 1;
+       return (n);
+}
+
+int
+_rtld_aux_info(int aux, void *buf, int buflen)
+{
+       int res;
+
+       switch (aux) {
+       case AT_CANARY:
+               if (canary != NULL && canary_len >= buflen) {
+                       memcpy(buf, canary, buflen);
+                       memset(canary, 0, canary_len);
+                       canary = NULL;
+                       res = 0;
+               } else
+                       res = ENOENT;
+               break;
+       case AT_PAGESZ:
+               if (buflen == sizeof(int)) {
+                       if (pagesize == 0)
+                               pagesize = __getpagesize();
+                       if (pagesize != 0) {
+                               *(int *)buf = pagesize;
+                               res = 0;
+                       } else
+                               res = ENOENT;
+               } else
+                       res = EINVAL;
+               break;
+       case AT_OSRELDATE:
+               if (buflen == sizeof(int)) {
+                       if (osreldate == 0)
+                               osreldate = __getosreldate();
+                       if (osreldate != 0) {
+                               *(int *)buf = osreldate;
+                               res = 0;
+                       } else
+                               res = ENOENT;
+               } else
+                       res = EINVAL;
+               break;
+       case AT_NCPUS:
+               if (buflen == sizeof(int)) {
+                       if (ncpus == 0)
+                               ncpus = __getncpus();
+                       if (ncpus != 0) {
+                               *(int *)buf = ncpus;
+                               res = 0;
+                       } else
+                               res = ENOENT;
+               } else
+                       res = EINVAL;
+               break;
+       default:
+               res = ENOENT;
+               break;
+       }
+       return (res);
+}
diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h
index 06086b4..928e3ed 100644
--- a/libexec/rtld-elf/rtld.h
+++ b/libexec/rtld-elf/rtld.h
@@ -286,7 +286,7 @@ const Ver_Entry *fetch_ventry(const Obj_Entry *obj, 
unsigned long);
  * MD function declarations.
  */
 int do_copy_relocations(Obj_Entry *);
-int reloc_non_plt(Obj_Entry *, Obj_Entry *);
+int reloc_non_plt(Obj_Entry *, Obj_Entry *, bool);
 int reloc_plt(Obj_Entry *);
 int reloc_jmpslots(Obj_Entry *);
 void allocate_initial_tls(Obj_Entry *);
diff --git a/sys/amd64/include/elf.h b/sys/amd64/include/elf.h
index e5c95f7..d541b9e 100644
--- a/sys/amd64/include/elf.h
+++ b/sys/amd64/include/elf.h
@@ -87,8 +87,12 @@ __ElfType(Auxinfo);
 #define        AT_GID          13      /* Real gid. */
 #define        AT_EGID         14      /* Effective gid. */
 #define        AT_EXECPATH     15      /* Path to the executable. */
+#define        AT_CANARY       16      /* Canary for SSP */
+#define        AT_CANARYLEN    17      /* Length of the canary. */
+#define        AT_OSRELDATE    18      /* OSRELDATE. */
+#define        AT_NCPUS        19      /* Number of CPUs. */
 
-#define        AT_COUNT        16      /* Count of defined aux entry types. */
+#define        AT_COUNT        20      /* Count of defined aux entry types. */
 
 /*
  * Relocation types.
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index af8168e..acf2c34 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -191,6 +191,7 @@ ia32_copyout_strings(struct image_params *imgp)
        struct freebsd32_ps_strings *arginfo;
        size_t execpath_len;
        int szsigcode;
+       char canary[sizeof(long) * 8];
 
        /*
         * Calculate string base and vector table pointers.
@@ -203,8 +204,9 @@ ia32_copyout_strings(struct image_params *imgp)
        arginfo = (struct freebsd32_ps_strings *)FREEBSD32_PS_STRINGS;
        szsigcode = *(imgp->proc->p_sysent->sv_szsigcode);
        destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
-               roundup(execpath_len, sizeof(char *)) -
-               roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
+           roundup(execpath_len, sizeof(char *)) -
+           roundup(sizeof(canary), sizeof(char *)) -
+           roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
 
        /*
         * install sigcode
@@ -223,6 +225,14 @@ ia32_copyout_strings(struct image_params *imgp)
        }
 
        /*
+        * Prepare the canary for SSP.
+        */
+       arc4rand(canary, sizeof(canary), 0);
+       imgp->canary = (uintptr_t)arginfo - szsigcode - execpath_len -
+           sizeof(canary);
+       copyout(canary, (void *)imgp->canary, sizeof(canary));
+
+       /*
         * If we have a valid auxargs ptr, prepare some room
         * on the stack.
         */
@@ -239,8 +249,8 @@ ia32_copyout_strings(struct image_params *imgp)
                 * for argument of Runtime loader.
                 */
                vectp = (u_int32_t *) (destp - (imgp->args->argc +
-                   imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) *
-                   sizeof(u_int32_t));
+                   imgp->args->envc + 2 + imgp->auxarg_size)
+                   * sizeof(u_int32_t));
        } else
                /*
                 * The '+ 2' is for the null pointers at the end of each of
diff --git a/sys/i386/include/elf.h b/sys/i386/include/elf.h
index af71ab8..a959e68 100644
--- a/sys/i386/include/elf.h
+++ b/sys/i386/include/elf.h
@@ -90,8 +90,12 @@ __ElfType(Auxinfo);
 #define        AT_GID          13      /* Real gid. */
 #define        AT_EGID         14      /* Effective gid. */
 #define        AT_EXECPATH     15      /* Path to the executable. */
+#define        AT_CANARY       16      /* Canary for SSP. */
+#define        AT_CANARYLEN    17      /* Length of the canary. */
+#define        AT_OSRELDATE    18      /* OSRELDATE. */
+#define        AT_NCPUS        19      /* Number of CPUs. */
 
-#define        AT_COUNT        16      /* Count of defined aux entry types. */
+#define        AT_COUNT        20      /* Count of defined aux entry types. */
 
 /*
  * Relocation types.
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index e2c0a12..b2c1d45 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/procfs.h>
 #include <sys/resourcevar.h>
 #include <sys/sf_buf.h>
+#include <sys/smp.h>
 #include <sys/systm.h>
 #include <sys/signalvar.h>
 #include <sys/stat.h>
@@ -887,6 +888,12 @@ __elfN(freebsd_fixup)(register_t **stack_base, struct 
image_params *imgp)
        AUXARGS_ENTRY(pos, AT_BASE, args->base);
        if (imgp->execpathp != 0)
                AUXARGS_ENTRY(pos, AT_EXECPATH, imgp->execpathp);
+       AUXARGS_ENTRY(pos, AT_OSRELDATE, imgp->proc->p_osrel);
+       if (imgp->canary != 0) {
+               AUXARGS_ENTRY(pos, AT_CANARY, imgp->canary);
+               AUXARGS_ENTRY(pos, AT_CANARYLEN, imgp->canarylen);
+       }
+       AUXARGS_ENTRY(pos, AT_NCPUS, mp_ncpus);
        AUXARGS_ENTRY(pos, AT_NULL, 0);
 
        free(imgp->auxargs, M_TEMP);
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 3f36658..6bed93f 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -380,6 +380,8 @@ do_execve(td, args, mac_p)
        imgp->args = args;
        imgp->execpath = imgp->freepath = NULL;
        imgp->execpathp = 0;
+       imgp->canary = 0;
+       imgp->canarylen = 0;
 
 #ifdef MAC
        error = mac_execve_enter(imgp, mac_p);
@@ -1175,6 +1177,7 @@ exec_copyout_strings(imgp)
        struct proc *p;
        size_t execpath_len;
        int szsigcode;
+       char canary[sizeof(long) * 8];
 
        /*
         * Calculate string base and vector table pointers.
@@ -1191,6 +1194,7 @@ exec_copyout_strings(imgp)
                szsigcode = *(p->p_sysent->sv_szsigcode);
        destp = (caddr_t)arginfo - szsigcode - SPARE_USRSPACE -
            roundup(execpath_len, sizeof(char *)) -
+           roundup(sizeof(canary), sizeof(char *)) -
            roundup((ARG_MAX - imgp->args->stringspace), sizeof(char *));
 
        /*
@@ -1210,6 +1214,15 @@ exec_copyout_strings(imgp)
        }
 
        /*
+        * Prepare the canary for SSP.
+        */
+       arc4rand(canary, sizeof(canary), 0);
+       imgp->canary = (uintptr_t)arginfo - szsigcode - execpath_len -
+           sizeof(canary);
+       copyout(canary, (void *)imgp->canary, sizeof(canary));
+       imgp->canarylen = sizeof(canary);
+
+       /*
         * If we have a valid auxargs ptr, prepare some room
         * on the stack.
         */
@@ -1226,8 +1239,8 @@ exec_copyout_strings(imgp)
                 * for argument of Runtime loader.
                 */
                vectp = (char **)(destp - (imgp->args->argc +
-                   imgp->args->envc + 2 + imgp->auxarg_size + execpath_len) *
-                   sizeof(char *));
+                   imgp->args->envc + 2 + imgp->auxarg_size)
+                   * sizeof(char *));
        } else {
                /*
                 * The '+ 2' is for the null pointers at the end of each of
diff --git a/sys/sys/imgact.h b/sys/sys/imgact.h
index e6acc00..8acd184 100644
--- a/sys/sys/imgact.h
+++ b/sys/sys/imgact.h
@@ -69,6 +69,8 @@ struct image_params {
        char *execpath;
        unsigned long execpathp;
        char *freepath;
+       unsigned long canary;
+       int canarylen;
 };
 
 #ifdef _KERNEL
diff --git a/sys/sys/link_elf.h b/sys/sys/link_elf.h
index 98840a5..30f3d75 100644
--- a/sys/sys/link_elf.h
+++ b/sys/sys/link_elf.h
@@ -92,6 +92,10 @@ __BEGIN_DECLS
 
 typedef int (*__dl_iterate_hdr_callback)(struct dl_phdr_info *, size_t, void 
*);
 extern int dl_iterate_phdr(__dl_iterate_hdr_callback, void *);
+extern int _rtld_aux_info(int, void *, int);
+#ifndef IN_RTLD
+#pragma weak _rtld_aux_info
+#endif
 
 __END_DECLS
 

Attachment: pgpy5Cv1gLEe7.pgp
Description: PGP signature

Reply via email to