2012-03-02 14:01:57 +04:00
|
|
|
#include <unistd.h>
|
2014-09-29 22:04:25 +04:00
|
|
|
#include <linux/netlink.h>
|
2012-03-02 14:01:57 +04:00
|
|
|
#include <sys/socket.h>
|
2012-04-05 15:43:00 +04:00
|
|
|
#include <sys/types.h>
|
2012-07-11 09:45:32 +04:00
|
|
|
#include <sys/eventfd.h>
|
2012-07-11 09:55:10 +04:00
|
|
|
#include <sys/epoll.h>
|
2012-07-11 10:26:46 +04:00
|
|
|
#include <sys/inotify.h>
|
2012-08-02 12:27:45 +04:00
|
|
|
#include <sys/signalfd.h>
|
2013-03-25 23:39:50 +04:00
|
|
|
#include <sys/ptrace.h>
|
|
|
|
#include <sys/wait.h>
|
2014-09-29 22:04:25 +04:00
|
|
|
#include <sys/socket.h>
|
2012-04-05 15:43:00 +04:00
|
|
|
#include <fcntl.h>
|
2012-08-02 12:27:45 +04:00
|
|
|
#include <signal.h>
|
2012-12-04 16:35:58 +03:00
|
|
|
#include <linux/if.h>
|
2012-09-12 20:00:56 +04:00
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <termios.h>
|
|
|
|
|
2012-04-05 15:43:00 +04:00
|
|
|
#include "proc_parse.h"
|
2012-03-02 14:01:57 +04:00
|
|
|
#include "sockets.h"
|
2012-03-02 14:01:08 +04:00
|
|
|
#include "crtools.h"
|
|
|
|
#include "log.h"
|
2013-07-29 12:43:30 +04:00
|
|
|
#include "util-pie.h"
|
2012-04-05 14:29:00 +04:00
|
|
|
#include "syscall.h"
|
2013-11-14 19:19:53 +04:00
|
|
|
#include "prctl.h"
|
2012-05-03 15:21:37 +04:00
|
|
|
#include "files.h"
|
|
|
|
#include "sk-inet.h"
|
2012-07-11 09:45:32 +04:00
|
|
|
#include "proc_parse.h"
|
2012-09-02 01:04:14 +04:00
|
|
|
#include "mount.h"
|
2012-09-12 20:00:56 +04:00
|
|
|
#include "tty.h"
|
2013-03-25 23:39:50 +04:00
|
|
|
#include "ptrace.h"
|
2013-04-15 13:24:32 +04:00
|
|
|
#include "kerndat.h"
|
2014-08-06 20:31:46 +04:00
|
|
|
#include "timerfd.h"
|
2013-08-23 19:18:47 +04:00
|
|
|
#include "tun.h"
|
2014-04-21 18:23:41 +04:00
|
|
|
#include "namespaces.h"
|
|
|
|
#include "pstree.h"
|
2014-04-25 08:22:00 +04:00
|
|
|
#include "cr_options.h"
|
2012-09-12 20:00:56 +04:00
|
|
|
|
|
|
|
static int check_tty(void)
|
|
|
|
{
|
|
|
|
int master = -1, slave = -1;
|
|
|
|
const int lock = 1;
|
|
|
|
struct termios t;
|
|
|
|
char *slavename;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (ARRAY_SIZE(t.c_cc) < TERMIOS_NCC) {
|
|
|
|
pr_msg("struct termios has %d @c_cc while "
|
|
|
|
"at least %d expected.\n",
|
|
|
|
(int)ARRAY_SIZE(t.c_cc),
|
|
|
|
TERMIOS_NCC);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
master = open("/dev/ptmx", O_RDWR);
|
|
|
|
if (master < 0) {
|
|
|
|
pr_msg("Can't open master pty.\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(master, TIOCSPTLCK, &lock)) {
|
|
|
|
pr_msg("Unable to lock pty device.\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
slavename = ptsname(master);
|
|
|
|
slave = open(slavename, O_RDWR);
|
|
|
|
if (slave < 0) {
|
|
|
|
if (errno != EIO) {
|
|
|
|
pr_msg("Unexpected error code on locked pty.\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pr_msg("Managed to open locked pty.\n");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
out:
|
|
|
|
close_safe(&master);
|
|
|
|
close_safe(&slave);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-03-02 14:01:57 +04:00
|
|
|
|
|
|
|
static int check_map_files(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = access("/proc/self/map_files", R_OK);
|
|
|
|
if (!ret)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_msg("/proc/<pid>/map_files directory is missing.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-09-29 22:04:25 +04:00
|
|
|
#ifndef NETLINK_SOCK_DIAG
|
|
|
|
#define NETLINK_SOCK_DIAG NETLINK_INET_DIAG
|
|
|
|
#endif
|
|
|
|
|
2012-03-02 14:01:57 +04:00
|
|
|
static int check_sock_diag(void)
|
|
|
|
{
|
|
|
|
int ret;
|
2014-09-29 22:04:25 +04:00
|
|
|
struct ns_id ns;
|
|
|
|
|
|
|
|
ns.pid = 0;
|
|
|
|
ns.net.nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_SOCK_DIAG);
|
|
|
|
if (ns.net.nlsk < 0) {
|
|
|
|
pr_perror("Can't make diag socket for check");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-03-02 14:01:57 +04:00
|
|
|
|
2014-09-29 22:04:25 +04:00
|
|
|
ret = collect_sockets(&ns);
|
2012-03-02 14:01:57 +04:00
|
|
|
if (!ret)
|
|
|
|
return 0;
|
|
|
|
|
2013-03-26 19:36:26 +04:00
|
|
|
pr_msg("The sock diag infrastructure is incomplete.\n");
|
|
|
|
pr_msg("Make sure you have:\n");
|
|
|
|
pr_msg(" 1. *_DIAG kernel config options turned on;\n");
|
|
|
|
pr_msg(" 2. *_diag.ko modules loaded (if compiled as modules).\n");
|
2012-03-02 14:01:57 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_ns_last_pid(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2014-06-05 20:16:41 +04:00
|
|
|
ret = access("/proc/" LAST_PID_PATH, W_OK);
|
2012-03-02 14:01:57 +04:00
|
|
|
if (!ret)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_msg("%s sysctl is missing.\n", LAST_PID_PATH);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_sock_peek_off(void)
|
|
|
|
{
|
|
|
|
int sk;
|
|
|
|
int ret, off, sz;
|
|
|
|
|
|
|
|
sk = socket(PF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (sk < 0) {
|
|
|
|
pr_perror("Can't create unix socket for check");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-24 14:02:31 +04:00
|
|
|
sz = sizeof(off);
|
2012-03-02 14:01:57 +04:00
|
|
|
ret = getsockopt(sk, SOL_SOCKET, SO_PEEK_OFF, &off, (socklen_t *)&sz);
|
|
|
|
close(sk);
|
|
|
|
|
|
|
|
if ((ret == 0) && (off == -1) && (sz == sizeof(int)))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_msg("SO_PEEK_OFF sockoption doesn't work.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-03-02 14:01:08 +04:00
|
|
|
|
2012-04-05 14:29:00 +04:00
|
|
|
static int check_kcmp(void)
|
|
|
|
{
|
|
|
|
int ret = sys_kcmp(getpid(), -1, -1, -1, -1);
|
|
|
|
|
|
|
|
if (ret != -ENOSYS)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_msg("System call kcmp is not supported\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-04-05 15:46:00 +04:00
|
|
|
static int check_prctl(void)
|
|
|
|
{
|
2012-04-05 15:43:00 +04:00
|
|
|
unsigned long user_auxv = 0;
|
2012-04-05 15:46:00 +04:00
|
|
|
unsigned int *tid_addr;
|
2014-10-24 14:10:48 +04:00
|
|
|
unsigned int size = 0;
|
2012-04-05 15:46:00 +04:00
|
|
|
int ret;
|
|
|
|
|
2012-04-25 21:59:00 +04:00
|
|
|
ret = sys_prctl(PR_GET_TID_ADDRESS, (unsigned long)&tid_addr, 0, 0, 0);
|
2012-04-05 15:46:00 +04:00
|
|
|
if (ret) {
|
2012-04-25 21:59:00 +04:00
|
|
|
pr_msg("prctl: PR_GET_TID_ADDRESS is not supported\n");
|
2012-04-05 15:46:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-24 14:10:48 +04:00
|
|
|
/*
|
|
|
|
* Either new or old interface must be supported in the kernel.
|
|
|
|
*/
|
|
|
|
ret = sys_prctl(PR_SET_MM, PR_SET_MM_MAP_SIZE, (unsigned long)&size, 0, 0);
|
2012-04-05 15:46:00 +04:00
|
|
|
if (ret) {
|
2014-11-07 21:27:28 +03:00
|
|
|
if (!opts.check_ms_kernel) {
|
|
|
|
pr_msg("prctl: PR_SET_MM_MAP is not supported, which "
|
|
|
|
"is required for restoring user namespaces\n");
|
|
|
|
return -1;
|
|
|
|
} else
|
|
|
|
pr_warn("Skipping unssuported PR_SET_MM_MAP\n");
|
2012-04-05 15:46:00 +04:00
|
|
|
|
2014-10-24 14:10:48 +04:00
|
|
|
ret = sys_prctl(PR_SET_MM, PR_SET_MM_BRK, sys_brk(0), 0, 0);
|
|
|
|
if (ret) {
|
|
|
|
if (ret == -EPERM)
|
|
|
|
pr_msg("prctl: One needs CAP_SYS_RESOURCE capability to perform testing\n");
|
|
|
|
else
|
|
|
|
pr_msg("prctl: PR_SET_MM is not supported\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-04-05 15:46:00 +04:00
|
|
|
|
2014-10-24 14:10:48 +04:00
|
|
|
ret = sys_prctl(PR_SET_MM, PR_SET_MM_EXE_FILE, -1, 0, 0);
|
|
|
|
if (ret != -EBADF) {
|
|
|
|
pr_msg("prctl: PR_SET_MM_EXE_FILE is not supported (%d)\n", ret);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = sys_prctl(PR_SET_MM, PR_SET_MM_AUXV, (long)&user_auxv, sizeof(user_auxv), 0);
|
|
|
|
if (ret) {
|
|
|
|
pr_msg("prctl: PR_SET_MM_AUXV is not supported\n");
|
|
|
|
return -1;
|
|
|
|
}
|
2012-04-05 15:43:00 +04:00
|
|
|
}
|
|
|
|
|
2012-04-05 15:46:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-05 15:43:00 +04:00
|
|
|
static int check_fcntl(void)
|
|
|
|
{
|
2014-11-19 12:18:00 +04:00
|
|
|
u32 v[2];
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
fd = open("/proc/self/comm", O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't open self comm file");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fcntl(fd, F_GETOWNER_UIDS, (long)v)) {
|
|
|
|
pr_perror("Can'r fetch file owner UIDs");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(fd);
|
2012-04-05 15:43:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-04-05 15:43:00 +04:00
|
|
|
static int check_proc_stat(void)
|
|
|
|
{
|
|
|
|
struct proc_pid_stat stat;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = parse_pid_stat(getpid(), &stat);
|
|
|
|
if (ret) {
|
|
|
|
pr_msg("procfs: stat extension is not supported\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-11 09:45:32 +04:00
|
|
|
static int check_one_fdinfo(union fdinfo_entries *e, void *arg)
|
|
|
|
{
|
|
|
|
*(int *)arg = (int)e->efd.counter;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_fdinfo_eventfd(void)
|
|
|
|
{
|
|
|
|
int fd, ret;
|
|
|
|
int cnt = 13, proc_cnt = 0;
|
|
|
|
|
|
|
|
fd = eventfd(cnt, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't make eventfd");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
ret = parse_fdinfo(fd, FD_TYPES__EVENTFD, check_one_fdinfo, &proc_cnt);
|
2012-07-11 09:45:32 +04:00
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Error parsing proc fdinfo\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (proc_cnt != cnt) {
|
|
|
|
pr_err("Counter mismatch (or not met) %d want %d\n",
|
|
|
|
proc_cnt, cnt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Eventfd fdinfo works OK (%d vs %d)\n", cnt, proc_cnt);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-02 12:27:45 +04:00
|
|
|
static int check_one_sfd(union fdinfo_entries *e, void *arg)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-21 18:23:49 +04:00
|
|
|
int check_mnt_id(void)
|
2014-04-21 18:23:48 +04:00
|
|
|
{
|
|
|
|
struct fdinfo_common fdinfo = { .mnt_id = -1 };
|
|
|
|
int ret;
|
|
|
|
|
2014-04-25 08:22:00 +04:00
|
|
|
if (opts.check_ms_kernel) {
|
|
|
|
pr_warn("Skipping mnt_id support check\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-04-21 18:23:48 +04:00
|
|
|
ret = parse_fdinfo(get_service_fd(LOG_FD_OFF), FD_TYPES__UND, NULL, &fdinfo);
|
|
|
|
if (ret < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (fdinfo.mnt_id == -1) {
|
|
|
|
pr_err("fdinfo doesn't contain the mnt_id field\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-02 12:27:45 +04:00
|
|
|
static int check_fdinfo_signalfd(void)
|
|
|
|
{
|
|
|
|
int fd, ret;
|
|
|
|
sigset_t mask;
|
|
|
|
|
|
|
|
sigemptyset(&mask);
|
|
|
|
sigaddset(&mask, SIGUSR1);
|
|
|
|
fd = signalfd(-1, &mask, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't make signalfd");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = parse_fdinfo(fd, FD_TYPES__SIGNALFD, check_one_sfd, NULL);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
pr_err("Error parsing proc fdinfo\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-11 09:55:10 +04:00
|
|
|
static int check_one_epoll(union fdinfo_entries *e, void *arg)
|
|
|
|
{
|
2014-08-25 23:19:58 +04:00
|
|
|
*(int *)arg = e->epl.e.tfd;
|
|
|
|
free_event_poll_entry(e);
|
2012-07-11 09:55:10 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_fdinfo_eventpoll(void)
|
|
|
|
{
|
2013-05-02 15:02:33 +08:00
|
|
|
int efd, pfd[2], proc_fd = 0, ret = -1;
|
2012-07-11 09:55:10 +04:00
|
|
|
struct epoll_event ev;
|
|
|
|
|
|
|
|
if (pipe(pfd)) {
|
|
|
|
pr_perror("Can't make pipe to watch");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
efd = epoll_create(1);
|
|
|
|
if (efd < 0) {
|
|
|
|
pr_perror("Can't make epoll fd");
|
2013-05-02 15:02:33 +08:00
|
|
|
goto pipe_err;
|
2012-07-11 09:55:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&ev, 0, sizeof(ev));
|
|
|
|
ev.events = EPOLLIN | EPOLLOUT;
|
|
|
|
|
|
|
|
if (epoll_ctl(efd, EPOLL_CTL_ADD, pfd[0], &ev)) {
|
|
|
|
pr_perror("Can't add epoll tfd");
|
2013-05-02 15:02:33 +08:00
|
|
|
goto epoll_err;
|
2012-07-11 09:55:10 +04:00
|
|
|
}
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
ret = parse_fdinfo(efd, FD_TYPES__EVENTPOLL, check_one_epoll, &proc_fd);
|
2012-07-11 09:55:10 +04:00
|
|
|
if (ret) {
|
2012-11-23 16:43:33 +04:00
|
|
|
pr_err("Error parsing proc fdinfo\n");
|
2013-05-02 15:02:33 +08:00
|
|
|
goto epoll_err;
|
2012-07-11 09:55:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pfd[0] != proc_fd) {
|
|
|
|
pr_err("TFD mismatch (or not met) %d want %d\n",
|
|
|
|
proc_fd, pfd[0]);
|
2013-05-02 15:02:33 +08:00
|
|
|
ret = -1;
|
|
|
|
goto epoll_err;
|
2012-07-11 09:55:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Epoll fdinfo works OK (%d vs %d)\n", pfd[0], proc_fd);
|
2013-05-02 15:02:33 +08:00
|
|
|
|
|
|
|
epoll_err:
|
|
|
|
close(efd);
|
|
|
|
pipe_err:
|
|
|
|
close(pfd[0]);
|
|
|
|
close(pfd[1]);
|
|
|
|
|
|
|
|
return ret;
|
2012-07-11 09:55:10 +04:00
|
|
|
}
|
|
|
|
|
2012-07-11 10:26:46 +04:00
|
|
|
static int check_one_inotify(union fdinfo_entries *e, void *arg)
|
|
|
|
{
|
2014-08-25 23:19:54 +04:00
|
|
|
*(int *)arg = e->ify.e.wd;
|
|
|
|
free_inotify_wd_entry(e);
|
2012-07-11 10:26:46 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_fdinfo_inotify(void)
|
|
|
|
{
|
|
|
|
int ifd, wd, proc_wd = -1, ret;
|
|
|
|
|
|
|
|
ifd = inotify_init1(0);
|
|
|
|
if (ifd < 0) {
|
|
|
|
pr_perror("Can't make inotify fd");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wd = inotify_add_watch(ifd, ".", IN_ALL_EVENTS);
|
|
|
|
if (wd < 0) {
|
|
|
|
pr_perror("Can't add watch");
|
2013-05-02 15:02:36 +08:00
|
|
|
close(ifd);
|
2012-07-11 10:26:46 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
ret = parse_fdinfo(ifd, FD_TYPES__INOTIFY, check_one_inotify, &proc_wd);
|
2012-07-11 10:26:46 +04:00
|
|
|
close(ifd);
|
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_err("Error parsing proc fdinfo\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wd != proc_wd) {
|
|
|
|
pr_err("WD mismatch (or not met) %d want %d\n", proc_wd, wd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Inotify fdinfo works OK (%d vs %d)\n", wd, proc_wd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-11 09:45:32 +04:00
|
|
|
static int check_fdinfo_ext(void)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ret |= check_fdinfo_eventfd();
|
2012-07-11 09:55:10 +04:00
|
|
|
ret |= check_fdinfo_eventpoll();
|
2012-08-02 12:27:45 +04:00
|
|
|
ret |= check_fdinfo_signalfd();
|
2012-07-11 10:26:46 +04:00
|
|
|
ret |= check_fdinfo_inotify();
|
2012-07-11 09:45:32 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-07-12 06:57:20 +04:00
|
|
|
static int check_unaligned_vmsplice(void)
|
|
|
|
{
|
|
|
|
int p[2], ret;
|
|
|
|
char buf; /* :) */
|
|
|
|
struct iovec iov;
|
|
|
|
|
2013-02-22 14:49:45 +04:00
|
|
|
ret = pipe(p);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't create pipe");
|
2013-04-29 16:11:32 +04:00
|
|
|
return ret;
|
2013-02-22 14:49:45 +04:00
|
|
|
}
|
2012-07-12 06:57:20 +04:00
|
|
|
iov.iov_base = &buf;
|
|
|
|
iov.iov_len = sizeof(buf);
|
|
|
|
ret = vmsplice(p[1], &iov, 1, SPLICE_F_GIFT | SPLICE_F_NONBLOCK);
|
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Unaligned vmsplice doesn't work");
|
2013-04-29 16:11:32 +04:00
|
|
|
goto err;
|
2012-07-12 06:57:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Unaligned vmsplice works OK\n");
|
2013-04-29 16:11:32 +04:00
|
|
|
ret = 0;
|
|
|
|
err:
|
|
|
|
close(p[0]);
|
|
|
|
close(p[1]);
|
|
|
|
|
|
|
|
return ret;
|
2012-07-12 06:57:20 +04:00
|
|
|
}
|
|
|
|
|
2012-11-02 16:07:56 +03:00
|
|
|
#ifndef SO_GET_FILTER
|
|
|
|
#define SO_GET_FILTER SO_ATTACH_FILTER
|
|
|
|
#endif
|
|
|
|
|
2012-12-04 16:35:58 +03:00
|
|
|
static int check_so_gets(void)
|
2012-11-02 16:07:56 +03:00
|
|
|
{
|
2013-04-05 01:44:28 +04:00
|
|
|
int sk, ret = -1;
|
2012-11-02 16:07:56 +03:00
|
|
|
socklen_t len;
|
2012-12-04 16:35:58 +03:00
|
|
|
char name[IFNAMSIZ];
|
2012-11-02 16:07:56 +03:00
|
|
|
|
|
|
|
sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
if (sk < 0) {
|
|
|
|
pr_perror("No socket");
|
2013-03-26 19:22:15 +04:00
|
|
|
return -1;
|
2012-11-02 16:07:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
len = 0;
|
|
|
|
if (getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len)) {
|
|
|
|
pr_perror("Can't get socket filter");
|
2013-04-05 01:44:28 +04:00
|
|
|
goto err;
|
2012-11-02 16:07:56 +03:00
|
|
|
}
|
|
|
|
|
2012-12-04 16:35:58 +03:00
|
|
|
len = sizeof(name);
|
|
|
|
if (getsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, name, &len)) {
|
|
|
|
pr_perror("Can't get socket bound dev");
|
2013-04-05 01:44:28 +04:00
|
|
|
goto err;
|
2012-12-04 16:35:58 +03:00
|
|
|
}
|
|
|
|
|
2013-04-05 01:44:28 +04:00
|
|
|
ret = 0;
|
|
|
|
err:
|
|
|
|
close(sk);
|
|
|
|
return ret;
|
2012-11-02 16:07:56 +03:00
|
|
|
}
|
|
|
|
|
2012-11-30 20:11:18 +04:00
|
|
|
static int check_ipc(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = access("/proc/sys/kernel/sem_next_id", R_OK | W_OK);
|
|
|
|
if (!ret)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_msg("/proc/sys/kernel/sem_next_id sysctl is missing.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-10-10 19:11:00 +04:00
|
|
|
static int check_sigqueuinfo()
|
2013-03-25 23:39:50 +04:00
|
|
|
{
|
|
|
|
siginfo_t info = { .si_code = 1 };
|
|
|
|
|
|
|
|
signal(SIGUSR1, SIG_IGN);
|
|
|
|
|
|
|
|
if (sys_rt_sigqueueinfo(getpid(), SIGUSR1, &info)) {
|
|
|
|
pr_perror("Unable to send siginfo with positive si_code to itself");
|
2013-03-26 19:22:15 +04:00
|
|
|
return -1;
|
2013-03-25 23:39:50 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-10 19:11:00 +04:00
|
|
|
static int check_ptrace_peeksiginfo()
|
2013-03-25 23:39:50 +04:00
|
|
|
{
|
|
|
|
struct ptrace_peeksiginfo_args arg;
|
|
|
|
siginfo_t siginfo;
|
|
|
|
pid_t pid, ret = 0;
|
2013-07-11 13:46:49 +04:00
|
|
|
k_rtsigset_t mask;
|
2013-03-25 23:39:50 +04:00
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0)
|
|
|
|
pr_perror("fork");
|
|
|
|
else if (pid == 0) {
|
|
|
|
while (1)
|
|
|
|
sleep(1000);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1)
|
2013-03-26 19:22:15 +04:00
|
|
|
return -1;
|
2013-03-25 23:39:50 +04:00
|
|
|
|
|
|
|
waitpid(pid, NULL, 0);
|
|
|
|
|
|
|
|
arg.flags = 0;
|
|
|
|
arg.off = 0;
|
|
|
|
arg.nr = 1;
|
|
|
|
|
|
|
|
if (ptrace(PTRACE_PEEKSIGINFO, pid, &arg, &siginfo) != 0) {
|
2013-04-10 00:55:24 +04:00
|
|
|
pr_perror("Unable to dump pending signals");
|
2013-03-26 19:22:15 +04:00
|
|
|
ret = -1;
|
2013-03-25 23:39:50 +04:00
|
|
|
}
|
|
|
|
|
2013-07-11 13:46:49 +04:00
|
|
|
if (ptrace(PTRACE_GETSIGMASK, pid, sizeof(mask), &mask) != 0) {
|
|
|
|
pr_perror("Unable to dump signal blocking mask");
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
2013-03-25 23:39:50 +04:00
|
|
|
ptrace(PTRACE_KILL, pid, NULL, NULL);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-04-15 13:24:32 +04:00
|
|
|
static int check_mem_dirty_track(void)
|
|
|
|
{
|
|
|
|
if (kerndat_get_dirty_track() < 0)
|
|
|
|
return -1;
|
|
|
|
|
2014-11-10 10:47:42 +04:00
|
|
|
if (!kdat.has_dirty_track)
|
2013-04-23 23:38:47 +04:00
|
|
|
pr_warn("Dirty tracking is OFF. Memory snapshot will not work.\n");
|
2013-04-15 13:24:32 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-01 16:23:51 +04:00
|
|
|
static int check_posix_timers(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = access("/proc/self/timers", R_OK);
|
|
|
|
if (!ret)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pr_msg("/proc/<pid>/timers file is missing.\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-03-02 14:01:08 +04:00
|
|
|
int cr_check(void)
|
|
|
|
{
|
2014-04-21 18:23:41 +04:00
|
|
|
struct ns_id ns = { .pid = getpid(), .nd = &mnt_ns_desc };
|
2012-03-02 14:01:57 +04:00
|
|
|
int ret = 0;
|
|
|
|
|
2013-04-23 23:25:13 +04:00
|
|
|
log_set_loglevel(LOG_WARN);
|
2012-11-12 17:04:24 +03:00
|
|
|
|
2013-12-13 00:02:00 +04:00
|
|
|
if (!is_root_user())
|
|
|
|
return -1;
|
|
|
|
|
2014-04-21 18:23:41 +04:00
|
|
|
root_item = alloc_pstree_item();
|
|
|
|
if (root_item == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
root_item->pid.real = getpid();
|
|
|
|
|
|
|
|
if (collect_pstree_ids())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ns.id = root_item->ids->mnt_ns_id;
|
|
|
|
|
|
|
|
mntinfo = collect_mntinfo(&ns);
|
|
|
|
if (mntinfo == NULL)
|
2012-09-02 01:04:14 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-03-02 14:01:57 +04:00
|
|
|
ret |= check_map_files();
|
|
|
|
ret |= check_sock_diag();
|
|
|
|
ret |= check_ns_last_pid();
|
|
|
|
ret |= check_sock_peek_off();
|
2012-04-05 14:29:00 +04:00
|
|
|
ret |= check_kcmp();
|
2012-04-05 15:46:00 +04:00
|
|
|
ret |= check_prctl();
|
2012-04-05 15:43:00 +04:00
|
|
|
ret |= check_fcntl();
|
2012-04-05 15:43:00 +04:00
|
|
|
ret |= check_proc_stat();
|
2013-02-14 20:27:55 +04:00
|
|
|
ret |= check_tcp();
|
2012-07-11 09:45:32 +04:00
|
|
|
ret |= check_fdinfo_ext();
|
2012-07-12 06:57:20 +04:00
|
|
|
ret |= check_unaligned_vmsplice();
|
2012-09-12 20:00:56 +04:00
|
|
|
ret |= check_tty();
|
2012-12-04 16:35:58 +03:00
|
|
|
ret |= check_so_gets();
|
2012-11-30 20:11:18 +04:00
|
|
|
ret |= check_ipc();
|
2013-03-25 23:39:50 +04:00
|
|
|
ret |= check_sigqueuinfo();
|
|
|
|
ret |= check_ptrace_peeksiginfo();
|
2013-04-15 13:24:32 +04:00
|
|
|
ret |= check_mem_dirty_track();
|
2013-07-01 16:23:51 +04:00
|
|
|
ret |= check_posix_timers();
|
2013-08-23 19:18:47 +04:00
|
|
|
ret |= check_tun();
|
2014-08-06 20:31:46 +04:00
|
|
|
ret |= check_timerfd();
|
2014-04-21 18:23:48 +04:00
|
|
|
ret |= check_mnt_id();
|
2012-03-02 14:01:57 +04:00
|
|
|
|
|
|
|
if (!ret)
|
|
|
|
pr_msg("Looks good.\n");
|
|
|
|
|
|
|
|
return ret;
|
2012-03-02 14:01:08 +04:00
|
|
|
}
|