aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2018-08-29 16:36:44 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2018-09-28 15:32:43 -0300
commit044c96f0d5595aeb0bb4e79355081c5a7f4faca5 (patch)
tree1761fac9877e225f7c98280f217bf4d5dac498d5
parent3a67c72c1512f778304a5644dea2fcf5bdece274 (diff)
downloadtermbaud-044c96f0d5595aeb0bb4e79355081c5a7f4faca5.tar.gz
termbaud-044c96f0d5595aeb0bb4e79355081c5a7f4faca5.tar.xz
termbaud-044c96f0d5595aeb0bb4e79355081c5a7f4faca5.zip
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 7a16bdbb9ff4122af0a28dc20996c95352011fdd)
-rw-r--r--ChangeLog14
-rw-r--r--NEWS1
-rw-r--r--misc/tst-preadvwritev2-common.c65
-rw-r--r--misc/tst-preadvwritev2.c2
-rw-r--r--misc/tst-preadvwritev64v2.c2
-rw-r--r--sysdeps/unix/sysv/linux/preadv2.c2
-rw-r--r--sysdeps/unix/sysv/linux/preadv64v2.c2
-rw-r--r--sysdeps/unix/sysv/linux/pwritev2.c2
-rw-r--r--sysdeps/unix/sysv/linux/pwritev64v2.c2
9 files changed, 85 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 4fbb9e2ad8f..11a9b8d98e8 100644
--- a/ChangeLog
+++ b/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-27 Andreas Schwab <schwab@suse.de>
[BZ #23717]
diff --git a/NEWS b/NEWS
index bc568bcec0a..fd149411283 100644
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,7 @@ The following bugs are resolved with this release:
[23521] nss_files aliases database file stream leak
[23538] pthread_cond_broadcast: Fix waiters-after-spinning case
[23578] regex: Fix memory overread in re_compile_pattern
+ [23579] libc: Errors misreported in preadv2
[23606] Missing ENDBR32 in sysdeps/i386/start.S
[23679] gethostid: Missing NULL check for gethostbyname_r result
[23717] Fix stack overflow in stdlib/tst-setcontext9
diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c
index f889a215449..50b9da3fea5 100644
--- a/misc/tst-preadvwritev2-common.c
+++ b/misc/tst-preadvwritev2-common.c
@@ -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);
diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c
index be22802dbe0..cb58cbe41ec 100644
--- a/misc/tst-preadvwritev2.c
+++ b/misc/tst-preadvwritev2.c
@@ -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);
}
diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c
index 8d3cc32b284..6a9de54c786 100644
--- a/misc/tst-preadvwritev64v2.c
+++ b/misc/tst-preadvwritev64v2.c
@@ -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);
}
diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c
index c8bf0764ef2..bb08cbc5fd9 100644
--- a/sysdeps/unix/sysv/linux/preadv2.c
+++ b/sysdeps/unix/sysv/linux/preadv2.c
@@ -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:
diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c
index d7400a0252a..b72a047347b 100644
--- a/sysdeps/unix/sysv/linux/preadv64v2.c
+++ b/sysdeps/unix/sysv/linux/preadv64v2.c
@@ -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:
diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c
index 29c2264c8f3..26333ebd43c 100644
--- a/sysdeps/unix/sysv/linux/pwritev2.c
+++ b/sysdeps/unix/sysv/linux/pwritev2.c
@@ -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:
diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c
index 42da321149b..17ea905aa6a 100644
--- a/sysdeps/unix/sysv/linux/pwritev64v2.c
+++ b/sysdeps/unix/sysv/linux/pwritev64v2.c
@@ -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: