Пример #1
0
int main(int argc, char* argv[]) {
  signal(SIGUSR1, sighandler);
  signal(SIGUSR2, sighandler);
  tgkill(getpid(), gettid(), SIGUSR1);
  tgkill(getpid(), gettid(), SIGUSR2);

  test_assert(2 == num_signals_caught);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Пример #2
0
int raise(int sig) {
  // Protect ourselves against stale cached PID/TID values by fetching them via syscall.
  // http://b/37769298
  pid_t pid = syscall(__NR_getpid);
  pid_t tid = syscall(__NR_gettid);
  return tgkill(pid, tid, sig);
}
Пример #3
0
static int r_debug_native_kill (RDebug *dbg, int pid, int tid, int sig) {
	int ret = false;
	if (pid == 0) pid = dbg->pid;
#if __WINDOWS__ && !__CYGWIN__
	ret = w32_terminate_process (dbg, pid);
#else
#if 0
	if (thread) {
// XXX this is linux>2.5 specific..ugly
		if (dbg->tid>0 && (ret = tgkill (dbg->pid, dbg->tid, sig))) {
			if (ret != -1)
				ret = true;
		}
	} else {
#endif
	if ((r_sandbox_kill (pid, sig) != -1)) ret = true;
	if (errno == 1) ret = -true; // EPERM
#if 0
//	}
#endif
#endif
	return ret;
}

struct r_debug_desc_plugin_t r_debug_desc_plugin_native;
static int r_debug_native_init (RDebug *dbg) {
	dbg->h->desc = r_debug_desc_plugin_native;
#if __WINDOWS__ && !__CYGWIN__
	return w32_dbg_init ();
#elif __APPLE__
	return xnu_init ();
#else
	return true;
#endif
}
Пример #4
0
int main(void) {
  signal(SIGUSR1, sighandler);
  signal(SIGUSR2, sighandler);
  tgkill(getpid(), sys_gettid(), SIGUSR1);
  tgkill(getpid(), sys_gettid(), SIGUSR2);

  test_assert(2 == num_signals_caught);

  syscall(SYS_tkill, sys_gettid(), SIGUSR1);
  syscall(SYS_tkill, sys_gettid(), SIGUSR2);

  test_assert(4 == num_signals_caught);

  atomic_puts("EXIT-SUCCESS");
  return 0;
}
Пример #5
0
/*
 * Catches fatal signals so we can ask debuggerd to ptrace us before
 * we crash.
 */
static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
  // 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 = NULL;
  }

  log_signal_summary(signal_number, info);

  send_debuggerd_packet(info);

  // Remove our net so we fault for real when we return.
  signal(signal_number, SIG_DFL);

  // These signals are not re-thrown when we resume.  This means that
  // crashing due to (say) SIGPIPE doesn't work the way you'd expect it
  // to.  We work around this by throwing them manually.  We don't want
  // to do this for *all* signals because it'll screw up the si_addr for
  // faults like SIGSEGV. It does screw up the si_code, which is why we
  // passed that to debuggerd above.
  switch (signal_number) {
    case SIGABRT:
    case SIGFPE:
    case SIGPIPE:
#if defined(SIGSTKFLT)
    case SIGSTKFLT:
#endif
    case SIGTRAP:
      tgkill(getpid(), gettid(), signal_number);
      break;
    default:    // SIGILL, SIGBUS, SIGSEGV
      break;
  }
}
Пример #6
0
static void *
start (void *arg)
{
    tgkill (getpid (), gettid (), SIGUSR1);
    assert (0);
    return NULL;
}
Пример #7
0
int pthread_kill(pthread_t t, int sig) {
  ErrnoRestorer errno_restorer;
  ErrnoRestorer_init(&errno_restorer);

  pthread_accessor thread;
  pthread_accessor_init(&thread, t);
  if (pthread_accessor_get(&thread) == NULL) {
    pthread_accessor_fini(&thread);
    ErrnoRestorer_fini(&errno_restorer);
    return ESRCH;
  }

  // There's a race here, but it's one we share with all other C libraries.
  pid_t tid = pthread_accessor_get(&thread)->tid;
  pthread_accessor_Unlock(&thread);

  int rc = tgkill(getpid(), tid, sig);
  if (rc == -1) {
    pthread_accessor_fini(&thread);
    int ret = errno;
    ErrnoRestorer_fini(&errno_restorer);
    return ret;
  }

  pthread_accessor_fini(&thread);
  ErrnoRestorer_fini(&errno_restorer);
  return 0;
}
Пример #8
0
static bool thread_signal(thread_t * thread, int signo) {
    debug("Sending signal %s to %s.", str_signal(signo), str_thread(thread));
    if (tgkill(thread->process->pid, thread->pid, signo) != 0) {
        thread_handle_ptrace_error(thread, "sending signal to", errno);
        return false;
    } else
        return true;
}
Пример #9
0
static void *fn(void *arg)
{
	struct timespec rem, req = {
		.tv_sec = 1,
		.tv_nsec = 0
	};

	other_tid = gettid();

	// The syscall will be interrupted by the main thread
	if (nanosleep(&req, &rem) != -1)
		TEST_EXIT(1);
	if (errno != EINTR)
		TEST_EXIT(1);

	// The handler for the signal must have run after the nanosleep()
	// syscall was interrupted
	if (!signal_serviced)
		TEST_EXIT(1);

	// Test is interrupted before timer has expired, there must
	// be some time remaining
	if (!rem.tv_sec && !rem.tv_nsec)
		TEST_EXIT(1);

	return 0;
}

