Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Mar 2019 01:43:02 +0000 (UTC)
From:      Enji Cooper <ngie@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r345046 - in vendor/google/capsicum-test: . dist
Message-ID:  <201903120143.x2C1h2lm072839@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ngie
Date: Tue Mar 12 01:43:01 2019
New Revision: 345046
URL: https://svnweb.freebsd.org/changeset/base/345046

Log:
  Import capsicum-test into ^/vendor/google/capsicum-test/dist
  
  The following change imports google/capsicum-test@9333154 from GitHub, omitting
  the embedded version of googletest, as well as the incomplete libcasper.
  
  This test suite helps verify capsicum(3) support via functional tests
  written in the GoogleTest test framework.
  
  Kernel support for capsicum(4) is tested by side-effect of testing
  capsicum(3).
  
  NB: as discussed in a previous [closed] PR [1], the casper(3) tests are
  incomplete/buggy and will not pass on FreeBSD. Thus, I have no intention of
  integrating them into the build/test on FreeBSD as-is.
  
  The import command used was:
  ```
  curl -L https://github.com/google/capsicum-test/tarball/9333154 | tar --strip-components=1 -xvzf - -C dist/
  rm -Rf dist/*/
  ```
  
  1. https://github.com/google/capsicum-test/pull/26
  
  Reviewed by:	emaste (mentor)
  Differential Revision:	https://reviews.freebsd.org/D19261

Added:
  vendor/google/capsicum-test/
  vendor/google/capsicum-test/dist/
  vendor/google/capsicum-test/dist/.gitignore
  vendor/google/capsicum-test/dist/CONTRIBUTING.md
  vendor/google/capsicum-test/dist/GNUmakefile
  vendor/google/capsicum-test/dist/LICENSE
  vendor/google/capsicum-test/dist/README.md
  vendor/google/capsicum-test/dist/capability-fd-pair.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/capability-fd.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/capmode.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum-freebsd.h   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum-linux.h   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum-rights.h   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum-test-main.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum-test.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum-test.h   (contents, props changed)
  vendor/google/capsicum-test/dist/capsicum.h   (contents, props changed)
  vendor/google/capsicum-test/dist/fcntl.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/fexecve.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/ioctl.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/linux.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/makefile   (contents, props changed)
  vendor/google/capsicum-test/dist/mini-me.c   (contents, props changed)
  vendor/google/capsicum-test/dist/mqueue.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/openat.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/overhead.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/procdesc.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/rename.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/sctp.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/select.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/showrights   (contents, props changed)
  vendor/google/capsicum-test/dist/smoketest.c   (contents, props changed)
  vendor/google/capsicum-test/dist/socket.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/syscalls.h   (contents, props changed)
  vendor/google/capsicum-test/dist/sysctl.cc   (contents, props changed)
  vendor/google/capsicum-test/dist/waittest.c   (contents, props changed)

Added: vendor/google/capsicum-test/dist/.gitignore
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/.gitignore	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,19 @@
+capsicum-test
+mini-me
+mini-me.noexec
+mini-me.setuid
+mini-me.32
+mini-me.x32
+mini-me.64
+libgtest.a
+smoketest
+*.o
+libcap*.deb
+libcap*.dsc
+libcap*.tar.gz
+libcap*.changes
+casper*.deb
+casper*.dsc
+casper*.tar.gz
+casper*.changes
+libcaprights.a
\ No newline at end of file

Added: vendor/google/capsicum-test/dist/CONTRIBUTING.md
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/CONTRIBUTING.md	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,20 @@
+## Contributor License Agreement ##
+
+Contributions to any Google project must be accompanied by a Contributor
+License Agreement.  This is not a copyright **assignment**, it simply gives
+Google permission to use and redistribute your contributions as part of the
+project.
+
+  * If you are an individual writing original source code and you're sure you
+    own the intellectual property, then you'll need to sign an [individual
+    CLA][].
+
+  * If you work for a company that wants to allow you to contribute your work,
+    then you'll need to sign a [corporate CLA][].
+
+You generally only need to submit a CLA once, so if you've already submitted
+one (even if it was for a different project), you probably don't need to do it
+again.
+
+[individual CLA]: https://developers.google.com/open-source/cla/individual
+[corporate CLA]: https://developers.google.com/open-source/cla/corporate

Added: vendor/google/capsicum-test/dist/GNUmakefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/GNUmakefile	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,78 @@
+OS:=$(shell uname)
+
+# Set ARCH to 32 or x32 for i386/x32 ABIs
+ARCH?=64
+ARCHFLAG=-m$(ARCH)
+
+ifeq ($(OS),Linux)
+PROCESSOR:=$(shell uname -p)
+
+ifneq ($(wildcard /usr/lib/$(PROCESSOR)-linux-gnu),)
+# Can use standard Debian location for static libraries.
+PLATFORM_LIBDIR=/usr/lib/$(PROCESSOR)-linux-gnu
+else
+# Attempt to determine library location from gcc configuration.
+PLATFORM_LIBDIR=$(shell gcc -v 2>&1 | grep "Configured with:" | sed 's/.*--libdir=\(\/usr\/[^ ]*\).*/\1/g')
+endif
+
+# Override for explicitly specified ARCHFLAG.
+# Use locally compiled libcaprights in this case, on the
+# assumption that any installed version is 64-bit.
+ifeq ($(ARCHFLAG),-m32)
+PROCESSOR=i386
+PLATFORM_LIBDIR=/usr/lib32
+LIBCAPRIGHTS=./libcaprights.a
+endif
+ifeq ($(ARCHFLAG),-mx32)
+PROCESSOR=x32
+PLATFORM_LIBDIR=/usr/libx32
+LIBCAPRIGHTS=./libcaprights.a
+endif
+
+# Detect presence of libsctp in normal Debian location
+ifneq ($(wildcard $(PLATFORM_LIBDIR)/libsctp.a),)
+LIBSCTP=-lsctp
+CXXFLAGS=-DHAVE_SCTP
+endif
+
+ifneq ($(LIBCAPRIGHTS),)
+# Build local libcaprights.a (assuming ./configure
+# has already been done in libcaprights/)
+LOCAL_LIBS=$(LIBCAPRIGHTS)
+LIBCAPRIGHTS_OBJS=libcaprights/capsicum.o libcaprights/linux-bpf-capmode.o libcaprights/procdesc.o libcaprights/signal.o
+LOCAL_CLEAN=$(LOCAL_LIBS) $(LIBCAPRIGHTS_OBJS)
+else
+# Detect installed libcaprights static library.
+ifneq ($(wildcard $(PLATFORM_LIBDIR)/libcaprights.a),)
+LIBCAPRIGHTS=$(PLATFORM_LIBDIR)/libcaprights.a
+else
+ifneq ($(wildcard /usr/lib/libcaprights.a),)
+LIBCAPRIGHTS=/usr/lib/libcaprights.a
+endif
+endif
+endif
+
+endif
+
+# Extra test programs for arch-transition tests
+EXTRA_PROGS = mini-me.32 mini-me.64
+ifneq ($(wildcard /usr/include/gnu/stubs-x32.h),)
+EXTRA_PROGS += mini-me.x32
+endif
+
+# Chain on to the master makefile
+include makefile
+
+./libcaprights.a: $(LIBCAPRIGHTS_OBJS)
+	ar cr $@ $^
+
+# Small static programs of known architectures
+# These may require additional packages to be installed; for example, for Debian:
+#  - libc6-dev-i386 provides 32-bit headers for a 64-bit system
+#  - libc6-dev-x32 provides headers for the x32 ABI.
+mini-me.32: mini-me.c
+	$(CC) $(CFLAGS) -m32 -static -o $@ $<
+mini-me.x32: mini-me.c
+	$(CC) $(CFLAGS) -mx32 -static -o $@ $<
+mini-me.64: mini-me.c
+	$(CC) $(CFLAGS) -m64 -static -o $@ $<

