2014-02-06 15:34:21 +01:00
/*
* Copyright ( C ) 2014 The Android Open Source Project
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# include <gtest/gtest.h>
# include <dlfcn.h>
2014-11-04 20:08:05 +01:00
# include <elf.h>
2014-02-27 14:18:00 +01:00
# include <errno.h>
# include <fcntl.h>
2014-11-04 20:08:05 +01:00
# include <inttypes.h>
2014-02-27 14:18:00 +01:00
# include <stdio.h>
# include <string.h>
# include <unistd.h>
2017-04-21 22:12:05 +02:00
2014-02-06 15:34:21 +01:00
# include <android/dlext.h>
2017-04-25 05:07:19 +02:00
# include <android-base/strings.h>
2017-04-21 22:12:05 +02:00
# include <linux/memfd.h>
2014-02-06 15:34:21 +01:00
# include <sys/mman.h>
2017-06-20 23:26:56 +02:00
# include <sys/syscall.h>
2014-05-02 15:57:42 +02:00
# include <sys/types.h>
2017-04-21 22:12:05 +02:00
# include <sys/vfs.h>
2014-02-27 14:18:00 +01:00
# include <sys/wait.h>
2014-02-06 15:34:21 +01:00
2014-05-02 15:57:42 +02:00
# include <pagemap/pagemap.h>
2016-01-20 05:32:37 +01:00
# include <ziparchive/zip_archive.h>
2014-05-02 15:57:42 +02:00
2016-09-21 20:17:13 +02:00
# include "gtest_globals.h"
2014-12-08 05:43:37 +01:00
# include "TemporaryFile.h"
2015-11-23 20:26:35 +01:00
# include "utils.h"
2016-05-10 02:37:39 +02:00
# include "dlext_private.h"
2016-09-19 19:50:28 +02:00
# include "dlfcn_symlink_support.h"
2014-02-06 15:34:21 +01:00
# define ASSERT_DL_NOTNULL(ptr) \
2016-06-03 19:18:07 +02:00
ASSERT_TRUE ( ( ptr ) ! = nullptr ) < < " dlerror: " < < dlerror ( )
2014-02-06 15:34:21 +01:00
# define ASSERT_DL_ZERO(i) \
ASSERT_EQ ( 0 , i ) < < " dlerror: " < < dlerror ( )
2014-02-27 14:18:00 +01:00
# define ASSERT_NOERROR(i) \
ASSERT_NE ( - 1 , i ) < < " errno: " < < strerror ( errno )
2014-11-04 20:08:05 +01:00
# define ASSERT_SUBSTR(needle, haystack) \
ASSERT_PRED_FORMAT2 ( : : testing : : IsSubstring , needle , haystack )
2014-02-06 15:34:21 +01:00
typedef int ( * fn ) ( void ) ;
2016-09-21 20:17:13 +02:00
constexpr const char * kLibName = " libdlext_test.so " ;
constexpr const char * kLibNameNoRelro = " libdlext_test_norelro.so " ;
constexpr const char * kLibZipSimpleZip = " libdir/libatest_simple_zip.so " ;
constexpr auto kLibSize = 1024 * 1024 ; // how much address space to reserve for it
2014-10-04 02:52:44 +02:00
2014-02-06 15:34:21 +01:00
class DlExtTest : public : : testing : : Test {
protected :
virtual void SetUp ( ) {
2014-10-04 02:52:44 +02:00
handle_ = nullptr ;
2014-02-06 15:34:21 +01:00
// verify that we don't have the library loaded already
2016-09-21 20:17:13 +02:00
void * h = dlopen ( kLibName , RTLD_NOW | RTLD_NOLOAD ) ;
2014-10-04 02:52:44 +02:00
ASSERT_TRUE ( h = = nullptr ) ;
2016-09-21 20:17:13 +02:00
h = dlopen ( kLibNameNoRelro , RTLD_NOW | RTLD_NOLOAD ) ;
2014-10-04 02:52:44 +02:00
ASSERT_TRUE ( h = = nullptr ) ;
2014-02-06 15:34:21 +01:00
// call dlerror() to swallow the error, and check it was the one we wanted
2016-09-21 20:17:13 +02:00
ASSERT_EQ ( std : : string ( " dlopen failed: library \" " ) + kLibNameNoRelro + " \" wasn't loaded and RTLD_NOLOAD prevented it " , dlerror ( ) ) ;
2014-02-06 15:34:21 +01:00
}
virtual void TearDown ( ) {
2014-10-04 02:52:44 +02:00
if ( handle_ ! = nullptr ) {
2014-02-06 15:34:21 +01:00
ASSERT_DL_ZERO ( dlclose ( handle_ ) ) ;
}
}
void * handle_ ;
} ;
TEST_F ( DlExtTest , ExtInfoNull ) {
2016-09-21 20:17:13 +02:00
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , nullptr ) ;
2014-02-06 15:34:21 +01:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
EXPECT_EQ ( 4 , f ( ) ) ;
}
TEST_F ( DlExtTest , ExtInfoNoFlags ) {
android_dlextinfo extinfo ;
extinfo . flags = 0 ;
2016-09-21 20:17:13 +02:00
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2014-02-06 15:34:21 +01:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
EXPECT_EQ ( 4 , f ( ) ) ;
}
2014-07-01 23:10:16 +02:00
TEST_F ( DlExtTest , ExtInfoUseFd ) {
2016-11-25 21:23:11 +01:00
const std : : string lib_path = get_testlib_root ( ) + " /libdlext_test_fd/libdlext_test_fd.so " ;
2014-07-01 23:10:16 +02:00
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_LIBRARY_FD ;
2015-03-19 06:50:01 +01:00
extinfo . library_fd = TEMP_FAILURE_RETRY ( open ( lib_path . c_str ( ) , O_RDONLY | O_CLOEXEC ) ) ;
2014-07-01 23:10:16 +02:00
ASSERT_TRUE ( extinfo . library_fd ! = - 1 ) ;
2015-03-19 06:50:01 +01:00
handle_ = android_dlopen_ext ( lib_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
2014-07-01 23:10:16 +02:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
EXPECT_EQ ( 4 , f ( ) ) ;
2015-09-03 01:32:02 +02:00
uint32_t * taxicab_number = reinterpret_cast < uint32_t * > ( dlsym ( handle_ , " dlopen_testlib_taxicab_number " ) ) ;
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
2014-07-01 23:10:16 +02:00
}
2014-10-04 02:52:44 +02:00
TEST_F ( DlExtTest , ExtInfoUseFdWithOffset ) {
2016-11-25 21:23:11 +01:00
const std : : string lib_path = get_testlib_root ( ) + " /libdlext_test_zip/libdlext_test_zip_zipaligned.zip " ;
2014-10-04 02:52:44 +02:00
android_dlextinfo extinfo ;
2014-10-21 21:09:18 +02:00
extinfo . flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET ;
2015-03-19 06:50:01 +01:00
extinfo . library_fd = TEMP_FAILURE_RETRY ( open ( lib_path . c_str ( ) , O_RDONLY | O_CLOEXEC ) ) ;
2016-01-20 05:32:37 +01:00
// Find the offset of the shared library in the zip.
ZipArchiveHandle handle ;
ASSERT_EQ ( 0 , OpenArchive ( lib_path . c_str ( ) , & handle ) ) ;
ZipEntry zip_entry ;
ZipString zip_name ;
2016-09-21 20:17:13 +02:00
zip_name . name = reinterpret_cast < const uint8_t * > ( kLibZipSimpleZip ) ;
zip_name . name_length = strlen ( kLibZipSimpleZip ) ;
2016-01-20 05:32:37 +01:00
ASSERT_EQ ( 0 , FindEntry ( handle , zip_name , & zip_entry ) ) ;
extinfo . library_fd_offset = zip_entry . offset ;
CloseArchive ( handle ) ;
2014-10-04 02:52:44 +02:00
2015-03-19 06:50:01 +01:00
handle_ = android_dlopen_ext ( lib_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
2014-10-04 02:52:44 +02:00
ASSERT_DL_NOTNULL ( handle_ ) ;
2015-09-29 01:38:31 +02:00
uint32_t * taxicab_number = reinterpret_cast < uint32_t * > ( dlsym ( handle_ , " dlopen_testlib_taxicab_number " ) ) ;
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
2014-10-04 02:52:44 +02:00
}
TEST_F ( DlExtTest , ExtInfoUseFdWithInvalidOffset ) {
2016-11-25 21:23:11 +01:00
const std : : string lib_path = get_testlib_root ( ) + " /libdlext_test_zip/libdlext_test_zip_zipaligned.zip " ;
2014-10-04 02:52:44 +02:00
android_dlextinfo extinfo ;
2014-10-21 21:09:18 +02:00
extinfo . flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET ;
2015-03-19 06:50:01 +01:00
extinfo . library_fd = TEMP_FAILURE_RETRY ( open ( lib_path . c_str ( ) , O_RDONLY | O_CLOEXEC ) ) ;
2014-10-21 21:09:18 +02:00
extinfo . library_fd_offset = 17 ;
2014-10-04 02:52:44 +02:00
handle_ = android_dlopen_ext ( " libname_placeholder " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle_ = = nullptr ) ;
2014-10-21 21:09:18 +02:00
ASSERT_STREQ ( " dlopen failed: file offset for the library \" libname_placeholder \" is not page-aligned: 17 " , dlerror ( ) ) ;
2014-11-04 20:08:05 +01:00
// Test an address above 2^44, for http://b/18178121 .
extinfo . library_fd_offset = ( 5LL < < 48 ) + PAGE_SIZE ;
handle_ = android_dlopen_ext ( " libname_placeholder " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle_ = = nullptr ) ;
ASSERT_SUBSTR ( " dlopen failed: file offset for the library \" libname_placeholder \" >= file size " , dlerror ( ) ) ;
extinfo . library_fd_offset = 0LL - PAGE_SIZE ;
2014-10-21 21:09:18 +02:00
handle_ = android_dlopen_ext ( " libname_placeholder " , RTLD_NOW , & extinfo ) ;
2014-11-04 20:08:05 +01:00
ASSERT_TRUE ( handle_ = = nullptr ) ;
ASSERT_SUBSTR ( " dlopen failed: file offset for the library \" libname_placeholder \" is negative " , dlerror ( ) ) ;
2014-10-21 21:09:18 +02:00
2015-09-29 01:38:31 +02:00
extinfo . library_fd_offset = 0 ;
2015-03-31 20:14:03 +02:00
handle_ = android_dlopen_ext ( " libname_ignored " , RTLD_NOW , & extinfo ) ;
2014-10-21 21:09:18 +02:00
ASSERT_TRUE ( handle_ = = nullptr ) ;
2016-09-01 20:37:39 +02:00
ASSERT_EQ ( " dlopen failed: \" " + lib_path + " \" has bad ELF magic " , dlerror ( ) ) ;
2014-10-21 21:09:18 +02:00
2015-11-06 19:44:37 +01:00
// Check if dlsym works after unsuccessful dlopen().
// Supply non-exiting one to make linker visit every soinfo.
void * sym = dlsym ( RTLD_DEFAULT , " this_symbol_does_not_exist___ " ) ;
ASSERT_TRUE ( sym = = nullptr ) ;
2014-10-21 21:09:18 +02:00
close ( extinfo . library_fd ) ;
2014-10-04 02:52:44 +02:00
}
2016-01-20 05:32:37 +01:00
TEST_F ( DlExtTest , ExtInfoUseOffsetWithoutFd ) {
2014-10-04 02:52:44 +02:00
android_dlextinfo extinfo ;
2014-10-21 21:09:18 +02:00
extinfo . flags = ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET ;
2016-01-20 05:32:37 +01:00
// This offset will not be used, so it doesn't matter.
extinfo . library_fd_offset = 0 ;
2014-10-04 02:52:44 +02:00
handle_ = android_dlopen_ext ( " /some/lib/that/does_not_exist " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle_ = = nullptr ) ;
2014-10-21 21:09:18 +02:00
ASSERT_STREQ ( " dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20 " , dlerror ( ) ) ;
2014-10-04 02:52:44 +02:00
}
2015-04-03 01:03:56 +02:00
TEST ( dlext , android_dlopen_ext_force_load_smoke ) {
2016-09-19 19:50:28 +02:00
DlfcnSymlink symlink ( " android_dlopen_ext_force_load_smoke " ) ;
const std : : string symlink_name = basename ( symlink . get_symlink_path ( ) . c_str ( ) ) ;
2015-04-03 01:03:56 +02:00
// 1. Open actual file
void * handle = dlopen ( " libdlext_test.so " , RTLD_NOW ) ;
ASSERT_DL_NOTNULL ( handle ) ;
// 2. Open link with force_load flag set
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_FORCE_LOAD ;
2016-09-19 19:50:28 +02:00
void * handle2 = android_dlopen_ext ( symlink_name . c_str ( ) , RTLD_NOW , & extinfo ) ;
2015-04-03 01:03:56 +02:00
ASSERT_DL_NOTNULL ( handle2 ) ;
ASSERT_TRUE ( handle ! = handle2 ) ;
dlclose ( handle2 ) ;
dlclose ( handle ) ;
}
TEST ( dlext , android_dlopen_ext_force_load_soname_exception ) {
2016-09-19 19:50:28 +02:00
DlfcnSymlink symlink ( " android_dlopen_ext_force_load_soname_exception " ) ;
const std : : string symlink_name = basename ( symlink . get_symlink_path ( ) . c_str ( ) ) ;
2015-04-03 01:03:56 +02:00
// Check if soname lookup still returns already loaded library
// when ANDROID_DLEXT_FORCE_LOAD flag is specified.
2016-09-19 19:50:28 +02:00
void * handle = dlopen ( symlink_name . c_str ( ) , RTLD_NOW ) ;
2015-04-03 01:03:56 +02:00
ASSERT_DL_NOTNULL ( handle ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_FORCE_LOAD ;
2016-09-19 19:50:28 +02:00
// Note that 'libdlext_test.so' is dt_soname for the symlink_name
2015-04-03 01:03:56 +02:00
void * handle2 = android_dlopen_ext ( " libdlext_test.so " , RTLD_NOW , & extinfo ) ;
ASSERT_DL_NOTNULL ( handle2 ) ;
ASSERT_TRUE ( handle = = handle2 ) ;
dlclose ( handle2 ) ;
dlclose ( handle ) ;
}
2015-03-19 06:50:01 +01:00
TEST ( dlfcn , dlopen_from_zip_absolute_path ) {
2016-09-21 20:17:13 +02:00
const std : : string lib_zip_path = " /libdlext_test_zip/libdlext_test_zip_zipaligned.zip " ;
2016-11-25 21:23:11 +01:00
const std : : string lib_path = get_testlib_root ( ) + lib_zip_path ;
2015-03-19 06:50:01 +01:00
2015-09-29 01:38:31 +02:00
void * handle = dlopen ( ( lib_path + " !/libdir/libatest_simple_zip.so " ) . c_str ( ) , RTLD_NOW ) ;
2015-03-19 06:50:01 +01:00
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
2015-09-29 01:38:31 +02:00
uint32_t * taxicab_number = reinterpret_cast < uint32_t * > ( dlsym ( handle , " dlopen_testlib_taxicab_number " ) ) ;
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
2015-03-19 06:50:01 +01:00
dlclose ( handle ) ;
}
2015-10-02 03:41:57 +02:00
TEST ( dlfcn , dlopen_from_zip_with_dt_runpath ) {
2016-09-21 20:17:13 +02:00
const std : : string lib_zip_path = " /libdlext_test_runpath_zip/libdlext_test_runpath_zip_zipaligned.zip " ;
2016-11-25 21:23:11 +01:00
const std : : string lib_path = get_testlib_root ( ) + lib_zip_path ;
2015-10-02 03:41:57 +02:00
void * handle = dlopen ( ( lib_path + " !/libdir/libtest_dt_runpath_d_zip.so " ) . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
typedef void * ( * dlopen_b_fn ) ( ) ;
dlopen_b_fn fn = ( dlopen_b_fn ) dlsym ( handle , " dlopen_b " ) ;
ASSERT_TRUE ( fn ! = nullptr ) < < dlerror ( ) ;
void * p = fn ( ) ;
ASSERT_TRUE ( p ! = nullptr ) < < dlerror ( ) ;
dlclose ( p ) ;
dlclose ( handle ) ;
}
2015-03-19 06:50:01 +01:00
TEST ( dlfcn , dlopen_from_zip_ld_library_path ) {
2016-09-21 20:17:13 +02:00
const std : : string lib_zip_path = " /libdlext_test_zip/libdlext_test_zip_zipaligned.zip " ;
2016-11-25 21:23:11 +01:00
const std : : string lib_path = get_testlib_root ( ) + lib_zip_path + " !/libdir " ;
2015-03-19 06:50:01 +01:00
typedef void ( * fn_t ) ( const char * ) ;
fn_t android_update_LD_LIBRARY_PATH =
reinterpret_cast < fn_t > ( dlsym ( RTLD_DEFAULT , " android_update_LD_LIBRARY_PATH " ) ) ;
ASSERT_TRUE ( android_update_LD_LIBRARY_PATH ! = nullptr ) < < dlerror ( ) ;
2015-09-29 01:38:31 +02:00
void * handle = dlopen ( " libdlext_test_zip.so " , RTLD_NOW ) ;
2015-03-19 06:50:01 +01:00
ASSERT_TRUE ( handle = = nullptr ) ;
android_update_LD_LIBRARY_PATH ( lib_path . c_str ( ) ) ;
2015-09-29 01:38:31 +02:00
handle = dlopen ( " libdlext_test_zip.so " , RTLD_NOW ) ;
2015-03-19 06:50:01 +01:00
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
int ( * fn ) ( void ) ;
fn = reinterpret_cast < int ( * ) ( void ) > ( dlsym ( handle , " getRandomNumber " ) ) ;
ASSERT_TRUE ( fn ! = nullptr ) ;
EXPECT_EQ ( 4 , fn ( ) ) ;
2016-01-15 20:13:35 +01:00
uint32_t * taxicab_number =
reinterpret_cast < uint32_t * > ( dlsym ( handle , " dlopen_testlib_taxicab_number " ) ) ;
2015-09-29 01:38:31 +02:00
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
2015-03-19 06:50:01 +01:00
dlclose ( handle ) ;
}
2014-02-06 15:34:21 +01:00
TEST_F ( DlExtTest , Reserved ) {
2016-09-21 20:17:13 +02:00
void * start = mmap ( nullptr , kLibSize , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2014-02-06 15:34:21 +01:00
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_RESERVED_ADDRESS ;
extinfo . reserved_addr = start ;
2016-09-21 20:17:13 +02:00
extinfo . reserved_size = kLibSize ;
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2014-02-06 15:34:21 +01:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
2014-08-27 22:45:37 +02:00
EXPECT_GE ( reinterpret_cast < void * > ( f ) , start ) ;
2014-02-06 15:34:21 +01:00
EXPECT_LT ( reinterpret_cast < void * > ( f ) ,
2016-09-21 20:17:13 +02:00
reinterpret_cast < char * > ( start ) + kLibSize ) ;
2014-02-06 15:34:21 +01:00
EXPECT_EQ ( 4 , f ( ) ) ;
2016-01-15 20:13:35 +01:00
// Check that after dlclose reserved address space is unmapped (and can be reused)
dlclose ( handle_ ) ;
handle_ = nullptr ;
void * new_start = mmap ( start , PAGE_SIZE , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
ASSERT_NE ( start , new_start ) < < " dlclose unmapped reserved space " ;
2014-02-06 15:34:21 +01:00
}
TEST_F ( DlExtTest , ReservedTooSmall ) {
2016-01-15 20:13:35 +01:00
void * start = mmap ( nullptr , PAGE_SIZE , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2014-02-06 15:34:21 +01:00
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_RESERVED_ADDRESS ;
extinfo . reserved_addr = start ;
extinfo . reserved_size = PAGE_SIZE ;
2016-09-21 20:17:13 +02:00
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2014-10-04 02:52:44 +02:00
EXPECT_EQ ( nullptr , handle_ ) ;
2014-02-06 15:34:21 +01:00
}
TEST_F ( DlExtTest , ReservedHint ) {
2016-09-21 20:17:13 +02:00
void * start = mmap ( nullptr , kLibSize , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2014-02-06 15:34:21 +01:00
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT ;
extinfo . reserved_addr = start ;
2016-09-21 20:17:13 +02:00
extinfo . reserved_size = kLibSize ;
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2014-02-06 15:34:21 +01:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
2014-08-27 22:45:37 +02:00
EXPECT_GE ( reinterpret_cast < void * > ( f ) , start ) ;
2014-02-06 15:34:21 +01:00
EXPECT_LT ( reinterpret_cast < void * > ( f ) ,
2016-09-21 20:17:13 +02:00
reinterpret_cast < char * > ( start ) + kLibSize ) ;
2014-02-06 15:34:21 +01:00
EXPECT_EQ ( 4 , f ( ) ) ;
}
TEST_F ( DlExtTest , ReservedHintTooSmall ) {
2016-01-15 20:13:35 +01:00
void * start = mmap ( nullptr , PAGE_SIZE , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2014-02-06 15:34:21 +01:00
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_RESERVED_ADDRESS_HINT ;
extinfo . reserved_addr = start ;
extinfo . reserved_size = PAGE_SIZE ;
2016-09-21 20:17:13 +02:00
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2014-02-06 15:34:21 +01:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
2014-08-27 22:45:37 +02:00
EXPECT_TRUE ( reinterpret_cast < void * > ( f ) < start | |
( reinterpret_cast < void * > ( f ) > =
reinterpret_cast < char * > ( start ) + PAGE_SIZE ) ) ;
2014-02-06 15:34:21 +01:00
EXPECT_EQ ( 4 , f ( ) ) ;
}
2014-02-27 14:18:00 +01:00
2015-10-08 01:34:20 +02:00
TEST_F ( DlExtTest , LoadAtFixedAddress ) {
2016-09-21 20:17:13 +02:00
void * start = mmap ( nullptr , kLibSize , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2015-10-08 01:34:20 +02:00
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
2016-09-21 20:17:13 +02:00
munmap ( start , kLibSize ) ;
2015-10-08 01:34:20 +02:00
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS ;
extinfo . reserved_addr = start ;
2016-09-21 20:17:13 +02:00
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2015-10-08 01:34:20 +02:00
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
EXPECT_GE ( reinterpret_cast < void * > ( f ) , start ) ;
2016-09-21 20:17:13 +02:00
EXPECT_LT ( reinterpret_cast < void * > ( f ) , reinterpret_cast < char * > ( start ) + kLibSize ) ;
2015-10-08 01:34:20 +02:00
EXPECT_EQ ( 4 , f ( ) ) ;
2016-01-15 20:13:35 +01:00
dlclose ( handle_ ) ;
handle_ = nullptr ;
// Check that dlclose unmapped the file
2016-09-21 20:17:13 +02:00
void * addr = mmap ( start , kLibSize , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2016-01-15 20:13:35 +01:00
ASSERT_EQ ( start , addr ) < < " dlclose did not unmap the memory " ;
2015-10-08 01:34:20 +02:00
}
TEST_F ( DlExtTest , LoadAtFixedAddressTooSmall ) {
2016-09-21 20:17:13 +02:00
void * start = mmap ( nullptr , kLibSize + PAGE_SIZE , PROT_NONE ,
2015-10-08 01:34:20 +02:00
MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
2016-09-21 20:17:13 +02:00
munmap ( start , kLibSize + PAGE_SIZE ) ;
void * new_addr = mmap ( reinterpret_cast < uint8_t * > ( start ) + PAGE_SIZE , kLibSize , PROT_NONE ,
2015-10-08 01:34:20 +02:00
MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
ASSERT_TRUE ( new_addr ! = MAP_FAILED ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS ;
extinfo . reserved_addr = start ;
2016-09-21 20:17:13 +02:00
handle_ = android_dlopen_ext ( kLibName , RTLD_NOW , & extinfo ) ;
2015-10-08 01:34:20 +02:00
ASSERT_TRUE ( handle_ = = nullptr ) ;
}
2014-04-30 16:48:40 +02:00
class DlExtRelroSharingTest : public DlExtTest {
protected :
virtual void SetUp ( ) {
DlExtTest : : SetUp ( ) ;
2016-09-21 20:17:13 +02:00
void * start = mmap ( nullptr , kLibSize , PROT_NONE , MAP_PRIVATE | MAP_ANONYMOUS , - 1 , 0 ) ;
2014-04-30 16:48:40 +02:00
ASSERT_TRUE ( start ! = MAP_FAILED ) ;
extinfo_ . flags = ANDROID_DLEXT_RESERVED_ADDRESS ;
extinfo_ . reserved_addr = start ;
2016-09-21 20:17:13 +02:00
extinfo_ . reserved_size = kLibSize ;
2014-04-30 16:48:40 +02:00
extinfo_ . relro_fd = - 1 ;
}
2014-02-27 14:18:00 +01:00
2014-04-30 16:48:40 +02:00
virtual void TearDown ( ) {
DlExtTest : : TearDown ( ) ;
2014-02-27 14:18:00 +01:00
}
2014-12-08 05:43:37 +01:00
void CreateRelroFile ( const char * lib , const char * relro_file ) {
int relro_fd = open ( relro_file , O_RDWR | O_TRUNC ) ;
2014-04-30 16:48:40 +02:00
ASSERT_NOERROR ( relro_fd ) ;
pid_t pid = fork ( ) ;
if ( pid = = 0 ) {
// child process
extinfo_ . flags | = ANDROID_DLEXT_WRITE_RELRO ;
extinfo_ . relro_fd = relro_fd ;
void * handle = android_dlopen_ext ( lib , RTLD_NOW , & extinfo_ ) ;
2014-10-04 02:52:44 +02:00
if ( handle = = nullptr ) {
2014-04-30 16:48:40 +02:00
fprintf ( stderr , " in child: %s \n " , dlerror ( ) ) ;
exit ( 1 ) ;
}
exit ( 0 ) ;
}
// continuing in parent
ASSERT_NOERROR ( close ( relro_fd ) ) ;
ASSERT_NOERROR ( pid ) ;
2016-01-26 22:04:57 +01:00
AssertChildExited ( pid , 0 ) ;
2014-04-30 16:48:40 +02:00
// reopen file for reading so it can be used
2014-12-08 05:43:37 +01:00
relro_fd = open ( relro_file , O_RDONLY ) ;
2014-04-30 16:48:40 +02:00
ASSERT_NOERROR ( relro_fd ) ;
extinfo_ . flags | = ANDROID_DLEXT_USE_RELRO ;
extinfo_ . relro_fd = relro_fd ;
}
void TryUsingRelro ( const char * lib ) {
handle_ = android_dlopen_ext ( lib , RTLD_NOW , & extinfo_ ) ;
ASSERT_DL_NOTNULL ( handle_ ) ;
fn f = reinterpret_cast < fn > ( dlsym ( handle_ , " getRandomNumber " ) ) ;
ASSERT_DL_NOTNULL ( f ) ;
EXPECT_EQ ( 4 , f ( ) ) ;
2015-09-03 01:32:02 +02:00
2016-01-15 20:13:35 +01:00
uint32_t * taxicab_number =
reinterpret_cast < uint32_t * > ( dlsym ( handle_ , " dlopen_testlib_taxicab_number " ) ) ;
2015-09-03 01:32:02 +02:00
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
2014-04-30 16:48:40 +02:00
}
2017-04-25 05:07:19 +02:00
void SpawnChildrenAndMeasurePss ( const char * lib , const char * relro_file , bool share_relro ,
size_t * pss_out ) ;
2014-05-02 15:57:42 +02:00
2014-04-30 16:48:40 +02:00
android_dlextinfo extinfo_ ;
} ;
TEST_F ( DlExtRelroSharingTest , ChildWritesGoodData ) {
2014-12-08 05:43:37 +01:00
TemporaryFile tf ; // Use tf to get an unique filename.
ASSERT_NOERROR ( close ( tf . fd ) ) ;
2016-09-21 20:17:13 +02:00
ASSERT_NO_FATAL_FAILURE ( CreateRelroFile ( kLibName , tf . filename ) ) ;
ASSERT_NO_FATAL_FAILURE ( TryUsingRelro ( kLibName ) ) ;
2014-12-08 05:43:37 +01:00
// Use destructor of tf to close and unlink the file.
tf . fd = extinfo_ . relro_fd ;
2014-04-30 16:48:40 +02:00
}
2014-02-27 14:18:00 +01:00
2014-04-30 16:48:40 +02:00
TEST_F ( DlExtRelroSharingTest , ChildWritesNoRelro ) {
2014-12-08 05:43:37 +01:00
TemporaryFile tf ; // // Use tf to get an unique filename.
ASSERT_NOERROR ( close ( tf . fd ) ) ;
2016-09-21 20:17:13 +02:00
ASSERT_NO_FATAL_FAILURE ( CreateRelroFile ( kLibNameNoRelro , tf . filename ) ) ;
ASSERT_NO_FATAL_FAILURE ( TryUsingRelro ( kLibNameNoRelro ) ) ;
2014-12-08 05:43:37 +01:00
// Use destructor of tf to close and unlink the file.
tf . fd = extinfo_ . relro_fd ;
2014-04-30 16:48:40 +02:00
}
TEST_F ( DlExtRelroSharingTest , RelroFileEmpty ) {
2016-09-21 20:17:13 +02:00
ASSERT_NO_FATAL_FAILURE ( TryUsingRelro ( kLibName ) ) ;
2014-02-27 14:18:00 +01:00
}
2014-05-02 15:57:42 +02:00
TEST_F ( DlExtRelroSharingTest , VerifyMemorySaving ) {
2014-09-03 20:30:21 +02:00
if ( geteuid ( ) ! = 0 ) {
GTEST_LOG_ ( INFO ) < < " This test must be run as root. \n " ;
return ;
}
2014-12-08 05:43:37 +01:00
TemporaryFile tf ; // Use tf to get an unique filename.
ASSERT_NOERROR ( close ( tf . fd ) ) ;
2016-09-21 20:17:13 +02:00
ASSERT_NO_FATAL_FAILURE ( CreateRelroFile ( kLibName , tf . filename ) ) ;
2014-12-08 05:43:37 +01:00
2014-05-02 15:57:42 +02:00
int pipefd [ 2 ] ;
ASSERT_NOERROR ( pipe ( pipefd ) ) ;
size_t without_sharing , with_sharing ;
2017-04-25 05:07:19 +02:00
ASSERT_NO_FATAL_FAILURE ( SpawnChildrenAndMeasurePss ( kLibName , tf . filename , false , & without_sharing ) ) ;
ASSERT_NO_FATAL_FAILURE ( SpawnChildrenAndMeasurePss ( kLibName , tf . filename , true , & with_sharing ) ) ;
ASSERT_LT ( with_sharing , without_sharing ) ;
2014-05-02 15:57:42 +02:00
2017-04-25 05:07:19 +02:00
// We expect the sharing to save at least 50% of the library's total PSS.
// In practice it saves 80%+ for this library in the test.
size_t pss_saved = without_sharing - with_sharing ;
size_t expected_min_saved = without_sharing / 2 ;
EXPECT_LT ( expected_min_saved , pss_saved ) ;
2014-12-08 05:43:37 +01:00
// Use destructor of tf to close and unlink the file.
tf . fd = extinfo_ . relro_fd ;
2014-05-02 15:57:42 +02:00
}
2017-04-25 05:07:19 +02:00
void GetPss ( bool shared_relro , const char * lib , const char * relro_file , pid_t pid ,
size_t * total_pss ) {
2014-05-02 15:57:42 +02:00
pm_kernel_t * kernel ;
ASSERT_EQ ( 0 , pm_kernel_create ( & kernel ) ) ;
pm_process_t * process ;
ASSERT_EQ ( 0 , pm_process_create ( kernel , pid , & process ) ) ;
pm_map_t * * maps ;
size_t num_maps ;
ASSERT_EQ ( 0 , pm_process_maps ( process , & maps , & num_maps ) ) ;
2017-04-25 05:07:19 +02:00
// Calculate total PSS of the library.
* total_pss = 0 ;
bool saw_relro_file = false ;
for ( size_t i = 0 ; i < num_maps ; + + i ) {
if ( android : : base : : EndsWith ( maps [ i ] - > name , lib ) | | strcmp ( maps [ i ] - > name , relro_file ) = = 0 ) {
if ( strcmp ( maps [ i ] - > name , relro_file ) = = 0 ) saw_relro_file = true ;
pm_memusage_t usage ;
ASSERT_EQ ( 0 , pm_map_usage ( maps [ i ] , & usage ) ) ;
* total_pss + = usage . pss ;
}
2014-05-02 15:57:42 +02:00
}
free ( maps ) ;
pm_process_destroy ( process ) ;
pm_kernel_destroy ( kernel ) ;
2017-04-25 05:07:19 +02:00
if ( shared_relro ) ASSERT_TRUE ( saw_relro_file ) ;
2014-05-02 15:57:42 +02:00
}
2017-04-25 05:07:19 +02:00
void DlExtRelroSharingTest : : SpawnChildrenAndMeasurePss ( const char * lib , const char * relro_file ,
bool share_relro , size_t * pss_out ) {
2014-05-02 15:57:42 +02:00
const int CHILDREN = 20 ;
// Create children
2016-01-26 22:04:57 +01:00
pid_t child_pids [ CHILDREN ] ;
2014-05-02 15:57:42 +02:00
int childpipe [ CHILDREN ] ;
for ( int i = 0 ; i < CHILDREN ; + + i ) {
char read_buf ;
int child_done_pipe [ 2 ] , parent_done_pipe [ 2 ] ;
ASSERT_NOERROR ( pipe ( child_done_pipe ) ) ;
ASSERT_NOERROR ( pipe ( parent_done_pipe ) ) ;
pid_t child = fork ( ) ;
if ( child = = 0 ) {
// close the 'wrong' ends of the pipes in the child
close ( child_done_pipe [ 0 ] ) ;
close ( parent_done_pipe [ 1 ] ) ;
// open the library
void * handle ;
if ( share_relro ) {
handle = android_dlopen_ext ( lib , RTLD_NOW , & extinfo_ ) ;
} else {
handle = dlopen ( lib , RTLD_NOW ) ;
}
2014-10-04 02:52:44 +02:00
if ( handle = = nullptr ) {
2014-05-02 15:57:42 +02:00
fprintf ( stderr , " in child: %s \n " , dlerror ( ) ) ;
exit ( 1 ) ;
}
// close write end of child_done_pipe to signal the parent that we're done.
close ( child_done_pipe [ 1 ] ) ;
// wait for the parent to close parent_done_pipe, then exit
read ( parent_done_pipe [ 0 ] , & read_buf , 1 ) ;
exit ( 0 ) ;
}
ASSERT_NOERROR ( child ) ;
// close the 'wrong' ends of the pipes in the parent
close ( child_done_pipe [ 1 ] ) ;
close ( parent_done_pipe [ 0 ] ) ;
// wait for the child to be done
read ( child_done_pipe [ 0 ] , & read_buf , 1 ) ;
close ( child_done_pipe [ 0 ] ) ;
// save the child's pid and the parent_done_pipe
2016-01-26 22:04:57 +01:00
child_pids [ i ] = child ;
2014-05-02 15:57:42 +02:00
childpipe [ i ] = parent_done_pipe [ 1 ] ;
}
2017-04-25 05:07:19 +02:00
// Sum the PSS of tested library of all the children
2014-05-02 15:57:42 +02:00
size_t total_pss = 0 ;
for ( int i = 0 ; i < CHILDREN ; + + i ) {
size_t child_pss ;
2017-04-25 05:07:19 +02:00
ASSERT_NO_FATAL_FAILURE ( GetPss ( share_relro , lib , relro_file , child_pids [ i ] , & child_pss ) ) ;
2014-05-02 15:57:42 +02:00
total_pss + = child_pss ;
}
* pss_out = total_pss ;
// Close pipes and wait for children to exit
for ( int i = 0 ; i < CHILDREN ; + + i ) {
ASSERT_NOERROR ( close ( childpipe [ i ] ) ) ;
}
2016-01-26 22:04:57 +01:00
for ( int i = 0 ; i < CHILDREN ; + + i ) {
AssertChildExited ( child_pids [ i ] , 0 ) ;
2014-05-02 15:57:42 +02:00
}
}
2015-10-30 01:01:24 +01:00
// Testing namespaces
static const char * g_public_lib = " libnstest_public.so " ;
2017-02-03 23:07:34 +01:00
// These are libs shared with default namespace
static const std : : string g_core_shared_libs = " libc.so:libc++.so:libdl.so:libm.so " ;
2015-10-30 01:01:24 +01:00
TEST ( dlext , ns_smoke ) {
static const char * root_lib = " libnstest_root.so " ;
2017-02-03 23:07:34 +01:00
std : : string shared_libs = g_core_shared_libs + " : " + g_public_lib ;
2015-10-30 01:01:24 +01:00
2017-02-03 23:07:34 +01:00
ASSERT_FALSE ( android_init_anonymous_namespace ( " " , nullptr ) ) ;
ASSERT_STREQ ( " android_init_anonymous_namespace failed: error linking namespaces "
" \" (anonymous) \" -> \" (default) \" : the list of shared libraries is empty. " ,
dlerror ( ) ) ;
2016-04-21 23:57:38 +02:00
2016-11-25 21:23:11 +01:00
const std : : string lib_public_path = get_testlib_root ( ) + " /public_namespace_libs/ " + g_public_lib ;
2015-12-05 03:28:49 +01:00
void * handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( handle_public ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_init_anonymous_namespace ( shared_libs . c_str ( ) , nullptr ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
2017-02-02 00:28:52 +01:00
// Check that libraries added to public namespace are not NODELETE
2015-10-30 01:01:24 +01:00
dlclose ( handle_public ) ;
2017-02-02 00:28:52 +01:00
handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW | RTLD_NOLOAD ) ;
ASSERT_TRUE ( handle_public = = nullptr ) ;
ASSERT_EQ ( std : : string ( " dlopen failed: library \" " ) + lib_public_path +
" \" wasn't loaded and RTLD_NOLOAD prevented it " , dlerror ( ) ) ;
handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
2015-10-30 01:01:24 +01:00
2017-02-03 23:07:34 +01:00
// create "public namespace", share limited set of public libraries with
2015-12-14 23:11:17 +01:00
android_namespace_t * ns1 =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " private " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2017-02-03 23:07:34 +01:00
ANDROID_NAMESPACE_TYPE_REGULAR ,
nullptr ,
nullptr ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( ns1 ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns1 , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
2015-12-14 23:11:17 +01:00
android_namespace_t * ns2 =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " private_isolated " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2017-02-03 23:07:34 +01:00
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( ns2 ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns2 , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
// This should not have affect search path for default namespace:
ASSERT_TRUE ( dlopen ( root_lib , RTLD_NOW ) = = nullptr ) ;
void * handle = dlopen ( g_public_lib , RTLD_NOW ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
dlclose ( handle ) ;
2017-03-27 23:11:02 +02:00
// dlopen for a public library using an absolute path should work
// 1. For isolated namespaces
2015-10-30 01:01:24 +01:00
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
2017-03-27 23:11:02 +02:00
extinfo . library_namespace = ns2 ;
handle = android_dlopen_ext ( lib_public_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( handle = = handle_public ) ;
dlclose ( handle ) ;
// 1.1 even if it wasn't loaded before
dlclose ( handle_public ) ;
handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW | RTLD_NOLOAD ) ;
ASSERT_TRUE ( handle_public = = nullptr ) ;
ASSERT_EQ ( std : : string ( " dlopen failed: library \" " ) + lib_public_path +
" \" wasn't loaded and RTLD_NOLOAD prevented it " , dlerror ( ) ) ;
handle = android_dlopen_ext ( lib_public_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle = = handle_public ) ;
dlclose ( handle ) ;
// 2. And for regular namespaces (make sure it does not load second copy of the library)
extinfo . library_namespace = ns1 ;
handle = android_dlopen_ext ( lib_public_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( handle = = handle_public ) ;
dlclose ( handle ) ;
// 2.1 Unless it was not loaded before - in which case it will load a duplicate.
// TODO(dimitry): This is broken. Maybe we need to deprecate non-isolated namespaces?
dlclose ( handle_public ) ;
handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW | RTLD_NOLOAD ) ;
ASSERT_TRUE ( handle_public = = nullptr ) ;
ASSERT_EQ ( std : : string ( " dlopen failed: library \" " ) + lib_public_path +
" \" wasn't loaded and RTLD_NOLOAD prevented it " , dlerror ( ) ) ;
handle = android_dlopen_ext ( lib_public_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle ! = handle_public ) ;
dlclose ( handle ) ;
2015-10-30 01:01:24 +01:00
extinfo . library_namespace = ns1 ;
void * handle1 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle1 ! = nullptr ) < < dlerror ( ) ;
extinfo . library_namespace = ns2 ;
void * handle2 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle2 ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( handle1 ! = handle2 ) ;
typedef const char * ( * fn_t ) ( ) ;
fn_t ns_get_local_string1 = reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_local_string " ) ) ;
ASSERT_TRUE ( ns_get_local_string1 ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_local_string2 = reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_local_string " ) ) ;
ASSERT_TRUE ( ns_get_local_string2 ! = nullptr ) < < dlerror ( ) ;
EXPECT_STREQ ( " This string is local to root library " , ns_get_local_string1 ( ) ) ;
EXPECT_STREQ ( " This string is local to root library " , ns_get_local_string2 ( ) ) ;
ASSERT_TRUE ( ns_get_local_string1 ( ) ! = ns_get_local_string2 ( ) ) ;
fn_t ns_get_private_extern_string1 =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_private_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string1 ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_private_extern_string2 =
reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_private_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string2 ! = nullptr ) < < dlerror ( ) ;
EXPECT_STREQ ( " This string is from private namespace " , ns_get_private_extern_string1 ( ) ) ;
EXPECT_STREQ ( " This string is from private namespace " , ns_get_private_extern_string2 ( ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string1 ( ) ! = ns_get_private_extern_string2 ( ) ) ;
fn_t ns_get_public_extern_string1 =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_public_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string1 ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_public_extern_string2 =
reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_public_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string2 ! = nullptr ) < < dlerror ( ) ;
EXPECT_STREQ ( " This string is from public namespace " , ns_get_public_extern_string1 ( ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string1 ( ) = = ns_get_public_extern_string2 ( ) ) ;
// and now check that dlopen() does the right thing in terms of preserving namespace
fn_t ns_get_dlopened_string1 = reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string1 ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_dlopened_string2 = reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string2 ! = nullptr ) < < dlerror ( ) ;
EXPECT_STREQ ( " This string is from private namespace (dlopened library) " , ns_get_dlopened_string1 ( ) ) ;
EXPECT_STREQ ( " This string is from private namespace (dlopened library) " , ns_get_dlopened_string2 ( ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string1 ( ) ! = ns_get_dlopened_string2 ( ) ) ;
2017-02-03 23:07:34 +01:00
// Check that symbols from non-shared libraries a shared library depends on are not visible
// from original namespace.
fn_t ns_get_internal_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_internal_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_internal_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( ns_get_internal_extern_string ( ) = = nullptr ) < <
" ns_get_internal_extern_string() expected to return null but returns \" " < <
ns_get_internal_extern_string ( ) < < " \" " ;
2015-10-30 01:01:24 +01:00
dlclose ( handle1 ) ;
// Check if handle2 is still alive (and well)
ASSERT_STREQ ( " This string is local to root library " , ns_get_local_string2 ( ) ) ;
ASSERT_STREQ ( " This string is from private namespace " , ns_get_private_extern_string2 ( ) ) ;
ASSERT_STREQ ( " This string is from public namespace " , ns_get_public_extern_string2 ( ) ) ;
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " , ns_get_dlopened_string2 ( ) ) ;
dlclose ( handle2 ) ;
}
2017-04-21 22:12:05 +02:00
TEST ( dlext , dlopen_ext_use_o_tmpfile_fd ) {
const std : : string lib_path = get_testlib_root ( ) + " /libtest_simple.so " ;
int tmpfd = TEMP_FAILURE_RETRY (
2017-08-04 18:34:19 +02:00
open ( get_testlib_root ( ) . c_str ( ) , O_TMPFILE | O_CLOEXEC | O_RDWR | O_EXCL , 0 ) ) ;
2017-04-21 22:12:05 +02:00
// Ignore kernels without O_TMPFILE flag support
if ( tmpfd = = - 1 & & ( errno = = EISDIR | | errno = = EINVAL | | errno = = EOPNOTSUPP ) ) {
return ;
}
ASSERT_TRUE ( tmpfd ! = - 1 ) < < strerror ( errno ) ;
android_namespace_t * ns =
android_create_namespace ( " testing-o_tmpfile " ,
nullptr ,
get_testlib_root ( ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_DL_NOTNULL ( ns ) ;
ASSERT_TRUE ( android_link_namespaces ( ns , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
std : : string content ;
ASSERT_TRUE ( android : : base : : ReadFileToString ( lib_path , & content ) ) < < strerror ( errno ) ;
ASSERT_TRUE ( android : : base : : WriteStringToFd ( content , tmpfd ) ) < < strerror ( errno ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_fd = tmpfd ;
extinfo . library_namespace = ns ;
void * handle = android_dlopen_ext ( " foobar " , RTLD_NOW , & extinfo ) ;
ASSERT_DL_NOTNULL ( handle ) ;
uint32_t * taxicab_number = reinterpret_cast < uint32_t * > ( dlsym ( handle , " dlopen_testlib_taxicab_number " ) ) ;
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
dlclose ( handle ) ;
}
TEST ( dlext , dlopen_ext_use_memfd ) {
const std : : string lib_path = get_testlib_root ( ) + " /libtest_simple.so " ;
// create memfd
int memfd = syscall ( __NR_memfd_create , " foobar " , MFD_CLOEXEC ) ;
if ( memfd = = - 1 & & errno = = ENOSYS ) {
return ;
}
ASSERT_TRUE ( memfd ! = - 1 ) < < strerror ( errno ) ;
// Check st.f_type is TMPFS_MAGIC for memfd
struct statfs st ;
ASSERT_TRUE ( TEMP_FAILURE_RETRY ( fstatfs ( memfd , & st ) ) = = 0 ) < < strerror ( errno ) ;
ASSERT_EQ ( static_cast < decltype ( st . f_type ) > ( TMPFS_MAGIC ) , st . f_type ) ;
android_namespace_t * ns =
android_create_namespace ( " testing-memfd " ,
nullptr ,
get_testlib_root ( ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_DL_NOTNULL ( ns ) ;
ASSERT_TRUE ( android_link_namespaces ( ns , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
// read file into memfd backed one.
std : : string content ;
ASSERT_TRUE ( android : : base : : ReadFileToString ( lib_path , & content ) ) < < strerror ( errno ) ;
ASSERT_TRUE ( android : : base : : WriteStringToFd ( content , memfd ) ) < < strerror ( errno ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_fd = memfd ;
extinfo . library_namespace = ns ;
void * handle = android_dlopen_ext ( " foobar " , RTLD_NOW , & extinfo ) ;
ASSERT_DL_NOTNULL ( handle ) ;
uint32_t * taxicab_number = reinterpret_cast < uint32_t * > ( dlsym ( handle , " dlopen_testlib_taxicab_number " ) ) ;
ASSERT_DL_NOTNULL ( taxicab_number ) ;
EXPECT_EQ ( 1729U , * taxicab_number ) ;
dlclose ( handle ) ;
}
2017-02-03 23:07:34 +01:00
TEST ( dlext , ns_symbol_visibilty_one_namespace ) {
static const char * root_lib = " libnstest_root.so " ;
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
const std : : string ns_search_path = get_testlib_root ( ) + " /public_namespace_libs: " +
get_testlib_root ( ) + " /private_namespace_libs " ;
android_namespace_t * ns =
android_create_namespace ( " one " ,
nullptr ,
ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns ;
void * handle = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
typedef const char * ( * fn_t ) ( ) ;
// Check that relocation worked correctly
fn_t ns_get_internal_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle , " ns_get_internal_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_internal_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from a library a shared library depends on " , ns_get_internal_extern_string ( ) ) ;
fn_t internal_extern_string_fn =
reinterpret_cast < fn_t > ( dlsym ( handle , " internal_extern_string " ) ) ;
ASSERT_TRUE ( internal_extern_string_fn ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from a library a shared library depends on " , internal_extern_string_fn ( ) ) ;
}
TEST ( dlext , ns_symbol_visibilty_between_namespaces ) {
static const char * root_lib = " libnstest_root.so " ;
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
const std : : string public_ns_search_path = get_testlib_root ( ) + " /public_namespace_libs " ;
const std : : string private_ns_search_path = get_testlib_root ( ) + " /private_namespace_libs " ;
android_namespace_t * ns_public =
android_create_namespace ( " public " ,
nullptr ,
public_ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_public , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_namespace_t * ns_private =
android_create_namespace ( " private " ,
nullptr ,
private_ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_private , ns_public , g_public_lib ) ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_private , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_private ;
void * handle = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
typedef const char * ( * fn_t ) ( ) ;
// Check that relocation worked correctly
fn_t ns_get_internal_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle , " ns_get_internal_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_internal_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( ns_get_internal_extern_string ( ) = = nullptr ) < <
" ns_get_internal_extern_string() expected to return null but returns \" " < <
ns_get_internal_extern_string ( ) < < " \" " ;
fn_t internal_extern_string_fn =
reinterpret_cast < fn_t > ( dlsym ( handle , " internal_extern_string " ) ) ;
ASSERT_TRUE ( internal_extern_string_fn = = nullptr ) ;
ASSERT_STREQ ( " undefined symbol: internal_extern_string " , dlerror ( ) ) ;
}
TEST ( dlext , ns_unload_between_namespaces ) {
static const char * root_lib = " libnstest_root.so " ;
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
const std : : string public_ns_search_path = get_testlib_root ( ) + " /public_namespace_libs " ;
const std : : string private_ns_search_path = get_testlib_root ( ) + " /private_namespace_libs " ;
android_namespace_t * ns_public =
android_create_namespace ( " public " ,
nullptr ,
public_ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_public , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_namespace_t * ns_private =
android_create_namespace ( " private " ,
nullptr ,
private_ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_private , ns_public , g_public_lib ) ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_private , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_private ;
void * handle = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
dlclose ( handle ) ;
// Check that root_lib was unloaded
handle = android_dlopen_ext ( root_lib , RTLD_NOW | RTLD_NOLOAD , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
ASSERT_EQ ( std : : string ( " dlopen failed: library \" " ) + root_lib +
" \" wasn't loaded and RTLD_NOLOAD prevented it " , dlerror ( ) ) ;
// Check that shared library was unloaded in public ns
extinfo . library_namespace = ns_public ;
handle = android_dlopen_ext ( g_public_lib , RTLD_NOW | RTLD_NOLOAD , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
ASSERT_EQ ( std : : string ( " dlopen failed: library \" " ) + g_public_lib +
" \" wasn't loaded and RTLD_NOLOAD prevented it " , dlerror ( ) ) ;
}
2017-05-05 15:07:05 +02:00
TEST ( dlext , ns_greylist_enabled ) {
2017-02-21 22:41:08 +01:00
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
const std : : string ns_search_path = get_testlib_root ( ) + " /private_namespace_libs " ;
android_namespace_t * ns =
android_create_namespace ( " namespace " ,
nullptr ,
ns_search_path . c_str ( ) ,
2017-05-05 15:07:05 +02:00
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED ,
2017-02-21 22:41:08 +01:00
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns ;
2017-02-27 21:17:47 +01:00
// An app targeting M can open libnativehelper.so because it's on the greylist.
2017-02-21 22:41:08 +01:00
android_set_application_target_sdk_version ( __ANDROID_API_M__ ) ;
void * handle = android_dlopen_ext ( " libnativehelper.so " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
2017-02-27 21:17:47 +01:00
// Check that loader did not load another copy of libdl.so while loading greylisted library.
void * dlsym_ptr = dlsym ( handle , " dlsym " ) ;
ASSERT_TRUE ( dlsym_ptr ! = nullptr ) < < dlerror ( ) ;
ASSERT_EQ ( & dlsym , dlsym_ptr ) ;
2017-02-21 22:41:08 +01:00
dlclose ( handle ) ;
2017-02-27 21:17:47 +01:00
// An app targeting N no longer has the greylist.
2017-02-21 22:41:08 +01:00
android_set_application_target_sdk_version ( __ANDROID_API_N__ ) ;
handle = android_dlopen_ext ( " libnativehelper.so " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnativehelper.so \" not found " , dlerror ( ) ) ;
}
2017-05-05 15:07:05 +02:00
TEST ( dlext , ns_greylist_disabled_by_default ) {
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
const std : : string ns_search_path = get_testlib_root ( ) + " /private_namespace_libs " ;
android_namespace_t * ns =
android_create_namespace ( " namespace " ,
nullptr ,
ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns ;
android_set_application_target_sdk_version ( __ANDROID_API_M__ ) ;
void * handle = android_dlopen_ext ( " libnativehelper.so " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnativehelper.so \" not found " , dlerror ( ) ) ;
}
2017-02-03 23:07:34 +01:00
TEST ( dlext , ns_cyclic_namespaces ) {
// Test that ns1->ns2->ns1 link does not break the loader
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
std : : string shared_libs = g_core_shared_libs + " :libthatdoesnotexist.so " ;
const std : : string ns_search_path = get_testlib_root ( ) + " /public_namespace_libs " ;
android_namespace_t * ns1 =
android_create_namespace ( " ns1 " ,
nullptr ,
ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns1 , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_namespace_t * ns2 =
android_create_namespace ( " ns1 " ,
nullptr ,
ns_search_path . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( android_link_namespaces ( ns2 , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns2 , ns1 , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns1 , ns2 , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns1 ;
void * handle = android_dlopen_ext ( " libthatdoesnotexist.so " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libthatdoesnotexist.so \" not found " , dlerror ( ) ) ;
}
2015-10-30 01:01:24 +01:00
TEST ( dlext , ns_isolated ) {
static const char * root_lib = " libnstest_root_not_isolated.so " ;
2017-02-03 23:07:34 +01:00
std : : string shared_libs = g_core_shared_libs + " : " + g_public_lib ;
2015-10-30 01:01:24 +01:00
2016-11-25 21:23:11 +01:00
const std : : string lib_public_path = get_testlib_root ( ) + " /public_namespace_libs/ " + g_public_lib ;
2015-12-05 03:28:49 +01:00
void * handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( handle_public ! = nullptr ) < < dlerror ( ) ;
2015-11-18 03:36:50 +01:00
android_set_application_target_sdk_version ( 42U ) ; // something > 23
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_init_anonymous_namespace ( shared_libs . c_str ( ) , nullptr ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
2015-12-14 23:11:17 +01:00
android_namespace_t * ns_not_isolated =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " private " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2017-02-03 23:07:34 +01:00
ANDROID_NAMESPACE_TYPE_REGULAR ,
nullptr ,
nullptr ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( ns_not_isolated ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns_not_isolated , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
2015-12-14 23:11:17 +01:00
android_namespace_t * ns_isolated =
2016-05-13 00:20:21 +02:00
android_create_namespace ( " private_isolated1 " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2016-05-13 00:20:21 +02:00
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( ns_isolated ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns_isolated , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
2015-12-14 23:11:17 +01:00
android_namespace_t * ns_isolated2 =
android_create_namespace ( " private_isolated2 " ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2016-05-13 00:20:21 +02:00
nullptr ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
2016-11-25 21:23:11 +01:00
get_testlib_root ( ) . c_str ( ) ,
2016-05-13 00:20:21 +02:00
nullptr ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( ns_isolated2 ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns_isolated2 , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-10-30 01:01:24 +01:00
ASSERT_TRUE ( dlopen ( root_lib , RTLD_NOW ) = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnstest_root_not_isolated.so \" not found " , dlerror ( ) ) ;
std : : string lib_private_external_path =
2016-11-25 21:23:11 +01:00
get_testlib_root ( ) + " /private_namespace_libs_external/libnstest_private_external.so " ;
2015-10-30 01:01:24 +01:00
// Load lib_private_external_path to default namespace
// (it should remain invisible for the isolated namespaces after this)
void * handle = dlopen ( lib_private_external_path . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_not_isolated ;
void * handle1 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle1 ! = nullptr ) < < dlerror ( ) ;
extinfo . library_namespace = ns_isolated ;
void * handle2 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle2 = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnstest_private_external.so \" not found " , dlerror ( ) ) ;
// Check dlopen by absolute path
handle2 = android_dlopen_ext ( lib_private_external_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle2 = = nullptr ) ;
2016-03-01 22:11:28 +01:00
ASSERT_EQ ( " dlopen failed: library \" " + lib_private_external_path + " \" needed "
2016-05-17 22:29:37 +02:00
" or dlopened by \" " + get_executable_path ( ) + " \" is not accessible "
2016-03-01 22:11:28 +01:00
" for the namespace \" private_isolated1 \" " , dlerror ( ) ) ;
2015-10-30 01:01:24 +01:00
extinfo . library_namespace = ns_isolated2 ;
2016-11-25 21:23:11 +01:00
// this should work because isolation_path for private_isolated2 includes get_testlib_root()
2015-10-30 01:01:24 +01:00
handle2 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
2015-12-08 19:47:13 +01:00
ASSERT_TRUE ( handle2 ! = nullptr ) < < dlerror ( ) ;
dlclose ( handle2 ) ;
2015-10-30 01:01:24 +01:00
// Check dlopen by absolute path
handle2 = android_dlopen_ext ( lib_private_external_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
2015-12-08 19:47:13 +01:00
ASSERT_TRUE ( handle2 ! = nullptr ) < < dlerror ( ) ;
dlclose ( handle2 ) ;
2015-10-30 01:01:24 +01:00
typedef const char * ( * fn_t ) ( ) ;
fn_t ns_get_local_string = reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_local_string " ) ) ;
ASSERT_TRUE ( ns_get_local_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is local to root library " , ns_get_local_string ( ) ) ;
fn_t ns_get_private_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_private_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from private namespace " , ns_get_private_extern_string ( ) ) ;
fn_t ns_get_public_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_public_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from public namespace " , ns_get_public_extern_string ( ) ) ;
fn_t ns_get_dlopened_string = reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " , ns_get_dlopened_string ( ) ) ;
dlclose ( handle1 ) ;
}
2015-11-23 20:26:35 +01:00
2015-12-14 23:11:17 +01:00
TEST ( dlext , ns_shared ) {
static const char * root_lib = " libnstest_root_not_isolated.so " ;
static const char * root_lib_isolated = " libnstest_root.so " ;
2017-02-03 23:07:34 +01:00
std : : string shared_libs = g_core_shared_libs + " : " + g_public_lib ;
2015-12-14 23:11:17 +01:00
2016-11-25 21:23:11 +01:00
const std : : string lib_public_path = get_testlib_root ( ) + " /public_namespace_libs/ " + g_public_lib ;
2015-12-14 23:11:17 +01:00
void * handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle_public ! = nullptr ) < < dlerror ( ) ;
android_set_application_target_sdk_version ( 42U ) ; // something > 23
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_init_anonymous_namespace ( shared_libs . c_str ( ) , nullptr ) ) < < dlerror ( ) ;
2015-12-14 23:11:17 +01:00
// preload this library to the default namespace to check if it
// is shared later on.
void * handle_dlopened =
2016-11-25 21:23:11 +01:00
dlopen ( ( get_testlib_root ( ) + " /private_namespace_libs/libnstest_dlopened.so " ) . c_str ( ) , RTLD_NOW ) ;
2015-12-14 23:11:17 +01:00
ASSERT_TRUE ( handle_dlopened ! = nullptr ) < < dlerror ( ) ;
android_namespace_t * ns_not_isolated =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " private " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2017-02-03 23:07:34 +01:00
ANDROID_NAMESPACE_TYPE_REGULAR ,
nullptr ,
nullptr ) ;
2015-12-14 23:11:17 +01:00
ASSERT_TRUE ( ns_not_isolated ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns_not_isolated , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-12-14 23:11:17 +01:00
android_namespace_t * ns_isolated_shared =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " private_isolated_shared " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2015-12-14 23:11:17 +01:00
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED ,
2017-02-03 23:07:34 +01:00
nullptr ,
nullptr ) ;
2015-12-14 23:11:17 +01:00
ASSERT_TRUE ( ns_isolated_shared ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns_isolated_shared , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-12-14 23:11:17 +01:00
ASSERT_TRUE ( dlopen ( root_lib , RTLD_NOW ) = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnstest_root_not_isolated.so \" not found " , dlerror ( ) ) ;
std : : string lib_private_external_path =
2016-11-25 21:23:11 +01:00
get_testlib_root ( ) + " /private_namespace_libs_external/libnstest_private_external.so " ;
2015-12-14 23:11:17 +01:00
// Load lib_private_external_path to default namespace
// (it should remain invisible for the isolated namespaces after this)
void * handle = dlopen ( lib_private_external_path . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_not_isolated ;
void * handle1 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle1 ! = nullptr ) < < dlerror ( ) ;
extinfo . library_namespace = ns_isolated_shared ;
void * handle2 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle2 = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnstest_private_external.so \" not found " , dlerror ( ) ) ;
// Check dlopen by absolute path
handle2 = android_dlopen_ext ( lib_private_external_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle2 = = nullptr ) ;
2016-03-01 22:11:28 +01:00
ASSERT_EQ ( " dlopen failed: library \" " + lib_private_external_path + " \" needed "
2016-05-17 22:29:37 +02:00
" or dlopened by \" " + get_executable_path ( ) + " \" is not accessible "
2016-03-01 22:11:28 +01:00
" for the namespace \" private_isolated_shared \" " , dlerror ( ) ) ;
2015-12-14 23:11:17 +01:00
// load libnstest_root.so to shared namespace in order to check that everything is different
// except shared libnstest_dlopened.so
handle2 = android_dlopen_ext ( root_lib_isolated , RTLD_NOW , & extinfo ) ;
typedef const char * ( * fn_t ) ( ) ;
fn_t ns_get_local_string = reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_local_string " ) ) ;
ASSERT_TRUE ( ns_get_local_string ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_local_string_shared = reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_local_string " ) ) ;
ASSERT_TRUE ( ns_get_local_string_shared ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is local to root library " , ns_get_local_string ( ) ) ;
ASSERT_STREQ ( " This string is local to root library " , ns_get_local_string_shared ( ) ) ;
ASSERT_TRUE ( ns_get_local_string ( ) ! = ns_get_local_string_shared ( ) ) ;
fn_t ns_get_private_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_private_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_private_extern_string_shared =
reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_private_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string_shared ( ) ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from private namespace " , ns_get_private_extern_string ( ) ) ;
ASSERT_STREQ ( " This string is from private namespace " , ns_get_private_extern_string_shared ( ) ) ;
ASSERT_TRUE ( ns_get_private_extern_string ( ) ! = ns_get_private_extern_string_shared ( ) ) ;
fn_t ns_get_public_extern_string =
reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_public_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_public_extern_string_shared =
reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_public_extern_string " ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string_shared ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from public namespace " , ns_get_public_extern_string ( ) ) ;
ASSERT_STREQ ( " This string is from public namespace " , ns_get_public_extern_string_shared ( ) ) ;
ASSERT_TRUE ( ns_get_public_extern_string ( ) = = ns_get_public_extern_string_shared ( ) ) ;
fn_t ns_get_dlopened_string = reinterpret_cast < fn_t > ( dlsym ( handle1 , " ns_get_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string ! = nullptr ) < < dlerror ( ) ;
fn_t ns_get_dlopened_string_shared = reinterpret_cast < fn_t > ( dlsym ( handle2 , " ns_get_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string_shared ! = nullptr ) < < dlerror ( ) ;
const char * * ns_dlopened_string = static_cast < const char * * > ( dlsym ( handle_dlopened , " g_private_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_dlopened_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " , ns_get_dlopened_string ( ) ) ;
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " , * ns_dlopened_string ) ;
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " , ns_get_dlopened_string_shared ( ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string ( ) ! = ns_get_dlopened_string_shared ( ) ) ;
ASSERT_TRUE ( * ns_dlopened_string = = ns_get_dlopened_string_shared ( ) ) ;
dlclose ( handle1 ) ;
dlclose ( handle2 ) ;
}
2017-05-02 02:45:38 +02:00
TEST ( dlext , ns_shared_links_and_paths ) {
// Create parent namespace (isolated, not shared)
android_namespace_t * ns_isolated =
android_create_namespace ( " private_isolated " ,
nullptr ,
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
( get_testlib_root ( ) + " /public_namespace_libs " ) . c_str ( ) ,
nullptr ) ;
ASSERT_TRUE ( ns_isolated ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_isolated , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
// Create shared namespace with ns_isolated parent
android_namespace_t * ns_shared =
android_create_namespace ( " private_shared " ,
nullptr ,
nullptr ,
ANDROID_NAMESPACE_TYPE_SHARED | ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
ns_isolated ) ;
ASSERT_TRUE ( ns_shared ! = nullptr ) < < dlerror ( ) ;
// 1. Load a library in ns_shared to check that it has inherited
// search path and the link to the default namespace.
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_shared ;
{
void * handle = android_dlopen_ext ( " libnstest_private.so " , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
const char * * ns_private_extern_string = static_cast < const char * * > ( dlsym ( handle , " g_private_extern_string " ) ) ;
ASSERT_TRUE ( ns_private_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from private namespace " , * ns_private_extern_string ) ;
dlclose ( handle ) ;
}
// 2. Load another test library by absolute path to check that
// it has inherited permitted_when_isolated_path
{
void * handle = android_dlopen_ext (
( get_testlib_root ( ) + " /public_namespace_libs/libnstest_public.so " ) . c_str ( ) ,
RTLD_NOW ,
& extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
const char * * ns_public_extern_string = static_cast < const char * * > ( dlsym ( handle , " g_public_extern_string " ) ) ;
ASSERT_TRUE ( ns_public_extern_string ! = nullptr ) < < dlerror ( ) ;
ASSERT_STREQ ( " This string is from public namespace " , * ns_public_extern_string ) ;
dlclose ( handle ) ;
}
// 3. Check that it is still isolated.
{
void * handle = android_dlopen_ext (
( get_testlib_root ( ) + " /libtest_empty.so " ) . c_str ( ) ,
RTLD_NOW ,
& extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
}
}
2016-04-11 21:42:58 +02:00
TEST ( dlext , ns_shared_dlclose ) {
android_set_application_target_sdk_version ( 42U ) ; // something > 23
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) < < dlerror ( ) ;
2016-04-11 21:42:58 +02:00
// preload this library to the default namespace to check if it
// is shared later on.
void * handle_dlopened =
2016-11-25 21:23:11 +01:00
dlopen ( ( get_testlib_root ( ) + " /private_namespace_libs/libnstest_dlopened.so " ) . c_str ( ) , RTLD_NOW ) ;
2016-04-11 21:42:58 +02:00
ASSERT_TRUE ( handle_dlopened ! = nullptr ) < < dlerror ( ) ;
android_namespace_t * ns_isolated_shared =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " private_isolated_shared " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2016-04-11 21:42:58 +02:00
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED ,
2017-02-03 23:07:34 +01:00
nullptr ,
nullptr ) ;
2016-04-11 21:42:58 +02:00
ASSERT_TRUE ( ns_isolated_shared ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns_isolated_shared , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2016-04-11 21:42:58 +02:00
// Check if "libnstest_dlopened.so" is loaded (and the same)
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_isolated_shared ;
void * handle = android_dlopen_ext ( " libnstest_dlopened.so " , RTLD_NOW | RTLD_NOLOAD , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( handle = = handle_dlopened ) ;
dlclose ( handle ) ;
dlclose ( handle_dlopened ) ;
// And now check that the library cannot be found by soname (and is no longer loaded)
handle = android_dlopen_ext ( " libnstest_dlopened.so " , RTLD_NOW | RTLD_NOLOAD , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr )
< < " Error: libnstest_dlopened.so is still accessible in shared namespace " ;
2016-11-25 21:23:11 +01:00
handle = android_dlopen_ext ( ( get_testlib_root ( ) + " /private_namespace_libs/libnstest_dlopened.so " ) . c_str ( ) ,
2016-04-11 21:42:58 +02:00
RTLD_NOW | RTLD_NOLOAD , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr )
< < " Error: libnstest_dlopened.so is still accessible in shared namespace " ;
handle = dlopen ( " libnstest_dlopened.so " , RTLD_NOW | RTLD_NOLOAD ) ;
ASSERT_TRUE ( handle = = nullptr )
< < " Error: libnstest_dlopened.so is still accessible in default namespace " ;
2016-11-25 21:23:11 +01:00
handle = dlopen ( ( get_testlib_root ( ) + " /private_namespace_libs/libnstest_dlopened.so " ) . c_str ( ) ,
2016-04-11 21:42:58 +02:00
RTLD_NOW | RTLD_NOLOAD ) ;
ASSERT_TRUE ( handle = = nullptr )
< < " Error: libnstest_dlopened.so is still accessible in default namespace " ;
// Now lets see if the soinfo area gets reused in the wrong way:
// load a library to default namespace.
2016-11-25 21:23:11 +01:00
const std : : string lib_public_path = get_testlib_root ( ) + " /public_namespace_libs/ " + g_public_lib ;
2016-04-11 21:42:58 +02:00
void * handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
ASSERT_TRUE ( handle_public ! = nullptr ) < < dlerror ( ) ;
// try to find it in shared namespace
handle = android_dlopen_ext ( g_public_lib , RTLD_NOW | RTLD_NOLOAD , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr )
< < " Error: " < < g_public_lib < < " is accessible in shared namespace " ;
}
2016-05-13 00:20:21 +02:00
TEST ( dlext , ns_isolated_rtld_global ) {
static const char * root_lib = " libnstest_root.so " ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
2016-05-13 00:20:21 +02:00
2016-11-25 21:23:11 +01:00
const std : : string lib_public_path = get_testlib_root ( ) + " /public_namespace_libs " ;
2016-05-13 00:20:21 +02:00
android_namespace_t * ns1 =
android_create_namespace ( " isolated1 " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2016-05-13 00:20:21 +02:00
ANDROID_NAMESPACE_TYPE_ISOLATED ,
lib_public_path . c_str ( ) ,
nullptr ) ;
ASSERT_TRUE ( ns1 ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns1 , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2016-05-13 00:20:21 +02:00
android_namespace_t * ns2 =
android_create_namespace ( " isolated2 " ,
nullptr ,
2016-11-25 21:23:11 +01:00
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
2016-05-13 00:20:21 +02:00
ANDROID_NAMESPACE_TYPE_ISOLATED ,
lib_public_path . c_str ( ) ,
nullptr ) ;
ASSERT_TRUE ( ns2 ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns2 , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2016-05-13 00:20:21 +02:00
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns1 ;
void * handle_global = android_dlopen_ext ( ( lib_public_path + " / " + g_public_lib ) . c_str ( ) ,
RTLD_GLOBAL ,
& extinfo ) ;
ASSERT_TRUE ( handle_global ! = nullptr ) < < dlerror ( ) ;
android_namespace_t * ns1_child =
2017-02-03 23:07:34 +01:00
android_create_namespace ( " isolated1_child " ,
nullptr ,
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
ns1 ) ;
ASSERT_TRUE ( ns1_child ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns1_child , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2016-05-13 00:20:21 +02:00
// Now - only ns1 and ns1 child should be able to dlopen root_lib
// attempt to use ns2 should result in dlerror()
// Check ns1_child first.
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns1_child ;
void * handle1 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle1 ! = nullptr ) < < dlerror ( ) ;
// now ns1
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns1 ;
handle1 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle1 ! = nullptr ) < < dlerror ( ) ;
// and ns2 should fail
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns2 ;
handle1 = android_dlopen_ext ( root_lib , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle1 = = nullptr ) ;
ASSERT_STREQ ( " dlopen failed: library \" libnstest_public.so \" not found " , dlerror ( ) ) ;
2017-10-23 15:10:10 +02:00
}
TEST ( dlext , ns_inaccessible_error_message ) {
// We set up 2 namespaces (a and b) and link a->b with a shared library
// libtestshared.so. Then try to dlopen different library with the same
// name from in namespace a. Note that library should not be accessible
// in either namespace but since it's soname is in the list of shared libs
// the linker will attempt to find it in linked namespace.
//
// Check the error message and make sure it mentions correct namespace name.
ASSERT_TRUE ( android_init_anonymous_namespace ( g_core_shared_libs . c_str ( ) , nullptr ) ) ;
android_namespace_t * ns_a =
android_create_namespace ( " ns_a " ,
nullptr ,
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( ns_a ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_a , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
android_namespace_t * ns_b =
android_create_namespace ( " ns_b " ,
nullptr ,
get_testlib_root ( ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_ISOLATED ,
nullptr ,
nullptr ) ;
ASSERT_TRUE ( ns_b ! = nullptr ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_b , nullptr , g_core_shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
ASSERT_TRUE ( android_link_namespaces ( ns_a , ns_b , " libtestshared.so " ) ) < < dlerror ( ) ;
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns_a ;
std : : string library_path = get_testlib_root ( ) + " /inaccessible_libs/libtestshared.so " ;
void * handle = android_dlopen_ext ( library_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle = = nullptr ) ;
std : : string expected_dlerror =
android : : base : : StringPrintf ( " dlopen failed: library \" %s \" needed or dlopened by \" %s \" "
" is not accessible for the namespace \" ns_a \" " ,
library_path . c_str ( ) ,
get_executable_path ( ) . c_str ( ) ) ;
ASSERT_EQ ( expected_dlerror , dlerror ( ) ) ;
2016-05-13 00:20:21 +02:00
}
2015-11-23 20:26:35 +01:00
TEST ( dlext , ns_anonymous ) {
static const char * root_lib = " libnstest_root.so " ;
2017-02-03 23:07:34 +01:00
std : : string shared_libs = g_core_shared_libs + " : " + g_public_lib ;
2015-11-23 20:26:35 +01:00
2016-11-25 21:23:11 +01:00
const std : : string lib_public_path = get_testlib_root ( ) + " /public_namespace_libs/ " + g_public_lib ;
2015-12-05 03:28:49 +01:00
void * handle_public = dlopen ( lib_public_path . c_str ( ) , RTLD_NOW ) ;
2015-11-23 20:26:35 +01:00
ASSERT_TRUE ( handle_public ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE (
android_init_anonymous_namespace ( shared_libs . c_str ( ) ,
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) )
) < < dlerror ( ) ;
2015-11-23 20:26:35 +01:00
2017-02-03 23:07:34 +01:00
android_namespace_t * ns =
android_create_namespace ( " private " ,
nullptr ,
( get_testlib_root ( ) + " /private_namespace_libs " ) . c_str ( ) ,
ANDROID_NAMESPACE_TYPE_REGULAR ,
nullptr ,
nullptr ) ;
2015-11-23 20:26:35 +01:00
ASSERT_TRUE ( ns ! = nullptr ) < < dlerror ( ) ;
2017-02-03 23:07:34 +01:00
ASSERT_TRUE ( android_link_namespaces ( ns , nullptr , shared_libs . c_str ( ) ) ) < < dlerror ( ) ;
2015-11-23 20:26:35 +01:00
2016-11-25 21:23:11 +01:00
std : : string private_library_absolute_path = get_testlib_root ( ) + " /private_namespace_libs/ " + root_lib ;
2015-11-23 20:26:35 +01:00
android_dlextinfo extinfo ;
extinfo . flags = ANDROID_DLEXT_USE_NAMESPACE ;
extinfo . library_namespace = ns ;
// we are going to copy this library to anonymous mmap and call the copy of ns_get_dlopened_string
void * handle = android_dlopen_ext ( private_library_absolute_path . c_str ( ) , RTLD_NOW , & extinfo ) ;
ASSERT_TRUE ( handle ! = nullptr ) < < dlerror ( ) ;
uintptr_t ns_get_dlopened_string_addr =
reinterpret_cast < uintptr_t > ( dlsym ( handle , " ns_get_dlopened_string " ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string_addr ! = 0 ) < < dlerror ( ) ;
typedef const char * ( * fn_t ) ( ) ;
fn_t ns_get_dlopened_string_private = reinterpret_cast < fn_t > ( ns_get_dlopened_string_addr ) ;
std : : vector < map_record > maps ;
Maps : : parse_maps ( & maps ) ;
uintptr_t addr_start = 0 ;
uintptr_t addr_end = 0 ;
2017-10-11 10:04:14 +02:00
bool has_executable_segment = false ;
2015-11-23 20:26:35 +01:00
std : : vector < map_record > maps_to_copy ;
for ( const auto & rec : maps ) {
if ( rec . pathname = = private_library_absolute_path ) {
if ( addr_start = = 0 ) {
addr_start = rec . addr_start ;
}
addr_end = rec . addr_end ;
2017-10-11 10:04:14 +02:00
has_executable_segment = has_executable_segment | | ( rec . perms & PROT_EXEC ) ! = 0 ;
2015-11-23 20:26:35 +01:00
maps_to_copy . push_back ( rec ) ;
}
}
// some sanity checks..
ASSERT_TRUE ( addr_start > 0 ) ;
ASSERT_TRUE ( addr_end > 0 ) ;
ASSERT_EQ ( 3U , maps_to_copy . size ( ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string_addr > addr_start ) ;
ASSERT_TRUE ( ns_get_dlopened_string_addr < addr_end ) ;
2017-10-11 10:04:14 +02:00
if ( ! has_executable_segment ) {
// For some natively bridged environments this code might be missing
// the executable flag. This is because the guest code is not supposed
// to be executed directly and making it non-executable is more secure.
// If this is the case we assume that the first segment is the one that
// has this flag.
ASSERT_TRUE ( ( maps_to_copy [ 0 ] . perms & PROT_WRITE ) = = 0 ) ;
maps_to_copy [ 0 ] . perms | = PROT_EXEC ;
}
2015-11-23 20:26:35 +01:00
// copy
uintptr_t reserved_addr = reinterpret_cast < uintptr_t > ( mmap ( nullptr , addr_end - addr_start ,
PROT_NONE , MAP_ANON | MAP_PRIVATE ,
- 1 , 0 ) ) ;
ASSERT_TRUE ( reinterpret_cast < void * > ( reserved_addr ) ! = MAP_FAILED ) ;
for ( const auto & rec : maps_to_copy ) {
uintptr_t offset = rec . addr_start - addr_start ;
size_t size = rec . addr_end - rec . addr_start ;
void * addr = reinterpret_cast < void * > ( reserved_addr + offset ) ;
void * map = mmap ( addr , size , PROT_READ | PROT_WRITE ,
MAP_ANON | MAP_PRIVATE | MAP_FIXED , - 1 , 0 ) ;
ASSERT_TRUE ( map ! = MAP_FAILED ) ;
memcpy ( map , reinterpret_cast < void * > ( rec . addr_start ) , size ) ;
mprotect ( map , size , rec . perms ) ;
}
// call the function copy
uintptr_t ns_get_dlopened_string_offset = ns_get_dlopened_string_addr - addr_start ;
fn_t ns_get_dlopened_string_anon = reinterpret_cast < fn_t > ( reserved_addr + ns_get_dlopened_string_offset ) ;
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " ,
ns_get_dlopened_string_anon ( ) ) ;
// They should belong to different namespaces (private and anonymous)
ASSERT_STREQ ( " This string is from private namespace (dlopened library) " ,
ns_get_dlopened_string_private ( ) ) ;
ASSERT_TRUE ( ns_get_dlopened_string_anon ( ) ! = ns_get_dlopened_string_private ( ) ) ;
}
2016-03-24 23:30:30 +01:00
TEST ( dlext , dlopen_handle_value_platform ) {
void * handle = dlopen ( " libtest_dlsym_from_this.so " , RTLD_NOW | RTLD_LOCAL ) ;
ASSERT_TRUE ( ( reinterpret_cast < uintptr_t > ( handle ) & 1 ) ! = 0 )
< < " dlopen should return odd value for the handle " ;
dlclose ( handle ) ;
}
TEST ( dlext , dlopen_handle_value_app_compat ) {
2016-11-16 20:35:43 +01:00
android_set_application_target_sdk_version ( __ANDROID_API_M__ ) ;
2016-03-24 23:30:30 +01:00
void * handle = dlopen ( " libtest_dlsym_from_this.so " , RTLD_NOW | RTLD_LOCAL ) ;
ASSERT_TRUE ( reinterpret_cast < uintptr_t > ( handle ) % sizeof ( uintptr_t ) = = 0 )
< < " dlopen should return valid pointer " ;
dlclose ( handle ) ;
}