From patchwork Thu May 18 08:28:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: stsp X-Patchwork-Id: 55776 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7FA813846444 for ; Thu, 18 May 2023 08:30:08 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from forward101b.mail.yandex.net (forward101b.mail.yandex.net [178.154.239.148]) by sourceware.org (Postfix) with ESMTPS id 024F23858CDB for ; Thu, 18 May 2023 08:29:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 024F23858CDB Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=yandex.ru Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=yandex.ru Received: from mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net (mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net [IPv6:2a02:6b8:c0c:1186:0:640:38cb:0]) by forward101b.mail.yandex.net (Yandex) with ESMTP id 7B21060140 for ; Thu, 18 May 2023 11:29:35 +0300 (MSK) Received: by mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net (smtp/Yandex) with ESMTPSA id XTYe39MDZ0U0-unpgSMqq; Thu, 18 May 2023 11:29:35 +0300 X-Yandex-Fwd: 1 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1684398575; bh=ZP6HioIz8gbRvBtw47NlujyYohpgFC1oOCQo9wbum0g=; h=Message-Id:Date:Cc:Subject:To:From; b=VyZecfDbQCQZWMobHZeLfwUfqAUL8UYNhU/v8nOuP3Ib3HaT3Svb7wxBP22siy6r3 CZkp/KgBPBHyJujQM9ni17yH4tDxbMVMzTY9rr93g5sH0F/h09meusI35vfi/3HK87 BI//53Doordd6sO+pTCUu6U0Zm5etMmWT+bv5DLs= Authentication-Results: mail-nwsmtp-smtp-production-main-91.iva.yp-c.yandex.net; dkim=pass header.i=@yandex.ru From: Stas Sergeev To: libc-alpha@sourceware.org Cc: Stas Sergeev Subject: [PATCH 00/14] implement RTLD_NORELOCATE api [BZ #30007] Date: Thu, 18 May 2023 13:28:40 +0500 Message-Id: <20230518082854.3903342-1-stsp2@yandex.ru> X-Mailer: git-send-email 2.39.2 MIME-Version: 1.0 X-Spam-Status: No, score=-3.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces+patchwork=sourceware.org@sourceware.org Sender: "Libc-alpha" RTLD_NORELOCATE api is a proposal that adds a fine-grained control over the solib dynamic-load process. It allows the user to load the solib to the particular address he needs, using the mapping type he needs. The basic idea is that after loading the solib with RTLD_NORELOCATE flag, the user can move an unrelocated object before relocating it. The API consist of the following elements: `RTLD_NORELOCATE' - new dlopen() flag. It defers the relocation of an object, allowing to perform the relocation later. Ctors are delayed, and are called immediately after the relocation is done. Relocation is performed upon the first dlsym() or dlrelocate() call with the obtained handle. This flag doesn't delay the load of an object deps, but their relocation and ctors are delayed. This flag doesn't delay the LA_ACT_CONSISTENT audit event. `int dlrelocate(void *handle)' - new function to perform the object relocation if the RTLD_NORELOCATE flag was used. The object itself and all of its dependencies are relocated. Returns EINVAL if already relocated. This function may be omitted even if RTLD_NORELOCATE was used, in which case the relocation will be performed upon the first dlsym() call with the obtained handle, but using dlrelocate() function allows to handle relocation errors and run ctors before using the object's handle. If the function returned success then ctors of an object and all of its deps were called by it. If it returned error other than EINVAL (EINVAL means object already relocated), then relocation error happened and the handle should be closed with dlclose(). `RTLD_DI_MAPINFO' - new dlinfo() request that fills in this structure: typedef struct { void *map_start; /* Beginning of mapping containing address. */ size_t map_length; /* Length of mapping. */ size_t map_align; /* Alignment of mapping. */ int relocated; /* Indicates whether an object was relocated. */ } Dl_mapinfo; The user have to check the `relocated` member, and if it is 0 then the object can be moved to the new location. The new location must be aligned according to the `map_aligned' member, which is usually equal to a page size. One way to move a solib image is to use mmap() for allocating a new memory mapping, then use memcpy() to copy an image, and finally use munmap() to unmap the memory space at an old location. This request may fail if the used handle was not obtained from dlopen(). `int dlset_object_base(void *handle, void *addr)' - new function to set the new base address of an unrelocated object, after it was moved. Returns error if the object is already relocated. The base address set by this function, will be used when relocation is performed. `RTLD_DI_DEPLIST' is a new dlinfo() request that fills in this structure: typedef struct { void **deps; /* Array of handles for the deps. */ unsigned int ndeps; /* Number of entries in the list. */ } Dl_deplist; It is needed if the user wants to move also the dependencies of the loaded solib. In this case he needs to traverse the `deps' array, make RTLD_DI_MAPINFO dlinfo() request per each handle from an array, find the object he needs by inspecting the filled-in Dl_mapinfo structure, make sure this object is not relocated yet, and move it, calling dlset_object_base() at the end. Use-case. Suppose you have a VM that runs a 32bit code. Suppose you wrote a compatibility layer that allows to compile the old 32bit non-unix code under linux, into the native 64bit shared libraries. But compiling is not enough and some calls should still go to a VM. VM's memory is available in a 4Gb window somewhere in a 64bit space. In order for the code under VM to handle the calls from a 64bit solib, you need to make sure all pointers, that may be passed as a call arguments, are within 32 bits. Heap and stack are dealt with by a custom libc, but in order to use pointers to .bss objects, we need to relocate the solib to the low 32bit address. But that's not enough, because in order for that lib to be visible to the code under VM, it must also be mirrored to the VM window under the map_address = reloc_address+VM_window_start. RTLD_NORELOCATE solves that problem by allowing the user to mmap the shared memory into the low 32bit address space and move an object there. He may want to do so for all the library deps as well (using RTLD_DI_DEPLIST), or only with the ones he is interested in. Then he maps the shared memory into the VM window and either calls dlrelocate() or just starts using the solib, in which case it will be relocated on the first symbol lookup.