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 <mostafas@synopsys.com>
  • Loading branch information
mostafa-salmaan committed Aug 1, 2024
1 parent f494a5d commit 4c87012
Show file tree
Hide file tree
Showing 40 changed files with 3,180 additions and 3 deletions.
5 changes: 5 additions & 0 deletions newlib/libc/include/errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ typedef int error_t;

#include <sys/errno.h>

#include <sys/_types.h>
#ifdef __STDC_WANT_LIB_EXT1__
typedef __errno_t errno_t;
#endif

#endif /* !__ERRNO_H__ */
13 changes: 12 additions & 1 deletion newlib/libc/include/stdint.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,17 @@ typedef __uint_least64_t uint_least64_t;
#endif
#endif

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

// could be defined by the user
#ifndef RSIZE_MAX
#define RSIZE_MAX SIZE_MAX
#endif

typedef __rsize_t rsize_t;
#endif

_END_STD_C

#endif /* _STDINT_H */
#endif /* _STDINT_H */
16 changes: 15 additions & 1 deletion newlib/libc/include/stdlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,24 @@ 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>

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

extern constraint_handler_t __cur_handler;

extern constraint_handler_t set_constraint_handler_s(
constraint_handler_t handler);
extern 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_ */
20 changes: 19 additions & 1 deletion newlib/libc/include/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,24 @@ 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;

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

#include <sys/string.h>

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

#endif /* _STRING_H_ */
#endif /* _STRING_H_ */
18 changes: 18 additions & 0 deletions newlib/libc/include/sys/_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,22 @@ 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

#ifndef __RSIZE_T
#define __RSIZE_T
typedef size_t __rsize_t;
#endif

typedef int __errno_t;

#endif
#endif

#endif /* _SYS__TYPES_H */
1 change: 1 addition & 0 deletions newlib/libc/include/sys/errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ SUCH DAMAGE.

#include <sys/cdefs.h>
#include <sys/config.h>
#include <sys/_types.h>

_BEGIN_STD_C

Expand Down
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
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
63 changes: 63 additions & 0 deletions newlib/libc/stdlib/set_constraint_handler_s.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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 <stdlib.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
)
106 changes: 106 additions & 0 deletions newlib/libc/string/memcpy_s.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* 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 <stdint.h>
#include <stdlib.h>

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

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

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

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

if (n > RSIZE_MAX)
{
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:
handler = set_constraint_handler_s(NULL);
(void) set_constraint_handler_s(handler);

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

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

return -1;
}
Loading

0 comments on commit 4c87012

Please sign in to comment.