Skip to content

Commit

Permalink
Add Support for Annex K functions according to C11
Browse files Browse the repository at this point in the history
Adding an implementation of the bounds-checking C functions (as specified in Annex K of the C11 standard) to the PicoLibc.
These functions lower the risk of introducing security vulnerabilities such as buffer overflows and format string vulnerabilities into your code by providing clear and easy-to-use interfaces.
For each C function a secure alternate function ending in a "_s" postfix is provided (e.g., strcpy_s).
Use of these functions is recommended by security experts and secure coding standards.

also, Implemented unit tests for the Annex-K functions to ensure their corrctness.
Covered various scenarios including normal operation, boundary conditions, and error handling.

Signed-off-by: Mostafa Salman <[email protected]>
  • Loading branch information
mostafa-salmaan committed Aug 6, 2024
1 parent f494a5d commit bf0a1e8
Show file tree
Hide file tree
Showing 41 changed files with 3,167 additions and 6 deletions.
2 changes: 1 addition & 1 deletion newlib/libc/include/errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ typedef int error_t;

#include <sys/errno.h>

#endif /* !__ERRNO_H__ */
#endif /* !__ERRNO_H__ */
16 changes: 14 additions & 2 deletions newlib/libc/include/stdint.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,18 @@ typedef __uint_least64_t uint_least64_t;
#endif
#endif

_END_STD_C
#if __STDC_WANT_LIB_EXT1__ == 1
// could be defined by the user
#ifndef RSIZE_MAX
#define RSIZE_MAX SIZE_MAX
#endif

#ifndef _RSIZE_T_DEFINED
typedef __rsize_t rsize_t;
#define _RSIZE_T_DEFINED
#endif
#endif

_END_STD_C

#endif /* _STDINT_H */
#endif /* _STDINT_H */
18 changes: 17 additions & 1 deletion newlib/libc/include/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,26 @@ char *__ldtoa (long double, int, int, int *, int *, char **);
void __eprintf (const char *, const char *, unsigned int, const char *);
#endif

#if __STDC_WANT_LIB_EXT1__ == 1
#include <sys/_types.h>

#ifndef _ERRNO_T_DEFINED
typedef __errno_t errno_t;
#define _ERRNO_T_DEFINED
#endif

typedef void (*constraint_handler_t)(const char *restrict msg,
void *restrict ptr, __errno_t error);

constraint_handler_t set_constraint_handler_s(constraint_handler_t handler);
void abort_handler_s(const char *restrict msg, void *restrict ptr,
__errno_t error);
#endif

_END_STD_C

#if __SSP_FORTIFY_LEVEL > 0
#include <ssp/stdlib.h>
#endif

#endif /* _STDLIB_H_ */
#endif /* _STDLIB_H_ */
19 changes: 18 additions & 1 deletion newlib/libc/include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,23 @@ int timingsafe_bcmp (const void *, const void *, size_t);
int timingsafe_memcmp (const void *, const void *, size_t);
#endif

#if __STDC_WANT_LIB_EXT1__ == 1
#include <sys/_types.h>

typedef __rsize_t rsize_t;

__errno_t memcpy_s(void *__restrict, rsize_t, const void *__restrict, rsize_t);
__errno_t memset_s(void *, rsize_t, int, rsize_t);
__errno_t memmove_s(void *, rsize_t, const void *, rsize_t);
__errno_t strcpy_s(char *__restrict, rsize_t, const char *__restrict);
__errno_t strcat_s(char *__restrict, rsize_t, const char *__restrict);
__errno_t strncpy_s(char *__restrict, rsize_t, const char *__restrict, rsize_t);
__errno_t strncat_s(char *__restrict, rsize_t, const char *__restrict, rsize_t);
size_t strnlen_s(const char *, size_t);
__errno_t strerror_s(char *, rsize_t, __errno_t); /* C11 */
size_t strerrorlen_s(__errno_t);
#endif

#include <sys/string.h>

_END_STD_C
Expand All @@ -209,4 +226,4 @@ _END_STD_C
#include <ssp/string.h>
#endif

#endif /* _STRING_H_ */
#endif /* _STRING_H_ */
11 changes: 11 additions & 0 deletions newlib/libc/include/sys/_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,15 @@ typedef unsigned short __nlink_t;
typedef long __suseconds_t; /* microseconds (signed) */
typedef unsigned long __useconds_t; /* microseconds (unsigned) */

#ifdef __STDC_WANT_LIB_EXT1__
#if (__STDC_WANT_LIB_EXT1__ != 0) && (__STDC_WANT_LIB_EXT1__ != 1)
#error Please define __STDC_WANT_LIB_EXT__ as 0 or 1
#endif

