This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC PATCH] Test for syscall templates


On Sat, Feb 11, 2017 at 9:46 AM, Yury Norov <ynorov@caviumnetworks.com> wrote:
>
> OK. Below is what I have. This is not the glibc test but standalone
> application. If I do what you mean, I will finish the syscall list
> (I take it from sysdeps/unix/syscalls.list), and send it as glibc test
> for POSIX syscalls.

Yes, this is what I had in mind.  (POSIX syscalls is not exactly the
same thing as sysdeps/unix/syscalls.list but it's probably easier to
put the test in sysdeps/unix than worry about which syscalls are or
are not standardized.)

> IIUC we need similar test for linux syscalls in
> sysdeps/unix/sysv/linux/syscalls.list

Right.

> Surprisingly, some syscalls cause segfaults on aarch64/lp64, which is
> presumably wrong.

I dug into this a bit.  The problem is that under any conditions where
a syscall is documented to return EFAULT, it is also allowed to
trigger a SIGSEGV.  (See
http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_03
under [EFAULT].)  So we cannot do this test for syscalls whose only
invalid-arguments failure mode is EFAULT, and we need to avoid setting
up EFAULT conditions for any other syscalls.

I've revised what you had with that in mind.  I also fixed the problem
with mmap, made sure that we were only setting up _one_ failure
condition for each system call, made it always run all the tests
instead of stopping at the first failure, and reformatted according to
GNU style.  It should be pretty easy to go on from here for the rest
of syscalls.list.

zw

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/mman.h>
#include <unistd.h>
#include <netinet/in.h>

// Test that failing system calls do set errno to the correct value.
//
// This is not an exhaustive test: only system calls that can be
// persuaded to fail with a consistent error code and no side effects
// are included.  Usually these are failures due to invalid arguments,
// with errno code EBADF or EINVAL.  The order of argument checks is
// unspecified, so we must take care to provide arguments that only
// allow _one_ failure mode.
//
// Note that all system calls that can fail with EFAULT are permitted
// to deliver a SIGSEGV signal instead, so we avoid supplying invalid
// pointers in general, and we do not attempt to test system calls
// that can only fail with EFAULT (e.g. gettimeofday, gethostname).
//
// Also note that root-only system calls (e.g. acct, reboot) may, when
// the test is run as an unprivileged user, fail due to insufficient
// privileges before bothering to do argument checks, so those are not
// tested either.
//
// Some tests assume "/bin/sh" names a file that exists and is not a
// directory.

#define test_wrp_rv(rtype, prtype, experr, syscall, ...)        \
  (__extension__ ({                            \
    errno = 0xdead;                            \
    rtype ret = syscall (__VA_ARGS__);                    \
    int err = errno;                            \
    int fail;                                \
    if (ret == (rtype)-1 && err == experr)                \
      fail = 0;                                \
    else                                \
      {                                    \
    fail = 1;                            \
    if (ret != (rtype)-1)                        \
      fprintf (stderr, #syscall ": didn't fail as expected"        \
           " (return "prtype")\n", ret);            \
    else if (err == 0xdead)                        \
      fputs(#syscall ": didn't update errno\n", stderr);        \
    else if (err != experr)                        \
      fprintf (stderr, #syscall                    \
           ": errno is: %d (%s) expected: %d (%s)\n",        \
           err, strerror (err), experr, strerror (experr));    \
      }                                    \
    fail;                                \
  }))

#define test_wrp(experr, syscall, ...) \
  test_wrp_rv(int, "%d", experr, syscall, __VA_ARGS__)

int
main(void)
{
  size_t pagesize = sysconf(_SC_PAGESIZE);
  struct statfs sfs;
  char buf[1];
  struct iovec iov[1] = { { buf, 1 } };
  struct sockaddr_in sin;
  sin.sin_family = AF_INET;
  sin.sin_port = htons (1026);
  sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
  struct msghdr msg;
  memset(&msg, 0, sizeof msg);
  msg.msg_iov = iov;
  msg.msg_iovlen = 1;

  int fails = 0;
  fails |= test_wrp (EINVAL, access, "/", -1);
  fails |= test_wrp (EBADF, bind, -1, (struct sockaddr *)&sin, sizeof sin);
  fails |= test_wrp (ENOTDIR, chdir, "/bin/sh");
  fails |= test_wrp (EBADF, close, -1);
  fails |= test_wrp (EBADF, connect, -1, (struct sockaddr *)&sin, sizeof sin);
  fails |= test_wrp (EBADF, dup, -1);
  fails |= test_wrp (EBADF, fcntl, -1, 0);
  fails |= test_wrp (EBADF, fstatfs, -1, &sfs);
  fails |= test_wrp (EBADF, fsync, -1);
  fails |= test_wrp (EBADF, ftruncate, -1, 0);
  fails |= test_wrp (EINVAL, getgroups, -1, 0);
  fails |= test_wrp (EBADF, ioctl, -1, TIOCNOTTY);
  fails |= test_wrp (EBADF, listen, -1, 1);
  fails |= test_wrp (EBADF, lseek, -1, 0, 0);
  fails |= test_wrp (EINVAL, madvise, (void *) -1, -1, 0);
  fails |= test_wrp_rv (void *, "%p", EBADF,
                        mmap, 0, pagesize, PROT_READ, MAP_PRIVATE, -1, 0);
  fails |= test_wrp (EINVAL, mprotect, (void *) -1, pagesize, -1);
  fails |= test_wrp (EINVAL, msync, (void *) -1, pagesize, -1);
  fails |= test_wrp (EINVAL, munmap, (void *) -1, 0);
  fails |= test_wrp (EINVAL, open, "/bin/sh", -1, 0);
  fails |= test_wrp (EBADF, read, -1, buf, 1);
  fails |= test_wrp (EINVAL, readlink, "/", buf, -1);
  fails |= test_wrp (EBADF, readv, -1, iov, 1);
  fails |= test_wrp (EBADF, recv, -1, buf, 1, 0);
  fails |= test_wrp (EBADF, recvmsg, -1, &msg, 0);
  fails |= test_wrp (EINVAL, select, -1, 0, 0, 0, 0);
  fails |= test_wrp (EBADF, write, -1, "Hello", sizeof("Hello") );

  return fails;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]