Avoiding sysctl at program startup using ELF aux vector (was:
concurrent sysctl implementation)
Jeremie Le Hen
jeremie at le-hen.org
Wed Jun 23 21:10:10 UTC 2010
Hi Kostik,
This patch seems to have faded out from memory. Is it possible to go
forward and commit it?
Thanks,
Regards.
On Sat, Jul 25, 2009 at 12:29:16AM +0300, Kostik Belousov wrote:
> 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
>
--
Jeremie Le Hen
Humans are born free and equal. But some are more equal than others.
Coluche
More information about the freebsd-hackers
mailing list