11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * All rights reserved. 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met: 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions of source code must retain the above copyright 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer. 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * * Redistributions in binary form must reproduce the above copyright 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * notice, this list of conditions and the following disclaimer in 121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the documentation and/or other materials provided with the 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distribution. 141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE. 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * libc_init_static.c 301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 31b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * The program startup function __libc_init() defined here is 32b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * used for static executables only (i.e. those that don't depend 33b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * on shared libraries). It is called from arch-$ARCH/bionic/crtbegin_static.S 34b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * which is directly invoked by the kernel when the program is launched. 351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 36b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * The 'structors' parameter contains pointers to various initializer 37b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner * arrays that must be run before the program's 'main' routine is launched. 381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 4042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <elf.h> 4142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <errno.h> 421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stddef.h> 4342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <stdint.h> 441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h> 451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h> 4642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <sys/auxv.h> 4742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include <sys/mman.h> 4842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes 493a654b1e04d4275ae315cfe1b196998acf10052cDavid 'Digit' Turner#include "atexit.h" 5042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include "bionic_tls.h" 5142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include "KernelArgumentBlock.h" 521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "libc_init_common.h" 5342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes#include "pthread_internal.h" 54ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich 55ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich// Returns the address of the page containing address 'x'. 56ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich#define PAGE_START(x) ((x) & PAGE_MASK) 57ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich 58ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich// Returns the address of the next page after address 'x', unless 'x' is 59ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich// itself at the start of a page. 60ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE-1)) 613a654b1e04d4275ae315cfe1b196998acf10052cDavid 'Digit' Turner 6242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughesstatic void call_array(void(**list)()) { 6342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // First element is -1, list is null-terminated 6442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes while (*++list) { 6542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes (*list)(); 6642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 67b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner} 68b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 692c5153b043b44e9935a334ae9b2d5a4bc5258b40Nick Kralevichstatic void apply_gnu_relro() { 7042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes Elf32_Phdr* phdr_start = reinterpret_cast<Elf32_Phdr*>(getauxval(AT_PHDR)); 7142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes unsigned long int phdr_ct = getauxval(AT_PHNUM); 72ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich 7342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes for (Elf32_Phdr* phdr = phdr_start; phdr < (phdr_start + phdr_ct); phdr++) { 7442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes if (phdr->p_type != PT_GNU_RELRO) { 7542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes continue; 76ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich } 77ac3de8d080745e62c77fdf03e3923726d0a6b50dNick Kralevich 7842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes Elf32_Addr seg_page_start = PAGE_START(phdr->p_vaddr); 7942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes Elf32_Addr seg_page_end = PAGE_END(phdr->p_vaddr + phdr->p_memsz); 80b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 8142b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Check return value here? What do we do if we fail? 8242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes mprotect(reinterpret_cast<void*>(seg_page_start), seg_page_end - seg_page_start, PROT_READ); 8342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 8442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes} 85b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 8642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes__noreturn void __libc_init(void* raw_args, 8742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes void (*onexit)(void), 8842b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes int (*slingshot)(int, char**, char**), 8942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes structors_array_t const * const structors) { 9042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes KernelArgumentBlock args(raw_args); 91d3920b3a996b358e48232f417aa0a1e44a60f155Elliott Hughes __libc_init_tls(args); 9242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes __libc_init_common(args); 93b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 9442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes apply_gnu_relro(); 95b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 9642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // Several Linux ABIs don't pass the onexit pointer, and the ones that 9742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // do never use it. Therefore, we ignore it. 98b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 9942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes call_array(structors->preinit_array); 10042b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes call_array(structors->init_array); 101b56b5659b3996e98c2060f168d1cff1474e77d2aDavid 'Digit' Turner 10242b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // The executable may have its own destructors listed in its .fini_array 10342b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // so we need to ensure that these are called when the program exits 10442b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes // normally. 10542b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes if (structors->fini_array != NULL) { 10642b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes __cxa_atexit(__libc_fini,structors->fini_array,NULL); 10742b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes } 1081df986c21ee52c6756846b4a5e45cb316f772112David 'Digit' Turner 10942b2c6a5eed5e4ef35315b8cd32d1355f12a69b6Elliott Hughes exit(slingshot(args.argc, args.argv, args.envp)); 1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 111