mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-04 19:00:09 +00:00
Fix misreported errno on preadv2/pwritev2 (BZ#23579)
The fallback code of Linux wrapper for preadv2/pwritev2 executes
regardless of the errno code for preadv2, instead of the case where
the syscall is not supported.
This fixes it by calling the fallback code iff errno is ENOSYS. The
patch also adds tests for both invalid file descriptor and invalid
iov_len and vector count.
The only discrepancy between preadv2 and fallback code regarding
error reporting is when an invalid flags are used. The fallback code
bails out earlier with ENOTSUP instead of EINVAL/EBADF when the syscall
is used.
Checked on x86_64-linux-gnu on a 4.4.0 and 4.15.0 kernel.
[BZ #23579]
* misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd): New
test.
* misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test):
Call do_test_with_invalid_fd.
* sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff
errno is ENOSYS.
* sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise.
* sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise.
* sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise.
(cherry picked from commit 7a16bdbb9f
)
This commit is contained in:
parent
3b3775697a
commit
a127df9f3e
14
ChangeLog
14
ChangeLog
@ -1,3 +1,17 @@
|
||||
2018-09-28 Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
||||
|
||||
[BZ #23579]
|
||||
* misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd,
|
||||
do_test_with_invalid_iov): New tests.
|
||||
* misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test):
|
||||
Call do_test_with_invalid_fd and do_test_with_invalid_iov.
|
||||
* sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff
|
||||
errno is ENOSYS.
|
||||
* sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise.
|
||||
* sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise.
|
||||
* sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise.
|
||||
* NEWS: Add bug fixed.
|
||||
|
||||
2018-09-28 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
[BZ #22753]
|
||||
|
1
NEWS
1
NEWS
@ -91,6 +91,7 @@ The following bugs are resolved with this release:
|
||||
[23456] Wrong index_cpu_LZCNT
|
||||
[23459] COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors
|
||||
[23538] pthread_cond_broadcast: Fix waiters-after-spinning case
|
||||
[23579] libc: Errors misreported in preadv2
|
||||
|
||||
|
||||
Version 2.27
|
||||
|
@ -19,9 +19,6 @@
|
||||
#include <limits.h>
|
||||
#include <support/check.h>
|
||||
|
||||
static void
|
||||
do_test_with_invalid_flags (void)
|
||||
{
|
||||
#ifndef RWF_HIPRI
|
||||
# define RWF_HIPRI 0
|
||||
#endif
|
||||
@ -39,6 +36,68 @@ do_test_with_invalid_flags (void)
|
||||
#endif
|
||||
#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
|
||||
| RWF_APPEND)
|
||||
|
||||
static void
|
||||
do_test_with_invalid_fd (void)
|
||||
{
|
||||
char buf[256];
|
||||
struct iovec iov = { buf, sizeof buf };
|
||||
|
||||
/* Check with flag being 0 to use the fallback code which calls pwritev
|
||||
or writev. */
|
||||
TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1);
|
||||
TEST_COMPARE (errno, EBADF);
|
||||
TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1);
|
||||
TEST_COMPARE (errno, EBADF);
|
||||
|
||||
/* Same tests as before but with flags being different than 0. Since
|
||||
there is no emulation for any flag value, fallback code returns
|
||||
ENOTSUP. This is different running on a kernel with preadv2/pwritev2
|
||||
support, where EBADF is returned). */
|
||||
TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
|
||||
TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
|
||||
}
|
||||
|
||||
static void
|
||||
do_test_with_invalid_iov (void)
|
||||
{
|
||||
{
|
||||
char buf[256];
|
||||
struct iovec iov;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = (size_t)SSIZE_MAX + 1;
|
||||
|
||||
TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1);
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1);
|
||||
TEST_COMPARE (errno, EINVAL);
|
||||
|
||||
/* Same as for invalid file descriptor tests, emulation fallback
|
||||
first checks for flag value and return ENOTSUP. */
|
||||
TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
|
||||
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
}
|
||||
|
||||
{
|
||||
/* An invalid iovec buffer should trigger an invalid memory access
|
||||
or an error (Linux for instance returns EFAULT). */
|
||||
struct iovec iov[IOV_MAX+1] = { 0 };
|
||||
|
||||
TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
|
||||
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
|
||||
TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_test_with_invalid_flags (void)
|
||||
{
|
||||
/* Set the next bit from the mask of all supported flags. */
|
||||
int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2;
|
||||
invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag);
|
||||
|
@ -30,6 +30,8 @@ do_test (void)
|
||||
{
|
||||
do_test_with_invalid_flags ();
|
||||
do_test_without_offset ();
|
||||
do_test_with_invalid_fd ();
|
||||
do_test_with_invalid_iov ();
|
||||
|
||||
return do_test_with_offset (0);
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ do_test (void)
|
||||
{
|
||||
do_test_with_invalid_flags ();
|
||||
do_test_without_offset ();
|
||||
do_test_with_invalid_fd ();
|
||||
do_test_with_invalid_iov ();
|
||||
|
||||
return do_test_with_offset (0);
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset,
|
||||
# ifdef __NR_preadv2
|
||||
ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
if (result >= 0)
|
||||
if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
# endif
|
||||
/* Trying to emulate the preadv2 syscall flags is troublesome:
|
||||
|
@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
|
||||
#ifdef __NR_preadv64v2
|
||||
ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
if (result >= 0)
|
||||
if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
#endif
|
||||
/* Trying to emulate the preadv2 syscall flags is troublesome:
|
||||
|
@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset,
|
||||
# ifdef __NR_pwritev2
|
||||
ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
if (result >= 0)
|
||||
if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
# endif
|
||||
/* Trying to emulate the pwritev2 syscall flags is troublesome:
|
||||
|
@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
|
||||
#ifdef __NR_pwritev64v2
|
||||
ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count,
|
||||
LO_HI_LONG (offset), flags);
|
||||
if (result >= 0)
|
||||
if (result >= 0 || errno != ENOSYS)
|
||||
return result;
|
||||
#endif
|
||||
/* Trying to emulate the pwritev2 syscall flags is troublesome:
|
||||
|
Loading…
Reference in New Issue
Block a user