From 547cd462f843df15db02ed0dd7a35528221b66bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 3 Nov 2013 00:18:57 +0100 Subject: [PATCH] trim: Added is_called_via_syscall() function. * And use it in get_trim_data_from_user(), formerly known as copy_*(). * This fixes differentiating between user and kernel buffers. --- headers/private/kernel/syscall_restart.h | 16 ++++++++++++- headers/private/kernel/util/fs_trim_support.h | 23 ++++++++++++++++--- .../drivers/disk/scsi/scsi_disk/scsi_disk.cpp | 5 ++-- .../file_systems/bfs/kernel_interface.cpp | 6 ++--- src/add-ons/kernel/network/stack/utility.cpp | 5 ++-- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/headers/private/kernel/syscall_restart.h b/headers/private/kernel/syscall_restart.h index 708f9d3373..88ac6aaafc 100644 --- a/headers/private/kernel/syscall_restart.h +++ b/headers/private/kernel/syscall_restart.h @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011, Haiku Inc. All rights reserved. + * Copyright 2008-2013, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef _KERNEL_SYSCALL_RESTART_H @@ -100,6 +100,20 @@ syscall_restart_is_restarted() } +/*! Returns whether or not a function has been called via a syscall. The flag + to determine this is currently only used where actually needed, such as + ioctl(). + + TODO: this function is actually needed as part of the public API for ioctl() +*/ +static inline bool +is_called_via_syscall(void) +{ + Thread* thread = thread_get_current_thread(); + return (thread->flags & THREAD_FLAGS_SYSCALL) != 0; +} + + struct SyscallFlagUnsetter { SyscallFlagUnsetter() { diff --git a/headers/private/kernel/util/fs_trim_support.h b/headers/private/kernel/util/fs_trim_support.h index a9f993c7b6..e36ca5335e 100644 --- a/headers/private/kernel/util/fs_trim_support.h +++ b/headers/private/kernel/util/fs_trim_support.h @@ -6,14 +6,23 @@ #define _FS_TRIM_SUPPORT_H -#include +#include #include +#include static inline status_t -copy_trim_data_from_user(void* buffer, size_t size, fs_trim_data*& _trimData) +get_trim_data_from_user(void* buffer, size_t size, MemoryDeleter& deleter, + fs_trim_data*& _trimData) { + if (!is_called_via_syscall() && !IS_USER_ADDRESS(buffer)) { + // Called from kernel + _trimData = (fs_trim_data*)buffer; + return B_OK; + } + + // Called from userland if (!IS_USER_ADDRESS(buffer)) return B_BAD_ADDRESS; @@ -29,8 +38,10 @@ copy_trim_data_from_user(void* buffer, size_t size, fs_trim_data*& _trimData) if (trimBuffer == NULL) return B_NO_MEMORY; - if (user_memcpy(trimBuffer, buffer, bytes) != B_OK) + if (user_memcpy(trimBuffer, buffer, bytes) != B_OK) { + free(trimBuffer); return B_BAD_ADDRESS; + } _trimData = (fs_trim_data*)trimBuffer; return B_OK; @@ -40,6 +51,12 @@ copy_trim_data_from_user(void* buffer, size_t size, fs_trim_data*& _trimData) static inline status_t copy_trim_data_to_user(void* buffer, fs_trim_data* trimData) { + if (!is_called_via_syscall() && !IS_USER_ADDRESS(buffer)) + return B_OK; + + if (!IS_USER_ADDRESS(buffer)) + return B_BAD_ADDRESS; + // Do not copy any ranges return user_memcpy(buffer, trimData, sizeof(uint64) * 2); } diff --git a/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp b/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp index f445764dd1..8499009ddc 100644 --- a/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp +++ b/src/add-ons/kernel/drivers/disk/scsi/scsi_disk/scsi_disk.cpp @@ -416,13 +416,12 @@ das_ioctl(void* cookie, uint32 op, void* buffer, size_t length) case B_TRIM_DEVICE: { fs_trim_data* trimData; - status_t status = copy_trim_data_from_user(buffer, length, + MemoryDeleter deleter; + status_t status = get_trim_data_from_user(buffer, length, deleter, trimData); if (status != B_OK) return status; - MemoryDeleter deleter(trimData); - status = trim_device(info, trimData); if (status != B_OK) return status; diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index ab68d576c9..84a2e54264 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -629,12 +629,12 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd, case B_TRIM_DEVICE: { fs_trim_data* trimData; - status_t status = copy_trim_data_from_user(buffer, bufferLength, - trimData); + MemoryDeleter deleter; + status_t status = get_trim_data_from_user(buffer, bufferLength, + deleter, trimData); if (status != B_OK) return status; - MemoryDeleter deleter(trimData); trimData->trimmed_size = 0; for (uint32 i = 0; i < trimData->range_count; i++) { diff --git a/src/add-ons/kernel/network/stack/utility.cpp b/src/add-ons/kernel/network/stack/utility.cpp index b2a6f0e1ab..55cf0dcc97 100644 --- a/src/add-ons/kernel/network/stack/utility.cpp +++ b/src/add-ons/kernel/network/stack/utility.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2011, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2013, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -699,8 +699,7 @@ uninit_timers(void) bool is_syscall(void) { - Thread* thread = thread_get_current_thread(); - return (thread->flags & THREAD_FLAGS_SYSCALL) != 0; + return is_called_via_syscall(); }