t_link.c revision 1.4
1/* $NetBSD: t_link.c,v 1.4 2022/03/30 14:24:50 christos Exp $ */ 2 3/*- 4 * Copyright (c) 2022 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/param.h> 33#include <sys/stat.h> 34#include <sys/time.h> 35#include <sys/sysctl.h> 36 37#include <atf-c.h> 38#include <libgen.h> 39#include <limits.h> 40#include <unistd.h> 41#include <stdbool.h> 42 43#include <rump/rump_syscalls.h> 44#include <rump/rump.h> 45 46#include "../common/h_fsmacros.h" 47#include "h_macros.h" 48 49#define USES_OWNER \ 50 if (FSTYPE_MSDOS(tc)) \ 51 atf_tc_skip("owner not supported by file system") 52#define USES_USERLEVEL \ 53 if (FSTYPE_PUFFS(tc) || FSTYPE_P2K_FFS(tc)) \ 54 atf_tc_skip("userlevel pass not supported, " \ 55 "since sysctl might not be set in underlying system") 56#define USES_OWNCHECK \ 57 if (FSTYPE_ZFS(tc)) \ 58 atf_tc_skip("zfs not supported since it has its " \ 59 "own rules for hardlinks") 60 61 62static void 63hardlink(const atf_tc_t *tc, const char *mp, uid_t u1, uid_t u2, 64 bool sysctl, bool allowed) 65{ 66 const char name[] = "foo"; 67 const char link[] = "bar"; 68 int one = 1, fd; 69 70 USES_OWNER; 71 USES_USERLEVEL; 72 USES_OWNCHECK; 73 74 FSTEST_ENTER(); 75 76 if (sysctl) { 77 if (sysctlbyname( 78 "security.models.extensions.hardlink_check_uid", 79 NULL, 0, &one, sizeof(one)) == -1) 80 atf_tc_fail_errno("sysctlbyname"); 81 } 82 83 rump_pub_lwproc_rfork(RUMP_RFCFDG); 84 if (rump_sys_chmod(".", 0777) == -1) 85 atf_tc_fail_errno("chmod"); 86 if (rump_sys_setuid(u1) == -1) 87 atf_tc_fail_errno("setuid"); 88 if ((fd = rump_sys_open(name, O_RDWR|O_CREAT, 0666)) == -1) 89 atf_tc_fail_errno("open"); 90 if (rump_sys_close(fd) == -1) 91 atf_tc_fail_errno("close"); 92 rump_pub_lwproc_releaselwp(); 93 94 rump_pub_lwproc_rfork(RUMP_RFCFDG); 95 if (rump_sys_setuid(u2) == -1) 96 atf_tc_fail_errno("setuid"); 97 if (rump_sys_link(name, link) == -1) { 98 if (errno != EOPNOTSUPP && allowed) 99 atf_tc_fail_errno("link"); 100 } else { 101 if (!allowed) 102 atf_tc_fail("failed to disallow hard link"); 103 } 104 rump_pub_lwproc_releaselwp(); 105 106 FSTEST_EXIT(); 107} 108 109 110static void 111hardlink_sameuser(const atf_tc_t *tc, const char *mp) 112{ 113 hardlink(tc, mp, 1, 1, false, true); 114} 115 116static void 117hardlink_sameuser_sysctl(const atf_tc_t *tc, const char *mp) 118{ 119 hardlink(tc, mp, 1, 1, true, true); 120} 121 122static void 123hardlink_otheruser(const atf_tc_t *tc, const char *mp) 124{ 125 hardlink(tc, mp, 1, 2, false, true); 126} 127 128static void 129hardlink_otheruser_sysctl(const atf_tc_t *tc, const char *mp) 130{ 131 hardlink(tc, mp, 1, 2, true, false); 132} 133 134static void 135hardlink_rootuser(const atf_tc_t *tc, const char *mp) 136{ 137 hardlink(tc, mp, 1, 0, false, true); 138} 139 140static void 141hardlink_rootuser_sysctl(const atf_tc_t *tc, const char *mp) 142{ 143 hardlink(tc, mp, 1, 0, true, true); 144} 145 146ATF_TC_FSAPPLY(hardlink_sameuser, "hardlink same user allowed"); 147ATF_TC_FSAPPLY(hardlink_sameuser_sysctl, "hardlink same user sysctl allowed"); 148ATF_TC_FSAPPLY(hardlink_otheruser, "hardlink other user allowed"); 149ATF_TC_FSAPPLY(hardlink_otheruser_sysctl, "hardlink other user sysctl denied"); 150ATF_TC_FSAPPLY(hardlink_rootuser, "hardlink root user allowed"); 151ATF_TC_FSAPPLY(hardlink_rootuser_sysctl, "hardlink root user sysctl allowed"); 152 153ATF_TP_ADD_TCS(tp) 154{ 155 ATF_TP_FSAPPLY(hardlink_sameuser); 156 ATF_TP_FSAPPLY(hardlink_sameuser_sysctl); 157 ATF_TP_FSAPPLY(hardlink_otheruser); 158 ATF_TP_FSAPPLY(hardlink_otheruser_sysctl); 159 ATF_TP_FSAPPLY(hardlink_rootuser); 160 ATF_TP_FSAPPLY(hardlink_rootuser_sysctl); 161 162 return atf_no_error(); 163} 164