int main(void)
{
	struct sigaction act = {
		.sa_handler = handler,
		.sa_flags = 0,
	};
	if (sigaction(SIGUSR1, &act, NULL))
		TEST_EXIT(1);

	pthread_t thread;
	if (pthread_create(&thread, NULL, fn, NULL))
		TEST_EXIT(1);

	// The other thread startup might be delayed depending on the
	// scheduler's prolicy
	while (other_tid == -1)
		sched_yield();

	// Interrupt the other thread which is blocking in a sleep operation
	if (tgkill(getpid(), other_tid, SIGUSR1))
		TEST_EXIT(1);

	// Join to make sure there other thread was interrupted with
	// some time remaining
	if (pthread_join(thread, NULL))
		TEST_EXIT(1);

	TEST_EXIT(0);
}
bool BacktraceThread::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
  if (ucontext) {
    // Unwind using an already existing ucontext.
    return impl_->Unwind(num_ignore_frames, ucontext);
  }

  // Prevent multiple threads trying to set the trigger action on different
  // threads at the same time.
  if (pthread_mutex_lock(&g_sigaction_mutex) < 0) {
    BACK_LOGW("sigaction failed: %s", strerror(errno));
    return false;
  }

  ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
  entry->Lock();

  struct sigaction act, oldact;
  memset(&act, 0, sizeof(act));
  act.sa_sigaction = SignalHandler;
  act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
  sigemptyset(&act.sa_mask);
  if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
    BACK_LOGW("sigaction failed %s", strerror(errno));
    entry->Unlock();
    ThreadEntry::Remove(entry);
    pthread_mutex_unlock(&g_sigaction_mutex);
    return false;
  }

  if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
    BACK_LOGW("tgkill %d failed: %s", Tid(), strerror(errno));
    sigaction(THREAD_SIGNAL, &oldact, NULL);
    entry->Unlock();
    ThreadEntry::Remove(entry);
    pthread_mutex_unlock(&g_sigaction_mutex);
    return false;
  }

  // Wait for the thread to get the ucontext.
  entry->Wait(0);

  // After the thread has received the signal, allow other unwinders to
  // continue.
  sigaction(THREAD_SIGNAL, &oldact, NULL);
  pthread_mutex_unlock(&g_sigaction_mutex);

  bool unwind_done = impl_->Unwind(num_ignore_frames, entry->GetUcontext());

  // Tell the signal handler to exit and release the entry.
  entry->Wake();

  return unwind_done;
}
bool BacktraceThread::TriggerUnwindOnThread(ThreadEntry* entry) {
  entry->state = STATE_WAITING;

  if (tgkill(Pid(), Tid(), SIGURG) != 0) {
    BACK_LOGW("tgkill failed %s", strerror(errno));
    return false;
  }

  // Allow up to ten seconds for the dump to start.
  int wait_millis = 10000;
  int32_t state;
  while (true) {
    state = android_atomic_acquire_load(&entry->state);
    if (state != STATE_WAITING) {
      break;
    }
    if (wait_millis--) {
      usleep(1000);
    } else {
      break;
    }
  }

  bool cancelled = false;
  if (state == STATE_WAITING) {
    if (android_atomic_acquire_cas(state, STATE_CANCEL, &entry->state) == 0) {
      BACK_LOGW("Cancelled dump of thread %d", entry->tid);
      state = STATE_CANCEL;
      cancelled = true;
    } else {
      state = android_atomic_acquire_load(&entry->state);
    }
  }

  // Wait for at most ten seconds for the cancel or dump to finish.
  wait_millis = 10000;
  while (android_atomic_acquire_load(&entry->state) != STATE_DONE) {
    if (wait_millis--) {
      usleep(1000);
    } else {
      BACK_LOGW("Didn't finish thread unwind in 60 seconds.");
      break;
    }
  }
  return !cancelled;
}
Пример #12
0
int pthread_kill(pthread_t t, int sig) {
  ErrnoRestorer errno_restorer;

  pthread_accessor thread(t);
  if (thread.get() == NULL) {
    return ESRCH;
  }

  // There's a race here, but it's one we share with all other C libraries.
  pid_t tid = thread->tid;
  thread.Unlock();

  int rc = tgkill(getpid(), tid, sig);
  if (rc == -1) {
    return errno;
  }

  return 0;
}
Пример #13
0
static int thread_signal(pid_t pid, pid_t tid, int sig)
{
	int status;
	int ret;
	
	ret = tgkill(pid, tid, sig);
	if (ret == -1)
		return -1;

	for(;;) {
		int stop_sig = 0;

		if (TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL)) == -1)
			return -1;

		if (WIFEXITED(status))
			return -1;

		if (WIFSTOPPED(status)) {
			stop_sig = WSTOPSIG(status);

			if (stop_sig == sig)
				break;

			if (stop_sig == SIGTRAP)
				stop_sig = 0;
			else
			if (stop_sig == SIGSTOP)
				stop_sig = 0;
		}

		if (ptrace(PTRACE_CONT, tid, 0, stop_sig) == -1) {
			fprintf(stderr, "%s:%d ptrace CONT (%s)\n", __FUNCTION__, __LINE__, strerror(errno));
			return -1;
		}
	}
	return 0;
}
Пример #14
0
/*
 * Catches fatal signals so we can ask debuggerd to ptrace us before
 * we crash.
 */
