Avoid SIGSTOP/SIGCONT race when ptrace is disabled.
diff --git a/server/process.c b/server/process.c
index 297ef00..8073e55 100644
--- a/server/process.c
+++ b/server/process.c
@@ -462,8 +462,7 @@
set_error( STATUS_ACCESS_DENIED );
return;
}
- suspend_thread( thread, 0 );
- if (thread->attached)
+ if (suspend_for_ptrace( thread ))
{
while (len > 0 && max)
{
@@ -483,10 +482,9 @@
}
if (len && (read_thread_int( thread, addr + len - 1, &dummy ) == -1)) goto done;
}
+ done:
+ resume_thread( thread );
}
- else set_error( STATUS_ACCESS_DENIED );
- done:
- resume_thread( thread );
}
/* write data to a process memory space */
@@ -508,8 +506,7 @@
set_error( STATUS_ACCESS_DENIED );
return;
}
- suspend_thread( thread, 0 );
- if (thread->attached)
+ if (suspend_for_ptrace( thread ))
{
/* first word is special */
if (len > 1)
@@ -544,10 +541,9 @@
}
if (len && (write_thread_int( thread, addr + len - 1, 0, 0 ) == -1)) goto done;
}
+ done:
+ resume_thread( thread );
}
- else set_error( STATUS_ACCESS_DENIED );
- done:
- resume_thread( thread );
}
/* take a snapshot of currently running processes */
diff --git a/server/ptrace.c b/server/ptrace.c
index 58339f6..9cd4c04 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -157,6 +157,25 @@
else ptrace( PTRACE_CONT, thread->unix_pid, 1, SIGSTOP );
}
+/* suspend a thread to allow using ptrace on it */
+/* you must do a resume_thread when finished with the thread */
+int suspend_for_ptrace( struct thread *thread )
+{
+ if (thread->attached)
+ {
+ suspend_thread( thread, 0 );
+ return 1;
+ }
+ if (attach_thread( thread ))
+ {
+ /* the attach will have suspended it */
+ thread->suspend++;
+ return 1;
+ }
+ set_error( STATUS_ACCESS_DENIED );
+ return 0;
+}
+
/* read an int from a thread address space */
int read_thread_int( struct thread *thread, const int *addr, int *data )
{
diff --git a/server/thread.c b/server/thread.c
index 37db99b..e82c4a7 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -541,8 +541,7 @@
set_error( STATUS_INVALID_PARAMETER ); /* FIXME */
return;
}
- suspend_thread( thread, 0 );
- if (thread->attached)
+ if (suspend_for_ptrace( thread ))
{
unsigned char flags_buf[4];
int *addr = (int *)thread->process->ldt_copy + 2 * entry;
@@ -551,10 +550,9 @@
addr = (int *)thread->process->ldt_flags + (entry >> 2);
if (read_thread_int( thread, addr, (int *)flags_buf ) == -1) goto done;
*flags = flags_buf[entry & 3];
+ done:
+ resume_thread( thread );
}
- else set_error( STATUS_ACCESS_DENIED );
- done:
- resume_thread( thread );
}
/* kill a thread on the spot */
diff --git a/server/thread.h b/server/thread.h
index 198b77d..71baa51 100644
--- a/server/thread.h
+++ b/server/thread.h
@@ -86,6 +86,7 @@
extern void stop_thread( struct thread *thread );
extern void continue_thread( struct thread *thread );
extern void detach_thread( struct thread *thread );
+extern int suspend_for_ptrace( struct thread *thread );
extern int read_thread_int( struct thread *thread, const int *addr, int *data );
extern int write_thread_int( struct thread *thread, int *addr, int data, unsigned int mask );