Esempio n. 1
0
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;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
  }
}
Esempio n. 4
0
File: vcd.c Progetto: SnookEE/nvc
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);
}
Esempio n. 5
0
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;
  }
}                                                                               
Esempio n. 6
0
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);
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 10
0
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);
}
Esempio n. 11
0
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;
    }
}
Esempio n. 12
0
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");
    }
}
Esempio n. 13
0
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;
    }
}
Esempio n. 14
0
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;
}
Esempio n. 15
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;
}
Esempio n. 16
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();
}
Esempio n. 17
0
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();
}
Esempio n. 18
0
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;
}
Esempio n. 20
0
// 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;
}
Esempio n. 22
-1
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;
}