[haiku-commits] haiku: hrev52007 - src/system/kernel headers/private/kernel/compat

  • From: Jérôme Duval <jerome.duval@xxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 12 Jun 2018 11:57:47 -0400 (EDT)

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)


Other related posts:

  • » [haiku-commits] haiku: hrev52007 - src/system/kernel headers/private/kernel/compat - Jérôme Duval