From c70cba914aa79c01bbc2da38085936f589899c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Fri, 18 May 2018 18:43:22 +0200 Subject: [PATCH] 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 --- headers/private/kernel/compat/image_compat.h | 129 +++++++++++++++++++ headers/private/kernel/util/syscall_args.h | 25 ++++ src/system/kernel/image.cpp | 30 ++--- 3 files changed, 169 insertions(+), 15 deletions(-) create mode 100644 headers/private/kernel/compat/image_compat.h 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 + + +#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 +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 inline @@ -35,4 +47,17 @@ copy_ref_var_to_user(T &kernel, T *user) } +template +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 #include #include +#include + +#ifdef _COMPAT_MODE +# include +#endif #include #include @@ -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; }