Skip to content

Commit

Permalink
Merge tag 'android-7.1.0_r4' of https://android.googlesource.com/plat…
Browse files Browse the repository at this point in the history
…form/bionic into 71

Android 7.1.0 release 4

Change-Id: I3072cf4bc6958e24d48dd64d04e3074336e0dc53
  • Loading branch information
ryzenforce990 committed Oct 25, 2016
2 parents 0d0b7a9 + 97cc201 commit d51d721
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 53 deletions.
6 changes: 4 additions & 2 deletions libc/bionic/pthread_cond.cpp
Expand Up @@ -224,16 +224,18 @@ extern "C" int pthread_cond_timedwait_monotonic_np(pthread_cond_t* cond_interfac
return pthread_cond_timedwait_monotonic(cond_interface, mutex, abs_timeout);
}

// Force this function using CLOCK_MONOTONIC because it was always using
// CLOCK_MONOTONIC in history.
extern "C" int pthread_cond_timedwait_relative_np(pthread_cond_t* cond_interface,
pthread_mutex_t* mutex,
const timespec* rel_timeout) {
timespec ts;
timespec* abs_timeout = nullptr;
if (rel_timeout != nullptr) {
absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_REALTIME);
absolute_timespec_from_timespec(ts, *rel_timeout, CLOCK_MONOTONIC);
abs_timeout = &ts;
}
return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, true, abs_timeout);
return __pthread_cond_timedwait(__get_internal_cond(cond_interface), mutex, false, abs_timeout);
}

