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 "lapi/syscalls.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 SAFE_SETEUID(NULL, ltpuser->pw_uid); 145 146 t->fd = ns_fds[i]; 147 t->ns_type = ns_types[i]; 148 } 149 150 static void cleanup4(struct testcase_t *t) 151 { 152 SAFE_SETEUID(NULL, 0); 153 } 154 155 static void test_setns(struct testcase_t *t) 156 { 157 int ret, i; 158 159 for (i = 0; i < ns_total; i++) { 160 if (t->setup) 161 t->setup(t, i); 162 163 if (t->skip) { 164 tst_resm(TINFO, "skip %s", tdat->msg); 165 continue; 166 } 167 168 tst_resm(TINFO, "setns(%d, 0x%x)", t->fd, t->ns_type); 169 ret = syscall(__NR_setns, t->fd, t->ns_type); 170 if (ret == t->exp_ret) { 171 if (ret == -1 && errno == t->exp_errno) 172 tst_resm(TPASS, "%s exp_errno=%d", t->msg, 173 t->exp_errno); 174 else 175 tst_resm(TFAIL|TERRNO, "%s exp_errno=%d", 176 t->msg, t->exp_errno); 177 } else { 178 tst_resm(TFAIL, "%s ret=%d expected=%d", t->msg, 179 ret, t->exp_ret); 180 } 181 182 if (t->cleanup) 183 t->cleanup(t); 184 } 185 } 186 187 int main(int argc, char *argv[]) 188 { 189 int lc, testno; 190 191 tst_parse_opts(argc, argv, NULL, NULL); 192 193 setup(); 194 for (lc = 0; TEST_LOOPING(lc); lc++) { 195 for (testno = 0; testno < TST_TOTAL; testno++) 196 test_setns(&tdat[testno]); 197 } 198 cleanup(); 199 tst_exit(); 200 } 201 202 static void setup(void) 203 { 204 tst_require_root(); 205 206 /* runtime check if syscall is supported */ 207 ltp_syscall(__NR_setns, -1, 0); 208 209 init_available_ns(); 210 if (ns_total == 0) 211 tst_brkm(TCONF, NULL, "no ns types/proc entries"); 212 213 ltpuser = getpwnam(nobody_uid); 214 if (ltpuser == NULL) 215 tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed"); 216 217 218 tst_tmpdir(); 219 TEST_PAUSE; 220 } 221 222 static void cleanup(void) 223 { 224 close_ns_fds(); 225 tst_rmdir(); 226 } 227 #else 228 int main(int argc, char *argv[]) 229 { 230 tst_brkm(TCONF, NULL, "__NR_setns is not defined on your system."); 231 232 } 233 #endif 234