From 46e5095ebfe63be4dcd813c4237d6a491a3f9768 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 13 Feb 2023 18:15:34 +0500 Subject: [PATCH v10 0/12] implement dlmem() function Changes in v10: - squashed patch 1 as suggested by Adhemerval Zanella - fixed a few bugs in an elf relocation machinery after various hot discussions - added a new test tst-dlmem-dloff that demo-implements dlopen_with_offset() Changes in v9: - use "zero-copy" machinery instead of memcpy(). It works on linux 5.13 and newer, falling back to memcpy() otherwise. Suggested by Florian Weimer. - implement fdlopen() using the above functionality. It is in a new test tst-dlmem-fdlopen. Suggested by Carlos O'Donell. - add DLMEM_DONTREPLACE flag that doesn't replace the backing-store mapping. It switches back to memcpy(). Test-case is called tst-dlmem-shm. Changes in v8: - drop audit machinery and instead add an extra arg (optional pointer to a struct) to dlmem() itself that allows to install a custom premap callback or to specify nsid. Audit machinery was meant to allow controling over the pre-existing APIs like dlopen(), but if someone ever needs such extensions to dlopen(), he can trivially implement dlopen() on top of dlmem(). Changes in v7: - add _dl_audit_premap audit extension and its usage example Changes in v6: - use __strdup("") for l_name as suggested by Andreas Schwab Changes in v5: - added _dl_audit_premap_dlmem audit extension for dlmem - added tst-auditmod-dlmem.c test-case that feeds shm fd to dlmem() Changes in v4: - re-target to GLIBC_2.38 - add tst-auditdlmem.c test-case to test auditing - drop length page-aligning in tst-dlmem: mmap() aligns length on its own - bugfix: in do_mmapcpy() allow mmaps past end of buffer Changes in v3: - Changed prototype of dlmem() (and all the internal machinery) to use "const unsigned char *buffer" instead of "const char *buffer". Changes in v2: - use instead of "../test-skeleton.c" - re-target to GLIBC_2.37 - update all libc.abilist files This patch-set implements the dlmem() function that allows to load the solib from page-aligned memory buffer. It has lots of optional functionality for the fine-grained control over the loading process. The API looks as below: /* Callback for dlmem. */ typedef void * (dlmem_premap_t) (void *mappref, size_t maplength, size_t mapalign, void *cookie); /* Do not replace mapping created by premap callback. dlmem() will then use memcpy(). */ #define DLMEM_DONTREPLACE 1 struct dlmem_args { /* Optional name to associate with the loaded object. */ const char *soname; /* Namespace where to load the object. */ Lmid_t nsid; /* dlmem-specific flags. */ unsigned flags; /* Optional premap callback. */ dlmem_premap_t *premap; /* Optional argument for premap callback. */ void *cookie; }; /* Like `dlmopen', but loads shared object from memory buffer. */ extern void *dlmem (const unsigned char *buffer, size_t size, int mode, struct dlmem_args *dlm_args); In most cases dlm_args should just be set to NULL. It provides the advanced functionality, most of which is obvious (soname, nsid). The premap callback allows to set the relocation address for the solib. More so, if DLMEM_DONTREPLACE flag is used, then the mapping established by the premap callback, will not be replaced with the file-backed mapping. In that case dlmem() have to use memcpy(), which is likely even faster than mmaps() but doesn't end up with the proper /proc/self/map_files or /proc/self/maps entries. So for example if the premap callback uses MAP_SHARED, then with the use of the DLMEM_DONTREPLACE flag you can get your solib relocated into a shared memory buffer. Such functionality may be interesting for virtualized environments where the relocation address may have a special constraints, like eg MAP_32BIT. -- 2.37.2