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