diff --git a/os/common/utils/include/errcodes.h b/os/common/utils/include/errcodes.h index fdb313eef..eeb6ab420 100644 --- a/os/common/utils/include/errcodes.h +++ b/os/common/utils/include/errcodes.h @@ -52,6 +52,7 @@ #define CH_RET_EBADF CH_ENCODE_ERROR(EBADF) /* Bad file number */ #define CH_RET_ENOMEM CH_ENCODE_ERROR(ENOMEM) /* Not enough space */ #define CH_RET_EACCES CH_ENCODE_ERROR(EACCES) /* Permission denied */ +#define CH_RET_EFAULT CH_ENCODE_ERROR(EACCES) /* Bad address */ #define CH_RET_EEXIST CH_ENCODE_ERROR(EEXIST) /* File exists */ #define CH_RET_ENOTDIR CH_ENCODE_ERROR(ENOTDIR) /* Not a directory */ #define CH_RET_EISDIR CH_ENCODE_ERROR(EISDIR) /* Is a directory */ diff --git a/os/oslib/include/chmemchecks.h b/os/oslib/include/chmemchecks.h index 3a7f23a30..9a9d38fc3 100644 --- a/os/oslib/include/chmemchecks.h +++ b/os/oslib/include/chmemchecks.h @@ -73,6 +73,9 @@ typedef struct { extern "C" { #endif #if CH_CFG_USE_MEMCHECKS == TRUE + bool chMemIsStringWithinX(const memory_area_t *map, + const char *s, + size_t n); bool chMemIsAreaContainedX(const memory_area_t areas[], const void *base, size_t size); @@ -93,10 +96,9 @@ extern "C" { /** * @brief Memory area check. - * @details Checks if specified area belongs to the specified area. + * @details Checks if specified area belongs to the specified memory area. * - * @param[in] map pointer to an array of valid areas terminated with - * a zero element + * @param[in] map pointer to a @p memory_area_t structure * @param[in] p pointer to the area to be checked * @param[in] size size of the area to be checked * @return The test result. diff --git a/os/oslib/src/chmemchecks.c b/os/oslib/src/chmemchecks.c index 32b7ac08e..7196e4839 100644 --- a/os/oslib/src/chmemchecks.c +++ b/os/oslib/src/chmemchecks.c @@ -76,6 +76,39 @@ CC_WEAK memory_area_t __ch_mem_readable_areas[] = { /* Module exported functions. */ /*===========================================================================*/ +/** + * @brief String check. + * @details Checks if specified string is entirely contained in the specified + * memory area. + * + * @param[in] map pointer to a @p memory_area_t structure + * @param[in] s pointer to the string to be checked + * @param[in] n maximum expected size of the string + * @return The test result. + * @retval false if the string is entirely contained within one of the + * specified areas. + * @retval true if the string check failed. + * + * @xclass + */ +bool chMemIsStringWithinX(const memory_area_t *map, const char *s, size_t n) { + const char *base = (const char *)map->base; + const char *end = (const char *)base + map->size; + + if (s >= base) { + while ((s < end) && (n > 0U)) { + if (*s == '\0') { + return true; + } + + s++; + n--; + } + } + + return false; +} + /** * @brief Memory area check. * @details Checks if specified area belongs to one of the specified areas. diff --git a/os/sb/common/sberr.h b/os/sb/common/sberr.h deleted file mode 100644 index a392206b8..000000000 --- a/os/sb/common/sberr.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014, - 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio. - - This file is part of ChibiOS. - - ChibiOS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation version 3 of the License. - - ChibiOS is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -/** - * @file sb/common/sberr.h - * @brief ARMv7-M sandbox common macros and structures. - * - * @addtogroup ARM_SANDBOX_ERRORS - * @{ - */ - -#ifndef SBERR_H -#define SBERR_H - -/*===========================================================================*/ -/* Module constants. */ -/*===========================================================================*/ - -/** - * @name Sandbox API error codes - * @{ - */ -#define SB_ERR_NOERROR 0U -#define SB_ERR_ENOENT ((uint32_t)(-2)) -#define SB_ERR_EFAULT ((uint32_t)(-14)) -#define SB_ERR_EBUSY ((uint32_t)(-16)) -#define SB_ERR_EINVAL ((uint32_t)(-22)) -#define SB_ERR_ESPIPE ((uint32_t)(-29)) -#define SB_ERR_EBADFD ((uint32_t)(-81)) -#define SB_ERR_ENOSYS ((uint32_t)(-88)) - -#define SB_ERR_ERRORMASK 0xFFFFFF00U -#define SB_ERR_ISERROR(x) (((uint32_t)(x) & SB_ERR_ERRORMASK) == SB_ERR_ERRORMASK) -/** @} */ - -/** - * @name Posix-like function codes - * @{ - */ -#define SB_POSIX_OPEN 1 -#define SB_POSIX_CLOSE 2 -#define SB_POSIX_READ 3 -#define SB_POSIX_WRITE 4 -#define SB_POSIX_LSEEK 5 -/** @} */ - -/*===========================================================================*/ -/* Module pre-compile time settings. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module data structures and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Module macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef __cplusplus -} -#endif - -/*===========================================================================*/ -/* Module inline functions. */ -/*===========================================================================*/ - -#endif /* SBERR_H */ - -/** @} */ diff --git a/os/sb/host/sb.h b/os/sb/host/sb.h index a752406aa..3b40a46da 100644 --- a/os/sb/host/sb.h +++ b/os/sb/host/sb.h @@ -94,6 +94,10 @@ #error "SB_CFG_ENABLE_VFS not defined in sbconf.h" #endif +#if !defined(SB_CFG_FD_NUM) || defined(__DOXYGEN__) +#error "SB_CFG_FD_NUM not defined in sbconf.h" +#endif + /* License checks.*/ #if !defined(CH_CUSTOMER_LIC_SB) || !defined(CH_LICENSE_FEATURES) #error "malformed chlicense.h" @@ -162,10 +166,13 @@ extern "C" { /* Module inline functions. */ /*===========================================================================*/ -#include "sberr.h" +#include "hal.h" +#include "errcodes.h" + +#include "sbsysc.h" #include "sbposix.h" -#include "sbhost.h" #include "sbapi.h" +#include "sbhost.h" #endif /* SBHOST_H */ diff --git a/os/sb/host/sbapi.c b/os/sb/host/sbapi.c index 526d6918e..d1c374090 100644 --- a/os/sb/host/sbapi.c +++ b/os/sb/host/sbapi.c @@ -915,7 +915,7 @@ const port_syscall_t sb_syscalls[256] = { static void sb_undef_handler(struct port_extctx *ectxp) { - ectxp->r0 = SB_ERR_ENOSYS; + ectxp->r0 = CH_RET_ENOSYS; } static thread_t *sb_msg_wait_timeout_s(sysinterval_t timeout) { @@ -979,7 +979,7 @@ void sb_api_stdio(struct port_extctx *ectxp) { ectxp->r3); break; default: - ectxp->r0 = SB_ERR_ENOSYS; + ectxp->r0 = CH_RET_ENOSYS; break; } } @@ -994,7 +994,7 @@ void sb_api_exit(struct port_extctx *ectxp) { chSysUnlock(); /* Cannot get here.*/ - ectxp->r0 = SB_ERR_ENOSYS; + ectxp->r0 = CH_RET_ENOSYS; } void sb_api_get_systime(struct port_extctx *ectxp) { @@ -1014,14 +1014,14 @@ void sb_api_sleep(struct port_extctx *ectxp) { chThdSleep(interval); } - ectxp->r0 = SB_ERR_NOERROR; + ectxp->r0 = CH_RET_SUCCESS; } void sb_api_sleep_until_windowed(struct port_extctx *ectxp) { chThdSleepUntilWindowed((systime_t )ectxp->r0, (systime_t )ectxp->r1); - ectxp->r0 = SB_ERR_NOERROR; + ectxp->r0 = CH_RET_SUCCESS; } void sb_api_wait_message(struct port_extctx *ectxp) { @@ -1038,12 +1038,12 @@ void sb_api_wait_message(struct port_extctx *ectxp) { thread_t *tp = sbcp->msg_tp; sbcp->msg_tp = NULL; chMsgReleaseS(tp, MSG_RESET); - ectxp->r0 = SB_ERR_EBUSY; + ectxp->r0 = MSG_RESET; } chSysUnlock(); #else - ectxp->r0 = SB_ERR_NOT_IMPLEMENTED; + ectxp->r0 = CH_RET_ENOSYS; #endif } @@ -1057,15 +1057,15 @@ void sb_api_reply_message(struct port_extctx *ectxp) { thread_t *tp = sbcp->msg_tp; sbcp->msg_tp = NULL; chMsgReleaseS(tp, (msg_t )ectxp->r0); - ectxp->r0 = SB_ERR_NOERROR; + ectxp->r0 = CH_RET_SUCCESS; } else { - ectxp->r0 = SB_ERR_EBUSY; + ectxp->r0 = MSG_RESET; } chSysUnlock(); #else - ectxp->r0 = SB_ERR_NOT_IMPLEMENTED; + ectxp->r0 = CH_RET_ENOSYS; #endif } @@ -1075,7 +1075,7 @@ void sb_api_wait_one_timeout(struct port_extctx *ectxp) { ectxp->r0 = (uint32_t)chEvtWaitOneTimeout((eventmask_t )ectxp->r0, (sysinterval_t )ectxp->r1); #else - ectxp->r0 = SB_ERR_NOT_IMPLEMENTED; + ectxp->r0 = CH_RET_ENOSYS; #endif } @@ -1085,7 +1085,7 @@ void sb_api_wait_any_timeout(struct port_extctx *ectxp) { ectxp->r0 = (uint32_t)chEvtWaitAnyTimeout((eventmask_t )ectxp->r0, (sysinterval_t )ectxp->r1); #else - ectxp->r0 = SB_ERR_NOT_IMPLEMENTED; + ectxp->r0 = CH_RET_ENOSYS; #endif } @@ -1095,7 +1095,7 @@ void sb_api_wait_all_timeout(struct port_extctx *ectxp) { ectxp->r0 = (uint32_t)chEvtWaitAllTimeout((eventmask_t )ectxp->r0, (sysinterval_t )ectxp->r1); #else - ectxp->r0 = SB_ERR_NOT_IMPLEMENTED; + ectxp->r0 = CH_RET_ENOSYS; #endif } @@ -1104,9 +1104,9 @@ void sb_api_broadcast_flags(struct port_extctx *ectxp) { sb_class_t *sbcp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; chEvtBroadcastFlags(&sbcp->es, (eventflags_t )ectxp->r0); - ectxp->r0 = SB_ERR_NOERROR; + ectxp->r0 = CH_RET_SUCCESS; #else - ectxp->r0 = SB_ERR_NOT_IMPLEMENTED; + ectxp->r0 = CH_RET_ENOSYS; #endif } diff --git a/os/sb/host/sbhost.c b/os/sb/host/sbhost.c index 18c649a18..dd382d0ae 100644 --- a/os/sb/host/sbhost.c +++ b/os/sb/host/sbhost.c @@ -74,7 +74,7 @@ bool sb_is_valid_write_range(sb_class_t *sbcp, void *start, size_t size) { const sb_memory_region_t *rp = &sbcp->config->regions[0]; do { - if (chMemIsAreaContainedX(&rp->area, start, size)) { + if (chMemIsAreaWithinX(&rp->area, start, size)) { return rp->writeable; } rp++; @@ -83,6 +83,19 @@ bool sb_is_valid_write_range(sb_class_t *sbcp, void *start, size_t size) { return false; } +bool sb_is_valid_string_range(sb_class_t *sbcp, const char *s, size_t n) { + const sb_memory_region_t *rp = &sbcp->config->regions[0]; + + do { + if (chMemIsAreaWithinX(&rp->area, s, n)) { + return true; + } + rp++; + } while (rp < &sbcp->config->regions[SB_CFG_NUM_REGIONS]); + + return false; +} + /** * @brief Sandbox object initialization. * diff --git a/os/sb/host/sbhost.h b/os/sb/host/sbhost.h index 6c2193448..728d538f0 100644 --- a/os/sb/host/sbhost.h +++ b/os/sb/host/sbhost.h @@ -28,9 +28,6 @@ #ifndef SBHOST_H #define SBHOST_H -#include "sberr.h" -#include "sbapi.h" - /*===========================================================================*/ /* Module constants. */ /*===========================================================================*/ @@ -151,8 +148,17 @@ typedef struct { thread_t *msg_tp; #endif #if (CH_CFG_USE_EVENTS == TRUE) || defined(__DOXYGEN__) + /** + * @brief Sandbox events source. + */ event_source_t es; #endif +#if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) + /** + * @brief VFS bindings for Posix API. + */ + sb_ioblock_t io; +#endif } sb_class_t; /** @@ -193,6 +199,7 @@ extern "C" { void port_syscall(struct port_extctx *ctxp, uint32_t n); bool sb_is_valid_read_range(sb_class_t *sbcp, const void *start, size_t size); bool sb_is_valid_write_range(sb_class_t *sbcp, void *start, size_t size); + bool sb_is_valid_string_range(sb_class_t *sbcp, const char *s, size_t n); void sbObjectInit(sb_class_t *sbcp); void sbStart(sb_class_t *sbcp, const sb_config_t *config); thread_t *sbStartThread(sb_class_t *sbcp, const sb_config_t *config, diff --git a/os/sb/host/sbposix.c b/os/sb/host/sbposix.c index d66ee3ce3..b17dbc89c 100644 --- a/os/sb/host/sbposix.c +++ b/os/sb/host/sbposix.c @@ -48,10 +48,127 @@ /* Module local functions. */ /*===========================================================================*/ +static msg_t create_descriptor(sb_ioblock_t *iop, + vfs_node_c *np, + uint8_t attributes) { + unsigned fd; + + for (fd = 0U; fd < SB_CFG_FD_NUM; fd++) { + if (iop->vfs_nodes[fd] == NULL) { + iop->vfs_nodes[fd] = np; + iop->attributes[fd] = attributes; + + return (msg_t)fd; + } + } + + return CH_RET_EMFILE; +} + +static bool is_valid_descriptor(sb_ioblock_t *iop, int fd) { + + return (fd >= 0) && (fd < SB_CFG_FD_NUM) && (iop->vfs_nodes[fd] != NULL); +} + /*===========================================================================*/ /* Module exported functions. */ /*===========================================================================*/ +#if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) +int sb_posix_open(const char *path, int flags) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + vfs_file_node_c *fnp = NULL; + msg_t ret; + + if (!sb_is_valid_string_range(sbp, (void *)path, VFS_CFG_PATHLEN_MAX)) { + return CH_RET_EFAULT; + } + + do { + ret = vfsDrvOpenFile(sbp->io.vfs_driver, path, (unsigned)flags, &fnp); + CH_BREAK_ON_ERROR(ret); + + ret = create_descriptor(&sbp->io, (vfs_node_c *)fnp, 0); + CH_BREAK_ON_ERROR(ret); + + return (int)ret; + } while (true); + + if (fnp != NULL) { + vfsCloseFile(fnp); + } + + return (int)ret; +} + +int sb_posix_close(int fd) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + if (!is_valid_descriptor(&sbp->io, fd)) { + return CH_RET_EBADF; + } + + if (sbp->io.attributes[fd] == 0) { + vfsCloseFile((vfs_file_node_c *)sbp->io.vfs_nodes[fd]); + } + else { + vfsCloseDirectory((vfs_directory_node_c *)sbp->io.vfs_nodes[fd]); + } + sbp->io.vfs_nodes[fd] = NULL; + + return CH_RET_SUCCESS; +} + +ssize_t sb_posix_read(int fd, void *buf, size_t count) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + if (!sb_is_valid_read_range(sbp, (void *)buf, count)) { + return CH_RET_EFAULT; + } + + if (!is_valid_descriptor(&sbp->io, fd)) { + return CH_RET_EBADF; + } + + if (sbp->io.attributes[fd] != 0) { + return CH_RET_EISDIR; + } + + return vfsReadFile((vfs_file_node_c *)sbp->io.vfs_nodes[fd], buf, count); +} + +ssize_t sb_posix_write(int fd, const void *buf, size_t count) { + sb_class_t *sbp = (sb_class_t *)chThdGetSelfX()->ctx.syscall.p; + + if (!sb_is_valid_write_range(sbp, (void *)buf, count)) { + return CH_RET_EFAULT; + } + + if (!is_valid_descriptor(&sbp->io, fd)) { + return CH_RET_EBADF; + } + + if (sbp->io.attributes[fd] != 0) { + return CH_RET_EISDIR; + } + + return vfsWriteFile((vfs_file_node_c *)sbp->io.vfs_nodes[fd], buf, count); +} + +off_t sb_posix_lseek(int fd, off_t offset, int whence) { + + (void)offset; + (void)whence; + + if ((fd == 0U) || (fd == 1U) || (fd == 2U)) { + + return CH_RET_ESPIPE; + } + + return CH_RET_EBADF; +} + +#else /* Fallbacks for when there is no VFS.*/ uint32_t sb_posix_open(const char *pathname, uint32_t flags) { (void)pathname; @@ -132,5 +249,6 @@ uint32_t sb_posix_lseek(uint32_t fd, uint32_t offset, uint32_t whence) { return SB_ERR_EBADFD; } +#endif /** @} */ diff --git a/os/sb/host/sbposix.h b/os/sb/host/sbposix.h index c28c72764..ee40a38aa 100644 --- a/os/sb/host/sbposix.h +++ b/os/sb/host/sbposix.h @@ -28,6 +28,10 @@ #ifndef SBPOSIX_H #define SBPOSIX_H +#if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) +#include "vfs.h" +#endif + /*===========================================================================*/ /* Module constants. */ /*===========================================================================*/ @@ -44,6 +48,26 @@ /* Module data structures and types. */ /*===========================================================================*/ +#if (SB_CFG_ENABLE_VFS == TRUE) || defined(__DOXYGEN__) +/** + * @brief Type of a sandbox I/O structure. + */ +typedef struct { + /** + * @brief VFS driver associated to the sandbox as root. + */ + vfs_driver_c *vfs_driver; + /** + * @brief VFS nodes associated to file descriptors. + */ + vfs_node_c *vfs_nodes[SB_CFG_FD_NUM]; + /** + * @brief Extra attributes added to the VFS nodes. + */ + uint8_t attributes[SB_CFG_FD_NUM]; +} sb_ioblock_t; +#endif + /*===========================================================================*/ /* Module macros. */ /*===========================================================================*/ @@ -55,11 +79,11 @@ #ifdef __cplusplus extern "C" { #endif - uint32_t sb_posix_open(const char *pathname, uint32_t flags); - uint32_t sb_posix_close(uint32_t fd); - uint32_t sb_posix_read(uint32_t fd, uint8_t *buf, size_t count); - uint32_t sb_posix_write(uint32_t fd, const uint8_t *buf, size_t count); - uint32_t sb_posix_lseek(uint32_t fd, uint32_t offset, uint32_t whence); + int sb_posix_open(const char *path, int flags); + int sb_posix_close(int fd); + ssize_t sb_posix_read(int fd, void *buf, size_t count); + ssize_t sb_posix_write(int fd, const void *buf, size_t count); + off_t sb_posix_lseek(int fd, off_t offset, int whence); #ifdef __cplusplus } #endif