signal_sender.cpp revision f5e8f0b9cd9ec0214a6f9cd38dd6d9af3268f9aa
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <errno.h>
18#include <signal.h>
19#include <string.h>
20#include <sys/socket.h>
21#include <sys/syscall.h>
22#include <sys/types.h>
23#include <sys/wait.h>
24#include <unistd.h>
25
26#include <log/logger.h>
27
28#include "signal_sender.h"
29
30static int signal_fd = -1;
31static pid_t signal_pid;
32struct signal_message {
33  pid_t pid;
34  pid_t tid;
35  int signal;
36};
37
38// Fork a process to send signals for the worker processes to use after they've dropped privileges.
39bool start_signal_sender() {
40  if (signal_pid == 0) {
41    ALOGE("debuggerd: attempted to start signal sender multiple times");
42    return false;
43  }
44
45  int sfd[2];
46  if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sfd) != 0) {
47    ALOGE("debuggerd: failed to create socketpair for signal sender: %s", strerror(errno));
48    return false;
49  }
50
51  pid_t parent = getpid();
52  pid_t fork_pid = fork();
53  if (fork_pid == -1) {
54    ALOGE("debuggerd: failed to initialize signal sender: fork failed: %s", strerror(errno));
55    return false;
56  } else if (fork_pid == 0) {
57    close(sfd[1]);
58
59    while (true) {
60      signal_message msg;
61      int rc = TEMP_FAILURE_RETRY(read(sfd[0], &msg, sizeof(msg)));
62      if (rc < 0) {
63        ALOGE("debuggerd: signal sender failed to read from socket");
64        break;
65      } else if (rc != sizeof(msg)) {
66        ALOGE("debuggerd: signal sender read unexpected number of bytes: %d", rc);
67        break;
68      }
69
70      // Report success after sending a signal
71      int err = 0;
72      if (msg.tid > 0) {
73        if (syscall(SYS_tgkill, msg.pid, msg.tid, msg.signal) != 0) {
74          err = errno;
75        }
76      } else {
77        if (kill(msg.pid, msg.signal) != 0) {
78          err = errno;
79        }
80      }
81
82      if (TEMP_FAILURE_RETRY(write(sfd[0], &err, sizeof(err))) < 0) {
83        ALOGE("debuggerd: signal sender failed to write: %s", strerror(errno));
84      }
85    }
86
87    // Our parent proably died, but if not, kill them.
88    if (getppid() == parent) {
89      kill(parent, SIGKILL);
90    }
91    _exit(1);
92  } else {
93    close(sfd[0]);
94    signal_fd = sfd[1];
95    signal_pid = fork_pid;
96    return true;
97  }
98}
99
100bool stop_signal_sender() {
101  if (signal_pid <= 0) {
102    return false;
103  }
104
105  if (kill(signal_pid, SIGKILL) != 0) {
106    ALOGE("debuggerd: failed to kill signal sender: %s", strerror(errno));
107    return false;
108  }
109
110  close(signal_fd);
111  signal_fd = -1;
112
113  int status;
114  waitpid(signal_pid, &status, 0);
115  signal_pid = 0;
116
117  return true;
118}
119
120bool send_signal(pid_t pid, pid_t tid, int signal) {
121  if (signal_fd == -1) {
122    ALOGE("debuggerd: attempted to send signal before signal sender was started");
123    errno = EHOSTUNREACH;
124    return false;
125  }
126
127  signal_message msg = {.pid = pid, .tid = tid, .signal = signal };
128  if (TEMP_FAILURE_RETRY(write(signal_fd, &msg, sizeof(msg))) < 0) {
129    ALOGE("debuggerd: failed to send message to signal sender: %s", strerror(errno));
130    errno = EHOSTUNREACH;
131    return false;
132  }
133
134  int response;
135  ssize_t rc = TEMP_FAILURE_RETRY(read(signal_fd, &response, sizeof(response)));
136  if (rc == 0) {
137    ALOGE("debuggerd: received EOF from signal sender");
138    errno = EHOSTUNREACH;
139    return false;
140  } else if (rc < 0) {
141    ALOGE("debuggerd: failed to receive response from signal sender: %s", strerror(errno));
142    errno = EHOSTUNREACH;
143    return false;
144  }
145
146  if (response == 0) {
147    return true;
148  }
149
150  errno = response;
151  return false;
152}
153