2014-11-04 18:38:18 +01:00
/*
* Copyright ( C ) 2012 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>
2017-08-30 04:30:53 +02:00
# if defined(__BIONIC__)
# include <android-base/properties.h>
# endif
2014-11-04 18:38:18 +01:00
# include <dlfcn.h>
# include <libgen.h>
# include <limits.h>
# include <stdio.h>
# include <stdint.h>
# include <string>
2017-05-19 18:01:24 +02:00
# include <iostream>
# include <fstream>
2014-11-04 18:38:18 +01:00
2017-03-29 22:48:02 +02:00
# include "gtest_globals.h"
2018-04-04 05:03:12 +02:00
# include "TemporaryFile.h"
2017-02-23 20:53:43 +01:00
# include "utils.h"
2014-11-04 18:38:18 +01:00
extern " C " int main_global_default_serial ( ) {
return 3370318 ;
}
extern " C " int main_global_protected_serial ( ) {
return 2716057 ;
}
// The following functions are defined in DT_NEEDED
// libdl_preempt_test.so library.
// This one calls main_global_default_serial
extern " C " int main_global_default_get_serial ( ) ;
// This one calls main_global_protected_serial
extern " C " int main_global_protected_get_serial ( ) ;
// This one calls lib_global_default_serial
extern " C " int lib_global_default_get_serial ( ) ;
// This one calls lib_global_protected_serial
extern " C " int lib_global_protected_get_serial ( ) ;
// This test verifies that the global default function
// main_global_default_serial() is preempted by
// the function defined above.
TEST ( dl , main_preempts_global_default ) {
ASSERT_EQ ( 3370318 , main_global_default_get_serial ( ) ) ;
}
// This one makes sure that the global protected
// symbols do not get preempted
TEST ( dl , main_does_not_preempt_global_protected ) {
ASSERT_EQ ( 3370318 , main_global_protected_get_serial ( ) ) ;
}
// check same things for lib
TEST ( dl , lib_preempts_global_default ) {
ASSERT_EQ ( 3370318 , lib_global_default_get_serial ( ) ) ;
}
TEST ( dl , lib_does_not_preempt_global_protected ) {
ASSERT_EQ ( 3370318 , lib_global_protected_get_serial ( ) ) ;
}
2017-02-23 20:53:43 +01:00
TEST ( dl , exec_linker ) {
# if defined(__BIONIC__)
# if defined(__LP64__)
static constexpr const char * kPathToLinker = " /system/bin/linker64 " ;
# else
static constexpr const char * kPathToLinker = " /system/bin/linker " ;
# endif
ExecTestHelper eth ;
std : : string expected_output = std : : string ( " This is " ) + kPathToLinker +
" , the helper program for dynamic executables. \n " ;
eth . SetArgs ( { kPathToLinker , nullptr } ) ;
eth . Run ( [ & ] ( ) { execve ( kPathToLinker , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , expected_output . c_str ( ) ) ;
# endif
}
2017-03-29 22:48:02 +02:00
TEST ( dl , preinit_system_calls ) {
# if defined(__BIONIC__)
std : : string helper = get_testlib_root ( ) +
" /preinit_syscall_test_helper/preinit_syscall_test_helper " ;
chmod ( helper . c_str ( ) , 0755 ) ; // TODO: "x" lost in CTS, b/34945607
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , nullptr ) ;
# endif
}
TEST ( dl , xfail_preinit_getauxval ) {
# if defined(__BIONIC__)
std : : string helper = get_testlib_root ( ) +
" /preinit_getauxval_test_helper/preinit_getauxval_test_helper " ;
chmod ( helper . c_str ( ) , 0755 ) ; // TODO: "x" lost in CTS, b/34945607
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , nullptr ) ;
# endif
}
2017-05-19 18:01:24 +02:00
TEST ( dl , exec_without_ld_preload ) {
# if defined(__BIONIC__)
std : : string helper = get_testlib_root ( ) +
" /ld_preload_test_helper/ld_preload_test_helper " ;
chmod ( helper . c_str ( ) , 0755 ) ;
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , " 12345 " ) ;
# endif
}
TEST ( dl , exec_with_ld_preload ) {
# if defined(__BIONIC__)
std : : string helper = get_testlib_root ( ) +
" /ld_preload_test_helper/ld_preload_test_helper " ;
std : : string env = std : : string ( " LD_PRELOAD= " ) + get_testlib_root ( ) + " /ld_preload_test_helper_lib2.so " ;
chmod ( helper . c_str ( ) , 0755 ) ;
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . SetEnv ( { env . c_str ( ) , nullptr } ) ;
// ld_preload_test_helper calls get_value_from_lib() and returns the value.
// The symbol is defined by two libs: ld_preload_test_helper_lib.so and
// ld_preloaded_lib.so. The former is DT_NEEDED and the latter is LD_PRELOADED
// via this execution. The main executable is linked to the LD_PRELOADED lib
// and the value given from the lib is returned.
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , " 54321 " ) ;
# endif
}
// ld_config_test_helper must fail because it is depending on a lib which is not
// in the search path
//
// Call sequence is...
// _helper -- (get_value_from_lib()) -->
// _lib1.so -- (get_value_from_another_lib()) -->
// _lib2.so (returns 12345)
// The two libs are in ns2/ subdir.
TEST ( dl , exec_without_ld_config_file ) {
# if defined(__BIONIC__)
std : : string error_message = " CANNOT LINK EXECUTABLE \" " + get_testlib_root ( ) + " /ld_config_test_helper/ld_config_test_helper \" : library \" ld_config_test_helper_lib1.so \" not found \n " ;
std : : string helper = get_testlib_root ( ) +
" /ld_config_test_helper/ld_config_test_helper " ;
chmod ( helper . c_str ( ) , 0755 ) ;
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
2017-09-29 11:52:17 +02:00
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , EXIT_FAILURE , error_message . c_str ( ) ) ;
2017-05-19 18:01:24 +02:00
# endif
}
# if defined(__BIONIC__)
2018-05-09 14:37:47 +02:00
extern " C " void android_get_LD_LIBRARY_PATH ( char * , size_t ) ;
2018-04-04 05:03:12 +02:00
static void create_ld_config_file ( const char * config_file ) {
2018-05-09 14:37:47 +02:00
char default_search_paths [ PATH_MAX ] ;
android_get_LD_LIBRARY_PATH ( default_search_paths , sizeof ( default_search_paths ) ) ;
2018-04-04 05:03:12 +02:00
std : : ofstream fout ( config_file , std : : ios : : out ) ;
2017-05-19 18:01:24 +02:00
fout < < " dir.test = " < < get_testlib_root ( ) < < " /ld_config_test_helper/ " < < std : : endl
< < " [test] " < < std : : endl
< < " additional.namespaces = ns2 " < < std : : endl
< < " namespace.default.search.paths = " < < get_testlib_root ( ) < < std : : endl
< < " namespace.default.links = ns2 " < < std : : endl
< < " namespace.default.link.ns2.shared_libs = libc.so:libm.so:libdl.so:ld_config_test_helper_lib1.so " < < std : : endl
2018-05-09 14:37:47 +02:00
< < " namespace.ns2.search.paths = " < < default_search_paths < < " : " < < get_testlib_root ( ) < < " /ns2 " < < std : : endl ;
2017-05-19 18:01:24 +02:00
fout . close ( ) ;
}
# endif
2017-09-19 02:48:07 +02:00
# if defined(__BIONIC__)
2017-10-18 13:23:08 +02:00
static bool is_debuggable_build ( ) {
return android : : base : : GetBoolProperty ( " ro.debuggable " , false ) ;
2017-09-19 02:48:07 +02:00
}
# endif
2017-05-19 18:01:24 +02:00
// _lib1.so and _lib2.so are now searchable by having another namespace 'ns2'
// whose search paths include the 'ns2/' subdir.
TEST ( dl , exec_with_ld_config_file ) {
# if defined(__BIONIC__)
2017-10-18 13:23:08 +02:00
if ( ! is_debuggable_build ( ) ) {
2017-09-19 02:48:07 +02:00
// LD_CONFIG_FILE is not supported on user build
return ;
}
2017-05-19 18:01:24 +02:00
std : : string helper = get_testlib_root ( ) +
" /ld_config_test_helper/ld_config_test_helper " ;
2018-04-04 05:03:12 +02:00
TemporaryFile config_file ;
create_ld_config_file ( config_file . filename ) ;
std : : string env = std : : string ( " LD_CONFIG_FILE= " ) + config_file . filename ;
2017-05-19 18:01:24 +02:00
chmod ( helper . c_str ( ) , 0755 ) ;
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . SetEnv ( { env . c_str ( ) , nullptr } ) ;
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , " 12345 " ) ;
# endif
}
// _lib3.so has same symbol as lib2.so but returns 54321. _lib3.so is
// LD_PRELOADed. This test is to ensure LD_PRELOADed libs are available to
// additional namespaces other than the default namespace.
TEST ( dl , exec_with_ld_config_file_with_ld_preload ) {
# if defined(__BIONIC__)
2017-10-18 13:23:08 +02:00
if ( ! is_debuggable_build ( ) ) {
2017-09-19 02:48:07 +02:00
// LD_CONFIG_FILE is not supported on user build
return ;
}
2017-05-19 18:01:24 +02:00
std : : string helper = get_testlib_root ( ) +
" /ld_config_test_helper/ld_config_test_helper " ;
2018-04-04 05:03:12 +02:00
TemporaryFile config_file ;
create_ld_config_file ( config_file . filename ) ;
std : : string env = std : : string ( " LD_CONFIG_FILE= " ) + config_file . filename ;
2017-05-19 18:01:24 +02:00
std : : string env2 = std : : string ( " LD_PRELOAD= " ) + get_testlib_root ( ) + " /ld_config_test_helper_lib3.so " ;
chmod ( helper . c_str ( ) , 0755 ) ;
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . SetEnv ( { env . c_str ( ) , env2 . c_str ( ) , nullptr } ) ;
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , 0 , " 54321 " ) ;
# endif
}
// ensures that LD_CONFIG_FILE env var does not work for production builds.
// The test input is the same as exec_with_ld_config_file, but it must fail in
// this case.
TEST ( dl , disable_ld_config_file ) {
# if defined(__BIONIC__)
if ( getuid ( ) = = 0 ) {
// when executed from the shell (e.g. not as part of CTS), skip the test.
// This test is only for CTS.
return ;
}
2017-10-18 13:23:08 +02:00
if ( is_debuggable_build ( ) ) {
2017-08-30 04:30:53 +02:00
// Skip the test for non production devices
return ;
}
2017-05-19 18:01:24 +02:00
std : : string error_message = " CANNOT LINK EXECUTABLE \" " + get_testlib_root ( ) + " /ld_config_test_helper/ld_config_test_helper \" : library \" ld_config_test_helper_lib1.so \" not found \n " ;
std : : string helper = get_testlib_root ( ) +
" /ld_config_test_helper/ld_config_test_helper " ;
2018-04-04 05:03:12 +02:00
TemporaryFile config_file ;
create_ld_config_file ( config_file . filename ) ;
std : : string env = std : : string ( " LD_CONFIG_FILE= " ) + config_file . filename ;
2017-05-19 18:01:24 +02:00
chmod ( helper . c_str ( ) , 0755 ) ;
ExecTestHelper eth ;
eth . SetArgs ( { helper . c_str ( ) , nullptr } ) ;
eth . SetEnv ( { env . c_str ( ) , nullptr } ) ;
2017-11-28 05:37:03 +01:00
eth . Run ( [ & ] ( ) { execve ( helper . c_str ( ) , eth . GetArgs ( ) , eth . GetEnv ( ) ) ; } , EXIT_FAILURE , error_message . c_str ( ) ) ;
2017-05-19 18:01:24 +02:00
# endif
}