void debugger_signal_handler(int n, siginfo_t* info, void*) {
    char msgbuf[128];

    /*
     * It's possible somebody cleared the SA_SIGINFO flag, which would mean
     * our "info" arg holds an undefined value.
     */
    if (!haveSiginfo(n)) {
        info = NULL;
    }

    logSignalSummary(n, info);

    pid_t tid = gettid();
    int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);

    if (s >= 0) {
        /* debugger knows our pid from the credentials on the
         * local socket but we need to tell it our tid.  It
         * is paranoid and will verify that we are giving a tid
         * that's actually in our process
         */
        int  ret;
        debugger_msg_t msg;
        msg.action = DEBUGGER_ACTION_CRASH;
        msg.tid = tid;
        ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
        if (ret == sizeof(msg)) {
            /* if the write failed, there is no point to read on
             * the file descriptor. */
            ret = TEMP_FAILURE_RETRY(read(s, &tid, 1));
            int saved_errno = errno;
            notify_gdb_of_libraries();
            errno = saved_errno;
        }

        if (ret < 0) {
            /* read or write failed -- broken connection? */
            format_buffer(msgbuf, sizeof(msgbuf),
                "Failed while talking to debuggerd: %s", strerror(errno));
            __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
        }

        close(s);
    } else {
        /* socket failed; maybe process ran out of fds */
        format_buffer(msgbuf, sizeof(msgbuf),
            "Unable to open connection to debuggerd: %s", strerror(errno));
        __libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
    }

    /* remove our net so we fault for real when we return */
    signal(n, SIG_DFL);

    /*
     * These signals are not re-thrown when we resume.  This means that
     * crashing due to (say) SIGPIPE doesn't work the way you'd expect it
     * to.  We work around this by throwing them manually.  We don't want
     * to do this for *all* signals because it'll screw up the address for
     * faults like SIGSEGV.
     */
    switch (n) {
        case SIGABRT:
        case SIGFPE:
        case SIGPIPE:
#ifdef SIGSTKFLT
        case SIGSTKFLT:
#endif
            (void) tgkill(getpid(), gettid(), n);
            break;
        default:    // SIGILL, SIGBUS, SIGSEGV
            break;
    }
}
Пример #15
0
/*
 * Catches fatal signals so we can ask debuggerd to ptrace us before
 * we crash.
 */
