hrev52006 adds 1 changeset to branch 'master'
old head: 2ffbe7aaca8668c5a68ac7488459bace7a0700f2
new head: c70cba914aa79c01bbc2da38085936f589899c8c
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=c70cba914aa7+%5E2ffbe7aaca86
----------------------------------------------------------------------------
c70cba914aa7: kernel/x86_64: compatibility syscalls for image.cpp.
* define compat_image_info, compat_extended_image_info
to be used for respective 32-bit types of syscalls in compatibility mode.
* handle 32-bit types in _user_register_image, _user_get_image_info,
_user_get_next_image_info, other syscalls are compatible as is.
Change-Id: Ibbd33e6796208dfa70d869e36bf745bc3e18d330
[ Jérôme Duval <jerome.duval@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev52006
Commit: c70cba914aa79c01bbc2da38085936f589899c8c
URL: https://git.haiku-os.org/haiku/commit/?id=c70cba914aa7
Author: Jérôme Duval <jerome.duval@xxxxxxxxx>
Date: Fri May 18 16:43:22 2018 UTC
----------------------------------------------------------------------------
3 files changed, 169 insertions(+), 15 deletions(-)
headers/private/kernel/compat/image_compat.h | 129 +++++++++++++++++++++++
headers/private/kernel/util/syscall_args.h | 25 +++++
src/system/kernel/image.cpp | 30 +++---
----------------------------------------------------------------------------
diff --git a/headers/private/kernel/compat/image_compat.h
b/headers/private/kernel/compat/image_compat.h
new file mode 100644
index 0000000000..eb52f03698
--- /dev/null
+++ b/headers/private/kernel/compat/image_compat.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2018, Haiku Inc. All rights reserved.
+ *
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_COMPAT_IMAGE_H
+#define _KERNEL_COMPAT_IMAGE_H
+
+
+#include <image.h>
+
+
+#define compat_uintptr_t uint32
+typedef struct {
+ image_id id;
+ image_type type;
+ int32 sequence;
+ int32 init_order;
+ compat_uintptr_t init_routine;
+ compat_uintptr_t term_routine;
+ dev_t device;
+ ino_t node;
+ char name[MAXPATHLEN];
+ compat_uintptr_t text;
+ compat_uintptr_t data;
+ int32 text_size;
+ int32 data_size;
+
+ /* Haiku R1 extensions */
+ int32 api_version; /* the Haiku API version used by the
image */
+ int32 abi; /* the Haiku ABI used by the
image */
+} _PACKED compat_image_info;
+
+
+typedef struct {
+ compat_image_info basic_info;
+ int32 text_delta;
+ compat_uintptr_t symbol_table;
+ compat_uintptr_t symbol_hash;
+ compat_uintptr_t string_table;
+} _PACKED compat_extended_image_info;
+
+
+static_assert(sizeof(compat_image_info) == 1084,
+ "size of compat_image_info mismatch");
+static_assert(sizeof(compat_extended_image_info) == 1100,
+ "size of compat_extended_image_info mismatch");
+
+
+inline status_t
+copy_ref_var_to_user(image_info &info, image_info* userInfo, size_t size)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ if (size > sizeof(compat_image_info))
+ return B_BAD_VALUE;
+ compat_image_info compat_info;
+ compat_info.id = info.id;
+ compat_info.type = info.type;
+ compat_info.sequence = info.sequence;
+ compat_info.init_order = info.init_order;
+ compat_info.init_routine = (uint32)(addr_t)info.init_routine;
+ compat_info.term_routine = (uint32)(addr_t)info.term_routine;
+ compat_info.device = info.device;
+ compat_info.node = info.node;
+ strlcpy(compat_info.name, info.name, MAXPATHLEN);
+ compat_info.text = (uint32)(addr_t)info.text;
+ compat_info.data = (uint32)(addr_t)info.data;
+ compat_info.text_size = info.text_size;
+ compat_info.data_size = info.data_size;
+ if (user_memcpy(userInfo, &compat_info, size) < B_OK)
+ return B_BAD_ADDRESS;
+ } else {
+ if (size > sizeof(image_info))
+ return B_BAD_VALUE;
+
+ if (user_memcpy(userInfo, &info, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+inline status_t
+copy_ref_var_from_user(extended_image_info* userInfo,
+ extended_image_info &info, size_t size)
+{
+ if (!IS_USER_ADDRESS(userInfo))
+ return B_BAD_ADDRESS;
+ Thread* thread = thread_get_current_thread();
+ bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
+ if (compatMode) {
+ compat_extended_image_info compat_info;
+ if (size != sizeof(compat_info))
+ return B_BAD_VALUE;
+ if (user_memcpy(&compat_info, userInfo, size) < B_OK)
+ return B_BAD_ADDRESS;
+ info.basic_info.id = compat_info.basic_info.id;
+ info.basic_info.type = compat_info.basic_info.type;
+ info.basic_info.sequence = compat_info.basic_info.sequence;
+ info.basic_info.init_order = compat_info.basic_info.init_order;
+ info.basic_info.init_routine =
(void(*)())(addr_t)compat_info.basic_info.init_routine;
+ info.basic_info.term_routine =
(void(*)())(addr_t)compat_info.basic_info.term_routine;
+ info.basic_info.device = compat_info.basic_info.device;
+ info.basic_info.node = compat_info.basic_info.node;
+ strlcpy(info.basic_info.name, compat_info.basic_info.name,
MAXPATHLEN);
+ info.basic_info.text =
(void*)(addr_t)compat_info.basic_info.text;
+ info.basic_info.data =
(void*)(addr_t)compat_info.basic_info.data;
+ info.basic_info.text_size = compat_info.basic_info.text_size;
+ info.basic_info.data_size = compat_info.basic_info.data_size;
+ info.text_delta = compat_info.text_delta;
+ info.symbol_table = (void*)(addr_t)compat_info.symbol_table;
+ info.symbol_hash = (void*)(addr_t)compat_info.symbol_hash;
+ info.string_table = (void*)(addr_t)compat_info.string_table;
+ } else {
+ if (size != sizeof(info))
+ return B_BAD_VALUE;
+
+ if (user_memcpy(&info, userInfo, size) < B_OK)
+ return B_BAD_ADDRESS;
+ }
+ return B_OK;
+}
+
+
+#endif // _KERNEL_COMPAT_IMAGE_H
diff --git a/headers/private/kernel/util/syscall_args.h
b/headers/private/kernel/util/syscall_args.h
index 46eab7342c..c6d1d6166d 100644
--- a/headers/private/kernel/util/syscall_args.h
+++ b/headers/private/kernel/util/syscall_args.h
@@ -23,6 +23,18 @@ copy_ref_var_from_user(T *user, T &kernel)
return user_memcpy(&kernel, user, sizeof(T));
}
+
+template<typename T>
+inline
+status_t
+copy_ref_var_from_user(T *user, T &kernel, size_t size)
+{
+ if (size != sizeof(T))
+ return B_BAD_VALUE;
+ return copy_ref_var_from_user(user, kernel);
+}
+
+
// copy_ref_var_to_user
template<typename T>
inline
@@ -35,4 +47,17 @@ copy_ref_var_to_user(T &kernel, T *user)
}
+template<typename T>
+inline
+status_t
+copy_ref_var_to_user(T &kernel, T *user, size_t size)
+{
+ if (size > sizeof(T))
+ return B_BAD_VALUE;
+ if (!IS_USER_ADDRESS(user))
+ return B_BAD_ADDRESS;
+ return user_memcpy(user, &kernel, size);
+}
+
+
#endif // _SYSCALL_ARGS_H
diff --git a/src/system/kernel/image.cpp b/src/system/kernel/image.cpp
index 30c4b293b0..41b79899f4 100644
--- a/src/system/kernel/image.cpp
+++ b/src/system/kernel/image.cpp
@@ -18,6 +18,11 @@
#include <thread_types.h>
#include <user_debugger.h>
#include <util/AutoLock.h>
+#include <util/syscall_args.h>
+
+#ifdef _COMPAT_MODE
+# include <image_compat.h>
+#endif
#include <stdlib.h>
#include <string.h>
@@ -464,12 +469,9 @@ _user_register_image(extended_image_info *userInfo, size_t
size)
{
extended_image_info info;
- if (size != sizeof(info))
- return B_BAD_VALUE;
-
- if (!IS_USER_ADDRESS(userInfo)
- || user_memcpy(&info, userInfo, size) < B_OK)
- return B_BAD_ADDRESS;
+ status_t status = copy_ref_var_from_user(userInfo, info, size);
+ if (status != B_OK)
+ return status;
return register_image(thread_get_current_thread()->team, &info, size);
}
@@ -525,9 +527,9 @@ _user_get_image_info(image_id id, image_info *userInfo,
size_t size)
status = _get_image_info(id, &info, sizeof(image_info));
- if (user_memcpy(userInfo, &info, size) < B_OK)
- return B_BAD_ADDRESS;
-
+ status_t err = copy_ref_var_to_user(info, userInfo, size);
+ if (err != B_OK)
+ return err;
return status;
}
@@ -540,9 +542,6 @@ _user_get_next_image_info(team_id team, int32 *_cookie,
image_info *userInfo,
status_t status;
int32 cookie;
- if (size > sizeof(image_info))
- return B_BAD_VALUE;
-
if (!IS_USER_ADDRESS(userInfo) || !IS_USER_ADDRESS(_cookie)
|| user_memcpy(&cookie, _cookie, sizeof(int32)) < B_OK) {
return B_BAD_ADDRESS;
@@ -550,10 +549,11 @@ _user_get_next_image_info(team_id team, int32 *_cookie,
image_info *userInfo,
status = _get_next_image_info(team, &cookie, &info, sizeof(image_info));
- if (user_memcpy(userInfo, &info, size) < B_OK
- || user_memcpy(_cookie, &cookie, sizeof(int32)) < B_OK) {
+ status_t err = copy_ref_var_to_user(info, userInfo, size);
+ if (err != B_OK)
+ return err;
+ if (user_memcpy(_cookie, &cookie, sizeof(int32)) < B_OK)
return B_BAD_ADDRESS;
- }
return status;
}