diff --git a/os/oslib/include/chmemchecks.h b/os/oslib/include/chmemchecks.h index 0b55a14eb..a8d09d026 100644 --- a/os/oslib/include/chmemchecks.h +++ b/os/oslib/include/chmemchecks.h @@ -80,9 +80,12 @@ extern const memory_area_t __ch_mem_executable_areas[]; extern "C" { #endif #if CH_CFG_USE_MEMCHECKS == TRUE - bool chMemIsStringWithinX(const memory_area_t *map, - const char *s, - size_t n); + size_t chMemIsStringWithinX(const memory_area_t *map, + const char *s, + size_t max); + size_t chMemIsPointersArrayWithinX(const memory_area_t *map, + const void *pp[], + size_t max); bool chMemIsSpaceContainedX(const memory_area_t areas[], const void *p, size_t size); diff --git a/os/oslib/src/chmemchecks.c b/os/oslib/src/chmemchecks.c index 3fcc94623..26a3a6725 100644 --- a/os/oslib/src/chmemchecks.c +++ b/os/oslib/src/chmemchecks.c @@ -94,30 +94,67 @@ CC_WEAK const memory_area_t __ch_mem_executable_areas[] = { * * @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 true if the string is entirely contained within one of the - * specified areas. - * @retval false if the string check failed. + * @param[in] max maximum expected size of the string inclusive of the + * final zero + * @return The string size inclusive of the final zero. + * @retval 0 if the string check failed. * * @xclass */ -bool chMemIsStringWithinX(const memory_area_t *map, const char *s, size_t n) { +size_t chMemIsStringWithinX(const memory_area_t *map, + const char *s, + size_t max) { const char *base = (const char *)map->base; const char *end = (const char *)base + map->size - (size_t)1; if (s >= base) { - while ((s <= end) && (n > 0U)) { - if (*s == '\0') { - return true; - } + size_t n; - s++; - n--; + n = (size_t)0; + while ((s <= end) && (n < max)) { + n++; + if (*s++ == '\0') { + return n; + } } } - return false; + return (size_t)0; +} + +/** + * @brief Pointers array check. + * @details Checks if specified pointers array is entirely contained in the + * specified memory area. + * + * @param[in] map pointer to a @p memory_area_t structure + * @param[in] pp zero-terminated pointers array to be checked + * @param[in] max maximum expected size of the pointers array inclusive + * of the final zero + * @return The pointers array size inclusive of the final zero. + * @retval 0 if the pointers array check failed. + * + * @xclass + */ +size_t chMemIsPointersArrayWithinX(const memory_area_t *map, + const void *pp[], + size_t max) { + const void **base = (const void **)(void *)map->base; + const void **end = (const void **)(void *)(map->base + map->size - sizeof (void *)); + + if (pp >= base) { + size_t n; + + n = (size_t)0; + while ((pp <= end) && (n < max)) { + n += sizeof (void *); + if (*pp++ == NULL) { + return n; + } + } + } + + return (size_t)0; } /** diff --git a/os/sb/host/sbhost.c b/os/sb/host/sbhost.c index 235315ec1..40bfe8c42 100644 --- a/os/sb/host/sbhost.c +++ b/os/sb/host/sbhost.c @@ -61,7 +61,7 @@ bool sb_is_valid_read_range(sb_class_t *sbcp, const void *start, size_t size) { const sb_memory_region_t *rp = &sbcp->config->regions[0]; do { - if (chMemIsSpaceWithinX(&rp->area, start, size)) { + if (rp->used && chMemIsSpaceWithinX(&rp->area, start, size)) { return true; } rp++; @@ -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 (chMemIsSpaceWithinX(&rp->area, start, size)) { + if (rp->used && chMemIsSpaceWithinX(&rp->area, start, size)) { return rp->writeable; } rp++; @@ -83,17 +83,57 @@ 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) { +size_t sb_check_string(sb_class_t *sbcp, const char *s, size_t max) { const sb_memory_region_t *rp = &sbcp->config->regions[0]; do { - if (chMemIsStringWithinX(&rp->area, s, n)) { - return true; + if (rp->used) { + size_t n = chMemIsStringWithinX(&rp->area, s, max); + if (n > (size_t)0) { + return n; + } } rp++; } while (rp < &sbcp->config->regions[SB_CFG_NUM_REGIONS]); - return false; + return (size_t)0; +} + +size_t sb_check_pointers_array(sb_class_t *sbcp, const void *pp[], size_t max) { + const sb_memory_region_t *rp = &sbcp->config->regions[0]; + + do { + if (rp->used) { + size_t an = chMemIsPointersArrayWithinX(&rp->area, pp, max); + if (an > (size_t)0) { + return an; + } + } + rp++; + } while (rp < &sbcp->config->regions[SB_CFG_NUM_REGIONS]); + + return (size_t)0; +} + +size_t sb_check_strings_array(sb_class_t *sbcp, const char *pp[], size_t max) { + const char *s; + size_t n; + + n = sb_check_pointers_array(sbcp, (const void **)pp, max); + if (n > (size_t)0) { + while ((s = *pp++) != NULL) { + size_t sn; + + sn = sb_check_string(sbcp, s, max - n); + if (sn == (size_t)0) { + return (size_t)0; + } + + n += sn; + } + } + + return n; } /** diff --git a/os/sb/host/sbhost.h b/os/sb/host/sbhost.h index db9cf9e1c..ea8e4ac20 100644 --- a/os/sb/host/sbhost.h +++ b/os/sb/host/sbhost.h @@ -94,7 +94,9 @@ 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); + size_t sb_check_string(sb_class_t *sbcp, const char *s, size_t max); + size_t sb_check_pointers_array(sb_class_t *sbcp, const void *pp[], size_t max); + size_t sb_check_strings_array(sb_class_t *sbcp, const char *pp[], size_t max); void sbObjectInit(sb_class_t *sbcp, const sb_config_t *config); thread_t *sbStartThread(sb_class_t *sbcp, const char *name, void *wsp, size_t size, tprio_t prio, diff --git a/os/sb/host/sbposix.c b/os/sb/host/sbposix.c index d852a0b1f..a15d00f6f 100644 --- a/os/sb/host/sbposix.c +++ b/os/sb/host/sbposix.c @@ -92,7 +92,7 @@ int sb_posix_open(const char *path, int flags) { vfs_node_c *np = NULL; msg_t ret; - if (!sb_is_valid_string_range(sbp, (void *)path, VFS_CFG_PATHLEN_MAX)) { + if (sb_check_string(sbp, (void *)path, VFS_CFG_PATHLEN_MAX + 1) == (size_t)0) { return CH_RET_EFAULT; }