#if __STDC_WANT_LIB_EXT1__ == 1
typedef size_t __rsize_t;
typedef int __errno_t;
#endif
#endif

#endif /* _SYS__TYPES_H */
2 changes: 1 addition & 1 deletion newlib/libc/include/sys/errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,4 +223,4 @@ extern NEWLIB_THREAD_LOCAL_ERRNO int errno;

_END_STD_C

#endif /* _SYS_ERRNO_H */
#endif /* _SYS_ERRNO_H */
1 change: 1 addition & 0 deletions newlib/libc/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ picolibc_sources(
pico-exit.c
pico-onexit.c
pico-cxa-atexit.c
set_constraint_handler_s.c
)

picolibc_sources_flags("-fno-builtin-malloc;-fno-builtin-free"
Expand Down
52 changes: 52 additions & 0 deletions newlib/libc/stdlib/local_s.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright © 2024, Synopsys Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef _LOCAL_S_H_
#define _LOCAL_S_H_

#if __STDC_WANT_LIB_EXT1__ == 1
#include <stdint.h>
#include <stdlib.h>

#if RSIZE_MAX == SIZE_MAX
#define CHECK_RSIZE(s) 0
#else
#define CHECK_RSIZE(s) (RSIZE_MAX == SIZE_MAX ? 0 : (s) > RSIZE_MAX)
#endif

extern constraint_handler_t __cur_handler;

#endif
#endif
1 change: 1 addition & 0 deletions newlib/libc/stdlib/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ srcs_stdlib = [
'wctob.c',
'wctomb.c',
'wctomb_r.c',
'set_constraint_handler_s.c',
]

srcs_stdlib_stdio = [
Expand Down
61 changes: 61 additions & 0 deletions newlib/libc/stdlib/set_constraint_handler_s.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright © 2024, Synopsys Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include "local_s.h"

constraint_handler_t __cur_handler = abort_handler_s;

void
abort_handler_s(const char *restrict msg, void *restrict ptr, __errno_t error)
{
(void)msg;
(void)ptr;
(void)error;
abort();
}

constraint_handler_t
set_constraint_handler_s(constraint_handler_t handler)
{
constraint_handler_t h = __cur_handler;

if (handler == (constraint_handler_t)NULL) {
__cur_handler = abort_handler_s; // null restores to default handler
} else {
__cur_handler = handler;
}

return h;
}
10 changes: 10 additions & 0 deletions newlib/libc/string/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,14 @@ picolibc_sources(
wmempcpy.c
wmemset.c
xpg_strerror_r.c
memcpy_s.c
memmove_s.c
memset_s.c
strcat_s.c
strcpy_s.c
strerror_s.c
strerrorlen_s.c
strncat_s.c
strncpy_s.c
strnlen_s.c
)
94 changes: 94 additions & 0 deletions newlib/libc/string/memcpy_s.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright © 2024, Synopsys Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define __STDC_WANT_LIB_EXT1__ 1
#include <string.h>
#include <stdbool.h>
#include "string_private.h"

__errno_t
memcpy_s(void *restrict s1, rsize_t s1max, const void *restrict s2, rsize_t n)
{
const char *msg = "";

if (s1 == NULL) {
msg = "memcpy_s: dest is NULL";
goto handle_error;
}

if (CHECK_RSIZE(s1max)) {
msg = "memcpy_s: buffer size exceeds RSIZE_MAX";
goto handle_error;
}

if (s2 == NULL) {
msg = "memcpy_s: source is NULL";
goto handle_error;
}

if (CHECK_RSIZE(n)) {
msg = "memcpy_s: copy count exceeds RSIZE_MAX";
goto handle_error;
}

if (n > s1max) {
msg = "memcpy_s: copy count exceeds buffer size";
goto handle_error;
}

const char *s1cp = (const char *)s1;
const char *s2cp = (const char *)s2;
const char *s1cp_limit = &s1cp[n];
const char *s2cp_limit = &s2cp[n];

if (((s1cp_limit <= s2cp) || (s2cp_limit <= s1cp)) == false) {
msg = "memcpy_s: overlapping copy";
goto handle_error;
}

// Normal return path
(void)memcpy(s1, s2, n);
return 0;

handle_error:
if (s1 != NULL) {
(void)memset(s1, (int32_t)'\0', s1max);
}

if (__cur_handler != NULL) {
__cur_handler(msg, NULL, -1);
}

return -1;
}
Loading

0 comments on commit bf0a1e8

Please sign in to comment.