1 /* 2 * Copyright (C) 2013 Linux Test Project, Inc. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of version 2 of the GNU General Public 6 * License as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * Further, this software is distributed without any warranty that it 13 * is free of the rightful claim of any third person regarding 14 * infringement or the like. Any license provided herein, whether 15 * implied or otherwise, applies only to this software file. Patent 16 * licenses, if any, provided herein do not apply to combinations of 17 * this program with other software, or any other product whatsoever. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 22 * 02110-1301, USA. 23 */ 24 /* 25 * errno tests for setns(2) - reassociate thread with a namespace 26 */ 27 #define _GNU_SOURCE 28 #include <sys/stat.h> 29 #include <sys/syscall.h> 30 #include <sys/types.h> 31 #include <errno.h> 32 #include <sched.h> 33 #include <pwd.h> 34 #include <string.h> 35 #include "config.h" 36 #include "test.h" 37 #include "linux_syscall_numbers.h" 38 #include "safe_macros.h" 39 40 char *TCID = "setns01"; 41 42 #if defined(__NR_setns) 43 #include "setns.h" 44 45 struct testcase_t { 46 const char *msg; 47 int fd; 48 int ns_type; 49 int exp_ret; 50 int exp_errno; 51 int skip; 52 void (*setup) (struct testcase_t *, int i); 53 void (*cleanup) (struct testcase_t *); 54 }; 55 56 static void setup(void); 57 static void cleanup(void); 58 static void setup0(struct testcase_t *, int); 59 static void setup1(struct testcase_t *, int); 60 static void setup2(struct testcase_t *, int); 61 static void setup3(struct testcase_t *, int); 62 static void setup4(struct testcase_t *, int); 63 static void cleanup1(struct testcase_t *); 64 static void cleanup4(struct testcase_t *); 65 66 struct testcase_t tdat[] = { 67 { 68 .msg = "invalid fd", 69 .fd = -1, 70 .exp_ret = -1, 71 .exp_errno = EBADF, 72 .setup = setup0, 73 }, 74 { 75 .msg = "regular file fd", 76 .exp_ret = -1, 77 .exp_errno = EINVAL, 78 .setup = setup1, 79 .cleanup = cleanup1 80 }, 81 { 82 .msg = "invalid ns_type", 83 .ns_type = -1, 84 .exp_ret = -1, 85 .exp_errno = EINVAL, 86 .setup = setup2, 87 }, 88 { 89 .msg = "mismatch ns_type/fd", 90 .exp_ret = -1, 91 .exp_errno = EINVAL, 92 .setup = setup3, 93 }, 94 { 95 .msg = "without CAP_SYS_ADMIN", 96 .exp_ret = -1, 97 .exp_errno = EPERM, 98 .setup = setup4, 99 .cleanup = cleanup4, 100 } 101 }; 102 103 static int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); 104 static const char nobody_uid[] = "nobody"; 105 static struct passwd *ltpuser; 106 107 static void setup0(struct testcase_t *t, int i) 108 { 109 t->ns_type = ns_types[i]; 110 } 111 112 static void setup1(struct testcase_t *t, int i) 113 { 114 t->ns_type = ns_types[i]; 115 t->fd = open("dummy", O_RDWR|O_CREAT, 0600); 116 if (t->fd == -1) 117 tst_brkm(TFAIL|TERRNO, cleanup, "setup1:open failed"); 118 unlink("dummy"); 119 } 120 121 static void cleanup1(struct testcase_t *t) 122 { 123 close(t->fd); 124 } 125 126 static void setup2(struct testcase_t *t, int i) 127 { 128 t->fd = ns_fds[i]; 129 } 130 131 static void setup3(struct testcase_t *t, int i) 132 { 133 if (ns_total < 2) { 134 t->skip = 1; 135 return; 136 } 137 138 t->fd = ns_fds[i]; 139 t->ns_type = ns_types[(i+1) % ns_total]; 140 } 141 142 static void setup4(struct testcase_t *t, int i) 143 { 144 if (seteuid(ltpuser->pw_uid) == -1) 145 tst_brkm(TBROK | TERRNO, NULL, "seteuid failed"); 146 147 t->fd = ns_fds[i]; 148 t->ns_type = ns_types[i]; 149 } 150 151 static void cleanup4(struct testcase_t *t) 152 { 153 if (seteuid(0) == -1) 154 tst_brkm(TBROK | TERRNO, NULL, "seteuid restore failed"); 155 } 156 157 static void test_setns(struct testcase_t *t) 158 { 159 int ret, i; 160 161 for (i = 0; i < ns_total; i++) { 162 if (t->setup) 163 t->setup(t, i); 164 165 if (t->skip) { 166 tst_resm(TINFO, "skip %s", tdat->msg); 167 continue; 168 } 169 170 tst_resm(TINFO, "setns(%d, 0x%x)", t->fd, t->ns_type); 171 ret = syscall(__NR_setns, t->fd, t->ns_type); 172 if (ret == t->exp_ret) { 173 if (ret == -1 && errno == t->exp_errno) 174 tst_resm(TPASS, "%s exp_errno=%d", t->msg, 175 t->exp_errno); 176 else 177 tst_resm(TFAIL|TERRNO, "%s exp_errno=%d", 178 t->msg, t->exp_errno); 179 } else { 180 tst_resm(TFAIL, "%s ret=%d expected=%d", t->msg, 181 ret, t->exp_ret); 182 } 183 184 if (t->cleanup) 185 t->cleanup(t); 186 } 187 } 188 189 int main(int argc, char *argv[]) 190 { 191 int lc, testno; 192 193 tst_parse_opts(argc, argv, NULL, NULL); 194 195 setup(); 196 for (lc = 0; TEST_LOOPING(lc); lc++) { 197 for (testno = 0; testno < TST_TOTAL; testno++) 198 test_setns(&tdat[testno]); 199 } 200 cleanup(); 201 tst_exit(); 202 } 203 204 static void setup(void) 205 { 206 tst_require_root(); 207 208 /* runtime check if syscall is supported */ 209 ltp_syscall(__NR_setns, -1, 0); 210 211 init_available_ns(); 212 if (ns_total == 0) 213 tst_brkm(TCONF, NULL, "no ns types/proc entries"); 214 215 ltpuser = getpwnam(nobody_uid); 216 if (ltpuser == NULL) 217 tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed"); 218 219 220 tst_tmpdir(); 221 TEST_PAUSE; 222 } 223 224 static void cleanup(void) 225 { 226 close_ns_fds(); 227 tst_rmdir(); 228 } 229 #else 230 int main(int argc, char *argv[]) 231 { 232 tst_brkm(TCONF, NULL, "__NR_setns is not defined on your system."); 233 234 } 235 #endif 236