From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 51197 invoked by alias); 28 Sep 2018 19:22:05 -0000 Mailing-List: contact libc-stable-help@sourceware.org; run by ezmlm Precedence: bulk List-Post: List-Help: List-Subscribe: List-Archive: Sender: libc-stable-owner@sourceware.org Received: (qmail 51136 invoked by uid 89); 28 Sep 2018 19:22:05 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.100.1 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.7 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=Wrong X-Spam-Status: No, score=-25.7 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: mail-qk1-f194.google.com Received: from mail-qk1-f194.google.com (HELO mail-qk1-f194.google.com) (209.85.222.194) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 28 Sep 2018 19:22:02 +0000 Received: by mail-qk1-f194.google.com with SMTP id c13-v6so4559009qkm.4 for ; Fri, 28 Sep 2018 12:22:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:subject:date:message-id:in-reply-to:references; bh=qZTpzU6XLTdu0ZRJ7Sx5ffUHB1eXtXxxybZBSlM70No=; b=Uo7M7rtXsYxeQmkvZ6alfokwOk8SaJSq1IRQMWfn53/mcfNST6peFdnyAcz0oIrZS7 Uj4VgqxKq6z0cAADna3ZQml16UT1uu43WjX77jkYMbEfIWl4hwCv8xIjRppoh9c3/UGN Zf4Na9RwvNwoEn3UDpPsF8tT7igwmRQKBCjeA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=qZTpzU6XLTdu0ZRJ7Sx5ffUHB1eXtXxxybZBSlM70No=; b=HKhYFfxnAGvPM43Wy0EycpDCCzlNSi6Nbm/1gefMOFNemLZrYYxiElDU9kQtGPc9/g khaFHm0qygXHcX9pLPoUieoQGmyh/kLBQpnpItfPDhFEV4JnkODMtOgiI42sDbUnhEMo Ao/VQaAvahk4+rGXG1vlDArlYwdZxsjWxQremTueDZeYCl0AlfFya0OWZ2SNx1Fm03yf 2unSVtYKqjNCBjY4V3uj8hkU+a/EiSCVbJV/RBtw5o7IwWL9+s+dzCc9VnOiKV/N00yI YzHw2BShG3VQEOnU0maKAFgihqcJvHYL9UcuegO4ejjliMgkmUgq9TyfiMRBN5cCUFBY /BWw== X-Gm-Message-State: ABuFfoi9RvBNXepdwO+VGR8+ZbXfw1xEc44SLrTVT0Mr8i861DuFxo/8 VJO2g7XsbC2bFIRKGAEX69PRc8RUE0E= X-Google-Smtp-Source: ACcGV628ADVFlW35WChcY9UjGtS/Czd7QXr0V0bi0LXBqVkisKU5kEshiozMazbrH2lkOpXT6LMrKw== X-Received: by 2002:a37:7946:: with SMTP id u67-v6mr7225qkc.283.1538162520807; Fri, 28 Sep 2018 12:22:00 -0700 (PDT) Received: from localhost.localdomain ([201.82.189.205]) by smtp.googlemail.com with ESMTPSA id k185-v6sm3182431qkd.27.2018.09.28.12.21.59 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 28 Sep 2018 12:22:00 -0700 (PDT) From: Adhemerval Zanella To: libc-stable@sourceware.org Subject: [2.26 COMMITTED 2/2] Fix misreported errno on preadv2/pwritev2 (BZ#23579) Date: Mon, 01 Jan 2018 00:00:00 -0000 Message-Id: <20180928192152.15005-2-adhemerval.zanella@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180928192152.15005-1-adhemerval.zanella@linaro.org> References: <20180928192152.15005-1-adhemerval.zanella@linaro.org> X-IsSubscribed: yes X-SW-Source: 2018-09/txt/msg00010.txt.bz2 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) --- ChangeLog | 14 +++++ NEWS | 1 + misc/tst-preadvwritev2-common.c | 77 ++++++++++++++++++++++++++- misc/tst-preadvwritev2.c | 2 + misc/tst-preadvwritev64v2.c | 2 + sysdeps/unix/sysv/linux/preadv2.c | 2 +- sysdeps/unix/sysv/linux/preadv64v2.c | 2 +- sysdeps/unix/sysv/linux/pwritev2.c | 2 +- sysdeps/unix/sysv/linux/pwritev64v2.c | 2 +- 9 files changed, 99 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index d5e3403e8b..299fba24b1 100644 --- a/NEWS +++ b/NEWS @@ -151,6 +151,7 @@ The following bugs are resolved with this release: [23363] stdio-common/tst-printf.c has non-free license [23456] Wrong index_cpu_LZCNT [23459] COMMON_CPUID_INDEX_80000001 isn't populated for Intel processors + [23579] libc: Errors misreported in preadv2 Version 2.26 diff --git a/misc/tst-preadvwritev2-common.c b/misc/tst-preadvwritev2-common.c index 8abedc14d0..9570882fa6 100644 --- a/misc/tst-preadvwritev2-common.c +++ b/misc/tst-preadvwritev2-common.c @@ -19,10 +19,85 @@ #include #include +#ifndef RWF_HIPRI +# define RWF_HIPRI 0 +#endif +#ifndef RWF_DSYNC +# define RWF_DSYNC 0 +#endif +#ifndef RWF_SYNC +# define RWF_SYNC 0 +#endif +#ifndef RWF_NOWAIT +# define RWF_NOWAIT 0 +#endif +#ifndef RWF_APPEND +# define RWF_APPEND 0 +#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) { -#define RWF_SUPPORTED (RWF_HIPRI | RWF_DSYNC | RWF_SYNC | RWF_NOWAIT) /* Set the next bit from the mask of all supported flags. */ int invalid_flag = __builtin_clz (RWF_SUPPORTED); invalid_flag = 0x1 << ((sizeof (int) * CHAR_BIT) - invalid_flag); diff --git a/misc/tst-preadvwritev2.c b/misc/tst-preadvwritev2.c index 225f5e59c1..bebd2e56d6 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 facdbdca61..3d03e32484 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 a7a3aeeee6..c7f91025f2 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 53c946861c..4dbea0a8d4 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 17677df98d..a33ed56c55 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 f5753eede5..f0ffd2f1f6 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: -- 2.17.1