extern "C" int pthread_cond_timeout_np(pthread_cond_t* cond_interface,
Expand Down
86 changes: 58 additions & 28 deletions linker/linker.cpp
Expand Up @@ -155,32 +155,35 @@ static soinfo* solist;
static soinfo* sonext;
static soinfo* somain; // main process, always the one after libdl_info

static const char* const kDefaultLdPaths[] = {
#if defined(__LP64__)
"/system/lib64",
"/vendor/lib64",
static const char* const kSystemLibDir = "/system/lib64";
static const char* const kVendorLibDir = "/vendor/lib64";
static const char* const kAsanSystemLibDir = "/data/lib64";
static const char* const kAsanVendorLibDir = "/data/vendor/lib64";
#else
"/system/lib",
"/vendor/lib",
static const char* const kSystemLibDir = "/system/lib";
static const char* const kVendorLibDir = "/vendor/lib";
static const char* const kAsanSystemLibDir = "/data/lib";
static const char* const kAsanVendorLibDir = "/data/vendor/lib";
#endif

static const char* const kDefaultLdPaths[] = {
kSystemLibDir,
kVendorLibDir,
nullptr
};

static const char* const kAsanDefaultLdPaths[] = {
#if defined(__LP64__)
"/data/lib64",
"/system/lib64",
"/data/vendor/lib64",
"/vendor/lib64",
#else
"/data/lib",
"/system/lib",
"/data/vendor/lib",
"/vendor/lib",
#endif
kAsanSystemLibDir,
kSystemLibDir,
kAsanVendorLibDir,
kVendorLibDir,
nullptr
};

// Is ASAN enabled?
static bool g_is_asan = false;

static bool is_system_library(const std::string& realpath) {
for (const auto& dir : g_default_namespace.get_default_library_paths()) {
if (file_is_in_dir(realpath, dir)) {
Expand All @@ -190,12 +193,16 @@ static bool is_system_library(const std::string& realpath) {
return false;
}

#if defined(__LP64__)
static const char* const kSystemLibDir = "/system/lib64";
#else
static const char* const kSystemLibDir = "/system/lib";
#endif

// Checks if the file exists and not a directory.
static bool file_exists(const char* path) {
int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
if (fd == -1) {
return false;
} else {
close(fd);
return true;
}
}
static std::string dirname(const char *path);

// TODO(dimitry): The grey-list is a workaround for http://b/26394120 ---
Expand Down Expand Up @@ -2433,9 +2440,28 @@ void* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo,
}
}

std::string asan_name_holder;

const char* translated_name = name;
if (g_is_asan) {
if (file_is_in_dir(name, kSystemLibDir)) {
asan_name_holder = std::string(kAsanSystemLibDir) + "/" + basename(name);
if (file_exists(asan_name_holder.c_str())) {
translated_name = asan_name_holder.c_str();
PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
}
} else if (file_is_in_dir(name, kVendorLibDir)) {
asan_name_holder = std::string(kAsanVendorLibDir) + "/" + basename(name);
if (file_exists(asan_name_holder.c_str())) {
translated_name = asan_name_holder.c_str();
PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
}
}
}

ProtectedDataGuard guard;
reset_g_active_shim_libs();
soinfo* si = find_library(ns, name, flags, extinfo, caller);
soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
if (si != nullptr) {
si->call_constructors();
return si->to_handle();
Expand Down Expand Up @@ -2568,8 +2594,8 @@ bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_
find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);

if (candidate == nullptr) {
DL_ERR("error initializing public namespace: \"%s\" was not found"
" in the default namespace", soname.c_str());
DL_ERR("error initializing public namespace: a library with soname \"%s\""
" was not found in the default namespace", soname.c_str());
return false;
}

Expand Down Expand Up @@ -4193,6 +4219,7 @@ static void init_default_namespace() {
const char* bname = basename(interp);
if (bname && (strcmp(bname, "linker_asan") == 0 || strcmp(bname, "linker_asan64") == 0)) {
g_default_ld_paths = kAsanDefaultLdPaths;
g_is_asan = true;
} else {
g_default_ld_paths = kDefaultLdPaths;
}
Expand Down Expand Up @@ -4269,12 +4296,15 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(
ldshim_libs_env = getenv("LD_SHIM_LIBS");
}

const char* executable_path = get_executable_path();
struct stat file_stat;
if (TEMP_FAILURE_RETRY(stat(executable_path, &file_stat)) != 0) {
__libc_fatal("unable to stat file for the executable \"%s\": %s", executable_path, strerror(errno));
// Stat "/proc/self/exe" instead of executable_path because
// the executable could be unlinked by this point and it should
// not cause a crash (see http://b/31084669)
if (TEMP_FAILURE_RETRY(stat("/proc/self/exe", &file_stat)) != 0) {
__libc_fatal("unable to stat \"/proc/self/exe\": %s", strerror(errno));
}

const char* executable_path = get_executable_path();
soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL);
if (si == nullptr) {
__libc_fatal("Couldn't allocate soinfo: out of memory?");
Expand Down
6 changes: 6 additions & 0 deletions linker/linker.h
Expand Up @@ -59,6 +59,12 @@
__libc_format_fd(2, "\n"); \
} while (false)

#define DL_ERR_AND_LOG(fmt, x...) \
do { \
DL_ERR(fmt, x); \
PRINT(fmt, x); \
} while (false)

#if defined(__LP64__)
#define ELFW(what) ELF64_ ## what
#else
Expand Down
44 changes: 26 additions & 18 deletions linker/linker_phdr.cpp
Expand Up @@ -248,14 +248,15 @@ bool ElfReader::VerifyElfHeader() {
return true;
}

bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size) {
bool ElfReader::CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment) {
off64_t range_start;
off64_t range_end;

return safe_add(&range_start, file_offset_, offset) &&
safe_add(&range_end, range_start, size) &&
range_start < file_size_ &&
range_end <= file_size_;
(range_start < file_size_) &&
(range_end <= file_size_) &&
((offset % alignment) == 0);
}

// Loads the program header table from an ELF file into a read-only private
Expand All @@ -272,8 +273,11 @@ bool ElfReader::ReadProgramHeaders() {

// Boundary checks
size_t size = phdr_num_ * sizeof(ElfW(Phdr));
if (!CheckFileRange(header_.e_phoff, size)) {
DL_ERR("\"%s\" has invalid phdr offset/size", name_.c_str());
if (!CheckFileRange(header_.e_phoff, size, alignof(ElfW(Phdr)))) {
DL_ERR_AND_LOG("\"%s\" has invalid phdr offset/size: %zu/%zu",
name_.c_str(),
static_cast<size_t>(header_.e_phoff),
size);
return false;
}

Expand All @@ -290,13 +294,16 @@ bool ElfReader::ReadSectionHeaders() {
shdr_num_ = header_.e_shnum;

if (shdr_num_ == 0) {
DL_ERR("\"%s\" has no section headers", name_.c_str());
DL_ERR_AND_LOG("\"%s\" has no section headers", name_.c_str());
return false;
}

size_t size = shdr_num_ * sizeof(ElfW(Shdr));
if (!CheckFileRange(header_.e_shoff, size)) {
DL_ERR("\"%s\" has invalid shdr offset/size", name_.c_str());
if (!CheckFileRange(header_.e_shoff, size, alignof(const ElfW(Shdr)))) {
DL_ERR_AND_LOG("\"%s\" has invalid shdr offset/size: %zu/%zu",
name_.c_str(),
static_cast<size_t>(header_.e_shoff),
size);
return false;
}

Expand All @@ -320,26 +327,27 @@ bool ElfReader::ReadDynamicSection() {
}

if (dynamic_shdr == nullptr) {
DL_ERR("\"%s\" .dynamic section header was not found", name_.c_str());
DL_ERR_AND_LOG("\"%s\" .dynamic section header was not found", name_.c_str());
return false;
}

if (dynamic_shdr->sh_link >= shdr_num_) {
DL_ERR("\"%s\" .dynamic section has invalid sh_link: %d", name_.c_str(), dynamic_shdr->sh_link);
DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid sh_link: %d",
name_.c_str(),
dynamic_shdr->sh_link);
return false;
}

const ElfW(Shdr)* strtab_shdr = &shdr_table_[dynamic_shdr->sh_link];

if (strtab_shdr->sh_type != SHT_STRTAB) {
DL_ERR("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
DL_ERR_AND_LOG("\"%s\" .dynamic section has invalid link(%d) sh_type: %d (expected SHT_STRTAB)",
name_.c_str(), dynamic_shdr->sh_link, strtab_shdr->sh_type);
return false;
}

if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size)) {
DL_ERR("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
PRINT("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
if (!CheckFileRange(dynamic_shdr->sh_offset, dynamic_shdr->sh_size, alignof(const ElfW(Dyn)))) {
DL_ERR_AND_LOG("\"%s\" has invalid offset/size of .dynamic section", name_.c_str());
return false;
}

Expand All @@ -350,9 +358,9 @@ bool ElfReader::ReadDynamicSection() {

dynamic_ = static_cast<const ElfW(Dyn)*>(dynamic_fragment_.data());

if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size)) {
DL_ERR("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
name_.c_str());
if (!CheckFileRange(strtab_shdr->sh_offset, strtab_shdr->sh_size, alignof(const char))) {
DL_ERR_AND_LOG("\"%s\" has invalid offset/size of the .strtab section linked from .dynamic section",
name_.c_str());
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion linker/linker_phdr.h
Expand Up @@ -65,7 +65,7 @@ class ElfReader {
bool LoadSegments();
bool FindPhdr();
bool CheckPhdr(ElfW(Addr));
bool CheckFileRange(ElfW(Addr) offset, size_t size);
bool CheckFileRange(ElfW(Addr) offset, size_t size, size_t alignment);

bool did_read_;
bool did_load_;
Expand Down
87 changes: 86 additions & 1 deletion tests/pty_test.cpp
Expand Up @@ -14,11 +14,17 @@
* limitations under the License.
*/

#include <pty.h>

#include <gtest/gtest.h>

#include <pty.h>
#include <pthread.h>
#include <sys/ioctl.h>

#include <atomic>

#include <android-base/file.h>

#include "utils.h"

TEST(pty, openpty) {
Expand Down Expand Up @@ -64,3 +70,82 @@ TEST(pty, forkpty) {

close(master);
}

struct PtyReader_28979140_Arg {
int slave_fd;
uint32_t data_count;
bool finished;
std::atomic<bool> matched;
};

static void PtyReader_28979140(PtyReader_28979140_Arg* arg) {
arg->finished = false;
cpu_set_t cpus;
ASSERT_EQ(0, sched_getaffinity(0, sizeof(cpu_set_t), &cpus));
CPU_CLR(0, &cpus);
ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));

uint32_t counter = 0;
while (counter <= arg->data_count) {
char buf[4096]; // Use big buffer to read to hit the bug more easily.
size_t to_read = std::min(sizeof(buf), (arg->data_count + 1 - counter) * sizeof(uint32_t));
ASSERT_TRUE(android::base::ReadFully(arg->slave_fd, buf, to_read));
size_t num_of_value = to_read / sizeof(uint32_t);
uint32_t* p = reinterpret_cast<uint32_t*>(buf);
while (num_of_value-- > 0) {
if (*p++ != counter++) {
arg->matched = false;
}
}
}
close(arg->slave_fd);
arg->finished = true;
}

TEST(pty, bug_28979140) {
// This test is to test a kernel bug, which uses a lock free ring-buffer to
// pass data through a raw pty, but missing necessary memory barriers.
if (sysconf(_SC_NPROCESSORS_ONLN) == 1) {
GTEST_LOG_(INFO) << "This test tests bug happens only on multiprocessors.";
return;
}
constexpr uint32_t TEST_DATA_COUNT = 200000;

// 1. Open raw pty.
int master;
int slave;
ASSERT_EQ(0, openpty(&master, &slave, nullptr, nullptr, nullptr));
termios tattr;
ASSERT_EQ(0, tcgetattr(slave, &tattr));
cfmakeraw(&tattr);
ASSERT_EQ(0, tcsetattr(slave, TCSADRAIN, &tattr));

// 2. Create thread for slave reader.
pthread_t thread;
PtyReader_28979140_Arg arg;
arg.slave_fd = slave;
arg.data_count = TEST_DATA_COUNT;
arg.matched = true;
ASSERT_EQ(0, pthread_create(&thread, nullptr,
reinterpret_cast<void*(*)(void*)>(PtyReader_28979140),
&arg));

// 3. Make master thread and slave thread running on different cpus:
// master thread uses cpu 0, and slave thread uses other cpus.
cpu_set_t cpus;
CPU_ZERO(&cpus);
CPU_SET(0, &cpus);
ASSERT_EQ(0, sched_setaffinity(0, sizeof(cpu_set_t), &cpus));

// 4. Send data to slave.
uint32_t counter = 0;
while (counter <= TEST_DATA_COUNT) {
ASSERT_TRUE(android::base::WriteFully(master, &counter, sizeof(counter)));
ASSERT_TRUE(arg.matched) << "failed at count = " << counter;
counter++;
}
ASSERT_EQ(0, pthread_join(thread, nullptr));
ASSERT_TRUE(arg.finished);
ASSERT_TRUE(arg.matched);
close(master);
}

0 comments on commit d51d721

Please sign in to comment.