linux-user/syscall.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
From: Igor Shevlyakov <igor@tachyum.com>
The kernel looks the fd up before validating the rest of the call, so a
negative fd is EBADF whatever else is wrong with the arguments. Several
arms of do_setsockopt()/do_getsockopt() reject optlen or optname and
return without ever reaching the host syscall, so the host never gets to
supply that EBADF and the guest sees the argument error instead:
setsockopt(-1, SOL_TCP, TCP_NODELAY, ptr, 0) EINVAL, want EBADF
setsockopt(-1, 0x4321, 1, ptr, sizeof(int)) ENOPROTOOPT
getsockopt(-1, 0x4321, 1, ptr, &len) EOPNOTSUPP
Caught by glibc's posix/test-errno.
Signed-off-by: Igor Shevlyakov <igor@tachyum.com>
---
linux-user/syscall.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9f454502cb..e7c9fb33a3 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2119,6 +2119,15 @@ static abi_long do_setsockopt(int sockfd, int level, int optname,
abi_long ret;
int val;
+ /*
+ * The kernel looks the fd up before it validates anything else, so a bad
+ * fd is EBADF even when the rest of the call is also wrong. Several arms
+ * below reject optlen or optname without ever reaching the host syscall,
+ * and would report that instead.
+ */
+ if (sockfd < 0) {
+ return -TARGET_EBADF;
+ }
switch(level) {
case SOL_TCP:
case SOL_UDP:
@@ -2623,6 +2632,10 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
int len, val;
socklen_t lv;
+ /* EBADF wins over the argument checks below; see do_setsockopt(). */
+ if (sockfd < 0) {
+ return -TARGET_EBADF;
+ }
switch(level) {
case TARGET_SOL_SOCKET:
level = SOL_SOCKET;
--
2.43.0
On 9/24/26 22:33, Michael Morrell wrote: > From: Igor Shevlyakov <igor@tachyum.com> > > The kernel looks the fd up before validating the rest of the call, so a > negative fd is EBADF whatever else is wrong with the arguments. Several > arms of do_setsockopt()/do_getsockopt() reject optlen or optname and > return without ever reaching the host syscall, so the host never gets to > supply that EBADF and the guest sees the argument error instead: > > setsockopt(-1, SOL_TCP, TCP_NODELAY, ptr, 0) EINVAL, want EBADF > setsockopt(-1, 0x4321, 1, ptr, sizeof(int)) ENOPROTOOPT > getsockopt(-1, 0x4321, 1, ptr, &len) EOPNOTSUPP EBADF is not just -1, it is any number which does not have open FD. Yes, -1 is probably most common bug here (passing -1 as fd is a bug in the user program), but it is definitely not everything. Thanks, /mjt
On 9/24/26 21:33, Michael Morrell wrote: > From: Igor Shevlyakov <igor@tachyum.com> > > The kernel looks the fd up before validating the rest of the call, so a > negative fd is EBADF whatever else is wrong with the arguments. Several > arms of do_setsockopt()/do_getsockopt() reject optlen or optname and > return without ever reaching the host syscall, so the host never gets to > supply that EBADF and the guest sees the argument error instead: > > setsockopt(-1, SOL_TCP, TCP_NODELAY, ptr, 0) EINVAL, want EBADF > setsockopt(-1, 0x4321, 1, ptr, sizeof(int)) ENOPROTOOPT > getsockopt(-1, 0x4321, 1, ptr, &len) EOPNOTSUPP > > Caught by glibc's posix/test-errno. > > Signed-off-by: Igor Shevlyakov <igor@tachyum.com> > ---> linux-user/syscall.c | 13 +++++++++++++ > 1 file changed, 13 insertions(+) Reviewed-by: Helge Deller <deller@gmx.de>
© 2016 - 2026 Red Hat, Inc.