LCOV - code coverage report
Current view: top level - crtools - cr-check.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 155 192 80.7 %
Date: 2012-12-28 Functions: 21 21 100.0 %
Branches: 38 78 48.7 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <sys/socket.h>
       3                 :            : #include <sys/types.h>
       4                 :            : #include <sys/eventfd.h>
       5                 :            : #include <sys/epoll.h>
       6                 :            : #include <sys/inotify.h>
       7                 :            : #include <sys/signalfd.h>
       8                 :            : #include <fcntl.h>
       9                 :            : #include <signal.h>
      10                 :            : #include <linux/if.h>
      11                 :            : #include <sys/ioctl.h>
      12                 :            : #include <termios.h>
      13                 :            : 
      14                 :            : #include "proc_parse.h"
      15                 :            : #include "sockets.h"
      16                 :            : #include "crtools.h"
      17                 :            : #include "log.h"
      18                 :            : #include "util-net.h"
      19                 :            : #include "syscall.h"
      20                 :            : #include "files.h"
      21                 :            : #include "sk-inet.h"
      22                 :            : #include "proc_parse.h"
      23                 :            : #include "mount.h"
      24                 :            : #include "tty.h"
      25                 :            : 
      26                 :          1 : static int check_tty(void)
      27                 :            : {
      28                 :          1 :         int master = -1, slave = -1;
      29                 :          1 :         const int lock = 1;
      30                 :            :         struct termios t;
      31                 :            :         char *slavename;
      32                 :          1 :         int ret = -1;
      33                 :            : 
      34                 :            :         if (ARRAY_SIZE(t.c_cc) < TERMIOS_NCC) {
      35                 :            :                 pr_msg("struct termios has %d @c_cc while "
      36                 :            :                         "at least %d expected.\n",
      37                 :            :                         (int)ARRAY_SIZE(t.c_cc),
      38                 :            :                         TERMIOS_NCC);
      39                 :            :                 goto out;
      40                 :            :         }
      41                 :            : 
      42                 :          1 :         master = open("/dev/ptmx", O_RDWR);
      43         [ -  + ]:          1 :         if (master < 0) {
      44                 :          0 :                 pr_msg("Can't open master pty.\n");
      45                 :          0 :                 goto out;
      46                 :            :         }
      47                 :            : 
      48         [ -  + ]:          1 :         if (ioctl(master, TIOCSPTLCK, &lock)) {
      49                 :          0 :                 pr_msg("Unable to lock pty device.\n");
      50                 :          0 :                 goto out;
      51                 :            :         }
      52                 :            : 
      53                 :          1 :         slavename = ptsname(master);
      54                 :          1 :         slave = open(slavename, O_RDWR);
      55         [ +  - ]:          1 :         if (slave < 0) {
      56         [ -  + ]:          1 :                 if (errno != EIO) {
      57                 :          0 :                         pr_msg("Unexpected error code on locked pty.\n");
      58                 :          0 :                         goto out;
      59                 :            :                 }
      60                 :            :         } else {
      61                 :          0 :                 pr_msg("Managed to open locked pty.\n");
      62                 :          0 :                 goto out;
      63                 :            :         }
      64                 :            : 
      65                 :            :         ret = 0;
      66                 :            : out:
      67                 :          1 :         close_safe(&master);
      68                 :          1 :         close_safe(&slave);
      69                 :          1 :         return ret;
      70                 :            : }
      71                 :            : 
      72                 :          1 : static int check_map_files(void)
      73                 :            : {
      74                 :            :         int ret;
      75                 :            : 
      76                 :          1 :         ret = access("/proc/self/map_files", R_OK);
      77         [ -  + ]:          1 :         if (!ret)
      78                 :            :                 return 0;
      79                 :            : 
      80                 :          0 :         pr_msg("/proc/<pid>/map_files directory is missing.\n");
      81                 :          1 :         return -1;
      82                 :            : }
      83                 :            : 
      84                 :          1 : static int check_sock_diag(void)
      85                 :            : {
      86                 :            :         int ret;
      87                 :            : 
      88                 :          1 :         ret = collect_sockets(getpid());
      89         [ -  + ]:          1 :         if (!ret)
      90                 :            :                 return 0;
      91                 :            : 
      92                 :          0 :         pr_msg("sock diag infrastructure is incomplete.\n");
      93                 :          1 :         return -1;
      94                 :            : }
      95                 :            : 
      96                 :          1 : static int check_ns_last_pid(void)
      97                 :            : {
      98                 :            :         int ret;
      99                 :            : 
     100                 :          1 :         ret = access(LAST_PID_PATH, W_OK);
     101         [ -  + ]:          1 :         if (!ret)
     102                 :            :                 return 0;
     103                 :            : 
     104                 :          0 :         pr_msg("%s sysctl is missing.\n", LAST_PID_PATH);
     105                 :          1 :         return -1;
     106                 :            : }
     107                 :            : 
     108                 :          1 : static int check_sock_peek_off(void)
     109                 :            : {
     110                 :            :         int sk;
     111                 :            :         int ret, off, sz;
     112                 :            : 
     113                 :          1 :         sk = socket(PF_UNIX, SOCK_DGRAM, 0);
     114         [ -  + ]:          1 :         if (sk < 0) {
     115                 :          0 :                 pr_perror("Can't create unix socket for check");
     116                 :            :                 return -1;
     117                 :            :         }
     118                 :            : 
     119                 :          1 :         sz = sizeof(off);
     120                 :          1 :         ret = getsockopt(sk, SOL_SOCKET, SO_PEEK_OFF, &off, (socklen_t *)&sz);
     121                 :          1 :         close(sk);
     122                 :            : 
     123 [ +  - ][ -  + ]:          1 :         if ((ret == 0) && (off == -1) && (sz == sizeof(int)))
                 [ +  - ]
     124                 :            :                 return 0;
     125                 :            : 
     126                 :          1 :         pr_msg("SO_PEEK_OFF sockoption doesn't work.\n");
     127                 :            :         return -1;
     128                 :            : }
     129                 :            : 
     130                 :          1 : static int check_kcmp(void)
     131                 :            : {
     132                 :          1 :         int ret = sys_kcmp(getpid(), -1, -1, -1, -1);
     133                 :            : 
     134         [ -  + ]:          1 :         if (ret != -ENOSYS)
     135                 :            :                 return 0;
     136                 :            : 
     137                 :          0 :         pr_msg("System call kcmp is not supported\n");
     138                 :          1 :         return -1;
     139                 :            : }
     140                 :            : 
     141                 :          1 : static int check_prctl(void)
     142                 :            : {
     143                 :          1 :         unsigned long user_auxv = 0;
     144                 :            :         unsigned int *tid_addr;
     145                 :            :         int ret;
     146                 :            : 
     147                 :          1 :         ret = sys_prctl(PR_GET_TID_ADDRESS, (unsigned long)&tid_addr, 0, 0, 0);
     148         [ -  + ]:          1 :         if (ret) {
     149                 :          0 :                 pr_msg("prctl: PR_GET_TID_ADDRESS is not supported\n");
     150                 :            :                 return -1;
     151                 :            :         }
     152                 :            : 
     153                 :          1 :         ret = sys_prctl(PR_SET_MM, PR_SET_MM_BRK, sys_brk(0), 0, 0);
     154         [ -  + ]:          1 :         if (ret) {
     155         [ #  # ]:          0 :                 if (ret == -EPERM)
     156                 :          0 :                         pr_msg("prctl: One needs CAP_SYS_RESOURCE capability to perform testing\n");
     157                 :            :                 else
     158                 :          0 :                         pr_msg("prctl: PR_SET_MM is not supported\n");
     159                 :            :                 return -1;
     160                 :            :         }
     161                 :            : 
     162                 :          1 :         ret = sys_prctl(PR_SET_MM, PR_SET_MM_EXE_FILE, -1, 0, 0);
     163         [ -  + ]:          1 :         if (ret != -EBADF) {
     164                 :          0 :                 pr_msg("prctl: PR_SET_MM_EXE_FILE is not supported (%d)\n", ret);
     165                 :            :                 return -1;
     166                 :            :         }
     167                 :            : 
     168                 :          1 :         ret = sys_prctl(PR_SET_MM, PR_SET_MM_AUXV, (long)&user_auxv, sizeof(user_auxv), 0);
     169         [ -  + ]:          1 :         if (ret) {
     170                 :          1 :                 pr_msg("prctl: PR_SET_MM_AUXV is not supported\n");
     171                 :            :                 return -1;
     172                 :            :         }
     173                 :            : 
     174                 :            :         return 0;
     175                 :            : }
     176                 :            : 
     177                 :            : static int check_fcntl(void)
     178                 :            : {
     179                 :            :         /*
     180                 :            :          * FIXME Add test for F_GETOWNER_UIDS once
     181                 :            :          * it's merged into mainline and kernel part
     182                 :            :          * settle down.
     183                 :            :          */
     184                 :            :         return 0;
     185                 :            : }
     186                 :            : 
     187                 :          1 : static int check_proc_stat(void)
     188                 :            : {
     189                 :            :         struct proc_pid_stat stat;
     190                 :            :         int ret;
     191                 :            : 
     192                 :          1 :         ret = parse_pid_stat(getpid(), &stat);
     193         [ -  + ]:          1 :         if (ret) {
     194                 :          1 :                 pr_msg("procfs: stat extension is not supported\n");
     195                 :            :                 return -1;
     196                 :            :         }
     197                 :            : 
     198                 :            :         return 0;
     199                 :            : }
     200                 :            : 
     201                 :          1 : static int check_one_fdinfo(union fdinfo_entries *e, void *arg)
     202                 :            : {
     203                 :          1 :         *(int *)arg = (int)e->efd.counter;
     204                 :          1 :         return 0;
     205                 :            : }
     206                 :            : 
     207                 :          1 : static int check_fdinfo_eventfd(void)
     208                 :            : {
     209                 :            :         int fd, ret;
     210                 :          1 :         int cnt = 13, proc_cnt = 0;
     211                 :            : 
     212                 :          1 :         fd = eventfd(cnt, 0);
     213         [ -  + ]:          1 :         if (fd < 0) {
     214                 :          0 :                 pr_perror("Can't make eventfd");
     215                 :            :                 return -1;
     216                 :            :         }
     217                 :            : 
     218                 :          1 :         ret = parse_fdinfo(fd, FD_TYPES__EVENTFD, check_one_fdinfo, &proc_cnt);
     219                 :          1 :         close(fd);
     220                 :            : 
     221         [ -  + ]:          1 :         if (ret) {
     222                 :          0 :                 pr_err("Error parsing proc fdinfo\n");
     223                 :            :                 return -1;
     224                 :            :         }
     225                 :            : 
     226         [ -  + ]:          1 :         if (proc_cnt != cnt) {
     227                 :          0 :                 pr_err("Counter mismatch (or not met) %d want %d\n",
     228                 :            :                                 proc_cnt, cnt);
     229                 :            :                 return -1;
     230                 :            :         }
     231                 :            : 
     232                 :          1 :         pr_info("Eventfd fdinfo works OK (%d vs %d)\n", cnt, proc_cnt);
     233                 :            :         return 0;
     234                 :            : }
     235                 :            : 
     236                 :          1 : static int check_one_sfd(union fdinfo_entries *e, void *arg)
     237                 :            : {
     238                 :          1 :         return 0;
     239                 :            : }
     240                 :            : 
     241                 :          1 : static int check_fdinfo_signalfd(void)
     242                 :            : {
     243                 :            :         int fd, ret;
     244                 :            :         sigset_t mask;
     245                 :            : 
     246                 :          1 :         sigemptyset(&mask);
     247                 :          1 :         sigaddset(&mask, SIGUSR1);
     248                 :          1 :         fd = signalfd(-1, &mask, 0);
     249         [ -  + ]:          1 :         if (fd < 0) {
     250                 :          0 :                 pr_perror("Can't make signalfd");
     251                 :            :                 return -1;
     252                 :            :         }
     253                 :            : 
     254                 :          1 :         ret = parse_fdinfo(fd, FD_TYPES__SIGNALFD, check_one_sfd, NULL);
     255                 :          1 :         close(fd);
     256                 :            : 
     257         [ -  + ]:          1 :         if (ret) {
     258                 :          1 :                 pr_err("Error parsing proc fdinfo\n");
     259                 :            :                 return -1;
     260                 :            :         }
     261                 :            : 
     262                 :            :         return 0;
     263                 :            : }
     264                 :            : 
     265                 :          1 : static int check_one_epoll(union fdinfo_entries *e, void *arg)
     266                 :            : {
     267                 :          1 :         *(int *)arg = e->epl.tfd;
     268                 :          1 :         return 0;
     269                 :            : }
     270                 :            : 
     271                 :          1 : static int check_fdinfo_eventpoll(void)
     272                 :            : {
     273                 :          1 :         int efd, pfd[2], proc_fd = 0, ret;
     274                 :            :         struct epoll_event ev;
     275                 :            : 
     276         [ -  + ]:          1 :         if (pipe(pfd)) {
     277                 :          0 :                 pr_perror("Can't make pipe to watch");
     278                 :            :                 return -1;
     279                 :            :         }
     280                 :            : 
     281                 :          1 :         efd = epoll_create(1);
     282         [ -  + ]:          1 :         if (efd < 0) {
     283                 :          0 :                 pr_perror("Can't make epoll fd");
     284                 :            :                 return -1;
     285                 :            :         }
     286                 :            : 
     287                 :          1 :         memset(&ev, 0, sizeof(ev));
     288                 :          1 :         ev.events = EPOLLIN | EPOLLOUT;
     289                 :            : 
     290         [ -  + ]:          1 :         if (epoll_ctl(efd, EPOLL_CTL_ADD, pfd[0], &ev)) {
     291                 :          0 :                 pr_perror("Can't add epoll tfd");
     292                 :            :                 return -1;
     293                 :            :         }
     294                 :            : 
     295                 :          1 :         ret = parse_fdinfo(efd, FD_TYPES__EVENTPOLL, check_one_epoll, &proc_fd);
     296                 :          1 :         close(efd);
     297                 :          1 :         close(pfd[0]);
     298                 :          1 :         close(pfd[1]);
     299                 :            : 
     300         [ -  + ]:          1 :         if (ret) {
     301                 :          0 :                 pr_err("Error parsing proc fdinfo\n");
     302                 :            :                 return -1;
     303                 :            :         }
     304                 :            : 
     305         [ -  + ]:          1 :         if (pfd[0] != proc_fd) {
     306                 :          0 :                 pr_err("TFD mismatch (or not met) %d want %d\n",
     307                 :            :                                 proc_fd, pfd[0]);
     308                 :            :                 return -1;
     309                 :            :         }
     310                 :            : 
     311                 :          1 :         pr_info("Epoll fdinfo works OK (%d vs %d)\n", pfd[0], proc_fd);
     312                 :            :         return 0;
     313                 :            : }
     314                 :            : 
     315                 :          1 : static int check_one_inotify(union fdinfo_entries *e, void *arg)
     316                 :            : {
     317                 :          1 :         *(int *)arg = e->ify.wd;
     318                 :          1 :         return 0;
     319                 :            : }
     320                 :            : 
     321                 :          1 : static int check_fdinfo_inotify(void)
     322                 :            : {
     323                 :          1 :         int ifd, wd, proc_wd = -1, ret;
     324                 :            : 
     325                 :          1 :         ifd = inotify_init1(0);
     326         [ -  + ]:          1 :         if (ifd < 0) {
     327                 :          0 :                 pr_perror("Can't make inotify fd");
     328                 :            :                 return -1;
     329                 :            :         }
     330                 :            : 
     331                 :          1 :         wd = inotify_add_watch(ifd, ".", IN_ALL_EVENTS);
     332         [ -  + ]:          1 :         if (wd < 0) {
     333                 :          0 :                 pr_perror("Can't add watch");
     334                 :            :                 return -1;
     335                 :            :         }
     336                 :            : 
     337                 :          1 :         ret = parse_fdinfo(ifd, FD_TYPES__INOTIFY, check_one_inotify, &proc_wd);
     338                 :          1 :         close(ifd);
     339                 :            : 
     340         [ -  + ]:          1 :         if (ret < 0) {
     341                 :          0 :                 pr_err("Error parsing proc fdinfo\n");
     342                 :            :                 return -1;
     343                 :            :         }
     344                 :            : 
     345         [ -  + ]:          1 :         if (wd != proc_wd) {
     346                 :          0 :                 pr_err("WD mismatch (or not met) %d want %d\n", proc_wd, wd);
     347                 :            :                 return -1;
     348                 :            :         }
     349                 :            : 
     350                 :          1 :         pr_info("Inotify fdinfo works OK (%d vs %d)\n", wd, proc_wd);
     351                 :            :         return 0;
     352                 :            : }
     353                 :            : 
     354                 :          1 : static int check_fdinfo_ext(void)
     355                 :            : {
     356                 :          1 :         int ret = 0;
     357                 :            : 
     358                 :          1 :         ret |= check_fdinfo_eventfd();
     359                 :          1 :         ret |= check_fdinfo_eventpoll();
     360                 :          1 :         ret |= check_fdinfo_signalfd();
     361                 :          1 :         ret |= check_fdinfo_inotify();
     362                 :            : 
     363                 :          1 :         return ret;
     364                 :            : }
     365                 :            : 
     366                 :          1 : static int check_unaligned_vmsplice(void)
     367                 :            : {
     368                 :            :         int p[2], ret;
     369                 :            :         char buf; /* :) */
     370                 :            :         struct iovec iov;
     371                 :            : 
     372                 :          1 :         pipe(p);
     373                 :          1 :         iov.iov_base = &buf;
     374                 :          1 :         iov.iov_len = sizeof(buf);
     375                 :          1 :         ret = vmsplice(p[1], &iov, 1, SPLICE_F_GIFT | SPLICE_F_NONBLOCK);
     376         [ -  + ]:          1 :         if (ret < 0) {
     377                 :          0 :                 pr_perror("Unaligned vmsplice doesn't work");
     378                 :            :                 return -1;
     379                 :            :         }
     380                 :            : 
     381                 :          1 :         pr_info("Unaligned vmsplice works OK\n");
     382                 :            :         return 0;
     383                 :            : }
     384                 :            : 
     385                 :            : #ifndef SO_GET_FILTER
     386                 :            : #define SO_GET_FILTER           SO_ATTACH_FILTER
     387                 :            : #endif
     388                 :            : 
     389                 :          1 : static int check_so_gets(void)
     390                 :            : {
     391                 :            :         int sk;
     392                 :            :         socklen_t len;
     393                 :            :         char name[IFNAMSIZ];
     394                 :            : 
     395                 :          1 :         sk = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
     396         [ -  + ]:          1 :         if (sk < 0) {
     397                 :          0 :                 pr_perror("No socket");
     398                 :            :                 return 1;
     399                 :            :         }
     400                 :            : 
     401                 :          1 :         len = 0;
     402         [ -  + ]:          1 :         if (getsockopt(sk, SOL_SOCKET, SO_GET_FILTER, NULL, &len)) {
     403                 :          0 :                 pr_perror("Can't get socket filter");
     404                 :            :                 return 1;
     405                 :            :         }
     406                 :            : 
     407                 :          1 :         len = sizeof(name);
     408         [ -  + ]:          1 :         if (getsockopt(sk, SOL_SOCKET, SO_BINDTODEVICE, name, &len)) {
     409                 :          1 :                 pr_perror("Can't get socket bound dev");
     410                 :            :                 return 1;
     411                 :            :         }
     412                 :            : 
     413                 :            :         return 0;
     414                 :            : }
     415                 :            : 
     416                 :          1 : static int check_ipc(void)
     417                 :            : {
     418                 :            :         int ret;
     419                 :            : 
     420                 :          1 :         ret = access("/proc/sys/kernel/sem_next_id", R_OK | W_OK);
     421         [ -  + ]:          1 :         if (!ret)
     422                 :            :                 return 0;
     423                 :            : 
     424                 :          0 :         pr_msg("/proc/sys/kernel/sem_next_id sysctl is missing.\n");
     425                 :          1 :         return -1;
     426                 :            : }
     427                 :            : 
     428                 :          1 : int cr_check(void)
     429                 :            : {
     430                 :          1 :         int ret = 0;
     431                 :            : 
     432                 :          1 :         log_set_loglevel(LOG_ERROR);
     433                 :            : 
     434         [ -  + ]:          1 :         if (mntns_collect_root(getpid())) {
     435                 :          0 :                 pr_err("Can't collect root mount point\n");
     436                 :          0 :                 return -1;
     437                 :            :         }
     438                 :            : 
     439                 :          1 :         ret |= check_map_files();
     440                 :          1 :         ret |= check_sock_diag();
     441                 :          1 :         ret |= check_ns_last_pid();
     442                 :          1 :         ret |= check_sock_peek_off();
     443                 :          1 :         ret |= check_kcmp();
     444                 :          1 :         ret |= check_prctl();
     445                 :          1 :         ret |= check_fcntl();
     446                 :          1 :         ret |= check_proc_stat();
     447                 :          1 :         ret |= check_tcp_repair();
     448                 :          1 :         ret |= check_fdinfo_ext();
     449                 :          1 :         ret |= check_unaligned_vmsplice();
     450                 :          1 :         ret |= check_tty();
     451                 :          1 :         ret |= check_so_gets();
     452                 :          1 :         ret |= check_ipc();
     453                 :            : 
     454         [ +  - ]:          1 :         if (!ret)
     455                 :          1 :                 pr_msg("Looks good.\n");
     456                 :            : 
     457                 :          1 :         return ret;
     458                 :            : }

Generated by: LCOV version 1.9