Merge pull request #17 from cryb-to/memsafe

Improved memory-safe functions
This commit is contained in:
Dag-Erling Smørgrav 2018-05-06 20:08:34 +02:00 committed by GitHub
commit d53673deee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 803 additions and 26 deletions

View file

@ -51,6 +51,10 @@ AC_TYPE_UINT8_T
AC_TYPE_UINTMAX_T
AC_TYPE_UINTPTR_T
AC_CHECK_TYPES([errno_t], [], [], [[#include <errno.h>]])
AC_CHECK_TYPES([rsize_t], [], [], [[#include <stdint.h>]])
AC_CHECK_DECL([RSIZE_MAX], [], [], [[#include <stdint.h>]])
############################################################################
#
# Headers and functions
@ -116,9 +120,7 @@ AC_CHECK_HEADERS([sys/resource.h])
AC_CHECK_FUNCS([setrlimit])
# C11 features
# XXX our version has an incorrect prototype due to the lack of a test
# for the existence of rsize_t and RSIZE_MAX.
AC_CHECK_FUNCS([memset_s])
AC_CHECK_FUNCS([memcpy_s memset_s])
############################################################################
#

View file

@ -22,12 +22,14 @@ cryb_HEADERS += \
ctype.h \
defs.h \
endian.h \
memcpy_s.h \
memset_s.h \
strchrnul.h \
string.h \
strlcat.h \
strlcmp.h \
strlcpy.h \
types.h \
wcschrnul.h \
wcslcat.h \
wcslcmp.h \

53
include/cryb/memcpy_s.h Normal file
View file

@ -0,0 +1,53 @@
/*-
* Copyright (c) 2015-2018 The University of Oslo
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 CRYB_MEMCPY_S_H_INCLUDED
#define CRYB_MEMCPY_S_H_INCLUDED
#ifndef CRYB_TO
#include <cryb/to.h>
#endif
#ifndef CRYB_TYPES_H_INCLUDED
#include <cryb/types.h>
#endif
CRYB_BEGIN
errno_t cryb_memcpy_s(void * restrict, rsize_t, const void * restrict,
rsize_t);
#if !HAVE_MEMCPY_S
#undef memcpy_s
#define memcpy_s(arg, ...) cryb_memcpy_s(arg, __VA_ARGS__)
#endif
CRYB_END
#endif

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2015 The University of Oslo
* Copyright (c) 2015-2018 The University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,9 +34,13 @@
#include <cryb/to.h>
#endif
#ifndef CRYB_TYPES_H_INCLUDED
#include <cryb/types.h>
#endif
CRYB_BEGIN
int cryb_memset_s(void *, size_t, int, size_t);
errno_t cryb_memset_s(void *, rsize_t, int, rsize_t);
#if !HAVE_MEMSET_S
#undef memset_s

45
include/cryb/types.h Normal file
View file

@ -0,0 +1,45 @@
/*-
* Copyright (c) 2018 The University of Oslo
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 CRYB_TYPES_H_INCLUDED
#define CRYB_TYPES_H_INCLUDED
#if !HAVE_ERRNO_T
typedef int errno_t;
#endif
#if !HAVE_RSIZE_T
typedef size_t rsize_t;
#endif
#if !HAVE_RSIZE_MAX
#define RSIZE_MAX (SIZE_MAX >> 1)
#endif
#endif

View file

@ -4,6 +4,7 @@ lib_LTLIBRARIES = libcryb-core.la
libcryb_core_la_SOURCES = \
cryb_assert.c \
cryb_memcpy_s.c \
cryb_memset_s.c \
cryb_strchrnul.c \
cryb_string.c \
@ -21,6 +22,8 @@ libcryb_core_la_SOURCES = \
EXTRA_DIST = cryb_string_impl.c
dist_man3_MANS = \
cryb_memcpy_s.3 \
cryb_memset_s.3 \
cryb_strlcat.3 \
cryb_strlcpy.3

136
lib/core/cryb_memcpy_s.3 Normal file
View file

@ -0,0 +1,136 @@
.\"-
.\" Copyright (c) 2015-2018 Universitetet i Oslo
.\" All rights reserved.
.\"
.\" 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. The name of the author may not be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
.\"
.Dd May 6, 2018
.Dt cryb_memcpy_s 3
.Os
.Sh NAME
.Nm cryb_memcpy_s
.Nd safely copy one buffer to another
.Sh LIBRARY
.Lb libcryb-core
.Sh SYNOPSIS
.In cryb/memcpy_s.h
.Ft errno_t
.Fn cryb_memcpy_s "void * restrict d" "rsize_t dsz" "const void * restrict s" "rsize_t n"
.Sh DESCRIPTION
The
.Nm cryb_memcpy_s
function copies the first
.Va n
bytes of the buffer pointed to by
.Va s
into the buffer pointed to by
.Va d ,
of size
.Va dsz .
If
.Va s
is
.Dv NULL ,
.Va n
is greater than
.Va dsz
or
.Dv RSIZE_MAX
or the source and destination overlap, the buffer pointed to by
.Va d
is filled with zeroes and an error is returned.
.Sh RETURN VALUES
The
.Fn cryb_memcpy_s
function returns zero if successful and a non-zero error code if an
error occurred.
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINVAL
The
.Va d
argument was
.Dv NULL
or the source and destination ranges were found to overlap.
.It Bq Er ERANGE
Either or both of the
.Va dsz
and
.Va n
arguments were greater than
.Dv SIZE_MAX .
.It Bq Er EOVERFLOW
The
.Va n
argument was greater than the
.Va dsz
argument.
.El
.Sh IMPLEMENTATION NOTES
If the
.Dv HAVE_MEMCPY_S
preprocessor macro is defined to 0 or undefined, the
.In cryb/memcpy_s.h
header provides a
.Fn memcpy_s
macro as an alias to
.Fn cryb_memcpy_s .
.Pp
Software that includes
.In cryb/memcpy_s.h
should ensure that the
.Dv HAVE_ERRNO_T ,
.Dv HAVE_RSIZE_T ,
.Dv HAVE_RSIZE_MAX
and
.Dv HAVE_MEMCPY_S
macros correctly reflect the availability of these features at compile
time.
For projects that use the GNU autotools, this can be achieved by
including the following code in
.Pa configure.ac :
.Bd -literal -offset indent
AC_CHECK_TYPES([errno_t], [], [], [[#include <errno.h>]])
AC_CHECK_TYPES([rsize_t], [], [], [[#include <stdint.h>]])
AC_CHECK_DECL([RSIZE_MAX], [], [], [[#include <stdint.h>]])
AC_CHECK_FUNCS([memcpy_s])
.Ed
.Sh SEE ALSO
.Xr cryb_memset_s 3 ,
.Xr memcpy 3
.Sh STANDARDS
The
.Fn cryb_memcpy_s
function is equivalent to the
.Fn memcpy_s
function described in ISO/IEC 9899:2011
.Pq Dq C11
section K.3.7.1.1.
.Sh AUTHORS
The
.Fn cryb_memcpy_s
function and this manual page were written for the University of Oslo
by
.An Dag-Erling Sm\(/orgrav Aq Mt d.e.smorgrav@usit.uio.no .

81
lib/core/cryb_memcpy_s.c Normal file
View file

@ -0,0 +1,81 @@
/*-
* Copyright (c) 2015-2018 The University of Oslo
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <cryb/coverage.h>
#include <cryb/memcpy_s.h>
#include <cryb/memset_s.h>
/*
* Like memcpy(), but checks for overflow and overwrites the destination
* range with zeroes on error.
*
* ISO/IEC 9899:2011 K.3.7.1.1
*/
errno_t
cryb_memcpy_s(void * restrict d, rsize_t dsz, const void * restrict s,
rsize_t n)
{
volatile uint8_t *D;
const uint8_t *S;
unsigned int i;
/* unrecoverable errors */
if (d == NULL)
return (EINVAL);
CRYB_DISABLE_COVERAGE
if (dsz > RSIZE_MAX)
return (ERANGE);
CRYB_RESTORE_COVERAGE
/* recoverable errors */
if (s == NULL || n > dsz ||
CRYB_DISABLE_COVERAGE
n > RSIZE_MAX ||
CRYB_RESTORE_COVERAGE
(s >= d && s < d + dsz) || (d >= s && d < s + n)) {
memset_s(d, dsz, 0, dsz);
if (n > dsz)
return (EOVERFLOW);
CRYB_DISABLE_COVERAGE
if (n > RSIZE_MAX)
return (ERANGE);
CRYB_RESTORE_COVERAGE
return (EINVAL);
}
for (D = d, S = s, i = 0; i < dsz && i < n; ++i)
D[i] = S[i];
return (0);
}

130
lib/core/cryb_memset_s.3 Normal file
View file

@ -0,0 +1,130 @@
.\"-
.\" Copyright (c) 2015 Universitetet i Oslo
.\" All rights reserved.
.\"
.\" 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. The name of the author may not be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
.\"
.Dd May 6, 2018
.Dt cryb_memset_s 3
.Os
.Sh NAME
.Nm cryb_memset_s
.Nd safely fill a buffer
.Sh LIBRARY
.Lb libcryb-core
.Sh SYNOPSIS
.In cryb/memset_s.h
.Ft errno_t
.Fn cryb_memset_s "void *d" "rsize_t dsz" "int ch" "rsize_t n"
.Sh DESCRIPTION
The
.Nm cryb_memset_s
function overwrites the first
.Va n
bytes of the buffer pointed to by
.Va d ,
of size
.Va dsz ,
with copies of the least-significant byte of
.Va ch .
If
.Va n
is greater than
.Va dsz ,
only
.Va dsz
bytes are overwritten, and an error is returned.
.Sh RETURN VALUES
The
.Nm
function returns zero if successful and a non-zero error code if an
error occurred.
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINVAL
The
.Va d
argument was
.Dv NULL .
.It Bq Er ERANGE
Either or both of the
.Va dsz
and
.Va n
arguments were greater than
.Dv RSIZE_MAX .
.It Bq Er EOVERFLOW
The
.Va n
argument was greater than the
.Va dsz
argument.
.El
.Sh IMPLEMENTATION NOTES
If the
.Dv HAVE_MEMSET_S
preprocessor macro is defined to 0 or undefined, the
.In cryb/memset_s.h
header provides a
.Fn memset_s
macro as an alias to
.Fn cryb_memset_s .
.Pp
Software that includes
.In cryb/memset_s.h
should ensure that the
.Dv HAVE_ERRNO_T ,
.Dv HAVE_RSIZE_T ,
.Dv HAVE_RSIZE_MAX
and
.Dv HAVE_MEMSET_S
macros correctly reflect the availability of these features at compile
time.
For projects that use the GNU autotools, this can be achieved by
including the following code in
.Pa configure.ac :
.Bd -literal -offset indent
AC_CHECK_TYPES([errno_t], [], [], [[#include <errno.h>]])
AC_CHECK_TYPES([rsize_t], [], [], [[#include <stdint.h>]])
AC_CHECK_DECL([RSIZE_MAX], [], [], [[#include <stdint.h>]])
AC_CHECK_FUNCS([memset_s])
.Ed
.Sh SEE ALSO
.Xr cryb_memcpy_s 3 ,
.Xr memset 3
.Sh STANDARDS
The
.Fn cryb_memset_s
function is equivalent to the
.Fn memset_s
function described in ISO/IEC 9899:2011
.Pq Dq C11
section K.3.7.4.1.
.Sh AUTHORS
The
.Fn cryb_memset_s
function and this manual page were written for the University of Oslo
by
.An Dag-Erling Sm\(/orgrav Aq Mt d.e.smorgrav@usit.uio.no .

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2015 The University of Oslo
* Copyright (c) 2015-2018 The University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -35,22 +35,31 @@
#include <stdint.h>
#include <string.h>
#include <cryb/coverage.h>
#include <cryb/memset_s.h>
/*
* Like memset(), but checks for overflow and guarantees that the buffer
* is overwritten even if the data will never be read.
*
* ISO/IEC 9899:2011 K.3.7.4.1
*/
int
cryb_memset_s(void *s, size_t smax, int c, size_t n)
errno_t
cryb_memset_s(void *d, rsize_t dsz, int c, rsize_t n)
{
volatile uint8_t *D;
unsigned int i;
uint8_t C;
if (s == NULL)
if (d == NULL)
return (EINVAL);
for (i = 0; i < n && i < smax; ++i)
((volatile unsigned char *)s)[i] = (unsigned char)c;
if (n > smax)
CRYB_DISABLE_COVERAGE
if (dsz > RSIZE_MAX || n > RSIZE_MAX)
return (ERANGE);
CRYB_RESTORE_COVERAGE
for (D = d, C = (uint8_t)c, i = 0; i < n && i < dsz; ++i)
D[i] = C;
if (n > dsz)
return (EOVERFLOW);
return (0);
}

1
t/.gitignore vendored
View file

@ -29,6 +29,7 @@
/t_md4_openssl
/t_md5
/t_md5_openssl
/t_memcpy_s
/t_memset_s
/t_mpi
/t_mpi_addsub

View file

@ -94,9 +94,12 @@ TESTS += t_core
t_core_LDADD = $(libt) $(libcore)
TESTS += t_assert
t_assert_LDADD = $(libt) $(libcore)
TESTS += t_ctype t_endian t_memset_s t_strchrnul t_strlcat t_strlcmp t_strlcpy
TESTS += t_ctype t_endian t_memcpy_s t_memset_s t_strchrnul t_strlcat t_strlcmp t_strlcpy
TESTS += t_string t_wstring
EXTRA_DIST += t__string.c
t_ctype_LDADD = $(libt) $(libcore)
t_endian_LDADD = $(libt) $(libcore)
t_memcpy_s_LDADD = $(libt) $(libcore)
t_memset_s_LDADD = $(libt) $(libcore)
t_strchrnul_LDADD = $(libt) $(libcore)
t_strlcat_LDADD = $(libt) $(libcore)

307
t/t_memcpy_s.c Normal file
View file

@ -0,0 +1,307 @@
/*-
* Copyright (c) 2015-2018 The University of Oslo
* All rights reserved.
*
* 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. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include "cryb/impl.h"
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#undef HAVE_MEMCPY_S
#include <cryb/memcpy_s.h>
#include <cryb/strlcpy.h>
#include <cryb/test.h>
#define T_BUF_LEN 40
struct t_plain_case {
const char *desc;
const char in[T_BUF_LEN];
rsize_t dsz;
const char s[T_BUF_LEN];
rsize_t len;
const char out[T_BUF_LEN];
rsize_t outlen;
int ret;
};
/***************************************************************************
* Plain test cases
*/
static struct t_plain_case t_plain_cases[] = {
{
.desc = "zero",
.in = "squeamish ossifrage",
.dsz = sizeof "squeamish ossifrage" - 1,
.s = "",
.len = 0,
.out = "squeamish ossifrage",
.ret = 0,
},
{
.desc = "short",
.in = "squeamish ossifrage",
.dsz = sizeof "squeamish ossifrage" - 1,
.s = "the quick",
.len = sizeof "the quick" - 1,
.out = "the quick ossifrage",
.ret = 0,
},
{
.desc = "exact",
.in = "squeamish ossifrage",
.dsz = sizeof "squeamish ossifrage" - 1,
.s = "the quick brown fox",
.len = sizeof "the quick brown fox" - 1,
.out = "the quick brown fox",
.ret = 0,
},
{
.desc = "long",
.in = "squeamish ossifrage",
.dsz = sizeof "squeamish ossifrage" - 1,
.s = "the quick brown fox jumps",
.len = sizeof "the quick brown fox jumps" + 1,
.out = "",
.ret = EOVERFLOW,
},
};
static int
t_memcpy_s(char **desc CRYB_UNUSED, void *arg)
{
struct t_plain_case *t = arg;
char buf[T_BUF_LEN];
int ret;
memset(buf, 0, sizeof buf);
strlcpy(buf, t->in, T_BUF_LEN);
ret = memcpy_s(buf, t->dsz, t->s, t->len);
return (t_compare_i(t->ret, ret) &
t_compare_mem(t->out, buf, T_BUF_LEN));
}
/***************************************************************************
* Overlapping test cases
*/
struct t_overlap_case {
const char *desc;
const char *in;
size_t s_off, d_off;
rsize_t s_len, d_len;
const char out[T_BUF_LEN];
int ret;
};
static struct t_overlap_case t_overlap_cases[] = {
{
/* [<<<<<<<<<< >>>>>>>>>>] */
.desc = "left, disjoint",
.in = "the magic words are squeamish ossifrage",
.s_off = 0,
.s_len = 15,
.d_off = 16,
.d_len = 23,
.out = "the magic words the magic wordsssifrage",
.ret = 0,
},
{
/* [<<<<<<<<<<>>>>>>>>>>] */
.desc = "left, adjoining",
.in = "the magic words are squeamish ossifrage",
.s_off = 0,
.s_len = 16,
.d_off = 16,
.d_len = 23,
.out = "the magic words the magic words sifrage",
.ret = 0,
},
{
/* [>>>>>>>>>> <<<<<<<<<<] */
.desc = "right, disjoint",
.in = "the magic words are squeamish ossifrage",
.s_off = 20,
.s_len = 19,
.d_off = 0,
.d_len = 19,
.out = "squeamish ossifrage squeamish ossifrage",
.ret = 0,
},
{
/* [>>>>>>>>>><<<<<<<<<<] */
.desc = "right, adjoining",
.in = "the magic words are squeamish ossifrage",
.s_off = 20,
.s_len = 19,
.d_off = 0,
.d_len = 19,
.out = "squeamish ossifrage squeamish ossifrage",
.ret = 0,
},
{
/* [<<<<<<<<XXXX>>>>>>>>] */
.desc = "left, overlapping",
.in = "the magic words are squeamish ossifrage",
.s_off = 4,
.s_len = 15,
.d_off = 16,
.d_len = 23,
.out = "the magic words ",
.ret = EINVAL,
},
{
/* [>>>>>>>>XXXX<<<<<<<<] */
.desc = "right, overlapping",
.in = "the magic words are squeamish ossifrage",
.s_off = 16,
.s_len = 23,
.d_off = 0,
.d_len = 29,
.out = "\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0"
" ossifrage",
.ret = EINVAL,
},
{
/* [>>>>>>>>XXXX>>>>>>>>] */
.desc = "inside",
.in = "the magic words are squeamish ossifrage",
.s_off = 10,
.s_len = 19,
.d_off = 0,
.d_len = 39,
.out = "",
.ret = EINVAL,
},
{
/* [<<<<<<<<XXXX<<<<<<<<] */
/* caught by n > sz before overlap is noticed */
.desc = "outside",
.in = "the magic words are squeamish ossifrage",
.s_off = 0,
.s_len = 39,
.d_off = 10,
.d_len = 19,
.out = "the magic "
"\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0"
" ossifrage",
.ret = EOVERFLOW,
},
{
/* [XXXXXXXXXXXXXXXXXXXX] */
.desc = "full overlap",
.in = "the magic words are squeamish ossifrage",
.s_off = 10,
.s_len = 19,
.d_off = 10,
.d_len = 19,
.out = "the magic "
"\0\0\0\0\0\0\0\0\0\0"
"\0\0\0\0\0\0\0\0\0"
" ossifrage",
.ret = EINVAL,
},
};
static int
t_memcpy_s_overlap(char **desc CRYB_UNUSED, void *arg)
{
struct t_overlap_case *t = arg;
char buf[T_BUF_LEN];
int ret;
strlcpy(buf, t->in, sizeof buf);
ret = memcpy_s(buf + t->d_off, t->d_len, buf + t->s_off, t->s_len);
return (t_compare_i(t->ret, ret) &
t_compare_mem(t->out, buf, T_BUF_LEN));
}
/***************************************************************************
* NULL cases
*/
static int
t_memcpy_s_null_d(char **desc CRYB_UNUSED, void *arg)
{
char buf[T_BUF_LEN];
int ret;
(void)arg;
memset(buf, 'x', sizeof buf);
ret = memcpy_s(NULL, sizeof buf, buf, sizeof buf);
return (t_compare_i(EINVAL, ret));
}
static int
t_memcpy_s_null_s(char **desc CRYB_UNUSED, void *arg)
{
char buf[T_BUF_LEN];
int ret;
(void)arg;
memset(buf, 0, sizeof buf);
ret = memcpy_s(buf, sizeof buf, NULL, sizeof buf);
return (t_compare_i(EINVAL, ret) &
t_compare_mem(buf, t_zero, sizeof buf));
}
/***************************************************************************
* Boilerplate
*/
int
t_prepare(int argc, char *argv[])
{
int i, n;
(void)argc;
(void)argv;
t_add_test(t_memcpy_s_null_s, NULL, "null source");
t_add_test(t_memcpy_s_null_d, NULL, "null destination");
n = sizeof t_plain_cases / sizeof t_plain_cases[0];
for (i = 0; i < n; ++i)
t_add_test(t_memcpy_s, &t_plain_cases[i], "%s",
t_plain_cases[i].desc);
n = sizeof t_overlap_cases / sizeof t_overlap_cases[0];
for (i = 0; i < n; ++i)
t_add_test(t_memcpy_s_overlap, &t_overlap_cases[i], "%s",
t_overlap_cases[i].desc);
return (0);
}
int
main(int argc, char *argv[])
{
t_main(t_prepare, NULL, argc, argv);
}

View file

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2015 The University of Oslo
* Copyright (c) 2015-2018 The University of Oslo
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -44,8 +44,8 @@
struct t_case {
const char *desc;
const char in[T_BUF_LEN];
size_t smax;
int c;
size_t dsz;
int ch;
size_t len;
const char out[T_BUF_LEN];
size_t outlen;
@ -59,8 +59,8 @@ static struct t_case t_cases[] = {
{
.desc = "zero",
.in = "squeamish ossifrage",
.smax = sizeof "squeamish ossifrage" - 1,
.c = 'x',
.dsz = sizeof "squeamish ossifrage" - 1,
.ch = 'x',
.len = 0,
.out = "squeamish ossifrage",
.ret = 0,
@ -68,8 +68,8 @@ static struct t_case t_cases[] = {
{
.desc = "short",
.in = "squeamish ossifrage",
.smax = sizeof "squeamish ossifrage" - 1,
.c = 'x',
.dsz = sizeof "squeamish ossifrage" - 1,
.ch = 'x',
.len = 9,
.out = "xxxxxxxxx ossifrage",
.ret = 0,
@ -77,8 +77,8 @@ static struct t_case t_cases[] = {
{
.desc = "exact",
.in = "squeamish ossifrage",
.smax = sizeof "squeamish ossifrage" - 1,
.c = 'x',
.dsz = sizeof "squeamish ossifrage" - 1,
.ch = 'x',
.len = sizeof "squeamish ossifrage" - 1,
.out = "xxxxxxxxxxxxxxxxxxx",
.ret = 0,
@ -86,8 +86,8 @@ static struct t_case t_cases[] = {
{
.desc = "long",
.in = "squeamish ossifrage",
.smax = sizeof "squeamish ossifrage" - 1,
.c = 'x',
.dsz = sizeof "squeamish ossifrage" - 1,
.ch = 'x',
.len = sizeof "squeamish ossifrage" + 1,
.out = "xxxxxxxxxxxxxxxxxxx",
.ret = EOVERFLOW,
@ -104,8 +104,9 @@ t_memset_s(char **desc CRYB_UNUSED, void *arg)
char buf[T_BUF_LEN];
int ret;
memcpy(buf, t->in, T_BUF_LEN);
ret = memset_s(buf, t->smax, t->c, t->len);
memset(buf, 0, sizeof buf);
strncpy(buf, t->in, sizeof buf);
ret = memset_s(buf, t->dsz, t->ch, t->len);
return (t_compare_i(t->ret, ret) &
t_compare_mem(t->out, buf, T_BUF_LEN));
}