int create_and_bind_tcp_socket(int port) { char port_as_string[20]; snprintf(port_as_string, sizeof(port_as_string), "%d", port); int rv; struct addrinfo hints, *localAddresses; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, port_as_string, &hints, &localAddresses)) != 0) { fatal_errno("getaddrinfo"); } // loop through all the results and bind to the first we can int yes = 1; int sock; struct addrinfo *localAddress; for(localAddress = localAddresses; localAddress != NULL; localAddress = localAddress->ai_next) { if ((sock = socket(localAddress->ai_family, localAddress->ai_socktype, localAddress->ai_protocol)) == -1) { continue; } if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) { close(sock); continue; } if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) { continue; } if (bind(sock, localAddress->ai_addr, localAddress->ai_addrlen) == -1) { close(sock); continue; } break; } // All done with this structure. freeaddrinfo(localAddresses); // Check if we succeeded. if (localAddress == NULL) { fatal("Couldn't bind"); } return sock; }
static void bind_file (const char *src_path, const char *dest_path, struct stat *st) { int fd; if (S_ISREG (st->st_mode)) { fd = creat (dest_path, st->st_mode & 0777); if (fd < 0) fatal_errno ("create dest"); close (fd); if (lchown(dest_path, st->st_uid, st->st_gid) < 0) fatal_errno ("lchown"); if (mount (src_path, dest_path, NULL, MS_MGC_VAL|MS_BIND|MS_NODEV|MS_NOSUID|MS_RDONLY|MS_NOATIME, NULL) != 0) fatal ("bind file %s", src_path); } else if (S_ISDIR (st->st_mode)) { if (mkdir (dest_path, st->st_mode & 0777)) fatal_errno ("create dest dir"); if (lchown(dest_path, st->st_uid, st->st_gid) < 0) fatal_errno ("lchown"); if (mount (src_path, dest_path, NULL, MS_MGC_VAL|MS_BIND|MS_NODEV|MS_NOSUID|MS_RDONLY|MS_NOATIME, NULL) != 0) fatal ("bind dir %s", src_path); } else if (S_ISLNK (st->st_mode)) { ssize_t res; char buf[1024]; res = readlink (src_path, buf, sizeof (buf)); if (res < 0) fatal_errno ("Could not read link"); if (res >= sizeof (buf)) fatal ("link to long"); buf[res] = 0; if (symlink (buf, dest_path) < 0) fatal_errno ("symlink"); chmod (dest_path, st->st_mode & 0777); if (lchown(dest_path, st->st_uid, st->st_gid) < 0) fatal_errno ("lchown"); } else fatal ("Uknown file type %s\n", src_path); }
void comm_send(comm_t comm, u1 *buf, u4 len) { while (len > 0) { ssize_t n = write(comm, (void *) buf, (size_t) len); if (n == -1) { if (errno == EINTR || errno == EAGAIN) { continue; } fatal_errno("write failed"); } len -= n; buf += n; } }
void vcd_init(const char *filename, tree_t top) { vcd_data_i = ident_new("vcd_data"); vcd_top = top; warnf("Use of the VCD file format is discouraged as it cannot fully " "represent many VHDL types and the performance is poor for large " "designs. If you are using GtkWave the --wave option will generate " "an FST file that overcomes these limitations."); vcd_file = fopen(filename, "w"); if (vcd_file == NULL) fatal_errno("failed to open VCD output %s", filename); }
void comm_recv(comm_t comm, u1 *buf, u4 len) { while (len > 0) { ssize_t n = read(comm, (void *) buf, (size_t) len); if (n == 0) fatal("unexpected EOF"); if (n == (ssize_t) -1) { if (errno == EINTR && errno == EAGAIN) { continue; } fatal_errno("read failed"); } len -= n; buf += n; } }
void init_transport_registration() { int s[2]; if(adb_socketpair(s)){ fatal_errno("cannot open transport registration socketpair"); } transport_registration_send = s[0]; transport_registration_recv = s[1]; fdevent_install(&transport_registration_fde, transport_registration_recv, transport_registration_func, NULL); fdevent_set(&transport_registration_fde, FDE_READ); }
static char * mount_image (const char *root, const char *image) { int loop_fd; char *mountpoint; char *loopdev; mountpoint = get_fs_mountpoint (root); loopdev = attach_loop_device (image, &loop_fd); if (mount (loopdev, mountpoint, "squashfs", MS_MGC_VAL|MS_RDONLY|MS_NODEV|MS_NOSUID, NULL) < 0) fatal_errno ("mount loopback"); close (loop_fd); return mountpoint; }
void local_init(int port) { sdb_thread_t thr; void* (*func)(void *); if(HOST) { func = client_socket_thread; } else { func = server_socket_thread; } D("transport: local %s init\n", HOST ? "client" : "server"); if(sdb_thread_create(&thr, func, (void *)port)) { fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server"); } }
static std::string GetLogFilePath() { const char log_name[] = "adb.log"; WCHAR temp_path[MAX_PATH]; // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path); if ((nchars >= arraysize(temp_path)) || (nchars == 0)) { // If string truncation or some other error. fatal("cannot retrieve temporary file path: %s\n", SystemErrorCodeToString(GetLastError()).c_str()); } std::string temp_path_utf8; if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) { fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8"); } return temp_path_utf8 + log_name; }
void init_transport_registration(void) { int s[2]; if (adb_socketpair(s)) { fatal_errno("cannot open transport registration socketpair"); } ADB_LOGD(ADB_TSPT, "socketpair: (%d,%d)", s[0], s[1]); transport_registration_send = s[0]; transport_registration_recv = s[1]; fdevent_install(&transport_registration_fde, transport_registration_recv, transport_registration_func, 0); fdevent_set(&transport_registration_fde, FDE_READ); }
void usb_init() { static bool initialized = false; if (!initialized) { atexit(usb_cleanup); adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); if (!adb_thread_create(RunLoopThread, nullptr)) { fatal_errno("cannot create input thread"); } // Wait for initialization to finish adb_mutex_lock(&start_lock); adb_cond_wait(&start_cond, &start_lock); adb_mutex_unlock(&start_lock); adb_mutex_destroy(&start_lock); adb_cond_destroy(&start_cond); initialized = true; } }
void local_init(int port) { adb_thread_t * thr = (adb_thread_t *)malloc(sizeof(adb_thread_t)); void* (*func)(void *); if(HOST) { D("Got client_socket_thread\n"); func = client_socket_thread; } else { D("Got server_socket_thread\n"); func = server_socket_thread; } D("transport: local %s init\n", HOST ? "client" : "server"); char tag[1024]; D("Just before adb_thread_create\n"); sprintf(tag, "local_socket %s", HOST ? "client" : "server"); if(adb_thread_create(thr, func, (void *)&port, tag)) { fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server"); } }
void usb_init() { if (!initialized) { adb_thread_t tid; adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); if(adb_thread_create(&tid, RunLoopThread, NULL)) fatal_errno("cannot create input thread"); // Wait for initialization to finish adb_mutex_lock(&start_lock); adb_cond_wait(&start_cond, &start_lock); adb_mutex_unlock(&start_lock); adb_mutex_destroy(&start_lock); adb_cond_destroy(&start_cond); initialized = 1; } }
static int debuggerd_dispatch_pseudothread(void* arg) { debugger_thread_info* thread_info = static_cast<debugger_thread_info*>(arg); for (int i = 0; i < 1024; ++i) { close(i); } int devnull = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)); // devnull will be 0. TEMP_FAILURE_RETRY(dup2(devnull, STDOUT_FILENO)); TEMP_FAILURE_RETRY(dup2(devnull, STDERR_FILENO)); int pipefds[2]; if (pipe(pipefds) != 0) { fatal_errno("failed to create pipe"); } // Don't use fork(2) to avoid calling pthread_atfork handlers. int forkpid = clone(nullptr, nullptr, 0, nullptr); if (forkpid == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to fork in debuggerd signal handler: %s", strerror(errno)); } else if (forkpid == 0) { TEMP_FAILURE_RETRY(dup2(pipefds[1], STDOUT_FILENO)); close(pipefds[0]); close(pipefds[1]); raise_caps(); char main_tid[10]; char pseudothread_tid[10]; char debuggerd_dump_type[10]; async_safe_format_buffer(main_tid, sizeof(main_tid), "%d", thread_info->crashing_tid); async_safe_format_buffer(pseudothread_tid, sizeof(pseudothread_tid), "%d", thread_info->pseudothread_tid); async_safe_format_buffer(debuggerd_dump_type, sizeof(debuggerd_dump_type), "%d", get_dump_type(thread_info)); execl(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type, nullptr); fatal_errno("exec failed"); } else { close(pipefds[1]); char buf[4]; ssize_t rc = TEMP_FAILURE_RETRY(read(pipefds[0], &buf, sizeof(buf))); if (rc == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", strerror(errno)); } else if (rc == 0) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper failed to exec"); } else if (rc != 1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe returned unexpected value: %zd", rc); } else { if (buf[0] != '\1') { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure"); } else { thread_info->crash_dump_started = true; } } close(pipefds[0]); // Don't leave a zombie child. int status; if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s", strerror(errno)); } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped"); thread_info->crash_dump_started = false; } } syscall(__NR_exit, 0); return 0; }
static int merge_dirs (const char *root, char **dirs, int n_dirs) { DIR *dir; char *subdirs[n_dirs]; struct dirent *dirent; struct stat st; char *src_path; char *dest_path; int conflict; int i, j; for (i = 0; i < n_dirs; i++) { if (dirs[i] == NULL) continue; dir = opendir (dirs[i]); if (dir == NULL) continue; while ((dirent = readdir (dir)) != NULL) { src_path = strconcat (dirs[i], "/", dirent->d_name); if (strcmp (dirent->d_name, ".") == 0 || strcmp (dirent->d_name, "..") == 0) continue; dest_path = strconcat (root, "/", dirent->d_name); if (lstat (dest_path, &st) == 0) { free (dest_path); continue; /* We already copyed this file */ } if (lstat (src_path, &st) < 0) { free (dest_path); continue; } if (S_ISCHR (st.st_mode) || S_ISBLK (st.st_mode) || S_ISFIFO (st.st_mode) || S_ISSOCK (st.st_mode)) { fprintf (stderr, "WARNING: ignoring special file %s\n", src_path); free (dest_path); continue; } conflict = has_conflict (dirs, n_dirs, dirent->d_name, i); if (conflict == NO_CONFLICTS) { bind_file (src_path, dest_path, &st); } else if (conflict == DIR_CONFLICT) { if (mkdir (dest_path, st.st_mode & 0777)) fatal_errno ("create merged dir"); if (lchown(dest_path, st.st_uid, st.st_gid) < 0) fatal_errno ("lchown"); for (j = 0; j < n_dirs; j++) subdirs[j] = get_subdir (dirs[j], dirent->d_name); merge_dirs (dest_path, subdirs, n_dirs); for (j = 0; j < n_dirs; j++) { if (subdirs[j]) free (subdirs[j]); } } else fatal ("Filename conflicts, refusing to mount\n"); free (dest_path); } } return 0; }
static void transport_registration_func(int _fd, unsigned ev, void *data) { tmsg * m = addTMessage(); int s[2]; atransport *t; if(!(ev & FDE_READ)) { return; } if(transport_read_action(_fd, m)) { fatal_errno("cannot read transport registration socket"); } t = m->transport; if(m->action == 0){ D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); /* IMPORTANT: the remove closes one half of the ** socket pair. The close closes the other half. */ fdevent_remove(&(t->transport_fde)); adb_close(t->fd); adb_mutex_lock(&transport_lock); t->next->prev = t->prev; t->prev->next = t->next; adb_mutex_unlock(&transport_lock); run_transport_disconnects(t); if (t->product) free(t->product); if (t->serial) free(t->serial); if (t->model) free(t->model); if (t->device) free(t->device); if (t->devpath) free(t->devpath); memset(t,0xee,sizeof(atransport)); free(t); update_transports(); return; } /* don't create transport threads for inaccessible devices */ if (t->connection_state != CS_NOPERM) { // adb_thread_t * output_thread_ptr = (adb_thread_t*)malloc(sizeof(adb_thread_t)); // adb_thread_t * input_thread_ptr = (adb_thread_t*)malloc(sizeof(adb_thread_t)); /* initial references are the two threads */ t->ref_count = 2; if(adb_socketpair(s)) { fatal_errno("cannot open transport socketpair"); } D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t); fdevent_set(&(t->transport_fde), FDE_READ); struct msg { atransport * t; }; struct msg m = { t }; send_js_msg("spawn-io-threads", &m); /*char i_tag[1024]; char o_tag[1024]; sprintf(i_tag, "I: %s_%d", t->serial, get_guid()); sprintf(o_tag, "O: %s_%d", t->serial, get_guid());*/ //dump_thread_tag(); /*if(adb_thread_create(input_thread_ptr, input_thread, t, i_tag)){ fatal_errno("cannot create input thread"); } if(adb_thread_create(output_thread_ptr, output_thread, t, o_tag)){ fatal_errno("cannot create output thread"); }*/ } /* put us on the master device list */ adb_mutex_lock(&transport_lock); t->next = &transport_list; t->prev = transport_list.prev; t->next->prev = t; t->prev->next = t; adb_mutex_unlock(&transport_lock); t->disconnects.next = t->disconnects.prev = &t->disconnects; update_transports(); }
static void transport_registration_func(int _fd, unsigned ev, void *data) { tmsg m; adb_thread_t output_thread_ptr; adb_thread_t input_thread_ptr; int s[2]; atransport *t; if(!(ev & FDE_READ)) { return; } if(transport_read_action(_fd, &m)) { fatal_errno("cannot read transport registration socket"); } t = m.transport; //action0 ÒƳý action1 ²åÈë if(m.action == 0) { D("transport: %s removing and free'ing %d\n", t->serial, t->transport_socket); /* IMPORTANT: the remove closes one half of the ** socket pair. The close closes the other half. */ fdevent_remove(&(t->transport_fde)); adb_close(t->fd); adb_mutex_lock(&transport_lock); t->next->prev = t->prev; t->prev->next = t->next; adb_mutex_unlock(&transport_lock); run_transport_disconnects(t); if (t->product) free(t->product); if (t->serial) free(t->serial); if (t->model) free(t->model); if (t->device) free(t->device); if (t->devpath) free(t->devpath); memset(t,0xee,sizeof(atransport)); free(t); update_transports(); return; } /* don't create transport threads for inaccessible devices */ if (t->connection_state != CS_NOPERM) { /* initial references are the two threads */ t->ref_count = 2; if(adb_socketpair(s)) { fatal_errno("cannot open transport socketpair"); } D("transport: %s (%d,%d) starting\n", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t); fdevent_set(&(t->transport_fde), FDE_READ); if(adb_thread_create(&input_thread_ptr, input_thread, t)){ fatal_errno("cannot create input thread"); } if(adb_thread_create(&output_thread_ptr, output_thread, t)){ fatal_errno("cannot create output thread"); } } adb_mutex_lock(&transport_lock); /* remove from pending list */ t->next->prev = t->prev; t->prev->next = t->next; /* put us on the master device list */ t->next = &transport_list; t->prev = transport_list.prev; t->next->prev = t; t->prev->next = t; adb_mutex_unlock(&transport_lock); t->disconnects.next = t->disconnects.prev = &t->disconnects; update_transports(); }
static void transport_registration_func(int _fd, unsigned ev, void *data) { tmsg m; int s[2]; atransport *t; if(!(ev & FDE_READ)) { return; } if(transport_read_action(_fd, &m)) { fatal_errno("cannot read transport registration socket"); } t = m.transport; if (m.action == 0) { D("transport: %s removing and free'ing %d", t->serial, t->transport_socket); /* IMPORTANT: the remove closes one half of the ** socket pair. The close closes the other half. */ fdevent_remove(&(t->transport_fde)); adb_close(t->fd); adb_mutex_lock(&transport_lock); transport_list.remove(t); adb_mutex_unlock(&transport_lock); if (t->product) free(t->product); if (t->serial) free(t->serial); if (t->model) free(t->model); if (t->device) free(t->device); if (t->devpath) free(t->devpath); delete t; update_transports(); return; } /* don't create transport threads for inaccessible devices */ if (t->connection_state != kCsNoPerm) { /* initial references are the two threads */ t->ref_count = 2; if (adb_socketpair(s)) { fatal_errno("cannot open transport socketpair"); } D("transport: %s socketpair: (%d,%d) starting", t->serial, s[0], s[1]); t->transport_socket = s[0]; t->fd = s[1]; fdevent_install(&(t->transport_fde), t->transport_socket, transport_socket_events, t); fdevent_set(&(t->transport_fde), FDE_READ); if (!adb_thread_create(write_transport_thread, t)) { fatal_errno("cannot create write_transport thread"); } if (!adb_thread_create(read_transport_thread, t)) { fatal_errno("cannot create read_transport thread"); } } adb_mutex_lock(&transport_lock); pending_list.remove(t); transport_list.push_front(t); adb_mutex_unlock(&transport_lock); update_transports(); }
int main (int argc, char **argv) { const char *program; uid_t ruid, euid, suid; gid_t rgid, egid, sgid; char **program_argv; int child_status = 0; pid_t child; if (argc <= 0) return 1; argc--; argv++; if (argc < 1) fatal ("PROGRAM [ARGS]... Run PROGRAM in an isolated network namespace"); program = argv[0]; program_argv = argv; if (getresgid (&rgid, &egid, &sgid) < 0) fatal_errno ("getresgid"); if (getresuid (&ruid, &euid, &suid) < 0) fatal_errno ("getresuid"); if (rgid == 0) rgid = ruid; if ((child = syscall (__NR_clone, SIGCHLD | CLONE_NEWNET, NULL)) < 0) perror ("clone"); if (child == 0) { /* Switch back to the uid of our invoking process. These calls are * irrevocable - see setuid(2) */ if (setgid (rgid) < 0) fatal_errno ("setgid"); if (setuid (ruid) < 0) fatal_errno ("setuid"); if (execvp (program, program_argv) < 0) fatal_errno ("execv"); } /* Let's also setuid back in the parent - there's no reason to stay uid 0, and * it's just better to drop privileges. */ if (setgid (rgid) < 0) fatal_errno ("setgid"); if (setuid (ruid) < 0) fatal_errno ("setuid"); /* Kind of lame to sit around blocked in waitpid, but oh well. */ if (waitpid (child, &child_status, 0) < 0) fatal_errno ("waitpid"); if (WIFEXITED (child_status)) return WEXITSTATUS (child_status); else return 1; }
// Handler that does crash dumping by forking and doing the processing in the child. // Do this by ptracing the relevant thread, and then execing debuggerd to do the actual dump. static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* context) { // Make sure we don't change the value of errno, in case a signal comes in between the process // making a syscall and checking errno. ErrnoRestorer restorer; // It's possible somebody cleared the SA_SIGINFO flag, which would mean // our "info" arg holds an undefined value. if (!have_siginfo(signal_number)) { info = nullptr; } struct siginfo si = {}; if (!info) { memset(&si, 0, sizeof(si)); si.si_signo = signal_number; si.si_code = SI_USER; si.si_pid = __getpid(); si.si_uid = getuid(); info = &si; } else if (info->si_code >= 0 || info->si_code == SI_TKILL) { // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels // that contain commit 66dd34a (3.9+). The manpage claims to only allow // negative si_code values that are not SI_TKILL, but 66dd34a changed the // check to allow all si_code values in calls coming from inside the house. } void* abort_message = nullptr; if (g_callbacks.get_abort_message) { abort_message = g_callbacks.get_abort_message(); } if (prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0) == 1) { // This check might be racy if another thread sets NO_NEW_PRIVS, but this should be unlikely, // you can only set NO_NEW_PRIVS to 1, and the effect should be at worst a single missing // ANR trace. debuggerd_fallback_handler(info, static_cast<ucontext_t*>(context), abort_message); resend_signal(info, false); return; } // Only allow one thread to handle a signal at a time. int ret = pthread_mutex_lock(&crash_mutex); if (ret != 0) { async_safe_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_lock failed: %s", strerror(ret)); return; } log_signal_summary(signal_number, info); // If this was a fatal crash, populate si_value with the abort message address if possible. // Note that applications can set an abort message without aborting. if (abort_message && signal_number != DEBUGGER_SIGNAL) { info->si_value.sival_ptr = abort_message; } debugger_thread_info thread_info = { .crash_dump_started = false, .pseudothread_tid = -1, .crashing_tid = __gettid(), .signal_number = signal_number, .info = info }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. int orig_dumpable = prctl(PR_GET_DUMPABLE); if (prctl(PR_SET_DUMPABLE, 1) != 0) { fatal_errno("failed to set dumpable"); } // Essentially pthread_create without CLONE_FILES (see debuggerd_dispatch_pseudothread). pid_t child_pid = clone(debuggerd_dispatch_pseudothread, pseudothread_stack, CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID, &thread_info, nullptr, nullptr, &thread_info.pseudothread_tid); if (child_pid == -1) { fatal_errno("failed to spawn debuggerd dispatch thread"); } // Wait for the child to start... futex_wait(&thread_info.pseudothread_tid, -1); // and then wait for it to finish. futex_wait(&thread_info.pseudothread_tid, child_pid); // Restore PR_SET_DUMPABLE to its original value. if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) { fatal_errno("failed to restore dumpable"); } // Signals can either be fatal or nonfatal. // For fatal signals, crash_dump will PTRACE_CONT us with the signal we // crashed with, so that processes using waitpid on us will see that we // exited with the correct exit status (e.g. so that sh will report // "Segmentation fault" instead of "Killed"). For this to work, we need // to deregister our signal handler for that signal before continuing. if (signal_number != DEBUGGER_SIGNAL) { signal(signal_number, SIG_DFL); } resend_signal(info, thread_info.crash_dump_started); if (info->si_signo == DEBUGGER_SIGNAL) { // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from // starting to dump right before our death. pthread_mutex_unlock(&crash_mutex); } } void debuggerd_init(debuggerd_callbacks_t* callbacks) { if (callbacks) { g_callbacks = *callbacks; } void* thread_stack_allocation = mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); if (thread_stack_allocation == MAP_FAILED) { fatal_errno("failed to allocate debuggerd thread stack"); } char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE; if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) { fatal_errno("failed to mprotect debuggerd thread stack"); } // Stack grows negatively, set it to the last byte in the page... stack = (stack + PAGE_SIZE - 1); // and align it. stack -= 15; pseudothread_stack = stack; struct sigaction action; memset(&action, 0, sizeof(action)); sigfillset(&action.sa_mask); action.sa_sigaction = debuggerd_signal_handler; action.sa_flags = SA_RESTART | SA_SIGINFO; // Use the alternate signal stack if available so we can catch stack overflows. action.sa_flags |= SA_ONSTACK; debuggerd_register_handlers(&action); }
int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) { #if defined(_WIN32) // adb start-server starts us up with stdout and stderr hooked up to // anonymous pipes. When the C Runtime sees this, it makes stderr and // stdout buffered, but to improve the chance that error output is seen, // unbuffer stdout and stderr just like if we were run at the console. // This also keeps stderr unbuffered when it is redirected to adb.log. if (is_daemon) { if (setvbuf(stdout, NULL, _IONBF, 0) == -1) { fatal("cannot make stdout unbuffered: %s", strerror(errno)); } if (setvbuf(stderr, NULL, _IONBF, 0) == -1) { fatal("cannot make stderr unbuffered: %s", strerror(errno)); } } SetConsoleCtrlHandler(ctrlc_handler, TRUE); #endif init_transport_registration(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); adb_auth_init(); std::string error; std::string local_name = android::base::StringPrintf("tcp:%d", server_port); if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) { fatal("could not install *smartsocket* listener: %s", error.c_str()); } // Inform our parent that we are up and running. if (is_daemon) { close_stdin(); setup_daemon_logging(); // Any error output written to stderr now goes to adb.log. We could // keep around a copy of the stderr fd and use that to write any errors // encountered by the following code, but that is probably overkill. #if defined(_WIN32) const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd); const CHAR ack[] = "OK\n"; const DWORD bytes_to_write = arraysize(ack) - 1; DWORD written = 0; if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) { fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle, SystemErrorCodeToString(GetLastError()).c_str()); } if (written != bytes_to_write) { fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes", bytes_to_write, written); } CloseHandle(ack_reply_handle); #else // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not // "OKAY". if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) { fatal_errno("error writing ACK to fd %d", ack_reply_fd); } unix_close(ack_reply_fd); #endif } D("Event loop starting"); fdevent_loop(); return 0; }
int main (int argc, char **argv) { char tempdir[] = "/tmp/approot_XXXXXX"; char *base_os; char **images; char *root; int n_images; pid_t child; int child_status = 0; char *app_root; char **mountpoints; int n_mountpoints; int i; uid_t ruid, euid, suid; gid_t rgid, egid, sgid; char cwd_buf[PATH_MAX]; char *cwd; if (argc < 2) fatal ("Too few arguments, need base and at least one image"); base_os = argv[1]; images = &argv[2]; n_images = argc - 2; root = mkdtemp (tempdir); if (root == NULL) fatal ("Can't create root"); if (getresgid (&rgid, &egid, &sgid) < 0) fatal_errno ("getresgid"); if (getresuid (&ruid, &euid, &suid) < 0) fatal_errno ("getresuid"); if ((child = syscall (__NR_clone, SIGCHLD | CLONE_NEWNS, NULL)) < 0) fatal_errno ("clone"); if (child == 0) { /* Child */ /* Disable setuid, new caps etc for children */ if (prctl (PR_SET_NO_NEW_PRIVS, 1) < 0 && errno != EINVAL) fatal_errno ("prctl (PR_SET_NO_NEW_PRIVS)"); else if (prctl (PR_SET_SECUREBITS, SECBIT_NOROOT | SECBIT_NOROOT_LOCKED) < 0) fatal_errno ("prctl (SECBIT_NOROOT)"); /* Don't leak our mounts to the parent namespace */ if (mount (NULL, "/", "none", MS_SLAVE | MS_REC, NULL) < 0) fatal_errno ("mount(/, MS_SLAVE | MS_REC)"); /* Check we're allowed to chdir into base os */ cwd = getcwd (cwd_buf, sizeof (cwd_buf)); if (fsuid_chdir (ruid, base_os) < 0) fatal_errno ("chdir"); if (chdir (cwd) < 0) fatal_errno ("chdir"); if (mount ("tmpfs", root, "tmpfs", MS_MGC_VAL | MS_PRIVATE, NULL) != 0) fatal_errno ("execv"); n_mountpoints = n_images + 1; mountpoints = calloc (n_mountpoints, sizeof (char *)); if (mountpoints == NULL) fatal ("oom"); mountpoints[0] = base_os; for (i = 0; i < n_images; i++) { if (fsuid_access (ruid, images[i], R_OK) < 0) fatal_errno ("access"); mountpoints[i+1] = mount_image (root, images[i]); if (mountpoints[i+1] == NULL) fatal ("mount image %s\n", images[i]); } app_root = make_fs_dir (root, "/root", 0555); if (app_root == NULL) fatal ("make_fs_dir root"); setup_base (app_root); merge_dirs (app_root, mountpoints, n_mountpoints); if (chdir (app_root) < 0) fatal_errno ("chdir"); if (chroot (".") < 0) fatal_errno ("chroot"); /* Switch back to the uid of our invoking process. These calls are * irrevocable - see setuid(2) */ if (setgid (rgid) < 0) fatal_errno ("setgid"); if (setuid (ruid) < 0) fatal_errno ("setuid"); if (execl ("/bin/sh", "/bin/sh", NULL) < 0) fatal_errno ("execl"); } /* Parent */ /* Let's also setuid back in the parent - there's no reason to stay uid 0, and * it's just better to drop privileges. */ if (setgid (rgid) < 0) fatal_errno ("setgid"); if (setuid (ruid) < 0) fatal_errno ("setuid"); if (child == -1) fatal_errno ("clone"); /* Ignore Ctrl-C in parent while waiting */ signal (SIGINT, SIG_IGN); if (waitpid (child, &child_status, 0) < 0) fatal_errno ("waitpid"); rmdir (root); if (WIFEXITED (child_status)) return WEXITSTATUS (child_status); else return 1; }