Date: Mon, 06 Jul 2026 01:06:17 +0000 From: Konstantin Belousov <kib@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org Subject: git: 682ebe10032d - stable/15 - rtld: stop using unbound alloca() Message-ID: <6a4aff89.3a4a0.f4f7824@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch stable/15 has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=682ebe10032d4e682381eb5f108a8297be7b682c commit 682ebe10032d4e682381eb5f108a8297be7b682c Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2026-06-27 15:11:37 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2026-07-06 01:05:50 +0000 rtld: stop using unbound alloca() PR: 295991 (cherry picked from commit 1e370f038778e16c4b31f8992dda339d429e5cb8) --- 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?6a4aff89.3a4a0.f4f7824>
