android13/external/ltp/testcases/kernel/syscalls/setns/setns01.c

176 lines
3.2 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) Linux Test Project, 2014-2020
*
* errno tests for setns(2) - reassociate thread with a namespace
*/
#define _GNU_SOURCE
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sched.h>
#include <pwd.h>
#include <string.h>
#include "config.h"
#include "tst_test.h"
#include "lapi/syscalls.h"
#include "setns.h"
static const char nobody_uid[] = "nobody";
static struct passwd *ltpuser;
static int regular_fd;
struct testcase_t {
const char *msg;
int fd;
int ns_type;
int exp_ret;
int exp_errno;
int skip;
void (*setup) (struct testcase_t *, int i);
void (*cleanup) (struct testcase_t *);
};
static void setup0(struct testcase_t *t, int i)
{
t->ns_type = ns_types[i];
}
static void setup1(struct testcase_t *t, int i)
{
t->ns_type = ns_types[i];
t->fd = regular_fd;
}
static void setup2(struct testcase_t *t, int i)
{
t->fd = ns_fds[i];
}
static void setup3(struct testcase_t *t, int i)
{
if (ns_total < 2) {
t->skip = 1;
return;
}
t->fd = ns_fds[i];
t->ns_type = ns_types[(i+1) % ns_total];
}
static void setup4(struct testcase_t *t, int i)
{
SAFE_SETEUID(ltpuser->pw_uid);
t->fd = ns_fds[i];
t->ns_type = ns_types[i];
}
static void cleanup4(LTP_ATTRIBUTE_UNUSED struct testcase_t *t)
{
SAFE_SETEUID(0);
}
static struct testcase_t tcases[] = {
{
.msg = "invalid fd",
.fd = -1,
.exp_ret = -1,
.exp_errno = EBADF,
.setup = setup0,
},
{
.msg = "regular file fd",
.exp_ret = -1,
.exp_errno = EINVAL,
.setup = setup1,
},
{
.msg = "invalid ns_type",
.ns_type = -1,
.exp_ret = -1,
.exp_errno = EINVAL,
.setup = setup2,
},
{
.msg = "mismatch ns_type/fd",
.exp_ret = -1,
.exp_errno = EINVAL,
.setup = setup3,
},
{
.msg = "without CAP_SYS_ADMIN",
.exp_ret = -1,
.exp_errno = EPERM,
.setup = setup4,
.cleanup = cleanup4,
}
};
static void test_setns(unsigned int testno)
{
int ret, i;
struct testcase_t *t = &tcases[testno];
for (i = 0; i < ns_total; i++) {
if (t->setup)
t->setup(t, i);
if (t->skip) {
tst_res(TCONF, "skip %s", t->msg);
continue;
}
tst_res(TINFO, "setns(%d, 0x%x)", t->fd, t->ns_type);
ret = tst_syscall(__NR_setns, t->fd, t->ns_type);
if (ret == t->exp_ret) {
if (ret == -1 && errno == t->exp_errno) {
tst_res(TPASS, "%s exp_errno=%d (%s)",
t->msg, t->exp_errno,
tst_strerrno(t->exp_errno));
} else {
tst_res(TFAIL|TERRNO, "%s exp_errno=%d (%s)",
t->msg, t->exp_errno,
tst_strerrno(t->exp_errno));
}
} else {
tst_res(TFAIL, "%s ret=%d expected=%d",
t->msg, ret, t->exp_ret);
}
if (t->cleanup)
t->cleanup(t);
}
}
static void setup(void)
{
/* runtime check if syscall is supported */
tst_syscall(__NR_setns, -1, 0);
init_available_ns();
if (ns_total == 0)
tst_brk(TCONF, "no ns types/proc entries");
ltpuser = SAFE_GETPWNAM(nobody_uid);
regular_fd = SAFE_OPEN("dummy", O_RDWR|O_CREAT, 0600);
SAFE_UNLINK("dummy");
}
static void cleanup(void)
{
close_ns_fds();
if (regular_fd)
SAFE_CLOSE(regular_fd);
}
static struct tst_test test = {
.tcnt = ARRAY_SIZE(tcases),
.test = test_setns,
.setup = setup,
.cleanup = cleanup,
.needs_root = 1,
.needs_tmpdir = 1,
};