void debuggerd_signal_handler(int n, siginfo_t* info, void*) {
    /*
     * It's possible somebody cleared the SA_SIGINFO flag, which would mean
     * our "info" arg holds an undefined value.
     */
    if (!have_siginfo(n)) {
        info = NULL;
    }

    log_signal_summary(n, info);

    pid_t tid = gettid();
    int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);

    if (s >= 0) {
        // debuggerd knows our pid from the credentials on the
        // local socket but we need to tell it the tid of the crashing thread.
        // debuggerd will be paranoid and verify that we sent a tid
        // that's actually in our process.
        debugger_msg_t msg;
        msg.action = DEBUGGER_ACTION_CRASH;
        msg.tid = tid;
        msg.abort_msg_address = reinterpret_cast<uintptr_t>(gAbortMessage);
        int ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
        if (ret == sizeof(msg)) {
#ifdef HAVE_AEE_FEATURE
            int tmppid = getpid();
            __libc_format_log(ANDROID_LOG_FATAL, "libc", "Send stop signal to pid:%d in %s", tmppid, __func__);
            kill(tmppid, SIGSTOP);
#endif
            // if the write failed, there is no point trying to read a response.
            ret = TEMP_FAILURE_RETRY(read(s, &tid, 1));
            int saved_errno = errno;
            notify_gdb_of_libraries();
            errno = saved_errno;
        }

        if (ret < 0) {
            /* read or write failed -- broken connection? */
            __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
                              strerror(errno));
        }

        close(s);
    } else {
        /* socket failed; maybe process ran out of fds */
        __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
                          strerror(errno));
    }

    /* remove our net so we fault for real when we return */
    signal(n, SIG_DFL);

    /*
     * These signals are not re-thrown when we resume.  This means that
     * crashing due to (say) SIGPIPE doesn't work the way you'd expect it
     * to.  We work around this by throwing them manually.  We don't want
     * to do this for *all* signals because it'll screw up the address for
     * faults like SIGSEGV.
     */
    switch (n) {
        case SIGABRT:
        case SIGFPE:
        case SIGPIPE:
#ifdef SIGSTKFLT
        case SIGSTKFLT:
#endif
            (void) tgkill(getpid(), gettid(), n);
            break;
        default:    // SIGILL, SIGBUS, SIGSEGV
            break;
    }
}
Пример #16
0
/* Kill the thread of the tid in current process */
int tkill(int tid, int sig)
{
	return tgkill(getpid(), tid, sig);
}
Пример #17
0
static void
handler (int signo)	/* step-0 */
{   /* step-0 */
    var++;		/* step-1 */
    tgkill (getpid (), gettid (), SIGUSR1);	/* step-2 */
}
Пример #18
0
int
main (int argc, char **argv)
{
  int i;
  int standalone = 0;
  struct sigaction act;

  if (argc == 2 && strcmp (argv[1], "-s") == 0)
    standalone = 1;
  else
    assert (argc == 1);

  setbuf (stdout, NULL);

  timed_mutex_lock (&thread1_tid_mutex);
  timed_mutex_lock (&thread2_tid_mutex);

  timed_mutex_lock (&terminate_mutex);

  errno = 0;
  memset (&act, 0, sizeof (act));
  act.sa_sigaction = handler;
  act.sa_flags = SA_RESTART | SA_SIGINFO;
  i = sigemptyset (&act.sa_mask);
  assert_perror (errno);
  assert (i == 0);
  i = sigaction (SIGUSR1, &act, NULL);
  assert_perror (errno);
  assert (i == 0);
  i = sigaction (SIGUSR2, &act, NULL);
  assert_perror (errno);
  assert (i == 0);

  pthread_barrier_init (&threads_started_barrier, NULL, 3);

  i = pthread_create (&thread1, NULL, thread1_func, NULL);
  assert (i == 0);

  i = pthread_create (&thread2, NULL, thread2_func, NULL);
  assert (i == 0);

  if (!standalone)
    {
      tracer = proc_ulong ("/proc/self/status", "TracerPid:\t");
      if (tracer == 0)
	{
	  fprintf (stderr, "The testcase must be run by GDB!\n");
	  exit (EXIT_FAILURE);
	}
      if (tracer != getppid ())
	{
	  fprintf (stderr, "The testcase parent must be our GDB tracer!\n");
	  exit (EXIT_FAILURE);
	}
    }

  /* SIGCONT our debugger in the case of our crash as we would deadlock
     otherwise.  */

  atexit (cleanup);

  /* Wait until all threads are seen running.  On Linux (at least),
     new threads start stopped, and the debugger must resume them.
     Need to wait for that before stopping GDB.  */
  pthread_barrier_wait (&threads_started_barrier);

  printf ("Stopping GDB PID %lu.\n", (unsigned long) tracer);

  if (tracer)
    {
      i = kill (tracer, SIGSTOP);
      assert (i == 0);
      state_wait (tracer, "T (stopped)");
    }

  /* Threads are now waiting at timed_mutex_lock (thread1_tid_mutex)
     and so they could not trigger the signals before GDB is unstopped
     later.  Threads get resumed by the pthread_cond_wait below.  Use
     `while' loops for protection against spurious pthread_cond_wait
     wakeups.  */

  printf ("Waiting till the threads initialize their TIDs.\n");

  while (thread1_tid == 0)
    {
      i = pthread_cond_wait (&thread1_tid_cond, &thread1_tid_mutex);
      assert (i == 0);
    }

  while (thread2_tid == 0)
    {
      i = pthread_cond_wait (&thread2_tid_cond, &thread2_tid_mutex);
      assert (i == 0);
    }

  printf ("Thread 1 TID = %lu, thread 2 TID = %lu, PID = %lu.\n",
	  (unsigned long) thread1_tid, (unsigned long) thread2_tid,
	  (unsigned long) getpid ());

  errno = 0;
  i = tgkill (getpid (), thread1_tid, SIGUSR1);
  assert_perror (errno);
  assert (i == 0);
  i = tgkill (getpid (), thread1_tid, SIGUSR2);
  assert_perror (errno);
  assert (i == 0);
  i = tgkill (getpid (), thread2_tid, SIGUSR1);
  assert_perror (errno);
  assert (i == 0);
  i = tgkill (getpid (), thread2_tid, SIGUSR2);
  assert_perror (errno);
  assert (i == 0);

  printf ("Waiting till the threads are trapped by the signals.\n");

  if (tracer)
    {
      /* s390x-unknown-linux-gnu will fail with "R (running)".  */

      state_wait (thread1_tid, "t (tracing stop)");

      state_wait (thread2_tid, "t (tracing stop)");
    }

  cleanup ();

  printf ("Joining the threads.\n");

  i = pthread_mutex_unlock (&terminate_mutex);
  assert (i == 0);

  i = pthread_join (thread1, NULL);
  assert (i == 0);

  i = pthread_join (thread2, NULL);
  assert (i == 0);

  printf ("Exiting.\n");	/* break-at-exit */

  return EXIT_SUCCESS;
}
Пример #19
0
static void stage_capability_test(void)
{
	char tmp1[128];
	char tmp2[128];
	memset(tmp1, 0, sizeof(tmp1));
	memset(tmp2, 0, sizeof(tmp2));

	capability = "inet_tcp_create";
	set_capability();
	if (write_policy()) {
		int fd = socket(AF_INET, SOCK_STREAM, 0);
		show_result(fd, 1);
		if (fd != EOF)
			close(fd);
		delete_policy();
		fd = socket(AF_INET, SOCK_STREAM, 0);
		show_result(fd, 0);
		if (fd != EOF)
			close(fd);
	}
	unset_capability();

	{
		int fd1 = socket(AF_INET, SOCK_STREAM, 0);
		int fd2 = socket(AF_INET, SOCK_STREAM, 0);
		int fd3 = socket(AF_INET, SOCK_STREAM, 0);
		int fd4 = socket(AF_INET, SOCK_STREAM, 0);
		struct sockaddr_in addr;
		socklen_t size = sizeof(addr);
		memset(&addr, 0, sizeof(addr));
		addr.sin_family = AF_INET;
		addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
		addr.sin_port = htons(0);
		bind(fd1, (struct sockaddr *) &addr, sizeof(addr));
		bind(fd2, (struct sockaddr *) &addr, sizeof(addr));
		bind(fd3, (struct sockaddr *) &addr, sizeof(addr));
		bind(fd4, (struct sockaddr *) &addr, sizeof(addr));
		getsockname(fd1, (struct sockaddr *) &addr, &size);

		capability = "inet_tcp_listen";
		set_capability();
		if (write_policy()) {
			show_result(listen(fd1, 5), 1);
			delete_policy();
			show_result(listen(fd2, 5), 0);
		}
		unset_capability();

		capability = "inet_tcp_connect";
		set_capability();
		if (write_policy()) {
			show_result(connect(fd3, (struct sockaddr *) &addr,
					    sizeof(addr)), 1);
			delete_policy();
			show_result(connect(fd4, (struct sockaddr *) &addr,
					    sizeof(addr)), 0);
		}
		unset_capability();

		if (fd1 != EOF)
			close(fd1);
		if (fd2 != EOF)
			close(fd2);
		if (fd3 != EOF)
			close(fd3);
		if (fd4 != EOF)
			close(fd4);
	}

	capability = "use_inet_udp";
	set_capability();
	if (write_policy()) {
		int fd = socket(AF_INET, SOCK_DGRAM, 0);
		show_result(fd, 1);
		if (fd != EOF)
			close(fd);
		delete_policy();
		fd = socket(AF_INET, SOCK_DGRAM, 0);
		show_result(fd, 0);
		if (fd != EOF)
			close(fd);
	}
	unset_capability();

	capability = "use_inet_ip";
	set_capability();
	if (write_policy()) {
		int fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
		show_result(fd, 1);
		if (fd != EOF)
			close(fd);
		delete_policy();
		fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
		show_result(fd, 0);
		if (fd != EOF)
			close(fd);
	}
	unset_capability();

	capability = "use_route";
	set_capability();
	if (write_policy()) {
		int fd = socket(AF_ROUTE, SOCK_RAW, 0);
		show_result(fd, 1);
		if (fd != EOF)
			close(fd);
		delete_policy();
		fd = socket(AF_ROUTE, SOCK_RAW, 0);
		show_result(fd, 0);
		if (fd != EOF)
			close(fd);
	}
	unset_capability();

	capability = "use_packet";
	set_capability();
	if (write_policy()) {
		int fd = socket(AF_PACKET, SOCK_RAW, 0);
		show_result(fd, 1);
		if (fd != EOF)
			close(fd);
		delete_policy();
		fd = socket(AF_PACKET, SOCK_RAW, 0);
		show_result(fd, 0);
		if (fd != EOF)
			close(fd);
	}
	unset_capability();

	capability = "use_kernel_module";
	set_capability();
	if (write_policy()) {
		if (!is_kernel26)
			show_result((int) create_module("", 0), 1);
		show_result(init_module("", NULL), 1);
		show_result(delete_module(""), 1);
		delete_policy();
		if (!is_kernel26)
			show_result((int) create_module("", 0), 0);
		show_result(init_module("", NULL), 0);
		show_result(delete_module(""), 0);
	}
	unset_capability();

	capability = "create_fifo";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/XXXXXX");
		close(mkstemp(tmp1));
		unlink(tmp1);
		show_result(mknod(tmp1, S_IFIFO, 0), 1);
		unlink(tmp1);
		delete_policy();
		show_result(mknod(tmp1, S_IFIFO, 0), 0);
		unlink(tmp1);
	}
	unset_capability();

	capability = "create_block_dev";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/XXXXXX");
		close(mkstemp(tmp1));
		unlink(tmp1);
		show_result(mknod(tmp1, S_IFBLK, MKDEV(1, 0)), 1);
		unlink(tmp1);
		delete_policy();
		show_result(mknod(tmp1, S_IFBLK, MKDEV(1, 0)), 0);
		unlink(tmp1);
	}
	unset_capability();

	capability = "create_char_dev";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/XXXXXX");
		close(mkstemp(tmp1));
		unlink(tmp1);
		show_result(mknod(tmp1, S_IFCHR, MKDEV(1, 3)), 1);
		unlink(tmp1);
		delete_policy();
		show_result(mknod(tmp1, S_IFCHR, MKDEV(1, 3)), 0);
		unlink(tmp1);
	}
	unset_capability();

	capability = "create_unix_socket";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/XXXXXX");
		close(mkstemp(tmp1));
		unlink(tmp1);
		show_result(mknod(tmp1, S_IFSOCK, 0), 1);
		unlink(tmp1);
		delete_policy();
		show_result(mknod(tmp1, S_IFSOCK, 0), 0);
		unlink(tmp1);
	}
	if (write_policy()) {
		struct sockaddr_un addr;
		int fd1 = socket(AF_UNIX, SOCK_STREAM, 0);
		int fd2 = socket(AF_UNIX, SOCK_STREAM, 0);
		memset(&addr, 0, sizeof(addr));
		addr.sun_family = AF_UNIX;
		strcpy(tmp1, "/tmp/XXXXXX");
		strncpy(addr.sun_path, tmp1, sizeof(addr.sun_path) - 1);
		show_result(bind(fd1, (struct sockaddr *) &addr, sizeof(addr)),
			    1);
		unlink(tmp1);
		delete_policy();
		show_result(bind(fd2, (struct sockaddr *) &addr, sizeof(addr)),
			    0);
		unlink(tmp1);
		if (fd1 != EOF)
			close(fd1);
		if (fd2 != EOF)
			close(fd2);
	}
	unset_capability();

	capability = "SYS_MOUNT";
	set_capability();
	if (write_policy()) {
		show_result(mount("/", "/", "tmpfs", 0, NULL), 1);
		delete_policy();
		show_result(mount("/", "/", "tmpfs", 0, NULL), 0);
	}
	unset_capability();

	capability = "SYS_UMOUNT";
	set_capability();
	if (write_policy()) {
		mount("/tmp", "/tmp", "tmpfs", 0, NULL);
		show_result(umount("/tmp"), 1);
		delete_policy();
		mount("/tmp", "/tmp", "tmpfs", 0, NULL);
		show_result(umount("/"), 0);
	}
	unset_capability();

	capability = "SYS_REBOOT";
	set_capability();
	if (write_policy()) {
		FILE *fp = fopen("/proc/sys/kernel/ctrl-alt-del", "a+");
		unsigned int c;
		if (fp && fscanf(fp, "%u", &c) == 1) {
			show_result(reboot(LINUX_REBOOT_CMD_CAD_ON), 1);
			delete_policy();
			show_result(reboot(LINUX_REBOOT_CMD_CAD_ON), 0);
			fprintf(fp, "%u\n", c);
		} else {
			/* Use invalid value */
			show_result(reboot(0x0000C0DE), 1);
			delete_policy();
			show_result(reboot(0x0000C0DE), 0);
		}
		if (fp)
			fclose(fp);
	}
	unset_capability();

	capability = "SYS_CHROOT";
	set_capability();
	if (write_policy()) {
		show_result(chroot("/"), 1);
		delete_policy();
		show_result(chroot("/"), 0);
	}
	unset_capability();

	capability = "SYS_PIVOT_ROOT";
	set_capability();
	if (write_policy()) {
		int error;
		char *stack = malloc(8192);
		pid_t pid = clone(child, stack + (8192 / 2), CLONE_NEWNS, NULL);
		while (waitpid(pid, &error, __WALL) == EOF && errno == EINTR)
			error += 0; /* Dummy. */
		errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1;
		show_result(errno ? EOF : 0, 1);
		delete_policy();
		pid = clone(child, stack + (8192 / 2), CLONE_NEWNS, NULL);
		while (waitpid(pid, &error, __WALL) == EOF && errno == EINTR)
			error += 0; /* Dummy. */
		errno = WIFEXITED(error) ? WEXITSTATUS(error) : -1;
		show_result(errno ? EOF : 0, 0);
		free(stack);
	}
	unset_capability();

	signal(SIGINT, SIG_IGN);
	capability = "SYS_KILL";
	set_capability();
	if (write_policy()) {
		show_result(kill(pid, SIGINT), 1);
		show_result(tkill(gettid(), SIGINT), 1);
#ifdef __NR_tgkill
		if (is_kernel26)
			show_result(tgkill(pid, gettid(), SIGINT), 1);
#endif
		delete_policy();
		show_result(kill(pid, SIGINT), 0);
		show_result(tkill(gettid(), SIGINT), 0);
#ifdef __NR_tgkill
		if (is_kernel26)
			show_result(tgkill(pid, gettid(), SIGINT), 0);
#endif
	}
	unset_capability();
	signal(SIGINT, SIG_DFL);

	capability = "SYS_KEXEC_LOAD";
	set_capability();
	if (write_policy()) {
#ifdef __NR_sys_kexec_load
		if (is_kernel26)
			show_result(sys_kexec_load(0, 0, NULL, 0), 1);
#endif
		delete_policy();
#ifdef __NR_sys_kexec_load
		if (is_kernel26)
			show_result(sys_kexec_load(0, 0, NULL, 0), 0);
#endif
	}
	unset_capability();

	capability = "SYS_VHANGUP";
	set_capability();
	if (write_policy()) {
		int pty_fd = EOF, status = 0;
		int pipe_fd[2] = { EOF, EOF };
		pipe(pipe_fd);
		switch (forkpty(&pty_fd, NULL, NULL, NULL)) {
		case 0:
			errno = 0;
			vhangup();
			/* Unreachable if vhangup() succeeded. */
			status = errno;
			write(pipe_fd[1], &status, sizeof(status));
			_exit(0);
		case -1:
			fprintf(stderr, "forkpty() failed.\n");
			break;
		default:
			close(pipe_fd[1]);
			read(pipe_fd[0], &status, sizeof(status));
			wait(NULL);
			close(pipe_fd[0]);
			close(pty_fd);
			errno = status;
			show_result(status ? EOF : 0, 1);
		}
		delete_policy();
		status = 0;
		pipe(pipe_fd);
		switch (forkpty(&pty_fd, NULL, NULL, NULL)) {
		case 0:
			errno = 0;
			vhangup();
			/* Unreachable if vhangup() succeeded. */
			status = errno;
			write(pipe_fd[1], &status, sizeof(status));
			_exit(0);
		case -1:
			fprintf(stderr, "forkpty() failed.\n");
			break;
		default:
			close(pipe_fd[1]);
			read(pipe_fd[0], &status, sizeof(status));
			wait(NULL);
			close(pipe_fd[0]);
			close(pty_fd);
			errno = status;
			show_result(status ? EOF : 0, 0);
		}
	}
	unset_capability();

	capability = "SYS_TIME";
	set_capability();
	if (write_policy()) {
		struct timeval tv;
		struct timezone tz;
		struct timex buf;
		time_t now = time(NULL);
		show_result(stime(&now), 1);
		gettimeofday(&tv, &tz);
		show_result(settimeofday(&tv, &tz), 1);
		memset(&buf, 0, sizeof(buf));
		buf.modes = 0x100; /* Use invalid value so that the clock
				      won't change. */
		show_result(adjtimex(&buf), 1);
		delete_policy();
		now = time(NULL);
		show_result(stime(&now), 0);
		gettimeofday(&tv, &tz);
		show_result(settimeofday(&tv, &tz), 0);
		memset(&buf, 0, sizeof(buf));
		buf.modes = 0x100; /* Use invalid value so that the clock
				      won't change. */
		show_result(adjtimex(&buf), 0);
	}
	unset_capability();

	capability = "SYS_NICE";
	set_capability();
	if (write_policy()) {
		show_result(nice(0), 1);
		show_result(setpriority(PRIO_PROCESS, pid,
					getpriority(PRIO_PROCESS, pid)), 1);
		delete_policy();
		show_result(nice(0), 0);
		show_result(setpriority(PRIO_PROCESS, pid,
					getpriority(PRIO_PROCESS, pid)), 0);
	}
	unset_capability();

	capability = "SYS_SETHOSTNAME";
	set_capability();
	if (write_policy()) {
		char buffer[4096];
		memset(buffer, 0, sizeof(buffer));
		gethostname(buffer, sizeof(buffer) - 1);
		show_result(sethostname(buffer, strlen(buffer)), 1);
		getdomainname(buffer, sizeof(buffer) - 1);
		show_result(setdomainname(buffer, strlen(buffer)), 1);
		delete_policy();
		gethostname(buffer, sizeof(buffer) - 1);
		show_result(sethostname(buffer, strlen(buffer)), 0);
		getdomainname(buffer, sizeof(buffer) - 1);
		show_result(setdomainname(buffer, strlen(buffer)), 0);
	}
	unset_capability();

	capability = "SYS_LINK";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/link_source_XXXXXX");
		close(mkstemp(tmp1));
		strcpy(tmp2, "/tmp/link_target_XXXXXX");
		show_result(link(tmp1, tmp2), 1);
		unlink(tmp2);
		unlink(tmp1);
		delete_policy();
		strcpy(tmp1, "/tmp/link_source_XXXXXX");
		close(mkstemp(tmp1));
		strcpy(tmp2, "/tmp/link_target_XXXXXX");
		show_result(link(tmp1, tmp2), 0);
		unlink(tmp2);
		unlink(tmp1);
	}
	unset_capability();

	capability = "SYS_SYMLINK";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/symlink_target_XXXXXX");
		close(mkstemp(tmp1));
		strcpy(tmp2, "/tmp/symlink_source_XXXXXX");
		show_result(symlink(tmp1, tmp2), 1);
		unlink(tmp2);
		unlink(tmp1);
		delete_policy();
		strcpy(tmp1, "/tmp/symlink_target_XXXXXX");
		close(mkstemp(tmp1));
		strcpy(tmp2, "/tmp/symlink_source_XXXXXX");
		show_result(symlink(tmp1, tmp2), 0);
		unlink(tmp2);
		unlink(tmp1);
	}
	unset_capability();

	capability = "SYS_RENAME";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/rename_old_XXXXXX");
		close(mkstemp(tmp1));
		strcpy(tmp2, "/tmp/rename_new_XXXXXX");
		show_result(rename(tmp1, tmp2), 1);
		unlink(tmp2);
		unlink(tmp1);
		delete_policy();
		strcpy(tmp1, "/tmp/rename_old_XXXXXX");
		close(mkstemp(tmp1));
		strcpy(tmp2, "/tmp/rename_new_XXXXXX");
		show_result(rename(tmp1, tmp2), 0);
		unlink(tmp2);
		unlink(tmp1);
	}
	unset_capability();

	capability = "SYS_UNLINK";
	set_capability();
	if (write_policy()) {
		strcpy(tmp1, "/tmp/unlinkXXXXXX");
		close(mkstemp(tmp1));
		show_result(unlink(tmp1), 1);
		delete_policy();
		strcpy(tmp1, "/tmp/unlinkXXXXXX");
		close(mkstemp(tmp1));
		show_result(unlink(tmp1), 0);
	}
	unset_capability();
	unlink(tmp1);

	capability = "SYS_CHMOD";
	set_capability();
	if (write_policy()) {
		show_result(chmod("/dev/null", 0222), 1);
		delete_policy();
		show_result(chmod("/dev/null", 0444), 0);
	}
	unset_capability();
	chmod("/dev/null", 0666);

	capability = "SYS_CHOWN";
	set_capability();
	if (write_policy()) {
		show_result(chown("/dev/null", 1, 1), 1);
		delete_policy();
		show_result(chown("/dev/null", 2, 2), 0);
	}
	unset_capability();
	chown("/dev/null", 0, 0);

	capability = "SYS_IOCTL";
	set_capability();
	if (0 && write_policy()) {
		int fd = open("/dev/null", O_RDONLY);
		show_result(ioctl(fd, 0 /* Use invalid value so that nothing
					   happen. */), 1);
		delete_policy();
		show_result(ioctl(fd, 0 /* Use invalid value so that nothing
					   happen. */), 0);
		close(fd);
	}
	if (write_policy()) {
		struct ifreq ifreq;
		int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
		memset(&ifreq, 0, sizeof(ifreq));
		snprintf(ifreq.ifr_name, sizeof(ifreq.ifr_name) - 1, "lo");
		show_result(ioctl(fd, 35123, &ifreq), 1);
		delete_policy();
		show_result(ioctl(fd, 35123, &ifreq), 0);
		close(fd);
	}
	unset_capability();

	capability = "SYS_PTRACE";
	set_capability();
	if (write_policy()) {
		int status = 0;
		int pipe_fd[2] = { EOF, EOF };
		pipe(pipe_fd);
		switch (fork()) {
		case 0:
			errno = 0;
			ptrace(PTRACE_TRACEME, 0, NULL, NULL);
			status = errno;
			write(pipe_fd[1], &status, sizeof(status));
			_exit(0);
		case -1:
			fprintf(stderr, "fork() failed.\n");
			break;
		default:
			close(pipe_fd[1]);
			read(pipe_fd[0], &status, sizeof(status));
			wait(NULL);
			close(pipe_fd[0]);
			errno = status;
			show_result(status ? EOF : 0, 1);
		}
		delete_policy();
		status = 0;
		pipe(pipe_fd);
		switch (fork()) {
		case 0:
			errno = 0;
			ptrace(PTRACE_TRACEME, 0, NULL, NULL);
			status = errno;
			write(pipe_fd[1], &status, sizeof(status));
			_exit(0);
		case -1:
			fprintf(stderr, "fork() failed.\n");
			break;
		default:
			close(pipe_fd[1]);
			read(pipe_fd[0], &status, sizeof(status));
			wait(NULL);
			close(pipe_fd[0]);
			errno = status;
			show_result(status ? EOF : 0, 0);
		}
	}
	unset_capability();
}
Пример #20
0
ssize_t unwind_backtrace_thread(pid_t tid, backtrace_frame_t* backtrace,
        size_t ignore_depth, size_t max_depth) {
    if (tid == gettid()) {
        return unwind_backtrace(backtrace, ignore_depth + 1, max_depth);
    }

    ALOGV("Unwinding thread %d from thread %d.", tid, gettid());

    // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
    // mach_port_t or the pthread_t rather than the tid.
#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
    struct sigaction act;
    struct sigaction oact;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction = unwind_backtrace_thread_signal_handler;
    act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
    sigemptyset(&act.sa_mask);

    pthread_mutex_lock(&g_unwind_signal_mutex);
    map_info_t* milist = acquire_my_map_info_list();

    ssize_t frames = -1;
    if (!sigaction(SIGURG, &act, &oact)) {
        g_unwind_signal_state.map_info_list = milist;
        g_unwind_signal_state.backtrace = backtrace;
        g_unwind_signal_state.ignore_depth = ignore_depth;
        g_unwind_signal_state.max_depth = max_depth;
        g_unwind_signal_state.returned_frames = 0;
        android_atomic_release_store(tid, &g_unwind_signal_state.tid_state);

        // Signal the specific thread that we want to dump.
        int32_t tid_state = tid;
        if (tgkill(getpid(), tid, SIGURG)) {
            ALOGV("Failed to send SIGURG to thread %d.", tid);
        } else {
            // Wait for the other thread to start dumping the stack, or time out.
            int wait_millis = 250;
            for (;;) {
                tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
                if (tid_state != tid) {
                    break;
                }
                if (wait_millis--) {
                    ALOGV("Waiting for thread %d to start dumping the stack...", tid);
                    usleep(1000);
                } else {
                    ALOGV("Timed out waiting for thread %d to start dumping the stack.", tid);
                    break;
                }
            }
        }

        // Try to cancel the dump if it has not started yet.
        if (tid_state == tid) {
            if (!android_atomic_acquire_cas(tid, STATE_CANCEL, &g_unwind_signal_state.tid_state)) {
                ALOGV("Canceled thread %d stack dump.", tid);
                tid_state = STATE_CANCEL;
            } else {
                tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
            }
        }

        // Wait indefinitely for the dump to finish or be canceled.
        // We cannot apply a timeout here because the other thread is accessing state that
        // is owned by this thread, such as milist.  It should not take very
        // long to take the dump once started.
        while (tid_state == STATE_DUMPING) {
            ALOGV("Waiting for thread %d to finish dumping the stack...", tid);
            usleep(1000);
            tid_state = android_atomic_acquire_load(&g_unwind_signal_state.tid_state);
        }

        if (tid_state == STATE_DONE) {
            frames = g_unwind_signal_state.returned_frames;
        }

        sigaction(SIGURG, &oact, NULL);
    }

    release_my_map_info_list(milist);
    pthread_mutex_unlock(&g_unwind_signal_mutex);
    return frames;
#else
    return -1;
#endif
}
/* Comments by Gene:
 * Here, syscall is the wrapper, and the call to syscall would be _real_syscall
 * We would add a special case for SYS_gettid, while all others default as below
 * It depends on the idea that arguments are stored in registers, whose
 *  natural size is:  sizeof(void*)
 * So, we pass six arguments to syscall, and it will ignore any extra arguments
 * I believe that all Linux system calls have no more than 7 args.
 * clone() is an example of one with 7 arguments.
 * If we discover system calls for which the 7 args strategy doesn't work,
 *  we can special case them.
 *
 * XXX: DO NOT USE JTRACE/JNOTE/JASSERT in this function; even better, do not
 *      use any STL here.  (--Kapil)
 */
