Index: Makefile.inc1 =================================================================== --- Makefile.inc1 +++ Makefile.inc1 @@ -947,7 +947,8 @@ # Syscall stubs rewritten in C and obsolete MD assembly implementations # Date SVN Rev Syscalls # 20180604 r334626 brk sbrk -.for f in brk sbrk +# 20190916 r35XXXX shm_open +.for f in brk sbrk shm_open @if [ -e "${OBJTOP}/lib/libc/.depend.${f}.o" ] && \ egrep -qw '${f}\.[sS]' ${OBJTOP}/lib/libc/.depend.${f}.o; then \ echo "Removing stale dependencies for ${f} syscall wrappers"; \ Index: lib/libc/include/libc_private.h =================================================================== --- lib/libc/include/libc_private.h +++ lib/libc/include/libc_private.h @@ -391,6 +391,7 @@ struct __wrusage *, struct __siginfo *); __ssize_t __sys_write(int, const void *, __size_t); __ssize_t __sys_writev(int, const struct iovec *, int); +int __sys_shm_open2(const char *, int, __mode_t, int, const char *); int __libc_sigaction(int, const struct sigaction *, struct sigaction *) __hidden; Index: lib/libc/sys/Makefile.inc =================================================================== --- lib/libc/sys/Makefile.inc +++ lib/libc/sys/Makefile.inc @@ -46,6 +46,7 @@ SRCS+= brk.c SRCS+= pipe.c +SRCS+= shm_open.c SRCS+= vadvise.c SRCS+= compat-stub.c @@ -475,7 +476,8 @@ setuid.2 seteuid.2 \ setuid.2 setgid.2 MLINKS+=shmat.2 shmdt.2 -MLINKS+=shm_open.2 shm_unlink.2 +MLINKS+=shm_open.2 memfd_create.3 \ + shm_open.2 shm_unlink.2 MLINKS+=sigwaitinfo.2 sigtimedwait.2 MLINKS+=stat.2 fstat.2 \ stat.2 fstatat.2 \ Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map +++ lib/libc/sys/Symbol.map @@ -409,6 +409,7 @@ fhreadlink; getfhat; funlinkat; + memfd_create; }; FBSDprivate_1.0 { Index: lib/libc/sys/shm_open.2 =================================================================== --- lib/libc/sys/shm_open.2 +++ lib/libc/sys/shm_open.2 @@ -28,11 +28,11 @@ .\" .\" $FreeBSD$ .\" -.Dd January 20, 2017 +.Dd September 24, 2019 .Dt SHM_OPEN 2 .Os .Sh NAME -.Nm shm_open , shm_unlink +.Nm memfd_create , shm_open , shm_unlink .Nd "shared memory object operations" .Sh LIBRARY .Lb libc @@ -41,6 +41,8 @@ .In sys/mman.h .In fcntl.h .Ft int +.Fn memfd_create "const char *name" "unsigned int flags" +.Ft int .Fn shm_open "const char *path" "int flags" "mode_t mode" .Ft int .Fn shm_unlink "const char *path" @@ -139,14 +141,64 @@ .Fn shm_unlink system call removes a shared memory object named .Fa path . +.Pp +The +.Fn memfd_create +function creates an anonymous shared memory object, identical to that created +by +.Fn shm_open +when +.Dv SHM_ANON +is specified. +Newly created objects start off with a size of zero. +The size of the new object must be adjusted via +.Xr ftruncate 2 . +.Pp +The +.Fa name +argument must not be +.Dv NULL , +but it may be an empty string. +The length of the +.Fa name +argument may not exceed +.Dv NAME_MAX +minus six characters for the prefix +.Dq memfd: , +which will be prepended. +The +.Fa name +argument is intended solely for debugging purposes and will never be used by the +kernel to identify a memfd. +Names are therefore not required to be unique. +.Pp +The following +.Fa flags +may be specified to +.Fn memfd_create : +.Bl -tag -width MFD_ALLOW_SEALING +.It Dv MFD_CLOEXEC +Set +.Dv FD_CLOEXEC +on the resulting file descriptor. +.It Dv MFD_ALLOW_SEALING +Allow adding seals to the resulting file descriptor using the +.Dv F_ADD_SEALS +.Xr fcntl 2 +command. +.It Dv MFD_HUGETLB +This flag is currently unsupported. +.El .Sh RETURN VALUES If successful, +.Fn memfd_create +and .Fn shm_open -returns a non-negative integer, +both return a non-negative integer, and .Fn shm_unlink returns zero. -Both functions return -1 on failure, and set +All three functions return -1 on failure, and set .Va errno to indicate the error. .Sh COMPATIBILITY @@ -220,6 +272,33 @@ errx(EX_IOERR, "%s: pwrite length mismatch", __func__); .Ed .Sh ERRORS +.Fn memfd_create +fails with these error codes for these conditions: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa name +argument was NULL. +.It Bq Er EINVAL +The +.Fa name +argument was too long. +.Pp +An invalid or unsupported flag was included in +.Fa flags . +.It Bq Er EMFILE +The process has already reached its limit for open file descriptors. +.It Bq Er ENFILE +The system file table is full. +.It Bq Er ENOSYS +In +.Fa memfd_create , +.Dv MFD_HUGETLB +was specified in +.Fa flags , +and this system does not support forced hugetlb mappings. +.El +.Pp .Fn shm_open fails with these error codes for these conditions: .Bl -tag -width Er @@ -290,6 +369,11 @@ .Xr sendfile 2 .Sh STANDARDS The +.Fn memfd_create +function is expected to be compatible with the Linux system call of the same +name. +.Pp +The .Fn shm_open and .Fn shm_unlink @@ -297,6 +381,11 @@ .St -p1003.1b-93 . .Sh HISTORY The +.Fn memfd_create +function appeared in +.Fx 13.0 . +.Pp +The .Fn shm_open and .Fn shm_unlink Index: lib/libc/sys/shm_open.c =================================================================== --- /dev/null +++ lib/libc/sys/shm_open.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2019 Kyle Evans + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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(S) 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 +#include +#include +#include +#include + +#include "libc_private.h" + +__weak_reference(shm_open, _shm_open); +__weak_reference(shm_open, __sys_shm_open); + +/* XXX TODO */ +#define SHM_OPEN2_OSREL 1300048 + +#define MEMFD_NAME_PREFIX "memfd:" + +int +shm_open(const char *path, int flags, mode_t mode) +{ + + if (__getosreldate() >= SHM_OPEN2_OSREL) + return (__sys_shm_open2(path, flags | O_CLOEXEC, mode, 0, + NULL)); + + /* + * Fallback to shm_open(2) on older kernels. The kernel will enforce + * O_CLOEXEC in this interface, unlike the newer shm_open2 which does + * not enforce it. The newer interface allows memfd_create(), for + * instance, to not have CLOEXEC on the returned fd. + */ + return (syscall(SYS_freebsd12_shm_open, path, flags, mode)); +} + +/* + * The path argument is passed to the kernel, but the kernel doesn't currently + * do anything with it. Linux exposes it in linprocfs for debugging purposes + * only, but our kernel currently will not do the same. + */ +int +memfd_create(const char *name, unsigned int flags) +{ + char memfd_name[NAME_MAX + 1]; + size_t namelen; + int oflags, shmflags; + + if (name == NULL) + return (EBADF); + namelen = strlen(name); + if (namelen + sizeof(MEMFD_NAME_PREFIX) - 1 > NAME_MAX) + return (EINVAL); + if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | + MFD_HUGE_MASK)) != 0) + return (EINVAL); + /* HUGETLB set with no size specified. */ + if ((flags & MFD_HUGETLB) != 0 && (flags & MFD_HUGE_MASK) == 0) + return (EINVAL); + /* Size specified but no HUGETLB. */ + if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) + return (EINVAL); + /* We don't actually support HUGETLB. */ + if ((flags & MFD_HUGETLB) != 0) + return (ENOSYS); + + /* We've already validated that we're sufficiently sized. */ + snprintf(memfd_name, NAME_MAX + 1, "%s%s", MEMFD_NAME_PREFIX, name); + oflags = O_RDWR; + shmflags = 0; + if ((flags & MFD_CLOEXEC) != 0) + oflags |= O_CLOEXEC; + if ((flags & MFD_ALLOW_SEALING) != 0) + shmflags |= SHM_ALLOW_SEALING; + return (__sys_shm_open2(SHM_ANON, oflags, 0, shmflags, memfd_name)); +} Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master +++ sys/compat/freebsd32/syscalls.master @@ -13,7 +13,7 @@ ; case where the event exists, but we don't want auditing, the ; event should be #defined to AUE_NULL in audit_kevents.h. ; type one of STD, OBSOL, UNIMPL, COMPAT, COMPAT4, COMPAT6, -; COMPAT7, COMPAT11, NODEF, NOARGS, NOPROTO, NOSTD +; COMPAT7, COMPAT11, COMPAT12, NODEF, NOARGS, NOPROTO, NOSTD ; The COMPAT* options may be combined with one or more NO* ; options separated by '|' with no spaces (e.g. COMPAT|NOARGS) ; name pseudo-prototype of syscall routine @@ -31,6 +31,7 @@ ; COMPAT7 included on COMPAT_FREEBSD7 #ifdef (FreeBSD 7 compat) ; COMPAT10 included on COMPAT_FREEBSD10 #ifdef (FreeBSD 10 compat) ; COMPAT11 included on COMPAT_FREEBSD11 #ifdef (FreeBSD 11 compat) +; COMPAT12 included on COMPAT_FREEBSD12 #ifdef (FreeBSD 12 compat) ; OBSOL obsolete, not included in system, only specifies name ; UNIMPL not implemented, placeholder only ; NOSTD implemented but as a lkm that can be statically @@ -909,8 +910,8 @@ uint32_t length1, uint32_t length2); } #endif 481 AUE_THR_KILL2 NOPROTO { int thr_kill2(pid_t pid, long id, int sig); } -482 AUE_SHMOPEN NOPROTO { int shm_open(const char *path, int flags, \ - mode_t mode); } +482 AUE_SHMOPEN COMPAT12|NOPROTO { int shm_open( \ + const char *path, int flags, mode_t mode); } 483 AUE_SHMUNLINK NOPROTO { int shm_unlink(const char *path); } 484 AUE_NULL NOPROTO { int cpuset(cpusetid_t *setid); } #ifdef PAD64_REQUIRED @@ -1153,5 +1154,8 @@ 570 AUE_SYSCTL STD { int freebsd32___sysctlbyname(const char *name, \ size_t namelen, void *old, uint32_t *oldlenp, \ void *new, size_t newlen); } +571 AUE_SHMOPEN NOPROTO { int shm_open2( \ + const char *path, int flags, mode_t mode, \ + int shmflags, const char *name); } ; vim: syntax=off Index: sys/kern/capabilities.conf =================================================================== --- sys/kern/capabilities.conf +++ sys/kern/capabilities.conf @@ -655,6 +655,7 @@ ## shm_open(2) is scoped so as to allow only access to new anonymous objects. ## shm_open +shm_open2 ## ## Allow I/O-related file descriptors, subject to capability rights. Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master +++ sys/kern/syscalls.master @@ -2578,7 +2578,7 @@ int sig ); } -482 AUE_SHMOPEN STD { +482 AUE_SHMOPEN COMPAT12 { int shm_open( _In_z_ const char *path, int flags, @@ -3194,6 +3194,15 @@ _In_reads_bytes_opt_(newlen) void *new, size_t newlen); } +571 AUE_SHMOPEN STD { + int shm_open2( + _In_z_ const char *path, + int flags, + mode_t mode, + int shmflags, + _In_z_ const char *name + ); + } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/kern/uipc_shm.c =================================================================== --- sys/kern/uipc_shm.c +++ sys/kern/uipc_shm.c @@ -905,13 +905,15 @@ } /* System calls. */ +#ifdef COMPAT_FREEBSD12 int -sys_shm_open(struct thread *td, struct shm_open_args *uap) +freebsd12_shm_open(struct thread *td, struct freebsd12_shm_open_args *uap) { return (kern_shm_open(td, uap->path, uap->flags | O_CLOEXEC, uap->mode, NULL, F_SEAL_SEAL)); } +#endif int sys_shm_unlink(struct thread *td, struct shm_unlink_args *uap) @@ -1317,3 +1319,36 @@ CTLFLAG_RD | CTLFLAG_MPSAFE | CTLTYPE_OPAQUE, NULL, 0, sysctl_posix_shm_list, "", "POSIX SHM list"); + +int +kern_shm_open2(struct thread *td, const char *path, int flags, mode_t mode, + int shmflags, const char *name __unused) +{ + int initial_seals; + + if ((shmflags & ~SHM_ALLOW_SEALING) != 0) + return (EINVAL); + + initial_seals = F_SEAL_SEAL; + if ((shmflags & SHM_ALLOW_SEALING) != 0) + initial_seals &= ~F_SEAL_SEAL; + return (kern_shm_open(td, path, flags, 0, NULL, initial_seals)); +} + +/* + * This version of the shm_open() interface leaves CLOEXEC behavior up to the + * caller, and libc will enforce it for the traditional shm_open() call. This + * allows other consumers, like memfd_create(), to opt-in for CLOEXEC. This + * interface also includes a 'name' argument that is currently unused, but could + * potentially be exported later via some interface for debugging purposes. + * From the kernel's perspective, it is optional. Individual consumers like + * memfd_create() may require it in order to be compatible with other systems + * implementing the same function. + */ +int +sys_shm_open2(struct thread *td, struct shm_open2_args *uap) +{ + + return (kern_shm_open2(td, uap->path, uap->flags, uap->mode, + uap->shmflags, uap->name)); +} Index: sys/sys/mman.h =================================================================== --- sys/sys/mman.h +++ sys/sys/mman.h @@ -176,6 +176,36 @@ * Anonymous object constant for shm_open(). */ #define SHM_ANON ((char *)1) + +/* + * shmflags for shm_open2() + */ +#define SHM_ALLOW_SEALING 0x00000001 + +/* + * Flags for memfd_create(). + */ +#define MFD_ALLOW_SEALING 0x00000001 +#define MFD_CLOEXEC 0x00000002 + +/* UNSUPPORTED */ +#define MFD_HUGETLB 0x00000004 + +#define MFD_HUGE_MASK 0xFC000000 +#define MFD_HUGE_SHIFT 26 +#define MFD_HUGE_64KB (16 << MFD_HUGE_SHIFT) +#define MFD_HUGE_512KB (19 << MFD_HUGE_SHIFT) +#define MFD_HUGE_1MB (20 << MFD_HUGE_SHIFT) +#define MFD_HUGE_2MB (21 << MFD_HUGE_SHIFT) +#define MFD_HUGE_8MB (23 << MFD_HUGE_SHIFT) +#define MFD_HUGE_16MB (24 << MFD_HUGE_SHIFT) +#define MFD_HUGE_32MB (25 << MFD_HUGE_SHIFT) +#define MFD_HUGE_256MB (28 << MFD_HUGE_SHIFT) +#define MFD_HUGE_512MB (29 << MFD_HUGE_SHIFT) +#define MFD_HUGE_1GB (30 << MFD_HUGE_SHIFT) +#define MFD_HUGE_2GB (31 << MFD_HUGE_SHIFT) +#define MFD_HUGE_16GB (34 << MFD_HUGE_SHIFT) + #endif /* __BSD_VISIBLE */ /* @@ -285,6 +315,9 @@ int shm_open(const char *, int, mode_t); int shm_unlink(const char *); #endif +#if __BSD_VISIBLE +int memfd_create(const char *, unsigned int); +#endif __END_DECLS #endif /* !_KERNEL */ Index: sys/sys/syscallsubr.h =================================================================== --- sys/sys/syscallsubr.h +++ sys/sys/syscallsubr.h @@ -251,6 +251,8 @@ struct timezone *tzp); int kern_shm_open(struct thread *td, const char *userpath, int flags, mode_t mode, struct filecaps *fcaps, int initial_seals); +int kern_shm_open2(struct thread *td, const char *path, int flags, + mode_t mode, int shmflags, const char *name); int kern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg); int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf, Index: tests/sys/kern/Makefile =================================================================== --- tests/sys/kern/Makefile +++ tests/sys/kern/Makefile @@ -9,6 +9,7 @@ ATF_TESTS_C+= kern_copyin ATF_TESTS_C+= kern_descrip_test ATF_TESTS_C+= kill_zombie +ATF_TESTS_C+= memfd_test ATF_TESTS_C+= ptrace_test TEST_METADATA.ptrace_test+= timeout="15" ATF_TESTS_C+= reaper Index: tests/sys/kern/memfd_test.c =================================================================== --- /dev/null +++ tests/sys/kern/memfd_test.c @@ -0,0 +1,276 @@ +/*- + * Copyright (c) 2019 Kyle Evans + * 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 + +ATF_TC_WITHOUT_HEAD(basic); +ATF_TC_BODY(basic, tc) +{ + int fd; + char buf[8]; + + ATF_REQUIRE((fd = memfd_create("...", 0)) != -1); + + /* File size should be initially 0 */ + ATF_REQUIRE(write(fd, buf, sizeof(buf)) == 0); + + /* ftruncate(2) must succeed without seals */ + ATF_REQUIRE(ftruncate(fd, sizeof(buf) - 1) == 0); + + ATF_REQUIRE(write(fd, buf, sizeof(buf)) == sizeof(buf) - 1); + + close(fd); +} + +ATF_TC_WITHOUT_HEAD(cloexec); +ATF_TC_BODY(cloexec, tc) +{ + int fd_nocl, fd_cl; + + ATF_REQUIRE((fd_nocl = memfd_create("...", 0)) != -1); + ATF_REQUIRE((fd_cl = memfd_create("...", MFD_CLOEXEC)) != -1); + + ATF_REQUIRE((fcntl(fd_nocl, F_GETFD) & FD_CLOEXEC) == 0); + ATF_REQUIRE((fcntl(fd_cl, F_GETFD) & FD_CLOEXEC) != 0); + + close(fd_nocl); + close(fd_cl); +} + +ATF_TC_WITHOUT_HEAD(disallowed_sealing); +ATF_TC_BODY(disallowed_sealing, tc) +{ + int fd; + + ATF_REQUIRE((fd = memfd_create("...", 0)) != -1); + ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == F_SEAL_SEAL); + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); + ATF_REQUIRE(errno == EPERM); + + close(fd); +} + +#define BUF_SIZE 1024 + +ATF_TC_WITHOUT_HEAD(write_seal); +ATF_TC_BODY(write_seal, tc) +{ + int fd; + char *addr, buf[BUF_SIZE]; + + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0); + + /* Write once, then we'll seal it and try again */ + ATF_REQUIRE(write(fd, buf, BUF_SIZE) == BUF_SIZE); + ATF_REQUIRE(lseek(fd, 0, SEEK_SET) == 0); + + addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); + ATF_REQUIRE(addr != MAP_FAILED); + ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0); + + ATF_REQUIRE(write(fd, buf, BUF_SIZE) == -1); + ATF_REQUIRE(errno == EPERM); + + ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, + fd, 0) == MAP_FAILED); + ATF_REQUIRE(errno == EPERM); + + close(fd); +} + +ATF_TC_WITHOUT_HEAD(mmap_write_seal); +ATF_TC_BODY(mmap_write_seal, tc) +{ + int fd; + char *addr, *paddr, *raddr; + + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + ATF_REQUIRE(ftruncate(fd, BUF_SIZE) == 0); + + /* Map it, both shared and privately */ + addr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0); + ATF_REQUIRE(addr != MAP_FAILED); + paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); + ATF_REQUIRE(paddr != MAP_FAILED); + raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0); + ATF_REQUIRE(raddr != MAP_FAILED); + + /* Now try to seal it before unmapping */ + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == -1); + ATF_REQUIRE(errno == EBUSY); + + ATF_REQUIRE(munmap(addr, BUF_SIZE) == 0); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE) == 0); + + ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0); + ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0); + ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, + fd, 0) == MAP_FAILED); + ATF_REQUIRE(errno == EPERM); + paddr = mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); + ATF_REQUIRE(paddr != MAP_FAILED); + raddr = mmap(0, BUF_SIZE, PROT_READ, MAP_SHARED, fd, 0); + ATF_REQUIRE(raddr != MAP_FAILED); + ATF_REQUIRE(munmap(raddr, BUF_SIZE) == 0); + ATF_REQUIRE(munmap(paddr, BUF_SIZE) == 0); + + close(fd); +} + +static int +memfd_truncate_test(int initial_size, int dest_size, int seals) +{ + int err, fd; + + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + ATF_REQUIRE(ftruncate(fd, initial_size) == 0); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, seals) == 0); + + err = ftruncate(fd, dest_size); + if (err != 0) + err = errno; + close(fd); + return (err); +} + +ATF_TC_WITHOUT_HEAD(truncate_seals); +ATF_TC_BODY(truncate_seals, tc) +{ + + ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW) == EPERM); + ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_SHRINK) == EPERM); + ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW) == 0); + ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_SHRINK) == 0); + + ATF_REQUIRE(memfd_truncate_test(4, 8, F_SEAL_GROW | F_SEAL_SHRINK) == + EPERM); + ATF_REQUIRE(memfd_truncate_test(8, 4, F_SEAL_GROW | F_SEAL_SHRINK) == + EPERM); + ATF_REQUIRE(memfd_truncate_test(4, 4, F_SEAL_GROW | F_SEAL_SHRINK) == + 0); +} + +ATF_TC_WITHOUT_HEAD(get_seals); +ATF_TC_BODY(get_seals, tc) +{ + int fd; + int seals; + + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0); + seals = fcntl(fd, F_GET_SEALS); + ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); + + close(fd); +} + +ATF_TC_WITHOUT_HEAD(dup_seals); +ATF_TC_BODY(dup_seals, tc) +{ + char buf[8]; + int fd, fdx; + int seals; + + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + ATF_REQUIRE((fdx = dup(fd)) != -1); + ATF_REQUIRE(fcntl(fd, F_GET_SEALS) == 0); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_WRITE | F_SEAL_GROW) == 0); + seals = fcntl(fd, F_GET_SEALS); + ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); + + seals = fcntl(fdx, F_GET_SEALS); + ATF_REQUIRE(seals == (F_SEAL_WRITE | F_SEAL_GROW)); + + /* Make sure the seal's actually being applied at the inode level */ + ATF_REQUIRE(write(fdx, buf, sizeof(buf)) == -1); + ATF_REQUIRE(errno == EPERM); + + ATF_REQUIRE(mmap(0, BUF_SIZE, (PROT_READ | PROT_WRITE), MAP_SHARED, + fdx, 0) == MAP_FAILED); + ATF_REQUIRE(errno == EPERM); + + close(fd); + close(fdx); +} + +ATF_TC_WITHOUT_HEAD(immutable_seals); +ATF_TC_BODY(immutable_seals, tc) +{ + int fd; + + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_SEAL) == 0); + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1); + ATF_REQUIRE_MSG(errno == EPERM, + "Added unique grow seal after restricting seals"); + + close(fd); + + /* + * Also check that adding a seal that already exists really doesn't + * do anything once we're sealed. + */ + ATF_REQUIRE((fd = memfd_create("...", MFD_ALLOW_SEALING)) != -1); + + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SEAL) == 0); + ATF_REQUIRE(fcntl(fd, F_ADD_SEALS, F_SEAL_GROW) == -1); + ATF_REQUIRE_MSG(errno == EPERM, + "Added duplicate grow seal after restricting seals"); + close(fd); +} + + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, basic); + ATF_TP_ADD_TC(tp, cloexec); + ATF_TP_ADD_TC(tp, disallowed_sealing); + ATF_TP_ADD_TC(tp, write_seal); + ATF_TP_ADD_TC(tp, mmap_write_seal); + ATF_TP_ADD_TC(tp, truncate_seals); + ATF_TP_ADD_TC(tp, get_seals); + ATF_TP_ADD_TC(tp, dup_seals); + ATF_TP_ADD_TC(tp, immutable_seals); + return (atf_no_error()); +} Index: usr.bin/kdump/kdump.c =================================================================== --- usr.bin/kdump/kdump.c +++ usr.bin/kdump/kdump.c @@ -1246,7 +1246,8 @@ ip++; narg--; break; - case SYS_shm_open: +#ifdef SYS_freebsd12_shm_open + case SYS_freebsd12_shm_open: print_number(ip, narg, c); putchar(','); print_mask_arg(sysdecode_open_flags, ip[0]); @@ -1255,6 +1256,7 @@ ip += 2; narg -= 2; break; +#endif case SYS_minherit: print_number(ip, narg, c); print_number(ip, narg, c);