11638Srgrimes/*- 21638Srgrimes * Copyright (c) 2006 nCircle Network Security, Inc. 31638Srgrimes * Copyright (c) 2007 Robert N. M. Watson 41638Srgrimes * All rights reserved. 51638Srgrimes * 61638Srgrimes * This software was developed by Robert N. M. Watson for the TrustedBSD 71638Srgrimes * Project under contract to nCircle Network Security, Inc. 81638Srgrimes * 91638Srgrimes * Redistribution and use in source and binary forms, with or without 101638Srgrimes * modification, are permitted provided that the following conditions 111638Srgrimes * are met: 12263142Seadler * 1. Redistributions of source code must retain the above copyright 131638Srgrimes * notice, this list of conditions and the following disclaimer. 141638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151638Srgrimes * notice, this list of conditions and the following disclaimer in the 161638Srgrimes * documentation and/or other materials provided with the distribution. 171638Srgrimes * 181638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 191638Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201638Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211638Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR, NCIRCLE NETWORK SECURITY, 221638Srgrimes * INC., OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 231638Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 241638Srgrimes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 251638Srgrimes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 261638Srgrimes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 271638Srgrimes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 281638Srgrimes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2950476Speter * 301638Srgrimes * $FreeBSD: releng/10.3/tools/regression/priv/priv_vfs_clearsugid.c 172106 2007-09-09 23:08:39Z rwatson $ 31169857Sdds */ 321638Srgrimes 331638Srgrimes/* 341638Srgrimes * There are three cases in which the file system will clear the setuid or 351638Srgrimes * setgid bits on a file when running unprivileged: 361638Srgrimes * 371638Srgrimes * - When the file is chown()'d and either of the uid or the gid is changed. 3884306Sru * (currently, only changing the file gid applies, as privilege is required 3984306Sru * to change the uid). 401638Srgrimes * 411638Srgrimes * - The file is written to successfully. 421638Srgrimes * 431638Srgrimes * - An extended attribute of the file is written to successfully. 4457731Ssheldonh * 4557731Ssheldonh * In each case, check that the flags are cleared if unprivileged, and that 461638Srgrimes * they aren't cleared if privileged. 471638Srgrimes * 481638Srgrimes * We can't use expect() as we're looking for side-effects rather than 491638Srgrimes * success/failure of the system call. 501638Srgrimes */ 51169857Sdds 52169857Sdds#include <sys/types.h> 531638Srgrimes#include <sys/extattr.h> 54169857Sdds#include <sys/stat.h> 55169857Sdds 56169857Sdds#include <err.h> 571638Srgrimes#include <fcntl.h> 581638Srgrimes#include <stdlib.h> 59169857Sdds#include <string.h> 60169857Sdds#include <unistd.h> 61169857Sdds 62169857Sdds#include "main.h" 63169857Sdds 64169857Sddsstatic char fpath[1024]; 65169857Sddsstatic int fpath_initialized; 66169857Sdds 67169857Sdds/* 68169857Sdds * If running as root, check that SUID is still set; otherwise, check that it 69169857Sdds * is not. 70169857Sdds */ 71169857Sddsstatic void 72169857Sddsconfirm_sugid(char *test_case, int asroot, int injail) 73169857Sdds{ 74169857Sdds struct stat sb; 75169857Sdds 76169857Sdds if (stat(fpath, &sb) < 0) { 77169857Sdds warn("%s stat(%s)", test_case, fpath); 78169857Sdds return; 79169857Sdds } 80169857Sdds if (asroot) { 81169857Sdds if (!(sb.st_mode & S_ISUID)) 82169857Sdds warnx("%s(root, %s): !SUID", test_case, injail ? 83169857Sdds "jail" : "!jail"); 84169857Sdds } else { 85169857Sdds if (sb.st_mode & S_ISUID) 86169857Sdds warnx("%s(!root, %s): SUID", test_case, injail ? 87169857Sdds "jail" : "!jail"); 88169857Sdds } 89169857Sdds} 90169857Sdds 911638Srgrimesint 921638Srgrimespriv_vfs_clearsugid_setup(int asroot, int injail, struct test *test) 931638Srgrimes{ 941638Srgrimes 951638Srgrimes setup_file("priv_vfs_clearsugid_setup: fpath", fpath, UID_OWNER, 961638Srgrimes GID_OTHER, 0600 | S_ISUID); 971638Srgrimes fpath_initialized = 1; 981638Srgrimes return (0); 991638Srgrimes} 10071895Sru 1011638Srgrimesvoid 1021638Srgrimespriv_vfs_clearsugid_chgrp(int asroot, int injail, struct test *test) 1031638Srgrimes{ 1041638Srgrimes 1051638Srgrimes if (chown(fpath, -1, asroot ? GID_WHEEL : GID_OWNER) < 0) 10682322Srwatson err(-1, "priv_vfs_clearsugid_chgrp(%s, %s): chrgrp", 10782322Srwatson asroot ? "root" : "!root", injail ? "jail" : "!jail"); 108169857Sdds confirm_sugid("priv_vfs_clearsugid_chgrp", asroot, injail); 109169857Sdds} 1101638Srgrimes 111169857Sdds#define EA_NAMESPACE EXTATTR_NAMESPACE_USER 1121638Srgrimes#define EA_NAME "clearsugid" 1131638Srgrimes#define EA_DATA "test" 1141638Srgrimes#define EA_SIZE (strlen(EA_DATA)) 1151638Srgrimes 1161638Srgrimesvoid 1171638Srgrimespriv_vfs_clearsugid_extattr(int asroot, int injail, struct test *test) 1181638Srgrimes{ 1191638Srgrimes 120169857Sdds if (extattr_set_file(fpath, EA_NAMESPACE, EA_NAME, EA_DATA, EA_SIZE) 121169857Sdds < 0) 122169857Sdds err(-1, 123169857Sdds "priv_vfs_clearsugid_extattr(%s, %s): extattr_set_file", 124169857Sdds asroot ? "root" : "!root", injail ? "jail" : "!jail"); 125169857Sdds confirm_sugid("priv_vfs_clearsugid_extattr", asroot, injail); 126169857Sdds} 127169857Sdds 128void 129priv_vfs_clearsugid_write(int asroot, int injail, struct test *test) 130{ 131 int fd; 132 133 fd = open(fpath, O_RDWR); 134 if (fd < 0) 135 err(-1, "priv_vfs_clearsugid_write(%s, %s): open", 136 asroot ? "root" : "!root", injail ? "jail" : "!jail"); 137 if (write(fd, EA_DATA, EA_SIZE) < 0) 138 err(-1, "priv_vfs_clearsugid_write(%s, %s): write", 139 asroot ? "root" : "!root", injail ? "jail" : "!jail"); 140 (void)close(fd); 141 confirm_sugid("priv_vfs_clearsugid_write", asroot, injail); 142} 143 144void 145priv_vfs_clearsugid_cleanup(int asroot, int injail, struct test *test) 146{ 147 148 if (fpath_initialized) { 149 (void)unlink(fpath); 150 fpath_initialized = 0; 151 } 152} 153