diff options
| -rw-r--r-- | coreutils/timeout.c | 18 | ||||
| -rw-r--r-- | include/mingw.h | 1 | ||||
| -rw-r--r-- | win32/process.c | 196 |
3 files changed, 101 insertions, 114 deletions
diff --git a/coreutils/timeout.c b/coreutils/timeout.c index ff58a753a..802ddfc07 100644 --- a/coreutils/timeout.c +++ b/coreutils/timeout.c | |||
| @@ -54,7 +54,9 @@ static HANDLE child = INVALID_HANDLE_VALUE; | |||
| 54 | static void kill_child(void) | 54 | static void kill_child(void) |
| 55 | { | 55 | { |
| 56 | if (child != INVALID_HANDLE_VALUE) { | 56 | if (child != INVALID_HANDLE_VALUE) { |
| 57 | kill_signal_by_handle(child, SIGTERM); | 57 | pid_t pid = (pid_t)GetProcessId(child); |
| 58 | if (pid) | ||
| 59 | kill(pid, SIGTERM); | ||
| 58 | } | 60 | } |
| 59 | } | 61 | } |
| 60 | 62 | ||
| @@ -206,13 +208,15 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
| 206 | status = signo == SIGKILL ? 137 : 124; | 208 | status = signo == SIGKILL ? 137 : 124; |
| 207 | 209 | ||
| 208 | pid = (pid_t)GetProcessId(child); | 210 | pid = (pid_t)GetProcessId(child); |
| 209 | kill(pid, signo); | 211 | if (pid) { |
| 212 | kill(pid, signo); | ||
| 210 | 213 | ||
| 211 | if (kill_timeout > 0) { | 214 | if (kill_timeout > 0) { |
| 212 | if (timeout_wait(kill_timeout, child, &status)) | 215 | if (timeout_wait(kill_timeout, child, &status)) |
| 213 | goto finish; | 216 | goto finish; |
| 214 | kill(pid, SIGKILL); | 217 | kill(pid, SIGKILL); |
| 215 | status = 137; | 218 | status = 137; |
| 219 | } | ||
| 216 | } | 220 | } |
| 217 | finish: | 221 | finish: |
| 218 | CloseHandle(child); | 222 | CloseHandle(child); |
diff --git a/include/mingw.h b/include/mingw.h index 41d4cd940..56a7285e5 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
| @@ -569,7 +569,6 @@ int mingw_execve(const char *cmd, char *const *argv, char *const *envp); | |||
| 569 | #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') | 569 | #define has_dos_drive_prefix(path) (isalpha(*(path)) && (path)[1] == ':') |
| 570 | 570 | ||
| 571 | BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType); | 571 | BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType); |
| 572 | int kill_signal_by_handle(HANDLE process, int sig); | ||
| 573 | int FAST_FUNC is_valid_signal(int number); | 572 | int FAST_FUNC is_valid_signal(int number); |
| 574 | int exit_code_to_wait_status(DWORD win_exit_code); | 573 | int exit_code_to_wait_status(DWORD win_exit_code); |
| 575 | int exit_code_to_posix(DWORD win_exit_code); | 574 | int exit_code_to_posix(DWORD win_exit_code); |
diff --git a/win32/process.c b/win32/process.c index 5be07e54a..b993bb2be 100644 --- a/win32/process.c +++ b/win32/process.c | |||
| @@ -685,14 +685,98 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | |||
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | /** | 687 | /** |
| 688 | * Determine whether a process runs in the same architecture as the current | ||
| 689 | * one. That test is required before we assume that GetProcAddress() returns | ||
| 690 | * a valid address *for the target process*. | ||
| 691 | */ | ||
| 692 | static inline int process_architecture_matches_current(HANDLE process) | ||
| 693 | { | ||
| 694 | static BOOL current_is_wow = -1; | ||
| 695 | BOOL is_wow; | ||
| 696 | |||
| 697 | if (current_is_wow == -1 && | ||
| 698 | !IsWow64Process (GetCurrentProcess(), ¤t_is_wow)) | ||
| 699 | current_is_wow = -2; | ||
| 700 | if (current_is_wow == -2) | ||
| 701 | return 0; /* could not determine current process' WoW-ness */ | ||
| 702 | if (!IsWow64Process (process, &is_wow)) | ||
| 703 | return 0; /* cannot determine */ | ||
| 704 | return is_wow == current_is_wow; | ||
| 705 | } | ||
| 706 | |||
| 707 | /** | ||
| 708 | * This function tries to terminate a Win32 process, as gently as possible, | ||
| 709 | * by injecting a thread that calls ExitProcess(). | ||
| 710 | * | ||
| 711 | * Note: as kernel32.dll is loaded before any process, the other process and | ||
| 712 | * this process will have ExitProcess() at the same address. | ||
| 713 | * | ||
| 714 | * The idea comes from the Dr Dobb's article "A Safer Alternative to | ||
| 715 | * TerminateProcess()" by Andrew Tucker (July 1, 1999), | ||
| 716 | * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 | ||
| 717 | * | ||
| 718 | */ | ||
| 719 | static int kill_signal_by_handle(HANDLE process, int sig) | ||
| 720 | { | ||
| 721 | DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID); | ||
| 722 | PVOID arg = (PVOID)(intptr_t)(sig << 24); | ||
| 723 | DWORD thread_id; | ||
| 724 | HANDLE thread; | ||
| 725 | |||
| 726 | if (!INIT_PROC_ADDR(kernel32, ExitProcess) || | ||
| 727 | !process_architecture_matches_current(process)) { | ||
| 728 | SetLastError(ERROR_ACCESS_DENIED); | ||
| 729 | return -1; | ||
| 730 | } | ||
| 731 | |||
| 732 | if (sig != 0 && (thread = CreateRemoteThread(process, NULL, 0, | ||
| 733 | ExitProcess, arg, 0, &thread_id))) { | ||
| 734 | CloseHandle(thread); | ||
| 735 | } | ||
| 736 | return 0; | ||
| 737 | } | ||
| 738 | |||
| 739 | static int kill_signal(pid_t pid, int sig) | ||
| 740 | { | ||
| 741 | HANDLE process; | ||
| 742 | int ret = 0; | ||
| 743 | DWORD code; | ||
| 744 | |||
| 745 | if (sig == SIGKILL) | ||
| 746 | process = OpenProcess(PROCESS_TERMINATE, FALSE, pid); | ||
| 747 | else | ||
| 748 | process = OpenProcess(SYNCHRONIZE | PROCESS_CREATE_THREAD | | ||
| 749 | PROCESS_QUERY_INFORMATION | | ||
| 750 | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | | ||
| 751 | PROCESS_VM_READ, FALSE, pid); | ||
| 752 | |||
| 753 | if (!process) | ||
| 754 | return -1; | ||
| 755 | |||
| 756 | if (!GetExitCodeProcess(process, &code) || code != STILL_ACTIVE) { | ||
| 757 | SetLastError(ERROR_INVALID_PARAMETER); | ||
| 758 | ret = -1; | ||
| 759 | } else if (sig == SIGKILL) { | ||
| 760 | /* This way of terminating processes is not gentle: they get no | ||
| 761 | * chance to clean up after themselves (closing file handles, | ||
| 762 | * removing .lock files, terminating spawned processes (if any), | ||
| 763 | * etc). */ | ||
| 764 | ret = !TerminateProcess(process, SIGKILL << 24); | ||
| 765 | } else { | ||
| 766 | ret = kill_signal_by_handle(process, sig); | ||
| 767 | } | ||
| 768 | CloseHandle(process); | ||
| 769 | |||
| 770 | return ret; | ||
| 771 | } | ||
| 772 | |||
| 773 | /** | ||
| 688 | * If the process ID is positive invoke the callback for that process | 774 | * If the process ID is positive invoke the callback for that process |
| 689 | * only. If negative or zero invoke the callback for all descendants | 775 | * only. If negative or zero invoke the callback for all descendants |
| 690 | * of the indicated process. Zero indicates the current process; negative | 776 | * of the indicated process. Zero indicates the current process; negative |
| 691 | * indicates the process with process ID -pid. | 777 | * indicates the process with process ID -pid. |
| 692 | */ | 778 | */ |
| 693 | typedef int (*kill_callback)(pid_t pid, int sig); | 779 | static int kill_pids(pid_t pid, int sig) |
| 694 | |||
| 695 | static int kill_pids(pid_t pid, int sig, kill_callback killer) | ||
| 696 | { | 780 | { |
| 697 | DWORD pids[16384]; | 781 | DWORD pids[16384]; |
| 698 | int max_len = sizeof(pids) / sizeof(*pids), i, len, ret = 0; | 782 | int max_len = sizeof(pids) / sizeof(*pids), i, len, ret = 0; |
| @@ -750,7 +834,7 @@ static int kill_pids(pid_t pid, int sig, kill_callback killer) | |||
| 750 | 834 | ||
| 751 | for (i = len - 1; i >= 0; i--) { | 835 | for (i = len - 1; i >= 0; i--) { |
| 752 | SetLastError(0); | 836 | SetLastError(0); |
| 753 | if (killer(pids[i], sig)) { | 837 | if (kill_signal(pids[i], sig)) { |
| 754 | errno = err_win_to_posix(); | 838 | errno = err_win_to_posix(); |
| 755 | ret = -1; | 839 | ret = -1; |
| 756 | } | 840 | } |
| @@ -759,104 +843,6 @@ static int kill_pids(pid_t pid, int sig, kill_callback killer) | |||
| 759 | return ret; | 843 | return ret; |
| 760 | } | 844 | } |
| 761 | 845 | ||
| 762 | /** | ||
| 763 | * Determine whether a process runs in the same architecture as the current | ||
| 764 | * one. That test is required before we assume that GetProcAddress() returns | ||
| 765 | * a valid address *for the target process*. | ||
| 766 | */ | ||
| 767 | static inline int process_architecture_matches_current(HANDLE process) | ||
| 768 | { | ||
| 769 | static BOOL current_is_wow = -1; | ||
| 770 | BOOL is_wow; | ||
| 771 | |||
| 772 | if (current_is_wow == -1 && | ||
| 773 | !IsWow64Process (GetCurrentProcess(), ¤t_is_wow)) | ||
| 774 | current_is_wow = -2; | ||
| 775 | if (current_is_wow == -2) | ||
| 776 | return 0; /* could not determine current process' WoW-ness */ | ||
| 777 | if (!IsWow64Process (process, &is_wow)) | ||
| 778 | return 0; /* cannot determine */ | ||
| 779 | return is_wow == current_is_wow; | ||
| 780 | } | ||
| 781 | |||
| 782 | /** | ||
| 783 | * This function tries to terminate a Win32 process, as gently as possible, | ||
| 784 | * by injecting a thread that calls ExitProcess(). | ||
| 785 | * | ||
| 786 | * Note: as kernel32.dll is loaded before any process, the other process and | ||
| 787 | * this process will have ExitProcess() at the same address. | ||
| 788 | * | ||
| 789 | * The idea comes from the Dr Dobb's article "A Safer Alternative to | ||
| 790 | * TerminateProcess()" by Andrew Tucker (July 1, 1999), | ||
| 791 | * http://www.drdobbs.com/a-safer-alternative-to-terminateprocess/184416547 | ||
| 792 | * | ||
| 793 | */ | ||
| 794 | int kill_signal_by_handle(HANDLE process, int sig) | ||
| 795 | { | ||
| 796 | DWORD code; | ||
| 797 | int ret = 0; | ||
| 798 | |||
| 799 | if (GetExitCodeProcess(process, &code) && code == STILL_ACTIVE) { | ||
| 800 | DECLARE_PROC_ADDR(DWORD, ExitProcess, LPVOID); | ||
| 801 | PVOID arg = (PVOID)(intptr_t)(sig << 24); | ||
| 802 | DWORD thread_id; | ||
| 803 | HANDLE thread; | ||
| 804 | |||
| 805 | if (!INIT_PROC_ADDR(kernel32, ExitProcess) || | ||
| 806 | !process_architecture_matches_current(process)) { | ||
| 807 | SetLastError(ERROR_ACCESS_DENIED); | ||
| 808 | ret = -1; | ||
| 809 | goto finish; | ||
| 810 | } | ||
| 811 | |||
| 812 | if ((thread = CreateRemoteThread(process, NULL, 0, | ||
| 813 | ExitProcess, arg, 0, &thread_id))) { | ||
| 814 | CloseHandle(thread); | ||
| 815 | } | ||
| 816 | } | ||
| 817 | |||
| 818 | finish: | ||
| 819 | CloseHandle(process); | ||
| 820 | return ret; | ||
| 821 | } | ||
| 822 | |||
| 823 | static int kill_signal(pid_t pid, int sig) | ||
| 824 | { | ||
| 825 | HANDLE process; | ||
| 826 | |||
| 827 | if (!(process = OpenProcess(SYNCHRONIZE | PROCESS_CREATE_THREAD | | ||
| 828 | PROCESS_QUERY_INFORMATION | | ||
| 829 | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | | ||
| 830 | PROCESS_VM_READ, FALSE, pid))) { | ||
| 831 | return -1; | ||
| 832 | } | ||
| 833 | |||
| 834 | return kill_signal_by_handle(process, sig); | ||
| 835 | } | ||
| 836 | |||
| 837 | /* | ||
| 838 | * This way of terminating processes is not gentle: they get no chance to | ||
| 839 | * clean up after themselves (closing file handles, removing .lock files, | ||
| 840 | * terminating spawned processes (if any), etc). | ||
| 841 | * | ||
| 842 | * If the signal isn't SIGKILL just check if the target process exists. | ||
| 843 | */ | ||
| 844 | static int kill_SIGKILL(pid_t pid, int sig) | ||
| 845 | { | ||
| 846 | HANDLE process; | ||
| 847 | int ret = 0; | ||
| 848 | |||
| 849 | if (!(process=OpenProcess(PROCESS_TERMINATE, FALSE, pid))) { | ||
| 850 | return -1; | ||
| 851 | } | ||
| 852 | |||
| 853 | if (sig == SIGKILL) | ||
| 854 | ret = !TerminateProcess(process, SIGKILL << 24); | ||
| 855 | CloseHandle(process); | ||
| 856 | |||
| 857 | return ret; | ||
| 858 | } | ||
| 859 | |||
| 860 | int FAST_FUNC is_valid_signal(int number) | 846 | int FAST_FUNC is_valid_signal(int number) |
| 861 | { | 847 | { |
| 862 | return isalpha(*get_signame(number)); | 848 | return isalpha(*get_signame(number)); |
| @@ -897,10 +883,8 @@ int exit_code_to_posix(DWORD exit_code) | |||
| 897 | 883 | ||
| 898 | int kill(pid_t pid, int sig) | 884 | int kill(pid_t pid, int sig) |
| 899 | { | 885 | { |
| 900 | if (sig == SIGKILL || sig == 0) | 886 | if (is_valid_signal(sig)) |
| 901 | return kill_pids(pid, sig, kill_SIGKILL); | 887 | return kill_pids(pid, sig); |
| 902 | else if (is_valid_signal(sig)) | ||
| 903 | return kill_pids(pid, sig, kill_signal); | ||
| 904 | 888 | ||
| 905 | errno = EINVAL; | 889 | errno = EINVAL; |
| 906 | return -1; | 890 | return -1; |
