aboutsummaryrefslogtreecommitdiff
path: root/win32/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/process.c')
-rw-r--r--win32/process.c196
1 files changed, 90 insertions, 106 deletions
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 */
692static 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(), &current_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 */
719static 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
739static 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 */
693typedef int (*kill_callback)(pid_t pid, int sig); 779static int kill_pids(pid_t pid, int sig)
694
695static 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 */
767static 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(), &current_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 */
794int 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
823static 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 */
844static 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
860int FAST_FUNC is_valid_signal(int number) 846int 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
898int kill(pid_t pid, int sig) 884int 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;