hrev52007 adds 1 changeset to branch 'master'
old head: c70cba914aa79c01bbc2da38085936f589899c8c
new head: aac8d4c317ca11a9a6e194e2c668e8183ec23dd6
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=aac8d4c317ca+%5Ec70cba914aa7
----------------------------------------------------------------------------
aac8d4c317ca: kernel/x86_64: compatibility syscalls for signal.cpp.
* handle 32-bit types in _user_send_signal(), _user_sigaction(),
_user_sigwait(),
_user_set_signal_stack(), _user_restore_signal_frame(), other syscalls are
compatible as is.
Change-Id: I4c8dc47bfa80f36e363d444d2a5a7be6c621606d
[ Jérôme Duval <jerome.duval@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev52007
Commit: aac8d4c317ca11a9a6e194e2c668e8183ec23dd6
URL: https://git.haiku-os.org/haiku/commit/?id=aac8d4c317ca
Author: Jérôme Duval <jerome.duval@xxxxxxxxx>
Date: Fri May 18 16:59:19 2018 UTC
----------------------------------------------------------------------------
3 files changed, 132 insertions(+), 26 deletions(-)
headers/private/kernel/compat/ksignal_compat.h | 1 +
headers/private/kernel/compat/signal_compat.h | 48 +++++++++
src/system/kernel/signal.cpp | 109 ++++++++++++++++-----
----------------------------------------------------------------------------
diff --git a/headers/private/kernel/compat/ksignal_compat.h
b/headers/private/kernel/compat/ksignal_compat.h
index 6b3ee64a38..d193e08dc5 100644
--- a/headers/private/kernel/compat/ksignal_compat.h
+++ b/headers/private/kernel/compat/ksignal_compat.h
@@ -39,6 +39,7 @@ typedef struct __compat_siginfo_t {
union compat_sigval si_value; /* signal value */
} compat_siginfo_t;
+
struct compat_signal_frame_data {
compat_siginfo_t info;
compat_ucontext_t context;
diff --git a/headers/private/kernel/compat/signal_compat.h
b/headers/private/kernel/compat/signal_compat.h
index 07a4686296..c81865f3f6 100644
--- a/headers/private/kernel/compat/signal_compat.h
+++ b/headers/private/kernel/compat/signal_compat.h
@@ -19,4 +19,52 @@ struct compat_sigaction {
} _PACKED;
+inline status_t
+copy_ref_var_from_user(struct sigaction* userAction, struct sigaction &action)
+{
+ if (!IS_USER_ADDRESS(userAction))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_sigaction compat_action;
+ if (user_memcpy(&compat_action, userAction,
sizeof(compat_sigaction))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ action.sa_handler =
(__sighandler_t)(addr_t)compat_action.sa_handler;
+ action.sa_mask = compat_action.sa_mask;
+ action.sa_flags = compat_action.sa_flags;
+ action.sa_userdata = (void*)(addr_t)compat_action.sa_userdata;
+ } else if (user_memcpy(&action, userAction, sizeof(action)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_to_user(struct sigaction &action, struct sigaction* userAction)
+{
+ if (!IS_USER_ADDRESS(userAction))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ struct compat_sigaction compat_action;
+ compat_action.sa_handler = (addr_t)action.sa_handler;
+ compat_action.sa_mask = action.sa_mask;
+ compat_action.sa_flags = action.sa_flags;
+ compat_action.sa_userdata = (addr_t)action.sa_userdata;
+ if (user_memcpy(userAction, &compat_action,
sizeof(compat_action))
+ < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ } else if (user_memcpy(userAction, &action, sizeof(action)) < B_OK) {
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
#endif // _KERNEL_COMPAT_SIGNAL_H
diff --git a/src/system/kernel/signal.cpp b/src/system/kernel/signal.cpp
index 3f96d7918d..f0a671028b 100644
--- a/src/system/kernel/signal.cpp
+++ b/src/system/kernel/signal.cpp
@@ -13,9 +13,6 @@
#include <ksignal.h>
-#ifdef _COMPAT_MODE
-# include <compat/ksignal.h>
-#endif
#include <errno.h>
#include <stddef.h>
@@ -38,6 +35,11 @@
#include <user_debugger.h>
#include <user_thread.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
+
+#ifdef _COMPAT_MODE
+# include <compat/ksignal_compat.h>
+#endif
//#define TRACE_SIGNAL
@@ -2298,11 +2300,10 @@ _user_send_signal(int32 id, uint32 signalNumber,
// Copy the user value from userland. If not given, use a dummy value.
union sigval userValue;
if (userUserValue != NULL) {
- if (!IS_USER_ADDRESS(userUserValue)
- || user_memcpy(&userValue, userUserValue,
sizeof(userValue))
- != B_OK) {
- return B_BAD_ADDRESS;
- }
+ status_t status = copy_ref_var_from_user((union
sigval*)userUserValue,
+ userValue);
+ if (status != B_OK)
+ return status;
} else
userValue.sival_ptr = NULL;
@@ -2359,20 +2360,23 @@ _user_sigaction(int signal, const struct sigaction
*userAction,
struct sigaction act, oact;
status_t status;
- if ((userAction != NULL && (!IS_USER_ADDRESS(userAction)
- || user_memcpy(&act, userAction, sizeof(struct
sigaction)) < B_OK))
- || (userOldAction != NULL && (!IS_USER_ADDRESS(userOldAction)
- || user_memcpy(&oact, userOldAction, sizeof(struct
sigaction))
- < B_OK)))
- return B_BAD_ADDRESS;
+ if (userAction != NULL) {
+ status = copy_ref_var_from_user((struct sigaction*)userAction,
act);
+ if (status < B_OK)
+ return status;
+ }
+ if (userOldAction != NULL) {
+ status = copy_ref_var_from_user(userOldAction, oact);
+ if (status < B_OK)
+ return status;
+ }
status = sigaction_internal(signal, userAction ? &act : NULL,
userOldAction ? &oact : NULL);
// only copy the old action if a pointer has been given
- if (status >= B_OK && userOldAction != NULL
- && user_memcpy(userOldAction, &oact, sizeof(struct sigaction))
< B_OK)
- return B_BAD_ADDRESS;
+ if (status >= B_OK && userOldAction != NULL)
+ status = copy_ref_var_to_user(oact, userOldAction);
return status;
}
@@ -2402,7 +2406,7 @@ _user_sigwait(const sigset_t *userSet, siginfo_t
*userInfo, uint32 flags,
if (status == B_OK) {
// copy the info back to userland, if userSet is non-NULL
if (userInfo != NULL)
- status = user_memcpy(userInfo, &info, sizeof(info));
+ status = copy_ref_var_to_user(info, userInfo);
} else if (status == B_INTERRUPTED) {
// make sure we'll be restarted
Thread* thread = thread_get_current_thread();
@@ -2456,11 +2460,17 @@ _user_set_signal_stack(const stack_t* newUserStack,
stack_t* oldUserStack)
struct stack_t newStack, oldStack;
bool onStack = false;
- if ((newUserStack != NULL && (!IS_USER_ADDRESS(newUserStack)
- || user_memcpy(&newStack, newUserStack,
sizeof(stack_t)) < B_OK))
- || (oldUserStack != NULL && (!IS_USER_ADDRESS(oldUserStack)
- || user_memcpy(&oldStack, oldUserStack,
sizeof(stack_t)) < B_OK)))
- return B_BAD_ADDRESS;
+ if (newUserStack != NULL) {
+ status_t status = copy_ref_var_from_user((stack_t*)newUserStack,
+ newStack);
+ if (status < B_OK)
+ return status;
+ }
+ if (oldUserStack != NULL) {
+ status_t status = copy_ref_var_from_user(oldUserStack,
oldStack);
+ if (status < B_OK)
+ return status;
+ }
if (thread->signal_stack_enabled) {
// determine whether or not the user thread is currently
@@ -2497,9 +2507,8 @@ _user_set_signal_stack(const stack_t* newUserStack,
stack_t* oldUserStack)
}
// only copy the old stack info if a pointer has been given
- if (oldUserStack != NULL
- && user_memcpy(oldUserStack, &oldStack, sizeof(stack_t)) < B_OK)
- return B_BAD_ADDRESS;
+ if (oldUserStack != NULL)
+ return copy_ref_var_to_user(oldStack, oldUserStack);
return B_OK;
}
@@ -2533,6 +2542,54 @@ _user_restore_signal_frame(struct signal_frame_data*
userSignalFrameData)
Thread *thread = thread_get_current_thread();
+#ifdef _COMPAT_MODE
+ if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) {
+ // copy the signal frame data from userland
+ compat_signal_frame_data signalFrameData;
+ if (userSignalFrameData == NULL ||
!IS_USER_ADDRESS(userSignalFrameData)
+ || user_memcpy(&signalFrameData, userSignalFrameData,
+ sizeof(signalFrameData)) != B_OK) {
+ // We failed to copy the signal frame data from
userland. This is a
+ // serious problem. Kill the thread.
+ dprintf("_user_restore_signal_frame(): thread %"
B_PRId32 ": Failed to "
+ "copy signal frame data (%p) from userland.
Killing thread...\n",
+ thread->id, userSignalFrameData);
+ kill_thread(thread->id);
+ return B_BAD_ADDRESS;
+ }
+
+ // restore the signal block mask
+ InterruptsSpinLocker locker(thread->team->signal_lock);
+
+ thread->sig_block_mask
+ = signalFrameData.context.uc_sigmask &
BLOCKABLE_SIGNALS;
+ update_current_thread_signals_flag();
+
+ locker.Unlock();
+
+ // restore the syscall restart related thread flags and the
syscall restart
+ // parameters
+ atomic_and(&thread->flags,
+ ~(THREAD_FLAGS_RESTART_SYSCALL |
THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
+ atomic_or(&thread->flags, signalFrameData.thread_flags
+ & (THREAD_FLAGS_RESTART_SYSCALL |
THREAD_FLAGS_64_BIT_SYSCALL_RETURN));
+
+ memcpy(thread->syscall_restart.parameters,
+ signalFrameData.syscall_restart_parameters,
+ sizeof(thread->syscall_restart.parameters));
+
+ // restore the previously stored Thread::user_signal_context
+ thread->user_signal_context =
(ucontext_t*)(addr_t)signalFrameData.context.uc_link;
+ if (thread->user_signal_context != NULL
+ && !IS_USER_ADDRESS(thread->user_signal_context)) {
+ thread->user_signal_context = NULL;
+ }
+
+ // let the architecture specific code restore the registers
+ return arch_restore_compat_signal_frame(&signalFrameData);
+ }
+#endif
+
// copy the signal frame data from userland
signal_frame_data signalFrameData;
if (userSignalFrameData == NULL || !IS_USER_ADDRESS(userSignalFrameData)