extern "C" long int syscall(long int sys_num, ... )
{
  long int ret;
  va_list ap;

  va_start(ap, sys_num);

  switch ( sys_num ) {
    case SYS_gettid:
    {
      ret = gettid();
      break;
    }
    case SYS_tkill:
    {
      SYSCALL_GET_ARGS_2(int, tid, int, sig);
      ret = tkill(tid, sig);
      break;
    }
    case SYS_tgkill:
    {
      SYSCALL_GET_ARGS_3(int, tgid, int, tid, int, sig);
      ret = tgkill(tgid, tid, sig);
      break;
    }

    case SYS_getpid:
    {
      ret = getpid();
      break;
    }
    case SYS_getppid:
    {
      ret = getppid();
      break;
    }

    case SYS_getpgrp:
    {
      ret = getpgrp();
      break;
    }

    case SYS_getpgid:
    {
      SYSCALL_GET_ARG(pid_t,pid);
      ret = getpgid(pid);
      break;
    }
    case SYS_setpgid:
    {
      SYSCALL_GET_ARGS_2(pid_t,pid,pid_t,pgid);
      ret = setpgid(pid, pgid);
      break;
    }

    case SYS_getsid:
    {
      SYSCALL_GET_ARG(pid_t,pid);
      ret = getsid(pid);
      break;
    }
    case SYS_setsid:
    {
      ret = setsid();
      break;
    }

    case SYS_kill:
    {
      SYSCALL_GET_ARGS_2(pid_t,pid,int,sig);
      ret = kill(pid, sig);
      break;
    }

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9))
    case SYS_waitid:
    {
      //SYSCALL_GET_ARGS_4(idtype_t,idtype,id_t,id,siginfo_t*,infop,int,options);
      SYSCALL_GET_ARGS_4(int,idtype,id_t,id,siginfo_t*,infop,int,options);
      ret = waitid((idtype_t)idtype, id, infop, options);
      break;
    }
