glibc/misc/tst-syscalls.c

168 lines
4.2 KiB
C

/* Test for syscall interfaces.
Copyright (C) 2020-2022 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/* This test verifies that the x32 system call handling zero-extends
unsigned 32-bit arguments to the 64-bit argument registers for
system calls (bug 25810). The bug is specific to x32, but the test
should pass on all architectures. */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <support/check.h>
#include <support/xunistd.h>
/* On x32, this can be passed in a single 64-bit integer register. */
struct Array
{
size_t length;
void *ptr;
};
static int error_count;
__attribute__ ((noclone, noinline))
struct Array
allocate (size_t bytes)
{
if (!bytes)
return __extension__ (struct Array) {0, 0};
void *p = mmap (0x0, bytes, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
if (p == MAP_FAILED)
return __extension__ (struct Array) {0, 0};
return __extension__ (struct Array) {bytes, p};
}
__attribute__ ((noclone, noinline))
void
deallocate (struct Array b)
{
/* On x32, the 64-bit integer register containing `b' may be copied
to another 64-bit integer register to pass the second argument to
munmap. */
if (b.length && munmap (b.ptr, b.length))
{
printf ("munmap error: %m\n");
error_count++;
}
}
__attribute__ ((noclone, noinline))
void *
do_mmap (void *addr, size_t length)
{
return mmap (addr, length, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
}
__attribute__ ((noclone, noinline))
void *
reallocate (struct Array b)
{
/* On x32, the 64-bit integer register containing `b' may be copied
to another 64-bit integer register to pass the second argument to
do_mmap. */
if (b.length)
return do_mmap (b.ptr, b.length);
return NULL;
}
__attribute__ ((noclone, noinline))
void
protect (struct Array b)
{
if (b.length)
{
/* On x32, the 64-bit integer register containing `b' may be copied
to another 64-bit integer register to pass the second argument
to mprotect. */
if (mprotect (b.ptr, b.length,
PROT_READ | PROT_WRITE | PROT_EXEC))
{
printf ("mprotect error: %m\n");
error_count++;
}
}
}
__attribute__ ((noclone, noinline))
ssize_t
do_read (int fd, void *ptr, struct Array b)
{
/* On x32, the 64-bit integer register containing `b' may be copied
to another 64-bit integer register to pass the second argument to
read. */
if (b.length)
return read (fd, ptr, b.length);
return 0;
}
__attribute__ ((noclone, noinline))
ssize_t
do_write (int fd, void *ptr, struct Array b)
{
/* On x32, the 64-bit integer register containing `b' may be copied
to another 64-bit integer register to pass the second argument to
write. */
if (b.length)
return write (fd, ptr, b.length);
return 0;
}
static int
do_test (void)
{
struct Array array;
array = allocate (1);
protect (array);
deallocate (array);
void *p = reallocate (array);
if (p == MAP_FAILED)
{
printf ("mmap error: %m\n");
error_count++;
}
array.ptr = p;
protect (array);
deallocate (array);
int fd = xopen ("/dev/null", O_RDWR, 0);
char buf[2];
array.ptr = buf;
if (do_read (fd, array.ptr, array) == -1)
{
printf ("read error: %m\n");
error_count++;
}
if (do_write (fd, array.ptr, array) == -1)
{
printf ("write error: %m\n");
error_count++;
}
xclose (fd);
return error_count ? EXIT_FAILURE : EXIT_SUCCESS;
}
#include <support/test-driver.c>