Date: Mon, 29 Jun 2026 20:33:31 +0000 From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 1e370f038778 - main - rtld: stop using unbound alloca() Message-ID: <6a42d69b.318e4.3be583aa@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=1e370f038778e16c4b31f8992dda339d429e5cb8 commit 1e370f038778e16c4b31f8992dda339d429e5cb8 Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2026-06-27 15:11:37 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2026-06-29 20:33:12 +0000 rtld: stop using unbound alloca() For DoneList allocations, its size depends on the number of loaded DSOs. Small images could be served by alloca(), but large donelists need to go into heap. For map_object(), alloca size is the number of segments in the object. In both cases, over-grown situations would cause a stack overflow. PR: 295991 Noted and reviewed by: kevans Tested by: Marek Zarychta <zarychtam@plan-b.pwste.edu.pl> Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D57908 --- libexec/rtld-elf/map_object.c | 4 ++- libexec/rtld-elf/rtld.c | 82 ++++++++++++++++++++++++++++++------------- libexec/rtld-elf/rtld.h | 2 ++ 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c index 6c6f0c9289b9..d769d01d3b24 100644 --- a/libexec/rtld-elf/map_object.c +++ b/libexec/rtld-elf/map_object.c @@ -113,7 +113,7 @@ map_object(int fd, const char *path, const struct stat *sb, bool ismain) note_end = 0; note_map = NULL; note_map_len = 0; - segs = alloca(sizeof(segs[0]) * hdr->e_phnum); + segs = xcalloc(hdr->e_phnum, sizeof(segs[0])); stack_flags = PF_X | PF_R | PF_W; text_end = 0; while (phdr < phlimit) { @@ -341,6 +341,7 @@ map_object(int fd, const char *path, const struct stat *sb, bool ismain) if (note_map != NULL) munmap(note_map, note_map_len); munmap(hdr, page_size); + free(segs); return (obj); error1: @@ -351,6 +352,7 @@ error: if (!phdr_in_zero_page(hdr)) munmap(phdr, hdr->e_phnum * sizeof(phdr[0])); munmap(hdr, page_size); + free(segs); return (NULL); } diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index 938e4b0b8a6b..864148df99ba 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -342,16 +342,6 @@ const char *ld_env_prefix = LD_; static void (*rtld_exit_ptr)(void); -/* - * Fill in a DoneList with an allocation large enough to hold all of - * the currently-loaded objects. Keep this as a macro since it calls - * alloca and we want that to occur within the scope of the caller. - */ -#define donelist_init(dlp) \ - ((dlp)->objs = alloca(obj_count * sizeof(dlp)->objs[0]), \ - assert((dlp)->objs != NULL), (dlp)->num_alloc = obj_count, \ - (dlp)->num_used = 0) - #define LD_UTRACE(e, h, mb, ms, r, n) \ do { \ if (ld_utrace != NULL) \ @@ -1042,6 +1032,38 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) return ((func_ptr_type)obj_main->entry); } +/* + * Fill in a DoneList with an allocation large enough to hold all of + * the currently-loaded Keep this as a macro since it calls + * alloca and we want that to occur within the scope of the caller. + */ +#define DLP_ALLOCA_LIMIT 100 /* 800 bytes on LP64 */ +#define donelist_init(_DLP, _REQ) do { \ + DoneList *_dlp = _DLP; \ + SymLook *_r = _REQ; \ + _dlp->num_alloc = obj_count, \ + _dlp->req = NULL; \ + if (_dlp->num_alloc > DLP_ALLOCA_LIMIT) { \ + _dlp->objs = xcalloc(_dlp->num_alloc, sizeof(_dlp->objs[0])); \ + if (_r != NULL && _r->donelist_mem == NULL) { \ + _r->donelist_mem = _dlp->objs; \ + _dlp->req = _r; \ + } \ + } else { \ + _dlp->objs = alloca(_dlp->num_alloc * sizeof(_dlp->objs[0])); \ + } \ + _dlp->num_used = 0; \ +} while (0) + +static void +donelist_free(DoneList *dlp) +{ + if (dlp->num_alloc > DLP_ALLOCA_LIMIT) + free(dlp->objs); + if (dlp->req != NULL) + dlp->req->donelist_mem = NULL; +} + void * rtld_resolve_ifunc(const Obj_Entry *obj, const Elf_Sym *def) { @@ -2319,7 +2341,7 @@ init_dag(Obj_Entry *root) if (root->dag_inited) return; - donelist_init(&donelist); + donelist_init(&donelist, NULL); /* Root object belongs to own DAG. */ objlist_push_tail(&root->dldags, root); @@ -2342,6 +2364,7 @@ init_dag(Obj_Entry *root) } } root->dag_inited = true; + donelist_free(&donelist); } static void @@ -4103,8 +4126,11 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, LD_UTRACE(UTRACE_DLSYM_START, handle, NULL, 0, 0, name); rlock_acquire(rtld_bind_lock, &lockstate); - if (sigsetjmp(lockstate.env, 0) != 0) + if (sigsetjmp(lockstate.env, 0) != 0) { lock_upgrade(rtld_bind_lock, &lockstate); + free(req.donelist_mem); + req.donelist_mem = NULL; + } if (handle == NULL || handle == RTLD_NEXT || handle == RTLD_DEFAULT || handle == RTLD_SELF) { if ((obj = obj_from_addr(retaddr)) == NULL) { @@ -4173,7 +4199,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, return (NULL); } - donelist_init(&donelist); + donelist_init(&donelist, &req); if (obj->mainprog) { /* Handle obtained by dlopen(NULL, ...) implies global * scope. */ @@ -4204,6 +4230,7 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve, defobj = req.defobj_out; } } + donelist_free(&donelist); } if (def != NULL) { @@ -4731,21 +4758,24 @@ get_program_var_addr(const char *name, RtldLockState *lockstate) { SymLook req; DoneList donelist; + const void **res; symlook_init(&req, name); req.lockstate = lockstate; - donelist_init(&donelist); + donelist_init(&donelist, NULL); if (symlook_global(&req, &donelist) != 0) return (NULL); if (ELF_ST_TYPE(req.sym_out->st_info) == STT_FUNC) - return ((const void **)make_function_pointer(req.sym_out, - req.defobj_out)); + res = (const void **)make_function_pointer(req.sym_out, + req.defobj_out); else if (ELF_ST_TYPE(req.sym_out->st_info) == STT_GNU_IFUNC) - return ((const void **)rtld_resolve_ifunc(req.defobj_out, - req.sym_out)); + res = (const void **)rtld_resolve_ifunc(req.defobj_out, + req.sym_out); else - return ((const void **)(req.defobj_out->relocbase + - req.sym_out->st_value)); + res = (const void **)(req.defobj_out->relocbase + + req.sym_out->st_value); + donelist_free(&donelist); + return (res); } /* @@ -4820,7 +4850,7 @@ symlook_default(SymLook *req, const Obj_Entry *refobj) SymLook req1; int res; - donelist_init(&donelist); + donelist_init(&donelist, req); symlook_init_from_req(&req1, req); /* @@ -4873,6 +4903,7 @@ symlook_default(SymLook *req, const Obj_Entry *refobj) } } + donelist_free(&donelist); return (req->sym_out != NULL ? 0 : ESRCH); } @@ -4954,13 +4985,15 @@ symlook_obj_load_filtees(SymLook *req, SymLook *req1, const Obj_Entry *obj, Needed_Entry *needed) { DoneList donelist; - int flags; + int flags, res; flags = (req->flags & SYMLOOK_EARLY) != 0 ? RTLD_LO_EARLY : 0; load_filtees(__DECONST(Obj_Entry *, obj), flags, req->lockstate); - donelist_init(&donelist); + donelist_init(&donelist, NULL); symlook_init_from_req(req1, req); - return (symlook_needed(req1, needed, &donelist)); + res = symlook_needed(req1, needed, &donelist); + donelist_free(&donelist); + return (res); } /* @@ -6305,6 +6338,7 @@ symlook_init_from_req(SymLook *dst, const SymLook *src) dst->defobj_out = NULL; dst->sym_out = NULL; dst->lockstate = src->lockstate; + dst->donelist_mem = NULL; } static int diff --git a/libexec/rtld-elf/rtld.h b/libexec/rtld-elf/rtld.h index 322d1ee94d6f..bdcfc3dc5ded 100644 --- a/libexec/rtld-elf/rtld.h +++ b/libexec/rtld-elf/rtld.h @@ -319,6 +319,7 @@ typedef struct Struct_SymCache { */ typedef struct Struct_DoneList { const Obj_Entry **objs; /* Array of object pointers */ + struct Struct_SymLook *req; unsigned int num_alloc; /* Allocated size of the array */ unsigned int num_used; /* Number of array slots used */ } DoneList; @@ -348,6 +349,7 @@ typedef struct Struct_SymLook { const Obj_Entry *defobj_out; const Elf_Sym *sym_out; struct Struct_RtldLockState *lockstate; + void *donelist_mem; } SymLook; enum {home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a42d69b.318e4.3be583aa>
