diff --git a/include/unistd.h b/include/unistd.h index 1d6f474a1239..7e46f0e69712 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -506,6 +506,7 @@ int execvP(const char *, const char *, char * const *); int feature_present(const char *); char *fflagstostr(u_long); int getdomainname(char *, int); +int getentropy(void *, size_t); int getgrouplist(const char *, gid_t, gid_t *, int *); int getloginclass(char *, size_t); mode_t getmode(const void *, mode_t); diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index d6e73ecaf087..c19655ec8a16 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -57,6 +57,7 @@ SRCS+= __getosreldate.c \ getcap.c \ getcwd.c \ getdomainname.c \ + getentropy.c \ getgrent.c \ getgrouplist.c \ gethostname.c \ @@ -220,6 +221,7 @@ MAN+= alarm.3 \ getcwd.3 \ getdiskbyname.3 \ getdomainname.3 \ + getentropy.3 \ getfsent.3 \ getgrent.3 \ getgrouplist.3 \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 44fb85a4fabe..908206e18e94 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -408,6 +408,7 @@ FBSD_1.5 { fts_set; fts_set_clientptr; ftw; + getentropy; getmntinfo; glob; globfree; diff --git a/lib/libc/gen/getentropy.3 b/lib/libc/gen/getentropy.3 new file mode 100644 index 000000000000..dae17cc1b5c1 --- /dev/null +++ b/lib/libc/gen/getentropy.3 @@ -0,0 +1,86 @@ +.\" $OpenBSD: getentropy.2,v 1.8 2015/01/31 00:20:12 schwarze Exp $ +.\" +.\" Copyright (c) 2018 Conrad Meyer +.\" Copyright (c) 2014 Theo de Raadt +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $FreeBSD$ +.\" +.Dd February 24, 2018 +.Dt GETENTROPY 3 +.Os +.Sh NAME +.Nm getentropy +.Nd get entropy +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn getentropy "void *buf" "size_t buflen" +.Sh DESCRIPTION +.Fn getentropy +fills a buffer with high-quality random data. +.Pp +The maximum +.Fa buflen +permitted is 256 bytes. +.Pp +If it does not produce an error, +.Fn getentropy +always provides the requested number of bytes of random data. +.Pp +Similar to reading from +.Pa /dev/urandom +just after boot, +.Fn getentropy +may block until the system has collected enough entropy to seed the CSPRNG. +.Sh IMPLEMENTATION NOTES +The +.Fn getentropy +function is implemented using +.Xr getrandom 2 . +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +.Fn getentropy +will succeed unless: +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa buf +parameter points to an +invalid address. +.It Bq Er EIO +Too many bytes requested, or some other fatal error occurred. +.El +.Sh SEE ALSO +.Xr arc4random 3 , +.Xr getrandom 2 , +.Xr random 4 +.Sh STANDARDS +.Fn getentropy +is non-standard. +It is present on +.Ox +and Linux. +.Sh HISTORY +The +.Fn getentropy +function appeared in +.Ox 5.6 . +The +.Fx +libc compatibility shim first appeared in +.Fx 12.0 . diff --git a/lib/libc/gen/getentropy.c b/lib/libc/gen/getentropy.c new file mode 100644 index 000000000000..8484570ba78d --- /dev/null +++ b/lib/libc/gen/getentropy.c @@ -0,0 +1,70 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Conrad Meyer + * 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. + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include + +#include +#include + +#include "libc_private.h" + +int +getentropy(void *buf, size_t buflen) +{ + ssize_t rd; + + if (buflen > 256) { + errno = EIO; + return (-1); + } + + while (buflen > 0) { + rd = getrandom(buf, buflen, 0); + if (rd == -1) { + if (errno == EINTR) + continue; + else if (errno == ENOSYS) + abort(); + else + return (-1); + } + + /* This cannot happen. */ + if (rd == 0) + abort(); + + buf = (char *)buf + rd; + buflen -= rd; + } + + return (0); +} diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index c1237cdab68f..39e1974375c7 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -197,6 +197,7 @@ MAN+= abort2.2 \ getpgrp.2 \ getpid.2 \ getpriority.2 \ + getrandom.2 \ getrlimit.2 \ getrusage.2 \ getsid.2 \ diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index ae58d4cd481d..1a711c99ba8a 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -392,6 +392,7 @@ FBSD_1.5 { getdents; getdirentries; getfsstat; + getrandom; kevent; lstat; mknod; @@ -627,6 +628,8 @@ FBSDprivate_1.0 { __sys_getppid; _getpriority; __sys_getpriority; + _getrandom; + __sys_getrandom; _getresgid; __sys_getresgid; _getresuid; diff --git a/lib/libc/sys/getrandom.2 b/lib/libc/sys/getrandom.2 new file mode 100644 index 000000000000..7f2144709beb --- /dev/null +++ b/lib/libc/sys/getrandom.2 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2018 Conrad Meyer +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. +.\" +.\" $FreeBSD$ +.\" +.Dd February 24, 2018 +.Dt GETRANDOM 2 +.Os +.Sh NAME +.Nm getrandom +.Nd get random data +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/random.h +.Ft ssize_t +.Fn getrandom "void *buf" "size_t buflen" "unsigned int flags" +.Sh DESCRIPTION +.Fn getrandom +fills +.Fa buf +with up to +.Fa buflen +bytes of random data. +.Pp +The +.Fa flags +argument may include zero or more of the following: +.Bl -tag -width _GRND_NONBLOCK_ +.It Ql GRND_NONBLOCK +Return +.Er EAGAIN +instead of blocking, if the +.Xr random 4 +device has not yet been seeded. +By default, +.Fn getrandom +will block until the device is seeded. +.It Ql GRND_RANDOM +This flag does nothing on +.Fx . +.Pa /dev/random +and +.Pa /dev/urandom +are identical. +.El +.Pp +If the +.Xr random 4 +device has been seeded, reads of up to 256 bytes will always return as many +bytes as requested and will not be interrupted by signals. +.Pp +.Sh RETURN VALUES +Upon successful completion, the number of bytes which were actually read is +returned. +For requests larger than 256 bytes, this can be fewer bytes than were +requested. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn getrandom +operation returns the following errors: +.Bl -tag -width Er +.It Bq Er EAGAIN +The +.Ql GRND_NONBLOCK +flag was set and the +.Xr random 4 +device was not yet seeded. +.It Bq Er EFAULT +The +.Fa buf +parameter points to an invalid address. +.It Bq Er EINTR +The sleep was interrupted by a signal. +.It Bq Er EINVAL +An invalid +.Fa flags +was specified. +.It Bq Er EINVAL +The requested +.Fa buflen +was larger than +.Dv IOSIZE_MAX . +.El +.Sh SEE ALSO +.Xr arc4random 3 , +.Xr getentropy 3 , +.Xr random 4 +.Sh STANDARDS +.Fn getentropy +is non-standard. +It is present in Linux. +.Sh HISTORY +The +.Fn getrandom +system call first appeared in +.Fx 12.0 . diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile index 0087a7069575..80bec69bbcaa 100644 --- a/lib/libc/tests/gen/Makefile +++ b/lib/libc/tests/gen/Makefile @@ -10,6 +10,7 @@ ATF_TESTS_C+= fmtmsg_test ATF_TESTS_C+= fnmatch2_test ATF_TESTS_C+= fpclassify2_test ATF_TESTS_C+= ftw_test +ATF_TESTS_C+= getentropy_test ATF_TESTS_C+= getmntinfo_test ATF_TESTS_C+= glob2_test ATF_TESTS_C+= makecontext_test @@ -61,6 +62,8 @@ NETBSD_ATF_TESTS_C+= vis_test .include "../Makefile.netbsd-tests" +CFLAGS.getentropy_test+= -I${SRCTOP}/include +LIBADD.getentropy_test+= c LIBADD.humanize_number_test+= util LIBADD.fpclassify_test+=m diff --git a/lib/libc/tests/gen/getentropy_test.c b/lib/libc/tests/gen/getentropy_test.c new file mode 100644 index 000000000000..731bed775263 --- /dev/null +++ b/lib/libc/tests/gen/getentropy_test.c @@ -0,0 +1,84 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Conrad Meyer + * 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. + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +ATF_TC_WITHOUT_HEAD(getentropy_count); +ATF_TC_BODY(getentropy_count, tc) +{ + char buf[2]; + int ret; + + /* getentropy(2) does not modify buf past the requested length */ + buf[1] = 0x7C; + ret = getentropy(buf, 1); + ATF_REQUIRE_EQ(ret, 0); + ATF_REQUIRE_EQ(buf[1], 0x7C); +} + +ATF_TC_WITHOUT_HEAD(getentropy_fault); +ATF_TC_BODY(getentropy_fault, tc) +{ + int ret; + + ret = getentropy(NULL, 1); + ATF_REQUIRE_EQ(ret, -1); + ATF_REQUIRE_EQ(errno, EFAULT); +} + +ATF_TC_WITHOUT_HEAD(getentropy_sizes); +ATF_TC_BODY(getentropy_sizes, tc) +{ + char buf[512]; + + ATF_REQUIRE_EQ(getentropy(buf, sizeof(buf)), -1); + ATF_REQUIRE_EQ(errno, EIO); + ATF_REQUIRE_EQ(getentropy(buf, 257), -1); + ATF_REQUIRE_EQ(errno, EIO); + + /* Smaller sizes always succeed: */ + ATF_REQUIRE_EQ(getentropy(buf, 256), 0); + ATF_REQUIRE_EQ(getentropy(buf, 128), 0); + ATF_REQUIRE_EQ(getentropy(buf, 0), 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getentropy_count); + ATF_TP_ADD_TC(tp, getentropy_fault); + ATF_TP_ADD_TC(tp, getentropy_sizes); + return (atf_no_error()); +} diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index 50613d037ca8..6e9a3a63d61f 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -1116,5 +1116,7 @@ cpuwhich_t which, uint32_t id1, uint32_t id2, \ size_t domainsetsize, domainset_t *mask, \ int policy); } +563 AUE_NULL NOPROTO { int getrandom(void *buf, size_t buflen, \ + unsigned int flags); } ; vim: syntax=off diff --git a/sys/conf/files b/sys/conf/files index 99b9c87734bb..92f39e6b1443 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -3895,6 +3895,7 @@ kern/subr_vmem.c standard kern/subr_witness.c optional witness kern/sys_capability.c standard kern/sys_generic.c standard +kern/sys_getrandom.c standard kern/sys_pipe.c standard kern/sys_procdesc.c standard kern/sys_process.c standard diff --git a/sys/kern/sys_getrandom.c b/sys/kern/sys_getrandom.c new file mode 100644 index 000000000000..34916df79be7 --- /dev/null +++ b/sys/kern/sys_getrandom.c @@ -0,0 +1,97 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Conrad Meyer + * 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. + * + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_compat.h" + +#include +#include +#include +#include +#include +#include +#include + +#define GRND_VALIDFLAGS (GRND_NONBLOCK | GRND_RANDOM) + +/* + * random_read_uio(9) returns EWOULDBLOCK if a nonblocking request would block, + * but the Linux API name is EAGAIN. On FreeBSD, they have the same numeric + * value for now. + */ +CTASSERT(EWOULDBLOCK == EAGAIN); + +static int +kern_getrandom(struct thread *td, void *user_buf, size_t buflen, + unsigned int flags) +{ + struct uio auio; + struct iovec aiov; + int error; + + if ((flags & ~GRND_VALIDFLAGS) != 0) + return (EINVAL); + if (buflen > IOSIZE_MAX) + return (EINVAL); + + if (buflen == 0) { + td->td_retval[0] = 0; + return (0); + } + + aiov.iov_base = user_buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_offset = 0; + auio.uio_resid = buflen; + auio.uio_segflg = UIO_USERSPACE; + auio.uio_rw = UIO_READ; + auio.uio_td = td; + + error = read_random_uio(&auio, (flags & GRND_NONBLOCK) != 0); + if (error == 0) + td->td_retval[0] = buflen - auio.uio_resid; + return (error); +} + +#ifndef _SYS_SYSPROTO_H_ +struct getrandom_args { + void *buf; + size_t buflen; + unsigned int flags; +}; +#endif + +int +sys_getrandom(struct thread *td, struct getrandom_args *uap) +{ + return (kern_getrandom(td, uap->buf, uap->buflen, uap->flags)); +} diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 00d47533c4e5..871d379034c6 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1021,6 +1021,8 @@ cpuwhich_t which, id_t id, \ size_t domainsetsize, domainset_t *mask, \ int policy); } +563 AUE_NULL STD { int getrandom(void *buf, size_t buflen, \ + unsigned int flags); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/sys/random.h b/sys/sys/random.h index cf8e663d8f9e..ed71f34b3386 100644 --- a/sys/sys/random.h +++ b/sys/sys/random.h @@ -31,10 +31,10 @@ #ifndef _SYS_RANDOM_H_ #define _SYS_RANDOM_H_ -#ifdef _KERNEL - #include +#ifdef _KERNEL + #if !defined(KLD_MODULE) #if defined(RANDOM_LOADABLE) && defined(RANDOM_YARROW) #error "Cannot define both RANDOM_LOADABLE and RANDOM_YARROW" @@ -127,4 +127,8 @@ void random_harvest_deregister_source(enum random_entropy_source); #endif /* _KERNEL */ +#define GRND_NONBLOCK 0x1 +#define GRND_RANDOM 0x2 +ssize_t getrandom(void *buf, size_t buflen, unsigned int flags); + #endif /* _SYS_RANDOM_H_ */ diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index d053ecccd940..3a0dbcbce25c 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -11,6 +11,7 @@ ATF_TESTS_C+= ptrace_test TEST_METADATA.ptrace_test+= timeout="15" ATF_TESTS_C+= reaper PLAIN_TESTS_C+= subr_unit_test +ATF_TESTS_C+= sys_getrandom ATF_TESTS_C+= unix_seqpacket_test ATF_TESTS_C+= unix_passfd_test TEST_METADATA.unix_seqpacket_test+= timeout="15" @@ -21,6 +22,10 @@ ATF_TESTS_SH+= coredump_phnum_test BINDIR= ${TESTSDIR} PROGS+= coredump_phnum_helper +CFLAGS.sys_getrandom+= -I${SRCTOP}/sys/contrib/zstd/lib +LIBADD.sys_getrandom+= zstd +LIBADD.sys_getrandom+= c +LIBADD.sys_getrandom+= pthread LIBADD.ptrace_test+= pthread LIBADD.unix_seqpacket_test+= pthread diff --git a/tests/sys/kern/sys_getrandom.c b/tests/sys/kern/sys_getrandom.c new file mode 100644 index 000000000000..d75e54003261 --- /dev/null +++ b/tests/sys/kern/sys_getrandom.c @@ -0,0 +1,130 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Conrad Meyer + * 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. + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include + +const static unsigned valid_flags[] = { 0, GRND_NONBLOCK, GRND_RANDOM, + GRND_NONBLOCK | GRND_RANDOM }; + +ATF_TC_WITHOUT_HEAD(getrandom_randomness); +ATF_TC_BODY(getrandom_randomness, tc) +{ + char randomb[4096], compressed[5000]; + ssize_t ret; + size_t i, j, c; + unsigned mode; + + for (i = 0; i < nitems(valid_flags); i++) { + mode = valid_flags[i]; + + /* Get new random data, filling randomb. */ + + memset(randomb, 0, sizeof(randomb)); + + for (j = 0; j < sizeof(randomb);) { + ret = getrandom(&randomb[j], sizeof(randomb) - j, mode); + if (ret < 0 && (mode & GRND_NONBLOCK) != 0 && + errno == EAGAIN) + continue; + + ATF_REQUIRE_MSG(ret >= 0, "other error: %d", errno); + ATF_REQUIRE_MSG(ret > 0, "bogus zero return"); + + j += (size_t)ret; + } + + /* Perform compressibility test */ + c = ZSTD_compress(compressed, sizeof(compressed), randomb, + sizeof(randomb), ZSTD_maxCLevel()); + ATF_REQUIRE_MSG(!ZSTD_isError(c), "zstd compress: %s", + ZSTD_getErrorName(c)); + + /* + * If the output is very compressible, it's probably not random + */ + ATF_REQUIRE_MSG(c > (sizeof(randomb) * 4 / 5), + "purportedly random data was compressible: %zu/%zu or %f%%", + c, sizeof(randomb), (double)c / (double)sizeof(randomb)); + } +} + +ATF_TC_WITHOUT_HEAD(getrandom_fault); +ATF_TC_BODY(getrandom_fault, tc) +{ + ssize_t ret; + + ret = getrandom(NULL, 1, 0); + ATF_REQUIRE_EQ(ret, -1); + ATF_REQUIRE_EQ(errno, EFAULT); +} + +ATF_TC_WITHOUT_HEAD(getrandom_count); +ATF_TC_BODY(getrandom_count, tc) +{ + char buf[4096], reference[4096]; + ssize_t ret; + + /* getrandom(2) does not modify buf past the requested length */ + _Static_assert(sizeof(reference) == sizeof(buf), "must match"); + memset(reference, 0x7C, sizeof(reference)); + + memset(buf, 0x7C, sizeof(buf)); + ret = getrandom(buf, 1, 0); + ATF_REQUIRE_EQ(ret, 1); + ATF_REQUIRE_EQ(memcmp(&buf[1], reference, sizeof(reference) - 1), 0); + + memset(buf, 0x7C, sizeof(buf)); + ATF_REQUIRE_EQ(getrandom(buf, 15, 0), 15); + ATF_REQUIRE_EQ(memcmp(&buf[15], reference, sizeof(reference) - 15), 0); + + memset(buf, 0x7C, sizeof(buf)); + ATF_REQUIRE_EQ(getrandom(buf, 255, 0), 255); + ATF_REQUIRE_EQ(memcmp(&buf[255], reference, sizeof(reference) - 255), 0); + + memset(buf, 0x7C, sizeof(buf)); + ATF_REQUIRE_EQ(getrandom(buf, 4095, 0), 4095); + ATF_REQUIRE_EQ(memcmp(&buf[4095], reference, sizeof(reference) - 4095), 0); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, getrandom_count); + ATF_TP_ADD_TC(tp, getrandom_fault); + ATF_TP_ADD_TC(tp, getrandom_randomness); + return (atf_no_error()); +} diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index 685291ebc56e..f92bc7485957 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -259,6 +259,8 @@ static struct syscall decoded_syscalls[] = { .args = { { Int, 0 } } }, { .name = "getpriority", .ret_type = 1, .nargs = 2, .args = { { Priowhich, 0 }, { Int, 1 } } }, + { .name = "getrandom", .ret_type = 1, .nargs = 3, + .args = { { BinString | OUT, 0 }, { Sizet, 1 }, { UInt, 2 } } }, { .name = "getrlimit", .ret_type = 1, .nargs = 2, .args = { { Resource, 0 }, { Rlimit | OUT, 1 } } }, { .name = "getrusage", .ret_type = 1, .nargs = 2,