Merge "Don't print 168^W143 lines of help when someone makes a typo."
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 58eaed7..4e083ae 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -18,10 +18,12 @@
#include <dirent.h>
#include <fcntl.h>
#include <stdlib.h>
-#include <syscall.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/un.h>
+#include <syscall.h>
#include <unistd.h>
#include <limits>
@@ -51,24 +53,25 @@
using android::base::unique_fd;
using android::base::StringPrintf;
-static bool pid_contains_tid(pid_t pid, pid_t tid) {
- std::string task_path = StringPrintf("/proc/%d/task/%d", pid, tid);
- return access(task_path.c_str(), F_OK) == 0;
+static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
+ struct stat st;
+ std::string task_path = StringPrintf("task/%d", tid);
+ return fstatat(pid_proc_fd, task_path.c_str(), &st, 0) == 0;
}
// Attach to a thread, and verify that it's still a member of the given process
-static bool ptrace_seize_thread(pid_t pid, pid_t tid, std::string* error) {
+static bool ptrace_seize_thread(int pid_proc_fd, pid_t tid, std::string* error) {
if (ptrace(PTRACE_SEIZE, tid, 0, 0) != 0) {
*error = StringPrintf("failed to attach to thread %d: %s", tid, strerror(errno));
return false;
}
// Make sure that the task we attached to is actually part of the pid we're dumping.
- if (!pid_contains_tid(pid, tid)) {
+ if (!pid_contains_tid(pid_proc_fd, tid)) {
if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
PLOG(FATAL) << "failed to detach from thread " << tid;
}
- *error = StringPrintf("thread %d is not in process %d", tid, pid);
+ *error = StringPrintf("thread %d is not in process", tid);
return false;
}
@@ -190,6 +193,24 @@
_exit(1);
}
+static void drop_capabilities() {
+ __user_cap_header_struct capheader;
+ memset(&capheader, 0, sizeof(capheader));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ __user_cap_data_struct capdata[2];
+ memset(&capdata, 0, sizeof(capdata));
+
+ if (capset(&capheader, &capdata[0]) == -1) {
+ PLOG(FATAL) << "failed to drop capabilities";
+ }
+
+ if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0) {
+ PLOG(FATAL) << "failed to set PR_SET_NO_NEW_PRIVS";
+ }
+}
+
static void check_process(int proc_fd, pid_t expected_pid) {
android::procinfo::ProcessInfo proc_info;
if (!android::procinfo::GetProcessInfoFromProcPidFd(proc_fd, &proc_info)) {
@@ -263,7 +284,7 @@
check_process(target_proc_fd, target);
std::string attach_error;
- if (!ptrace_seize_thread(target, main_tid, &attach_error)) {
+ if (!ptrace_seize_thread(target_proc_fd, main_tid, &attach_error)) {
LOG(FATAL) << attach_error;
}
@@ -304,6 +325,7 @@
}
int signo = siginfo.si_signo;
+ bool fatal_signal = signo != DEBUGGER_SIGNAL;
bool backtrace = false;
uintptr_t abort_address = 0;
@@ -319,17 +341,16 @@
// Now that we have the signal that kicked things off, attach all of the
// sibling threads, and then proceed.
- bool fatal_signal = signo != DEBUGGER_SIGNAL;
- std::set<pid_t> siblings;
std::set<pid_t> attached_siblings;
- if (fatal_signal || backtrace) {
+ {
+ std::set<pid_t> siblings;
if (!android::procinfo::GetProcessTids(target, &siblings)) {
PLOG(FATAL) << "failed to get process siblings";
}
siblings.erase(main_tid);
for (pid_t sibling_tid : siblings) {
- if (!ptrace_seize_thread(target, sibling_tid, &attach_error)) {
+ if (!ptrace_seize_thread(target_proc_fd, sibling_tid, &attach_error)) {
LOG(WARNING) << attach_error;
} else {
attached_siblings.insert(sibling_tid);
@@ -337,11 +358,18 @@
}
}
+ std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
+ if (!backtrace_map) {
+ LOG(FATAL) << "failed to create backtrace map";
+ }
+
+ // Drop our capabilities now that we've attached to the threads we care about.
+ drop_capabilities();
+
check_process(target_proc_fd, target);
// TODO: Use seccomp to lock ourselves down.
- std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(main_tid));
std::string amfd_data;
if (backtrace) {
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 9469bbd..38a7be3 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -39,6 +39,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/capability.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/socket.h>
@@ -207,7 +208,7 @@
}
// Don't use fork(2) to avoid calling pthread_atfork handlers.
- int forkpid = clone(nullptr, nullptr, SIGCHLD, nullptr);
+ int forkpid = clone(nullptr, nullptr, 0, nullptr);
if (forkpid == -1) {
__libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s",
strerror(errno));
@@ -216,6 +217,11 @@
close(pipefds[0]);
close(pipefds[1]);
+ // Set all of the ambient capability bits we can, so that crash_dump can ptrace us.
+ for (unsigned long i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) != -1; ++i) {
+ prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0);
+ }
+
char buf[10];
snprintf(buf, sizeof(buf), "%d", thread_info->crashing_tid);
execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, buf, nullptr);
@@ -242,10 +248,12 @@
close(pipefds[0]);
// Don't leave a zombie child.
- siginfo_t child_siginfo;
- if (TEMP_FAILURE_RETRY(waitid(P_PID, forkpid, &child_siginfo, WEXITED)) != 0) {
+ int status;
+ if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, __WCLONE)) == -1 && errno != ECHILD) {
__libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
strerror(errno));
+ } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
thread_info->crash_dump_started = false;
}
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 965a81f..2388edc 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -265,10 +265,14 @@
if (!svc) {
return -1;
}
- if (!svc->Start()) {
+ if (!start_waiting_for_exec()) {
return -1;
}
- waiting_for_exec = true;
+ if (!svc->Start()) {
+ stop_waiting_for_exec();
+ ServiceManager::GetInstance().RemoveService(*svc);
+ return -1;
+ }
return 0;
}
@@ -1018,7 +1022,7 @@
<< "\") failed: value too long";
return -1;
}
- if (!wait_property(name, value)) {
+ if (!start_waiting_for_property(name, value)) {
LOG(ERROR) << "do_wait_for_prop(\"" << name << "\", \"" << value
<< "\") failed: init already in waiting";
return -1;
diff --git a/init/init.cpp b/init/init.cpp
index c8c18d2..43f601f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -82,7 +82,7 @@
const char *ENV[32];
-bool waiting_for_exec = false;
+static std::unique_ptr<Timer> waiting_for_exec(nullptr);
static int epoll_fd = -1;
@@ -131,7 +131,24 @@
return -1;
}
-bool wait_property(const char *name, const char *value)
+bool start_waiting_for_exec()
+{
+ if (waiting_for_exec) {
+ return false;
+ }
+ waiting_for_exec.reset(new Timer());
+ return true;
+}
+
+void stop_waiting_for_exec()
+{
+ if (waiting_for_exec) {
+ LOG(INFO) << "Wait for exec took " << *waiting_for_exec;
+ waiting_for_exec.reset();
+ }
+}
+
+bool start_waiting_for_property(const char *name, const char *value)
{
if (waiting_for_prop) {
return false;
@@ -142,7 +159,8 @@
wait_prop_value = value;
waiting_for_prop.reset(new Timer());
} else {
- LOG(INFO) << "wait_property(\"" << name << "\", \"" << value << "\"): already set";
+ LOG(INFO) << "start_waiting_for_property(\""
+ << name << "\", \"" << value << "\"): already set";
}
return true;
}
diff --git a/init/init.h b/init/init.h
index 4e4da32..3768c02 100644
--- a/init/init.h
+++ b/init/init.h
@@ -23,7 +23,6 @@
class Service;
extern const char *ENV[32];
-extern bool waiting_for_exec;
extern std::string default_console;
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
@@ -36,6 +35,10 @@
int add_environment(const char* key, const char* val);
-bool wait_property(const char *name, const char *value);
+bool start_waiting_for_exec();
+
+void stop_waiting_for_exec();
+
+bool start_waiting_for_property(const char *name, const char *value);
#endif /* _INIT_INIT_H */
diff --git a/init/service.cpp b/init/service.cpp
index 0f7f62f..e186f27 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -997,7 +997,7 @@
}
if (svc->Reap()) {
- waiting_for_exec = false;
+ stop_waiting_for_exec();
RemoveService(*svc);
}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 013999a..b701bba 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -177,11 +177,8 @@
CAP_MASK_LONG(CAP_SETPCAP),
"system/bin/webview_zygote64" },
- { 00755, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SYS_PTRACE),
- "system/bin/crash_dump32" },
- { 00755, AID_ROOT, AID_SHELL, CAP_MASK_LONG(CAP_SYS_PTRACE),
- "system/bin/crash_dump64" },
-
+ { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
diff --git a/liblog/logger_write.c b/liblog/logger_write.c
index 1a2d506..4324125 100644
--- a/liblog/logger_write.c
+++ b/liblog/logger_write.c
@@ -514,6 +514,14 @@
strcpy(buf, "Unspecified assertion failed");
}
+ // Log assertion failures to stderr for the benefit of "adb shell" users
+ // and gtests (http://b/23675822).
+ struct iovec iov[2] = {
+ { buf, strlen(buf) },
+ { (char*) "\n", 1 },
+ };
+ TEMP_FAILURE_RETRY(writev(2, iov, 2));
+
__android_log_write(ANDROID_LOG_FATAL, tag, buf);
abort(); /* abort so we have a chance to debug the situation */
/* NOTREACHED */
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index d7b5cb5..2f23c2c 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -246,7 +246,9 @@
// For now we rely on CTS test to catch things like this but
// it should probably be addressed in the future.
for (const auto& soname : sonames) {
- dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE);
+ LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+ "Error preloading public library %s: %s",
+ soname.c_str(), dlerror());
}
public_libraries_ = base::Join(sonames, ':');
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index 671200f..e074a92 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -74,12 +74,9 @@
EXPECT_EQ(other[3], 5);
}
-// TODO: gtest isn't capable of parsing Abort messages formatted by
-// Android (fails differently on host and target), so we always need to
-// use an empty error message for death tests.
TEST_F(VectorTest, SetCapacity_Overflow) {
Vector<int> vector;
- EXPECT_DEATH(vector.setCapacity(SIZE_MAX / sizeof(int) + 1), "");
+ EXPECT_DEATH(vector.setCapacity(SIZE_MAX / sizeof(int) + 1), "Assertion failed");
}
TEST_F(VectorTest, SetCapacity_ShrinkBelowSize) {
@@ -95,20 +92,13 @@
ASSERT_EQ(8U, vector.capacity());
}
-// NOTE: All of the tests below are useless because of the "TODO" above.
-// We have no way of knowing *why* the process crashed. Given that we're
-// inserting a NULL array, we'll fail with a SIGSEGV eventually. We need
-// the ability to make assertions on the abort message to make sure we're
-// failing for the right reasons.
TEST_F(VectorTest, _grow_OverflowSize) {
Vector<int> vector;
vector.add(1);
// Checks that the size calculation (not the capacity calculation) doesn't
// overflow : the size here will be (1 + SIZE_MAX).
- //
- // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size_overflow");
- EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "");
+ EXPECT_DEATH(vector.insertArrayAt(NULL, 0, SIZE_MAX), "new_size overflow");
}
TEST_F(VectorTest, _grow_OverflowCapacityDoubling) {
@@ -116,18 +106,14 @@
// This should fail because the calculated capacity will overflow even though
// the size of the vector doesn't.
- //
- // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity_overflow");
- EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "");
+ EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX - 1)), "new_capacity overflow");
}
TEST_F(VectorTest, _grow_OverflowBufferAlloc) {
Vector<int> vector;
// This should fail because the capacity * sizeof(int) overflows, even
// though the capacity itself doesn't.
- //
- // EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
- EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "");
+ EXPECT_DEATH(vector.insertArrayAt(NULL, 0, (SIZE_MAX / 2)), "new_alloc_size overflow");
}
TEST_F(VectorTest, editArray_Shared) {