[PATCH] linux-user: report EBADF for setsockopt()/getsockopt() on a bad fd

Michael Morrell posted 1 patch 1 day, 22 hours ago
linux-user/syscall.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
[PATCH] linux-user: report EBADF for setsockopt()/getsockopt() on a bad fd
Posted by Michael Morrell 1 day, 22 hours ago
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
Re: [PATCH] linux-user: report EBADF for setsockopt()/getsockopt() on a bad fd
Posted by Michael Tokarev 23 hours ago
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
Re: [PATCH] linux-user: report EBADF for setsockopt()/getsockopt() on a bad fd
Posted by Helge Deller 1 day, 21 hours ago
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>