Added: vendor/google/capsicum-test/dist/LICENSE
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/LICENSE	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,26 @@
+Copyright (c) 2009-2011 Robert N. M. Watson
+Copyright (c) 2011 Jonathan Anderson
+Copyright (C) 2012 The Chromium OS Authors <chromium-os-dev@chromium.org>
+Copyright (c) 2013-2014 Google Inc.
+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.

Added: vendor/google/capsicum-test/dist/README.md
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/README.md	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,62 @@
+# Capsicum User Space Tests
+
+This directory holds unit tests for [Capsicum](http://www.cl.cam.ac.uk/research/security/capsicum/)
+object-capabilities. The tests exercise the syscall interface to a Capsicum-enabled operating system,
+currently either [FreeBSD >=10.x](http://www.freebsd.org) or a modified Linux kernel (the
+[capsicum-linux](http://github.com/google/capsicum-linux) project).
+
+The tests are written in C++98, and use the [Google Test](https://code.google.com/p/googletest/)
+framework, with some additions to fork off particular tests (because a process that enters capability
+mode cannot leave it again).
+
+## Provenance
+
+The original basis for these tests was:
+
+ - [unit tests](https://github.com/freebsd/freebsd/tree/master/tools/regression/security/cap_test)
+   written by Robert Watson and Jonathan Anderson for the original FreeBSD 9.x Capsicum implementation
+ - [unit tests](http://git.chromium.org/gitweb/?p=chromiumos/third_party/kernel-capsicum.git;a=tree;f=tools/testing/capsicum_tests;hb=refs/heads/capsicum) written by Meredydd Luff for the original Capsicum-Linux port.
+
+These tests were coalesced and moved into an independent repository to enable
+comparative testing across multiple OSes, and then substantially extended.
+
+## OS Configuration
+
+### Linux
+
+The following kernel configuration options are needed to run the tests:
+
+ - `CONFIG_SECURITY_CAPSICUM`: enable the Capsicum framework
+ - `CONFIG_PROCDESC`: enable Capsicum process-descriptor functionality
+ - `CONFIG_DEBUG_FS`: enable debug filesystem
+ - `CONFIG_IP_SCTP`: enable SCTP support
+
+### FreeBSD (>= 10.x)
+
+The following kernel configuration options are needed so that all tests can run:
+
+  - `options P1003_1B_MQUEUE`: Enable POSIX message queues (or `kldload mqueuefs`)
+
+## Other Dependencies
+
+### Linux
+
+The following additional development packages are needed to build the full test suite on Linux.
+
+ - `libcaprights`: See below
+ - `libcap-dev`: Provides headers for POSIX.1e capabilities.
+ - `libsctp1`: Provides SCTP library functions.
+ - `libsctp-dev`: Provides headers for SCTP library functions.
+
+
+## Linux libcaprights
+
+The Capsicum userspace library is held in the `libcaprights/` subdirectory.  Ideally, this
+library should be built (with `./configure; make` or `dpkg-buildpackage -uc -us`) and
+installed (with `make install` or `dpkg -i libcaprights*.deb`) so that the tests will
+use behave like a normal Capsicum-aware application.
+
+However, if no installed copy of the library is found, the `GNUmakefile` will attempt
+to use the local `libcaprights/*.c` source; this requires `./configure` to have been
+performed in the `libcaprights` subdirectory. The local code is also used for
+cross-compiled builds of the test suite (e.g. `make ARCH=32` or `make ARCH=x32`).

Added: vendor/google/capsicum-test/dist/capability-fd-pair.cc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/capability-fd-pair.cc	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,188 @@
+// Tests involving 2 capability file descriptors.
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+#include "capsicum.h"
+#include "syscalls.h"
+#include "capsicum-test.h"
+
+TEST(CapabilityPair, sendfile) {
+  int in_fd = open(TmpFile("cap_sendfile_in"), O_CREAT|O_RDWR, 0644);
+  EXPECT_OK(write(in_fd, "1234", 4));
+  // Output fd for sendfile must be a stream socket in FreeBSD.
+  int sock_fds[2];
+  EXPECT_OK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds));
+
+  cap_rights_t r_rs;
+  cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
+  cap_rights_t r_ws;
+  cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
+
+  int cap_in_ro = dup(in_fd);
+  EXPECT_OK(cap_in_ro);
+  EXPECT_OK(cap_rights_limit(cap_in_ro, &r_rs));
+  int cap_in_wo = dup(in_fd);
+  EXPECT_OK(cap_in_wo);
+  EXPECT_OK(cap_rights_limit(cap_in_wo, &r_ws));
+  int cap_out_ro = dup(sock_fds[0]);
+  EXPECT_OK(cap_out_ro);
+  EXPECT_OK(cap_rights_limit(cap_out_ro, &r_rs));
+  int cap_out_wo = dup(sock_fds[0]);
+  EXPECT_OK(cap_out_wo);
+  EXPECT_OK(cap_rights_limit(cap_out_wo, &r_ws));
+
+  off_t offset = 0;
+  EXPECT_NOTCAPABLE(sendfile_(cap_out_ro, cap_in_ro, &offset, 4));
+  EXPECT_NOTCAPABLE(sendfile_(cap_out_wo, cap_in_wo, &offset, 4));
+  EXPECT_OK(sendfile_(cap_out_wo, cap_in_ro, &offset, 4));
+
+  close(cap_in_ro);
+  close(cap_in_wo);
+  close(cap_out_ro);
+  close(cap_out_wo);
+  close(in_fd);
+  close(sock_fds[0]);
+  close(sock_fds[1]);
+  unlink(TmpFile("cap_sendfile_in"));
+}
+
+#ifdef HAVE_TEE
+TEST(CapabilityPair, tee) {
+  int pipe1_fds[2];
+  EXPECT_OK(pipe2(pipe1_fds, O_NONBLOCK));
+  int pipe2_fds[2];
+  EXPECT_OK(pipe2(pipe2_fds, O_NONBLOCK));
+
+  // Put some data into pipe1.
+  unsigned char buffer[4] = {1, 2, 3, 4};
+  EXPECT_OK(write(pipe1_fds[1], buffer, 4));
+
+  cap_rights_t r_ro;
+  cap_rights_init(&r_ro, CAP_READ);
+  cap_rights_t r_wo;
+  cap_rights_init(&r_wo, CAP_WRITE);
+  cap_rights_t r_rw;
+  cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
+
+  // Various attempts to tee into pipe2.
+  int cap_in_wo = dup(pipe1_fds[0]);
+  EXPECT_OK(cap_in_wo);
+  EXPECT_OK(cap_rights_limit(cap_in_wo, &r_wo));
+  int cap_in_rw = dup(pipe1_fds[0]);
+  EXPECT_OK(cap_in_rw);
+  EXPECT_OK(cap_rights_limit(cap_in_rw, &r_rw));
+  int cap_out_ro = dup(pipe2_fds[1]);
+  EXPECT_OK(cap_out_ro);
+  EXPECT_OK(cap_rights_limit(cap_out_ro, &r_ro));
+  int cap_out_rw = dup(pipe2_fds[1]);
+  EXPECT_OK(cap_out_rw);
+  EXPECT_OK(cap_rights_limit(cap_out_rw, &r_rw));
+
+  EXPECT_NOTCAPABLE(tee(cap_in_wo, cap_out_rw, 4, SPLICE_F_NONBLOCK));
+  EXPECT_NOTCAPABLE(tee(cap_in_rw, cap_out_ro, 4, SPLICE_F_NONBLOCK));
+  EXPECT_OK(tee(cap_in_rw, cap_out_rw, 4, SPLICE_F_NONBLOCK));
+
+  close(cap_in_wo);
+  close(cap_in_rw);
+  close(cap_out_ro);
+  close(cap_out_rw);
+  close(pipe1_fds[0]);
+  close(pipe1_fds[1]);
+  close(pipe2_fds[0]);
+  close(pipe2_fds[1]);
+}
+#endif
+
+#ifdef HAVE_SPLICE
+TEST(CapabilityPair, splice) {
+  int pipe1_fds[2];
+  EXPECT_OK(pipe2(pipe1_fds, O_NONBLOCK));
+  int pipe2_fds[2];
+  EXPECT_OK(pipe2(pipe2_fds, O_NONBLOCK));
+
+  // Put some data into pipe1.
+  unsigned char buffer[4] = {1, 2, 3, 4};
+  EXPECT_OK(write(pipe1_fds[1], buffer, 4));
+
+  cap_rights_t r_ro;
+  cap_rights_init(&r_ro, CAP_READ);
+  cap_rights_t r_wo;
+  cap_rights_init(&r_wo, CAP_WRITE);
+  cap_rights_t r_rs;
+  cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
+  cap_rights_t r_ws;
+  cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
+
+  // Various attempts to splice.
+  int cap_in_wo = dup(pipe1_fds[0]);
+  EXPECT_OK(cap_in_wo);
+  EXPECT_OK(cap_rights_limit(cap_in_wo, &r_wo));
+  int cap_in_ro = dup(pipe1_fds[0]);
+  EXPECT_OK(cap_in_ro);
+  EXPECT_OK(cap_rights_limit(cap_in_ro, &r_ro));
+  int cap_in_ro_seek = dup(pipe1_fds[0]);
+  EXPECT_OK(cap_in_ro_seek);
+  EXPECT_OK(cap_rights_limit(cap_in_ro_seek, &r_rs));
+  int cap_out_wo = dup(pipe2_fds[1]);
+  EXPECT_OK(cap_out_wo);
+  EXPECT_OK(cap_rights_limit(cap_out_wo, &r_wo));
+  int cap_out_ro = dup(pipe2_fds[1]);
+  EXPECT_OK(cap_out_ro);
+  EXPECT_OK(cap_rights_limit(cap_out_ro, &r_ro));
+  int cap_out_wo_seek = dup(pipe2_fds[1]);
+  EXPECT_OK(cap_out_wo_seek);
+  EXPECT_OK(cap_rights_limit(cap_out_wo_seek, &r_ws));
+
+  EXPECT_NOTCAPABLE(splice(cap_in_ro, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
+  EXPECT_NOTCAPABLE(splice(cap_in_wo, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
+  EXPECT_NOTCAPABLE(splice(cap_in_ro_seek, NULL, cap_out_ro, NULL, 4, SPLICE_F_NONBLOCK));
+  EXPECT_NOTCAPABLE(splice(cap_in_ro_seek, NULL, cap_out_wo, NULL, 4, SPLICE_F_NONBLOCK));
+  EXPECT_OK(splice(cap_in_ro_seek, NULL, cap_out_wo_seek, NULL, 4, SPLICE_F_NONBLOCK));
+
+  close(cap_in_wo);
+  close(cap_in_ro);
+  close(cap_in_ro_seek);
+  close(cap_out_wo);
+  close(cap_out_ro);
+  close(cap_out_wo_seek);
+  close(pipe1_fds[0]);
+  close(pipe1_fds[1]);
+  close(pipe2_fds[0]);
+  close(pipe2_fds[1]);
+}
+#endif
+
+#ifdef HAVE_VMSPLICE
+// Although it only involves a single file descriptor, test vmsplice(2) here too.
+TEST(CapabilityPair, vmsplice) {
+  int pipe_fds[2];
+  EXPECT_OK(pipe2(pipe_fds, O_NONBLOCK));
+
+  cap_rights_t r_ro;
+  cap_rights_init(&r_ro, CAP_READ);
+  cap_rights_t r_rw;
+  cap_rights_init(&r_rw, CAP_READ, CAP_WRITE);
+
+  int cap_ro = dup(pipe_fds[1]);
+  EXPECT_OK(cap_ro);
+  EXPECT_OK(cap_rights_limit(cap_ro, &r_ro));
+  int cap_rw = dup(pipe_fds[1]);
+  EXPECT_OK(cap_rw);
+  EXPECT_OK(cap_rights_limit(cap_rw, &r_rw));
+
+  unsigned char buffer[4] = {1, 2, 3, 4};
+  struct iovec iov;
+  memset(&iov, 0, sizeof(iov));
+  iov.iov_base = buffer;
+  iov.iov_len = sizeof(buffer);
+
+  EXPECT_NOTCAPABLE(vmsplice(cap_ro, &iov, 1, SPLICE_F_NONBLOCK));
+  EXPECT_OK(vmsplice(cap_rw, &iov, 1, SPLICE_F_NONBLOCK));
+
+  close(cap_ro);
+  close(cap_rw);
+  close(pipe_fds[0]);
+  close(pipe_fds[1]);
+}
+#endif

Added: vendor/google/capsicum-test/dist/capability-fd.cc
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/google/capsicum-test/dist/capability-fd.cc	Tue Mar 12 01:43:01 2019	(r345046)
@@ -0,0 +1,1271 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <stdint.h>
+
+#include "capsicum.h"
+#include "syscalls.h"
+#include "capsicum-test.h"
+
+/* Utilities for printing rights information */
+/* Written in C style to allow for: */
+/* TODO(drysdale): migrate these to somewhere in libcaprights/ */
+#define RIGHTS_INFO(RR) { (RR), #RR}
+typedef struct {
+  uint64_t right;
+  const char* name;
+} right_info;
+right_info known_rights[] = {
+  /* Rights that are common to all versions of Capsicum */
+  RIGHTS_INFO(CAP_READ),
+  RIGHTS_INFO(CAP_WRITE),
+  RIGHTS_INFO(CAP_SEEK_TELL),
+  RIGHTS_INFO(CAP_SEEK),
+  RIGHTS_INFO(CAP_PREAD),
+  RIGHTS_INFO(CAP_PWRITE),
+  RIGHTS_INFO(CAP_MMAP),
+  RIGHTS_INFO(CAP_MMAP_R),
+  RIGHTS_INFO(CAP_MMAP_W),
+  RIGHTS_INFO(CAP_MMAP_X),
+  RIGHTS_INFO(CAP_MMAP_RW),
+  RIGHTS_INFO(CAP_MMAP_RX),
+  RIGHTS_INFO(CAP_MMAP_WX),
+  RIGHTS_INFO(CAP_MMAP_RWX),
+  RIGHTS_INFO(CAP_CREATE),
+  RIGHTS_INFO(CAP_FEXECVE),
+  RIGHTS_INFO(CAP_FSYNC),
+  RIGHTS_INFO(CAP_FTRUNCATE),
+  RIGHTS_INFO(CAP_LOOKUP),
+  RIGHTS_INFO(CAP_FCHDIR),
+  RIGHTS_INFO(CAP_FCHFLAGS),
+  RIGHTS_INFO(CAP_CHFLAGSAT),
+  RIGHTS_INFO(CAP_FCHMOD),
+  RIGHTS_INFO(CAP_FCHMODAT),
+  RIGHTS_INFO(CAP_FCHOWN),
+  RIGHTS_INFO(CAP_FCHOWNAT),
+  RIGHTS_INFO(CAP_FCNTL),
+  RIGHTS_INFO(CAP_FLOCK),
+  RIGHTS_INFO(CAP_FPATHCONF),
+  RIGHTS_INFO(CAP_FSCK),
+  RIGHTS_INFO(CAP_FSTAT),
+  RIGHTS_INFO(CAP_FSTATAT),
+  RIGHTS_INFO(CAP_FSTATFS),
+  RIGHTS_INFO(CAP_FUTIMES),
+  RIGHTS_INFO(CAP_FUTIMESAT),
+  RIGHTS_INFO(CAP_MKDIRAT),
+  RIGHTS_INFO(CAP_MKFIFOAT),
+  RIGHTS_INFO(CAP_MKNODAT),
+  RIGHTS_INFO(CAP_RENAMEAT_SOURCE),
+  RIGHTS_INFO(CAP_SYMLINKAT),
+  RIGHTS_INFO(CAP_UNLINKAT),
+  RIGHTS_INFO(CAP_ACCEPT),
+  RIGHTS_INFO(CAP_BIND),
+  RIGHTS_INFO(CAP_CONNECT),
+  RIGHTS_INFO(CAP_GETPEERNAME),
+  RIGHTS_INFO(CAP_GETSOCKNAME),
+  RIGHTS_INFO(CAP_GETSOCKOPT),
+  RIGHTS_INFO(CAP_LISTEN),
+  RIGHTS_INFO(CAP_PEELOFF),
+  RIGHTS_INFO(CAP_RECV),
+  RIGHTS_INFO(CAP_SEND),
+  RIGHTS_INFO(CAP_SETSOCKOPT),
+  RIGHTS_INFO(CAP_SHUTDOWN),
+  RIGHTS_INFO(CAP_BINDAT),
+  RIGHTS_INFO(CAP_CONNECTAT),
+  RIGHTS_INFO(CAP_LINKAT_SOURCE),
+  RIGHTS_INFO(CAP_RENAMEAT_TARGET),
+  RIGHTS_INFO(CAP_SOCK_CLIENT),
+  RIGHTS_INFO(CAP_SOCK_SERVER),
+  RIGHTS_INFO(CAP_MAC_GET),
+  RIGHTS_INFO(CAP_MAC_SET),
+  RIGHTS_INFO(CAP_SEM_GETVALUE),
+  RIGHTS_INFO(CAP_SEM_POST),
+  RIGHTS_INFO(CAP_SEM_WAIT),
+  RIGHTS_INFO(CAP_EVENT),
+  RIGHTS_INFO(CAP_KQUEUE_EVENT),
+  RIGHTS_INFO(CAP_IOCTL),
+  RIGHTS_INFO(CAP_TTYHOOK),
+  RIGHTS_INFO(CAP_PDWAIT),
+  RIGHTS_INFO(CAP_PDGETPID),
+  RIGHTS_INFO(CAP_PDKILL),
+  RIGHTS_INFO(CAP_EXTATTR_DELETE),
+  RIGHTS_INFO(CAP_EXTATTR_GET),
+  RIGHTS_INFO(CAP_EXTATTR_LIST),
+  RIGHTS_INFO(CAP_EXTATTR_SET),
+  RIGHTS_INFO(CAP_ACL_CHECK),
+  RIGHTS_INFO(CAP_ACL_DELETE),
+  RIGHTS_INFO(CAP_ACL_GET),
+  RIGHTS_INFO(CAP_ACL_SET),
+  RIGHTS_INFO(CAP_KQUEUE_CHANGE),
+  RIGHTS_INFO(CAP_KQUEUE),
+  /* Rights that are only present in some version or some OS, and so are #ifdef'ed */
+  /* LINKAT got split */
+#ifdef CAP_LINKAT
+  RIGHTS_INFO(CAP_LINKAT),
+#endif
+#ifdef CAP_LINKAT_SOURCE
+  RIGHTS_INFO(CAP_LINKAT_SOURCE),
+#endif
+#ifdef CAP_LINKAT_TARGET
+  RIGHTS_INFO(CAP_LINKAT_TARGET),
+#endif
+  /* Linux aliased some FD operations for pdgetpid/pdkill */
+#ifdef CAP_PDGETPID_FREEBSD
+  RIGHTS_INFO(CAP_PDGETPID_FREEBSD),
+#endif
+#ifdef CAP_PDKILL_FREEBSD
+  RIGHTS_INFO(CAP_PDKILL_FREEBSD),
+#endif
+  /* Linux-specific rights */
+#ifdef CAP_FSIGNAL
+  RIGHTS_INFO(CAP_FSIGNAL),
+#endif
+#ifdef CAP_EPOLL_CTL
+  RIGHTS_INFO(CAP_EPOLL_CTL),
+#endif
+#ifdef CAP_NOTIFY
+  RIGHTS_INFO(CAP_NOTIFY),
+#endif
+#ifdef CAP_SETNS
+  RIGHTS_INFO(CAP_SETNS),
+#endif
+#ifdef CAP_PERFMON
+  RIGHTS_INFO(CAP_PERFMON),
+#endif
+#ifdef CAP_BPF
+  RIGHTS_INFO(CAP_BPF),
+#endif
+  /* Rights in later versions of FreeBSD (>10.0) */
+};
+
+void ShowCapRights(FILE *out, int fd) {
+  size_t ii;
+  bool first = true;
+  cap_rights_t rights;
+  CAP_SET_NONE(&rights);
+  if (cap_rights_get(fd, &rights) < 0) {
+    fprintf(out, "Failed to get rights for fd %d: errno %d\n", fd, errno);
+    return;
+  }
+
+  /* First print out all known rights */
+  size_t num_known = (sizeof(known_rights)/sizeof(known_rights[0]));
+  for (ii = 0; ii < num_known; ii++) {
+    if (cap_rights_is_set(&rights, known_rights[ii].right)) {
+      if (!first) fprintf(out, ",");
+      first = false;
+      fprintf(out, "%s", known_rights[ii].name);
+    }
+  }
+  /* Now repeat the loop, clearing rights we know of; this needs to be
+   * a separate loop because some named rights overlap.
+   */
+  for (ii = 0; ii < num_known; ii++) {
+    cap_rights_clear(&rights, known_rights[ii].right);
+  }
+  /* The following relies on the internal structure of cap_rights_t to
+   * try to show rights we don't know about. */
+  for (ii = 0; ii < (size_t)CAPARSIZE(&rights); ii++) {
+    uint64_t bits = (rights.cr_rights[0] & 0x01ffffffffffffffULL);
+    if (bits != 0) {
+      uint64_t which = 1;
+      for (which = 1; which < 0x0200000000000000 ; which <<= 1) {
+        if (bits & which) {
+          if (!first) fprintf(out, ",");
+          fprintf(out, "CAP_RIGHT(%d, 0x%016llxULL)", (int)ii, (long long unsigned)which);
+        }
+      }
+    }
+  }
+  fprintf(out, "\n");
+}
+
+void ShowAllCapRights(FILE *out) {
+  int fd;
+  struct rlimit limits;
+  if (getrlimit(RLIMIT_NOFILE, &limits) != 0) {
+    fprintf(out, "Failed to getrlimit for max FDs: errno %d\n", errno);
+    return;
+  }
+  for (fd = 0; fd < (int)limits.rlim_cur; fd++) {
+    if (fcntl(fd, F_GETFD, 0) != 0) {
+      continue;
+    }
+    fprintf(out, "fd %d: ", fd);
+    ShowCapRights(out, fd);
+  }
+}
+
+FORK_TEST(Capability, CapNew) {
+  cap_rights_t r_rws;
+  cap_rights_init(&r_rws, CAP_READ, CAP_WRITE, CAP_SEEK);
+  cap_rights_t r_all;
+  CAP_SET_ALL(&r_all);
+
+  int cap_fd = dup(STDOUT_FILENO);
+  cap_rights_t rights;
+  CAP_SET_NONE(&rights);
+  EXPECT_OK(cap_rights_get(cap_fd, &rights));
+  EXPECT_RIGHTS_EQ(&r_all, &rights);
+
+  EXPECT_OK(cap_fd);
+  EXPECT_OK(cap_rights_limit(cap_fd, &r_rws));
+  if (cap_fd < 0) return;
+  int rc = write(cap_fd, "OK!\n", 4);
+  EXPECT_OK(rc);
+  EXPECT_EQ(4, rc);
+  EXPECT_OK(cap_rights_get(cap_fd, &rights));
+  EXPECT_RIGHTS_EQ(&r_rws, &rights);
+
+  // dup/dup2 should preserve rights.
+  int cap_dup = dup(cap_fd);
+  EXPECT_OK(cap_dup);
+  EXPECT_OK(cap_rights_get(cap_dup, &rights));
+  EXPECT_RIGHTS_EQ(&r_rws, &rights);
+  close(cap_dup);
+  EXPECT_OK(dup2(cap_fd, cap_dup));
+  EXPECT_OK(cap_rights_get(cap_dup, &rights));
+  EXPECT_RIGHTS_EQ(&r_rws, &rights);
+  close(cap_dup);
+#ifdef HAVE_DUP3
+  EXPECT_OK(dup3(cap_fd, cap_dup, 0));
+  EXPECT_OK(cap_rights_get(cap_dup, &rights));
+  EXPECT_RIGHTS_EQ(&r_rws, &rights);
+  close(cap_dup);
+#endif
+
+  // Try to get a disjoint set of rights in a sub-capability.
+  cap_rights_t r_rs;
+  cap_rights_init(&r_rs, CAP_READ, CAP_SEEK);
+  cap_rights_t r_rsmapchmod;
+  cap_rights_init(&r_rsmapchmod, CAP_READ, CAP_SEEK, CAP_MMAP, CAP_FCHMOD);
+  int cap_cap_fd = dup(cap_fd);
+  EXPECT_OK(cap_cap_fd);
+  EXPECT_NOTCAPABLE(cap_rights_limit(cap_cap_fd, &r_rsmapchmod));
+
+  // Dump rights info to stderr (mostly to ensure that Show[All]CapRights()
+  // is working.
+  ShowAllCapRights(stderr);
+
+  EXPECT_OK(close(cap_fd));
+}
+
+FORK_TEST(Capability, CapEnter) {
+  EXPECT_EQ(0, cap_enter());
+}
+
+FORK_TEST(Capability, BasicInterception) {
+  cap_rights_t r_0;
+  cap_rights_init(&r_0, 0);
+  int cap_fd = dup(1);
+  EXPECT_OK(cap_fd);
+  EXPECT_OK(cap_rights_limit(cap_fd, &r_0));
+
+  EXPECT_NOTCAPABLE(write(cap_fd, "", 0));
+
+  EXPECT_OK(cap_enter());  // Enter capability mode
+
+  EXPECT_NOTCAPABLE(write(cap_fd, "", 0));
+
+  // Create a new capability which does have write permission
+  cap_rights_t r_ws;
+  cap_rights_init(&r_ws, CAP_WRITE, CAP_SEEK);
+  int cap_fd2 = dup(1);
+  EXPECT_OK(cap_fd2);
+  EXPECT_OK(cap_rights_limit(cap_fd2, &r_ws));
+  EXPECT_OK(write(cap_fd2, "", 0));
+
+  // Tidy up.
+  if (cap_fd >= 0) close(cap_fd);
+  if (cap_fd2 >= 0) close(cap_fd2);
+}
+
+FORK_TEST_ON(Capability, OpenAtDirectoryTraversal, TmpFile("cap_openat_testfile")) {
+  int dir = open(tmpdir.c_str(), O_RDONLY);
+  EXPECT_OK(dir);
+
+  cap_enter();
+
+  int file = openat(dir, "cap_openat_testfile", O_RDONLY|O_CREAT, 0644);
+  EXPECT_OK(file);
+
+  // Test that we are confined to /tmp, and cannot
+  // escape using absolute paths or ../.
+  int new_file = openat(dir, "../dev/null", O_RDONLY);
+  EXPECT_EQ(-1, new_file);
+
+  new_file = openat(dir, "..", O_RDONLY);
+  EXPECT_EQ(-1, new_file);
+
+  new_file = openat(dir, "/dev/null", O_RDONLY);
+  EXPECT_EQ(-1, new_file);
+
+  new_file = openat(dir, "/", O_RDONLY);
+  EXPECT_EQ(-1, new_file);
+
+  // Tidy up.
+  close(file);
+  close(dir);
+}
+
+FORK_TEST_ON(Capability, FileInSync, TmpFile("cap_file_sync")) {
+  int fd = open(TmpFile("cap_file_sync"), O_RDWR|O_CREAT, 0644);
+  EXPECT_OK(fd);
+  const char* message = "Hello capability world";
+  EXPECT_OK(write(fd, message, strlen(message)));
+
+  cap_rights_t r_rsstat;
+  cap_rights_init(&r_rsstat, CAP_READ, CAP_SEEK, CAP_FSTAT);
+
+  int cap_fd = dup(fd);
+  EXPECT_OK(cap_fd);
+  EXPECT_OK(cap_rights_limit(cap_fd, &r_rsstat));
+  int cap_cap_fd = dup(cap_fd);
+  EXPECT_OK(cap_cap_fd);
+  EXPECT_OK(cap_rights_limit(cap_cap_fd, &r_rsstat));
+
+  EXPECT_OK(cap_enter());  // Enter capability mode.
+
+  // Changes to one file descriptor affect the others.
+  EXPECT_EQ(1, lseek(fd, 1, SEEK_SET));
+  EXPECT_EQ(1, lseek(fd, 0, SEEK_CUR));
+  EXPECT_EQ(1, lseek(cap_fd, 0, SEEK_CUR));
+  EXPECT_EQ(1, lseek(cap_cap_fd, 0, SEEK_CUR));
+  EXPECT_EQ(3, lseek(cap_fd, 3, SEEK_SET));
+  EXPECT_EQ(3, lseek(fd, 0, SEEK_CUR));
+  EXPECT_EQ(3, lseek(cap_fd, 0, SEEK_CUR));
+  EXPECT_EQ(3, lseek(cap_cap_fd, 0, SEEK_CUR));
+  EXPECT_EQ(5, lseek(cap_cap_fd, 5, SEEK_SET));
+  EXPECT_EQ(5, lseek(fd, 0, SEEK_CUR));
+  EXPECT_EQ(5, lseek(cap_fd, 0, SEEK_CUR));
+  EXPECT_EQ(5, lseek(cap_cap_fd, 0, SEEK_CUR));
+
+  close(cap_cap_fd);
+  close(cap_fd);
+  close(fd);
+}
+
+// Create a capability on /tmp that does not allow CAP_WRITE,
+// and check that this restriction is inherited through openat().
+FORK_TEST_ON(Capability, Inheritance, TmpFile("cap_openat_write_testfile")) {
+  int dir = open(tmpdir.c_str(), O_RDONLY);
+  EXPECT_OK(dir);
+
+  cap_rights_t r_rl;
+  cap_rights_init(&r_rl, CAP_READ, CAP_LOOKUP);
+
+  int cap_dir = dup(dir);
+  EXPECT_OK(cap_dir);
+  EXPECT_OK(cap_rights_limit(cap_dir, &r_rl));
+
+  const char *filename = "cap_openat_write_testfile";
+  int file = openat(dir, filename, O_WRONLY|O_CREAT, 0644);
+  EXPECT_OK(file);
+  EXPECT_EQ(5, write(file, "TEST\n", 5));
+  if (file >= 0) close(file);
+
+  EXPECT_OK(cap_enter());
+  file = openat(cap_dir, filename, O_RDONLY);
+  EXPECT_OK(file);
+
+  cap_rights_t rights;
+  cap_rights_init(&rights, 0);
+  EXPECT_OK(cap_rights_get(file, &rights));
+  EXPECT_RIGHTS_EQ(&r_rl, &rights);
+  if (file >= 0) close(file);
+
+  file = openat(cap_dir, filename, O_WRONLY|O_APPEND);
+  EXPECT_NOTCAPABLE(file);
+  if (file > 0) close(file);
+
+  if (dir > 0) close(dir);
+  if (cap_dir > 0) close(cap_dir);
+}
+
+
+// Ensure that, if the capability had enough rights for the system call to
+// pass, then it did. Otherwise, ensure that the errno is ENOTCAPABLE;
+// capability restrictions should kick in before any other error logic.
+#define CHECK_RIGHT_RESULT(result, rights, ...) do {    \
+  cap_rights_t rights_needed;                           \
+  cap_rights_init(&rights_needed, __VA_ARGS__);         \
+  if (cap_rights_contains(&rights, &rights_needed)) {   \
+    EXPECT_OK(result) << std::endl                      \
+                      << " need: " << rights_needed     \
+                      << std::endl                      \
+                      << " got:  " << rights;           \
+  } else {                                              \
+    EXPECT_EQ(-1, result) << " need: " << rights_needed \
+                          << std::endl                  \
+                          << " got:  "<< rights;        \
+    EXPECT_EQ(ENOTCAPABLE, errno);                      \
+  }                                                     \
+} while (0)
+
+#define EXPECT_MMAP_NOTCAPABLE(result) do {         \
+  void *rv = result;                                \
+  EXPECT_EQ(MAP_FAILED, rv);                        \
+  EXPECT_EQ(ENOTCAPABLE, errno);                    \
+  if (rv != MAP_FAILED) munmap(rv, getpagesize());  \
+} while (0)
+
+#define EXPECT_MMAP_OK(result) do {                     \
+  void *rv = result;                                    \
+  EXPECT_NE(MAP_FAILED, rv) << " with errno " << errno; \
+  if (rv != MAP_FAILED) munmap(rv, getpagesize());      \
+} while (0)
+
+
+// As above, but for the special mmap() case: unmap after successful mmap().
+#define CHECK_RIGHT_MMAP_RESULT(result, rights, ...) do { \
+  cap_rights_t rights_needed;                             \
+  cap_rights_init(&rights_needed, __VA_ARGS__);           \
+  if (cap_rights_contains(&rights, &rights_needed)) {     \
+    EXPECT_MMAP_OK(result);                               \
+  } else {                                                \
+    EXPECT_MMAP_NOTCAPABLE(result);                       \
+  }                                                       \
+} while (0)
+
+FORK_TEST_ON(Capability, Mmap, TmpFile("cap_mmap_operations")) {
+  int fd = open(TmpFile("cap_mmap_operations"), O_RDWR | O_CREAT, 0644);
+  EXPECT_OK(fd);
+  if (fd < 0) return;
+
+  cap_rights_t r_0;
+  cap_rights_init(&r_0, 0);
+  cap_rights_t r_mmap;
+  cap_rights_init(&r_mmap, CAP_MMAP);
+  cap_rights_t r_r;
+  cap_rights_init(&r_r, CAP_PREAD);
+  cap_rights_t r_rmmap;
+  cap_rights_init(&r_rmmap, CAP_PREAD, CAP_MMAP);
+
+  // If we're missing a capability, it will fail.
+  int cap_none = dup(fd);
+  EXPECT_OK(cap_none);
+  EXPECT_OK(cap_rights_limit(cap_none, &r_0));
+  int cap_mmap = dup(fd);
+  EXPECT_OK(cap_mmap);
+  EXPECT_OK(cap_rights_limit(cap_mmap, &r_mmap));
+  int cap_read = dup(fd);
+  EXPECT_OK(cap_read);
+  EXPECT_OK(cap_rights_limit(cap_read, &r_r));
+  int cap_both = dup(fd);
+  EXPECT_OK(cap_both);
+  EXPECT_OK(cap_rights_limit(cap_both, &r_rmmap));
+
+  EXPECT_OK(cap_enter());  // Enter capability mode.
+
+  EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_none, 0));
+  EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_mmap, 0));
+  EXPECT_MMAP_NOTCAPABLE(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_read, 0));
+
+  EXPECT_MMAP_OK(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE, cap_both, 0));
+
+  // A call with MAP_ANONYMOUS should succeed without any capability requirements.
+  EXPECT_MMAP_OK(mmap(NULL, getpagesize(), PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0));
+
+  EXPECT_OK(close(cap_both));
+  EXPECT_OK(close(cap_read));
+  EXPECT_OK(close(cap_mmap));
+  EXPECT_OK(close(cap_none));
+  EXPECT_OK(close(fd));
+}
+
+// Given a file descriptor, create a capability with specific rights and
+// make sure only those rights work.
+#define TRY_FILE_OPS(fd, ...) do {       \
+  cap_rights_t rights;                   \
+  cap_rights_init(&rights, __VA_ARGS__); \
+  TryFileOps((fd), rights);              \
+} while (0)
+
+static void TryFileOps(int fd, cap_rights_t rights) {
+  int cap_fd = dup(fd);
+  EXPECT_OK(cap_fd);
+  EXPECT_OK(cap_rights_limit(cap_fd, &rights));
+  if (cap_fd < 0) return;
+  cap_rights_t erights;
+  EXPECT_OK(cap_rights_get(cap_fd, &erights));
+  EXPECT_RIGHTS_EQ(&rights, &erights);
+
+  // Check creation of a capability from a capability.
+  int cap_cap_fd = dup(cap_fd);
+  EXPECT_OK(cap_cap_fd);
+  EXPECT_OK(cap_rights_limit(cap_cap_fd, &rights));
+  EXPECT_NE(cap_fd, cap_cap_fd);
+  EXPECT_OK(cap_rights_get(cap_cap_fd, &erights));
+  EXPECT_RIGHTS_EQ(&rights, &erights);
+  close(cap_cap_fd);
+
+  char ch;
+  CHECK_RIGHT_RESULT(read(cap_fd, &ch, sizeof(ch)), rights, CAP_READ, CAP_SEEK_ASWAS);
+
+  ssize_t len1 = pread(cap_fd, &ch, sizeof(ch), 0);
+  CHECK_RIGHT_RESULT(len1, rights, CAP_PREAD);
+  ssize_t len2 = pread(cap_fd, &ch, sizeof(ch), 0);
+  CHECK_RIGHT_RESULT(len2, rights, CAP_PREAD);
+  EXPECT_EQ(len1, len2);
+
+  CHECK_RIGHT_RESULT(write(cap_fd, &ch, sizeof(ch)), rights, CAP_WRITE, CAP_SEEK_ASWAS);
+  CHECK_RIGHT_RESULT(pwrite(cap_fd, &ch, sizeof(ch), 0), rights, CAP_PWRITE);
+  CHECK_RIGHT_RESULT(lseek(cap_fd, 0, SEEK_SET), rights, CAP_SEEK);
+
+#ifdef HAVE_CHFLAGS
+  // Note: this is not expected to work over NFS.
+  struct statfs sf;
+  EXPECT_OK(fstatfs(fd, &sf));
+  bool is_nfs = (strncmp("nfs", sf.f_fstypename, sizeof(sf.f_fstypename)) == 0);
+  if (!is_nfs) {
+    CHECK_RIGHT_RESULT(fchflags(cap_fd, UF_NODUMP), rights, CAP_FCHFLAGS);
+  }
+#endif
+
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_NONE, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_R);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_WRITE, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_W);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_EXEC, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_X);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_RW);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_EXEC, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_RX);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_EXEC | PROT_WRITE, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_WX);
+  CHECK_RIGHT_MMAP_RESULT(mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, cap_fd, 0),
+                          rights, CAP_MMAP_RWX);
+
+  CHECK_RIGHT_RESULT(fsync(cap_fd), rights, CAP_FSYNC);
+#ifdef HAVE_SYNC_FILE_RANGE
+  CHECK_RIGHT_RESULT(sync_file_range(cap_fd, 0, 1, 0), rights, CAP_FSYNC, CAP_SEEK);
+#endif
+
+  int rc = fcntl(cap_fd, F_GETFL);
+  CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
+  rc = fcntl(cap_fd, F_SETFL, rc);
+  CHECK_RIGHT_RESULT(rc, rights, CAP_FCNTL);
+
+  CHECK_RIGHT_RESULT(fchown(cap_fd, -1, -1), rights, CAP_FCHOWN);
+
+  CHECK_RIGHT_RESULT(fchmod(cap_fd, 0644), rights, CAP_FCHMOD);
+
+  CHECK_RIGHT_RESULT(flock(cap_fd, LOCK_SH), rights, CAP_FLOCK);
+  CHECK_RIGHT_RESULT(flock(cap_fd, LOCK_UN), rights, CAP_FLOCK);
+
+  CHECK_RIGHT_RESULT(ftruncate(cap_fd, 0), rights, CAP_FTRUNCATE);
+
+  struct stat sb;
+  CHECK_RIGHT_RESULT(fstat(cap_fd, &sb), rights, CAP_FSTAT);
+
+  struct statfs cap_sf;
+  CHECK_RIGHT_RESULT(fstatfs(cap_fd, &cap_sf), rights, CAP_FSTATFS);
+
+#ifdef HAVE_FPATHCONF
+  CHECK_RIGHT_RESULT(fpathconf(cap_fd, _PC_NAME_MAX), rights, CAP_FPATHCONF);
+#endif
+
+  CHECK_RIGHT_RESULT(futimes(cap_fd, NULL), rights, CAP_FUTIMES);
+
+  struct pollfd pollfd;
+  pollfd.fd = cap_fd;
+  pollfd.events = POLLIN | POLLERR | POLLHUP;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201903120143.x2C1h2lm072839>