/*
* Copyright (c) International Business Machines Corp., 2001
* Copyright (c) 2018 Xiao Yang <yangx.jy@cn.fujitsu.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*/
/*
* DESCRIPTION
* 1) Call sysctl(2) as a root user, and attempt to write data
* to the kernel_table[]. Since the table does not have write
* permissions even for the root, it should fail EPERM.
* 2) Call sysctl(2) as a non-root user, and attempt to write data
* to the kernel_table[]. Since the table does not have write
* permission for the regular user, it should fail with EPERM.
*
* NOTE: There is a documentation bug in 2.6.33-rc1 where unfortunately
* the behavior of sysctl(2) isn't properly documented, as discussed
* in detail in the following thread:
* http://sourceforge.net/mailarchive/message.php?msg_name=4B7BA24F.2010705%40linux.vnet.ibm.com.
*
* The documentation bug is filed as:
* https://bugzilla.kernel.org/show_bug.cgi?id=15446 . If you want the
* message removed, please ask your fellow kernel maintainer to fix their
* documentation.
*
* Thanks!
* -Ngie
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/sysctl.h>
#include <pwd.h>
#include "tst_test.h"
#include "lapi/syscalls.h"
static int exp_eno;
static void verify_sysctl(void)
{
char *osname = "Linux";
int name[] = {CTL_KERN, KERN_OSTYPE};
struct __sysctl_args args = {
.name = name,
.nlen = ARRAY_SIZE(name),
.newval = osname,
.newlen = sizeof(osname),
};
TEST(tst_syscall(__NR__sysctl, &args));
if (TST_RET != -1) {
tst_res(TFAIL, "sysctl(2) succeeded unexpectedly");
return;
}
if (TST_ERR == exp_eno) {
tst_res(TPASS | TTERRNO, "Got expected error");
} else {
tst_res(TFAIL | TTERRNO, "Got unexpected error, expected %s",
tst_strerrno(exp_eno));
}
}
static void setup(void)
{
if ((tst_kvercmp(2, 6, 32)) <= 0) {
exp_eno = EPERM;
} else {
/* Look above this warning. */
tst_res(TINFO,
"this test's results are based on potentially undocumented behavior in the kernel. read the NOTE in the source file for more details");
exp_eno = EACCES;
}
}
static void do_test(void)
{
pid_t pid;
struct passwd *ltpuser;
pid = SAFE_FORK();
if (!pid) {
ltpuser = SAFE_GETPWNAM("nobody");
SAFE_SETUID(ltpuser->pw_uid);
verify_sysctl();
} else {
verify_sysctl();
tst_reap_children();
}
}
static struct tst_test test = {
.needs_root = 1,
.forks_child = 1,
.setup = setup,
.test_all = do_test,
};