1224653Sjonathan/*- 2224653Sjonathan * Copyright (c) 2009-2011 Robert N. M. Watson 3224653Sjonathan * Copyright (c) 2011 Jonathan Anderson 4224653Sjonathan * All rights reserved. 5224653Sjonathan * 6224653Sjonathan * Redistribution and use in source and binary forms, with or without 7224653Sjonathan * modification, are permitted provided that the following conditions 8224653Sjonathan * are met: 9224653Sjonathan * 1. Redistributions of source code must retain the above copyright 10224653Sjonathan * notice, this list of conditions and the following disclaimer. 11224653Sjonathan * 2. Redistributions in binary form must reproduce the above copyright 12224653Sjonathan * notice, this list of conditions and the following disclaimer in the 13224653Sjonathan * documentation and/or other materials provided with the distribution. 14224653Sjonathan * 15224653Sjonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16224653Sjonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17224653Sjonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18224653Sjonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19224653Sjonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20224653Sjonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21224653Sjonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22224653Sjonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23224653Sjonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24224653Sjonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25224653Sjonathan * SUCH DAMAGE. 26224653Sjonathan */ 27224653Sjonathan 28224653Sjonathan/* 29224653Sjonathan * Test that fcntl works in capability mode. 30224653Sjonathan */ 31224653Sjonathan 32224653Sjonathan#include <sys/cdefs.h> 33224653Sjonathan__FBSDID("$FreeBSD$"); 34224653Sjonathan 35224653Sjonathan#include <sys/types.h> 36263234Srwatson#include <sys/capsicum.h> 37224653Sjonathan#include <sys/errno.h> 38224653Sjonathan#include <sys/ipc.h> 39224653Sjonathan#include <sys/mman.h> 40224653Sjonathan#include <sys/socket.h> 41224653Sjonathan#include <sys/stat.h> 42224653Sjonathan#include <sys/sysctl.h> 43224653Sjonathan#include <sys/wait.h> 44224653Sjonathan 45224653Sjonathan#include <err.h> 46224653Sjonathan#include <fcntl.h> 47224653Sjonathan#include <stdio.h> 48224653Sjonathan#include <stdlib.h> 49224653Sjonathan#include <unistd.h> 50224653Sjonathan 51224653Sjonathan#include "cap_test.h" 52224653Sjonathan 53224653Sjonathan/* A filename->descriptor mapping. */ 54224653Sjonathanstruct fd { 55224653Sjonathan char *f_name; 56224653Sjonathan int f_fd; 57224653Sjonathan}; 58224653Sjonathan 59224653Sjonathan/* 60224653Sjonathan * Ensure that fcntl() works consistently for both regular file descriptors and 61224653Sjonathan * capability-wrapped ones. 62224653Sjonathan */ 63224653Sjonathanint 64224653Sjonathantest_fcntl(void) 65224653Sjonathan{ 66224653Sjonathan int success = PASSED; 67224653Sjonathan cap_rights_t rights = CAP_READ | CAP_FCNTL; 68224653Sjonathan 69224653Sjonathan /* 70224653Sjonathan * Open some files of different types, and wrap them in capabilities. 71224653Sjonathan */ 72224653Sjonathan struct fd files[] = { 73224653Sjonathan { "file", open("/etc/passwd", O_RDONLY) }, 74224653Sjonathan { "socket", socket(PF_LOCAL, SOCK_STREAM, 0) }, 75224653Sjonathan { "SHM", shm_open(SHM_ANON, O_RDWR, 0600) }, 76224653Sjonathan }; 77224653Sjonathan REQUIRE(files[0].f_fd); 78224653Sjonathan REQUIRE(files[1].f_fd); 79224653Sjonathan REQUIRE(files[2].f_fd); 80224653Sjonathan 81224653Sjonathan struct fd caps[] = { 82224653Sjonathan { "file cap", cap_new(files[0].f_fd, rights) }, 83224653Sjonathan { "socket cap", cap_new(files[1].f_fd, rights) }, 84224653Sjonathan { "SHM cap", cap_new(files[2].f_fd, rights) }, 85224653Sjonathan }; 86224653Sjonathan REQUIRE(caps[0].f_fd); 87224653Sjonathan REQUIRE(caps[1].f_fd); 88224653Sjonathan REQUIRE(caps[2].f_fd); 89224653Sjonathan 90224653Sjonathan struct fd all[] = { 91224653Sjonathan files[0], caps[0], 92224653Sjonathan files[1], caps[1], 93224653Sjonathan files[2], caps[2], 94224653Sjonathan }; 95224653Sjonathan const size_t len = sizeof(all) / sizeof(struct fd); 96224653Sjonathan 97224653Sjonathan REQUIRE(cap_enter()); 98224653Sjonathan 99224653Sjonathan /* 100224653Sjonathan * Ensure that we can fcntl() all the files that we opened above. 101224653Sjonathan */ 102224653Sjonathan for (size_t i = 0; i < len; i++) 103224653Sjonathan { 104224653Sjonathan struct fd f = all[i]; 105224653Sjonathan int cap; 106224653Sjonathan 107224653Sjonathan CHECK_SYSCALL_SUCCEEDS(fcntl, f.f_fd, F_GETFL, 0); 108224653Sjonathan REQUIRE(cap = cap_new(f.f_fd, CAP_READ)); 109224653Sjonathan if (fcntl(f.f_fd, F_GETFL, 0) == -1) 110224653Sjonathan FAIL("Error calling fcntl('%s', F_GETFL)", f.f_name); 111224653Sjonathan else 112224653Sjonathan CHECK_NOTCAPABLE(fcntl, cap, F_GETFL, 0); 113224653Sjonathan } 114224653Sjonathan 115224653Sjonathan return (success); 116224653Sjonathan} 117224653Sjonathan 118