|
|
077c9d |
commit 7a16bdbb9ff4122af0a28dc20996c95352011fdd
|
|
|
077c9d |
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
|
|
|
077c9d |
Date: Wed Aug 29 16:36:44 2018 -0300
|
|
|
077c9d |
|
|
|
077c9d |
Fix misreported errno on preadv2/pwritev2 (BZ#23579)
|
|
|
077c9d |
|
|
|
077c9d |
The fallback code of Linux wrapper for preadv2/pwritev2 executes
|
|
|
077c9d |
regardless of the errno code for preadv2, instead of the case where
|
|
|
077c9d |
the syscall is not supported.
|
|
|
077c9d |
|
|
|
077c9d |
This fixes it by calling the fallback code iff errno is ENOSYS. The
|
|
|
077c9d |
patch also adds tests for both invalid file descriptor and invalid
|
|
|
077c9d |
iov_len and vector count.
|
|
|
077c9d |
|
|
|
077c9d |
The only discrepancy between preadv2 and fallback code regarding
|
|
|
077c9d |
error reporting is when an invalid flags are used. The fallback code
|
|
|
077c9d |
bails out earlier with ENOTSUP instead of EINVAL/EBADF when the syscall
|
|
|
077c9d |
is used.
|
|
|
077c9d |
|
|
|
077c9d |
Checked on x86_64-linux-gnu on a 4.4.0 and 4.15.0 kernel.
|
|
|
077c9d |
|
|
|
077c9d |
[BZ #23579]
|
|
|
077c9d |
* misc/tst-preadvwritev2-common.c (do_test_with_invalid_fd): New
|
|
|
077c9d |
test.
|
|
|
077c9d |
* misc/tst-preadvwritev2.c, misc/tst-preadvwritev64v2.c (do_test):
|
|
|
077c9d |
Call do_test_with_invalid_fd.
|
|
|
077c9d |
* sysdeps/unix/sysv/linux/preadv2.c (preadv2): Use fallback code iff
|
|
|
077c9d |
errno is ENOSYS.
|
|
|
077c9d |
* sysdeps/unix/sysv/linux/preadv64v2.c (preadv64v2): Likewise.
|
|
|
077c9d |
* sysdeps/unix/sysv/linux/pwritev2.c (pwritev2): Likewise.
|
|
|
077c9d |
* sysdeps/unix/sysv/linux/pwritev64v2.c (pwritev64v2): Likewise.
|
|
|
077c9d |
|
|
|
077c9d |
diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c
|
|
|
077c9d |
index f889a21544947042..50b9da3fea56d288 100644
|
|
|
077c9d |
--- a/misc/tst-preadvwritev2-common.c
|
|
|
077c9d |
+++ b/misc/tst-preadvwritev2-common.c
|
|
|
077c9d |
@@ -19,9 +19,6 @@
|
|
|
077c9d |
#include <limits.h>
|
|
|
077c9d |
#include <support/check.h>
|
|
|
077c9d |
|
|
|
077c9d |
-static void
|
|
|
077c9d |
-do_test_with_invalid_flags (void)
|
|
|
077c9d |
-{
|
|
|
077c9d |
#ifndef RWF_HIPRI
|
|
|
077c9d |
# define RWF_HIPRI 0
|
|
|
077c9d |
#endif
|
|
|
077c9d |
@@ -39,6 +36,68 @@ do_test_with_invalid_flags (void)
|
|
|
077c9d |
#endif
|
|
|
077c9d |
#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT \
|
|
|
077c9d |
| RWF_APPEND)
|
|
|
077c9d |
+
|
|
|
077c9d |
+static void
|
|
|
077c9d |
+do_test_with_invalid_fd (void)
|
|
|
077c9d |
+{
|
|
|
077c9d |
+ char buf[256];
|
|
|
077c9d |
+ struct iovec iov = { buf, sizeof buf };
|
|
|
077c9d |
+
|
|
|
077c9d |
+ /* Check with flag being 0 to use the fallback code which calls pwritev
|
|
|
077c9d |
+ or writev. */
|
|
|
077c9d |
+ TEST_VERIFY (preadv2 (-1, &iov, 1, -1, 0) == -1);
|
|
|
077c9d |
+ TEST_COMPARE (errno, EBADF);
|
|
|
077c9d |
+ TEST_VERIFY (pwritev2 (-1, &iov, 1, -1, 0) == -1);
|
|
|
077c9d |
+ TEST_COMPARE (errno, EBADF);
|
|
|
077c9d |
+
|
|
|
077c9d |
+ /* Same tests as before but with flags being different than 0. Since
|
|
|
077c9d |
+ there is no emulation for any flag value, fallback code returns
|
|
|
077c9d |
+ ENOTSUP. This is different running on a kernel with preadv2/pwritev2
|
|
|
077c9d |
+ support, where EBADF is returned). */
|
|
|
077c9d |
+ TEST_VERIFY (preadv2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
|
|
|
077c9d |
+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
|
|
|
077c9d |
+ TEST_VERIFY (pwritev2 (-1, &iov, 1, 0, RWF_HIPRI) == -1);
|
|
|
077c9d |
+ TEST_VERIFY (errno == EBADF || errno == ENOTSUP);
|
|
|
077c9d |
+}
|
|
|
077c9d |
+
|
|
|
077c9d |
+static void
|
|
|
077c9d |
+do_test_with_invalid_iov (void)
|
|
|
077c9d |
+{
|
|
|
077c9d |
+ {
|
|
|
077c9d |
+ char buf[256];
|
|
|
077c9d |
+ struct iovec iov;
|
|
|
077c9d |
+
|
|
|
077c9d |
+ iov.iov_base = buf;
|
|
|
077c9d |
+ iov.iov_len = (size_t)SSIZE_MAX + 1;
|
|
|
077c9d |
+
|
|
|
077c9d |
+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, 0) == -1);
|
|
|
077c9d |
+ TEST_COMPARE (errno, EINVAL);
|
|
|
077c9d |
+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, 0) == -1);
|
|
|
077c9d |
+ TEST_COMPARE (errno, EINVAL);
|
|
|
077c9d |
+
|
|
|
077c9d |
+ /* Same as for invalid file descriptor tests, emulation fallback
|
|
|
077c9d |
+ first checks for flag value and return ENOTSUP. */
|
|
|
077c9d |
+ TEST_VERIFY (preadv2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
|
|
|
077c9d |
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
|
|
077c9d |
+ TEST_VERIFY (pwritev2 (temp_fd, &iov, 1, 0, RWF_HIPRI) == -1);
|
|
|
077c9d |
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
|
|
077c9d |
+ }
|
|
|
077c9d |
+
|
|
|
077c9d |
+ {
|
|
|
077c9d |
+ /* An invalid iovec buffer should trigger an invalid memory access
|
|
|
077c9d |
+ or an error (Linux for instance returns EFAULT). */
|
|
|
077c9d |
+ struct iovec iov[IOV_MAX+1] = { 0 };
|
|
|
077c9d |
+
|
|
|
077c9d |
+ TEST_VERIFY (preadv2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
|
|
|
077c9d |
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
|
|
077c9d |
+ TEST_VERIFY (pwritev2 (temp_fd, iov, IOV_MAX + 1, 0, RWF_HIPRI) == -1);
|
|
|
077c9d |
+ TEST_VERIFY (errno == EINVAL || errno == ENOTSUP);
|
|
|
077c9d |
+ }
|
|
|
077c9d |
+}
|
|
|
077c9d |
+
|
|
|
077c9d |
+static void
|
|
|
077c9d |
+do_test_with_invalid_flags (void)
|
|
|
077c9d |
+{
|
|
|
077c9d |
/* Set the next bit from the mask of all supported flags. */
|
|
|
077c9d |
int invalid_flag = RWF_SUPPORTED != 0 ? __builtin_clz (RWF_SUPPORTED) : 2;
|
|
|
077c9d |
invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag);
|
|
|
077c9d |
diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c
|
|
|
077c9d |
index be22802dbe00317f..cb58cbe41ecc639d 100644
|
|
|
077c9d |
--- a/misc/tst-preadvwritev2.c
|
|
|
077c9d |
+++ b/misc/tst-preadvwritev2.c
|
|
|
077c9d |
@@ -30,6 +30,8 @@ do_test (void)
|
|
|
077c9d |
{
|
|
|
077c9d |
do_test_with_invalid_flags ();
|
|
|
077c9d |
do_test_without_offset ();
|
|
|
077c9d |
+ do_test_with_invalid_fd ();
|
|
|
077c9d |
+ do_test_with_invalid_iov ();
|
|
|
077c9d |
|
|
|
077c9d |
return do_test_with_offset (0);
|
|
|
077c9d |
}
|
|
|
077c9d |
diff --git a/misc/tst-preadvwritev64v2.c b/misc/tst-preadvwritev64v2.c
|
|
|
077c9d |
index 8d3cc32b284dbf4c..6a9de54c786acc53 100644
|
|
|
077c9d |
--- a/misc/tst-preadvwritev64v2.c
|
|
|
077c9d |
+++ b/misc/tst-preadvwritev64v2.c
|
|
|
077c9d |
@@ -32,6 +32,8 @@ do_test (void)
|
|
|
077c9d |
{
|
|
|
077c9d |
do_test_with_invalid_flags ();
|
|
|
077c9d |
do_test_without_offset ();
|
|
|
077c9d |
+ do_test_with_invalid_fd ();
|
|
|
077c9d |
+ do_test_with_invalid_iov ();
|
|
|
077c9d |
|
|
|
077c9d |
return do_test_with_offset (0);
|
|
|
077c9d |
}
|
|
|
077c9d |
diff --git a/sysdeps/unix/sysv/linux/preadv2.c b/sysdeps/unix/sysv/linux/preadv2.c
|
|
|
077c9d |
index c8bf0764ef2629fc..bb08cbc5fd96962e 100644
|
|
|
077c9d |
--- a/sysdeps/unix/sysv/linux/preadv2.c
|
|
|
077c9d |
+++ b/sysdeps/unix/sysv/linux/preadv2.c
|
|
|
077c9d |
@@ -32,7 +32,7 @@ preadv2 (int fd, const struct iovec *vector, int count, off_t offset,
|
|
|
077c9d |
# ifdef __NR_preadv2
|
|
|
077c9d |
ssize_t result = SYSCALL_CANCEL (preadv2, fd, vector, count,
|
|
|
077c9d |
LO_HI_LONG (offset), flags);
|
|
|
077c9d |
- if (result >= 0)
|
|
|
077c9d |
+ if (result >= 0 || errno != ENOSYS)
|
|
|
077c9d |
return result;
|
|
|
077c9d |
# endif
|
|
|
077c9d |
/* Trying to emulate the preadv2 syscall flags is troublesome:
|
|
|
077c9d |
diff --git a/sysdeps/unix/sysv/linux/preadv64v2.c b/sysdeps/unix/sysv/linux/preadv64v2.c
|
|
|
077c9d |
index d7400a0252a8c6a1..b72a047347b1db0e 100644
|
|
|
077c9d |
--- a/sysdeps/unix/sysv/linux/preadv64v2.c
|
|
|
077c9d |
+++ b/sysdeps/unix/sysv/linux/preadv64v2.c
|
|
|
077c9d |
@@ -30,7 +30,7 @@ preadv64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
|
|
|
077c9d |
#ifdef __NR_preadv64v2
|
|
|
077c9d |
ssize_t result = SYSCALL_CANCEL (preadv64v2, fd, vector, count,
|
|
|
077c9d |
LO_HI_LONG (offset), flags);
|
|
|
077c9d |
- if (result >= 0)
|
|
|
077c9d |
+ if (result >= 0 || errno != ENOSYS)
|
|
|
077c9d |
return result;
|
|
|
077c9d |
#endif
|
|
|
077c9d |
/* Trying to emulate the preadv2 syscall flags is troublesome:
|
|
|
077c9d |
diff --git a/sysdeps/unix/sysv/linux/pwritev2.c b/sysdeps/unix/sysv/linux/pwritev2.c
|
|
|
077c9d |
index 29c2264c8f3d949a..26333ebd43c5f0af 100644
|
|
|
077c9d |
--- a/sysdeps/unix/sysv/linux/pwritev2.c
|
|
|
077c9d |
+++ b/sysdeps/unix/sysv/linux/pwritev2.c
|
|
|
077c9d |
@@ -28,7 +28,7 @@ pwritev2 (int fd, const struct iovec *vector, int count, off_t offset,
|
|
|
077c9d |
# ifdef __NR_pwritev2
|
|
|
077c9d |
ssize_t result = SYSCALL_CANCEL (pwritev2, fd, vector, count,
|
|
|
077c9d |
LO_HI_LONG (offset), flags);
|
|
|
077c9d |
- if (result >= 0)
|
|
|
077c9d |
+ if (result >= 0 || errno != ENOSYS)
|
|
|
077c9d |
return result;
|
|
|
077c9d |
# endif
|
|
|
077c9d |
/* Trying to emulate the pwritev2 syscall flags is troublesome:
|
|
|
077c9d |
diff --git a/sysdeps/unix/sysv/linux/pwritev64v2.c b/sysdeps/unix/sysv/linux/pwritev64v2.c
|
|
|
077c9d |
index 42da321149bce40d..17ea905aa6a8db94 100644
|
|
|
077c9d |
--- a/sysdeps/unix/sysv/linux/pwritev64v2.c
|
|
|
077c9d |
+++ b/sysdeps/unix/sysv/linux/pwritev64v2.c
|
|
|
077c9d |
@@ -30,7 +30,7 @@ pwritev64v2 (int fd, const struct iovec *vector, int count, off64_t offset,
|
|
|
077c9d |
#ifdef __NR_pwritev64v2
|
|
|
077c9d |
ssize_t result = SYSCALL_CANCEL (pwritev64v2, fd, vector, count,
|
|
|
077c9d |
LO_HI_LONG (offset), flags);
|
|
|
077c9d |
- if (result >= 0)
|
|
|
077c9d |
+ if (result >= 0 || errno != ENOSYS)
|
|
|
077c9d |
return result;
|
|
|
077c9d |
#endif
|
|
|
077c9d |
/* Trying to emulate the pwritev2 syscall flags is troublesome:
|