#endif
    case SYS_wait4:
    {
      SYSCALL_GET_ARGS_4(pid_t,pid,__WAIT_STATUS,status,int,options,
                         struct rusage*,rusage);
      ret = wait4(pid, status, options, rusage);
      break;
    }
#ifdef __i386__
    case SYS_waitpid:
    {
      SYSCALL_GET_ARGS_3(pid_t,pid,int*,status,int,options);
      ret = waitpid(pid, status, options);
      break;
    }
#endif

    case SYS_setgid:
    {
      SYSCALL_GET_ARG(gid_t,gid);
      ret = setgid(gid);
      break;
    }
    case SYS_setuid:
    {
      SYSCALL_GET_ARG(uid_t,uid);
      ret = setuid(uid);
      break;
    }

#ifndef DISABLE_SYS_V_IPC
# ifdef __x86_64__
// These SYS_xxx are only defined for 64-bit Linux
    case SYS_shmget:
    {
      SYSCALL_GET_ARGS_3(key_t,key,size_t,size,int,shmflg);
      ret = shmget(key, size, shmflg);
      break;
    }
    case SYS_shmat:
    {
      SYSCALL_GET_ARGS_3(int,shmid,const void*,shmaddr,int,shmflg);
      ret = (unsigned long) shmat(shmid, shmaddr, shmflg);
      break;
    }
    case SYS_shmdt:
    {
      SYSCALL_GET_ARG(const void*,shmaddr);
      ret = shmdt(shmaddr);
      break;
    }
    case SYS_shmctl:
    {
      SYSCALL_GET_ARGS_3(int,shmid,int,cmd,struct shmid_ds*,buf);
      ret = shmctl(shmid, cmd, buf);
      break;
    }
# endif
#endif

    default:
    {
      SYSCALL_GET_ARGS_7(void*, arg1, void*, arg2, void*, arg3, void*, arg4,
                         void*, arg5, void*, arg6, void*, arg7);
      ret = _real_syscall(sys_num, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
      break;
    }
  }
  va_end(ap);
  return ret;
}