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
pgpy5Cv1gLEe7.pgp
Description: PGP signature