Project

General

Profile

Actions

Feature #2998

closed

accept4 returns EPERM instead of ENOSYS on some platforms

Added by alex-che about 5 years ago. Updated almost 5 years ago.

Status:
Fixed
Priority:
Normal
Category:
core
Target version:
ASK QUESTIONS IN Forums:

Description

I'm working on embedded Freescale ARM Linux, kernel 2.6.35, glibc 2.21. On this platform:
1) accept4() system call is not supported,
2) glibc returns EPERM instead of ENOSYS for missing implementations.
For this reason the fdevent_accept_listenfd() wrapper in fdevent.c does not fallback to calling accept() after trying to call accept4(), and just fails.
After I added || errno == EPERM to the else if clause near the line 594, everything works fine.

Actions #1

Updated by gstrauss about 5 years ago

linux kernel 2.6.35 was released 1 Aug 2010, about 9 1/2 years ago. ( https://kernelnewbies.org/LinuxVersions )
glibc 2.21 was released 6 Feb 2015 ( https://www.gnu.org/software/libc/ )

Why such a disparity in release dates?

Actions #2

Updated by gstrauss about 5 years ago

Please double-check your versions and the kernel headers against which you cross-compiled glibc and the kernel.

According to the man page for accept4() on a (modern!) Linux system:

The accept4() system call is available starting with Linux 2.6.28; support in glibc is available starting with version 2.10.

The man page also documents:

In addition, Linux accept() may fail if:

EPERM Firewall rules forbid connection.

Your suggested fix is at odds with the documentation in the man page.

Actions #3

Updated by alex-che almost 5 years ago

The docs was the first thing I checked. I completely agree that EPERM is not the expected error for this case. That's why it took me too much time to find the real reason.

I develop an app which needs to run on an old platform, which I cannot upgrade. A lot of modern libraries won't compile with the original ARM GCC toolchain used for that platform, that's why I use newer toolchain and copy the whole bunch of needed libs, including libc.so, to the platform, so that they are used instead of the original libs of the platform. Hence the version disparity.

As to accept4() syscall availability. According to some sources accept4() was not added to all platforms on 2.6.28. E.g., it was added to ARM only on 2.6.36. Please, see https://lwn.net/Articles/789961/ or just google 'ARM accept4'. Given that my ARM kernel is 2.6.35, it looks likely.

I also found several mentions that on some systems EPERM is incorrectly returned in case of missing syscall table implementation. E.g., see https://github.com/borgbackup/borg/issues/4710 or https://www.postgresql.org/message-id/flat/CA%2BhUKG%2BydOUT4zjxb6QmJWy8U9WbC-q%2BJWV7wLsEY9Df%3Dmw0Mw%40mail.gmail.com#ac8f14897647dc7eae3c7e7cbed36d93 or http://lists.busybox.net/pipermail/buildroot/2011-April/042860.html

Actually, I understand that this case is pretty exotic. And I can understand if you're not willing to change lighttpd code to support undocumented and highly unprobable cases. On the other hand, adding one more error code to the if clause seems to be a tiny code change, which won't break anything, since if EPERM in accept4() is really caused by the firewall (as per documentation), then the accept() should fail with the same error code as well.

Actions #4

Updated by gstrauss almost 5 years ago

  • Tracker changed from Bug to Feature
  • Status changed from New to Patch Pending
  • Target version changed from 1.4.x to 1.4.55
--- a/src/fdevent.c
+++ b/src/fdevent.c
@@ -629,9 +629,18 @@ int fdevent_accept_listenfd(int listenfd, struct sockaddr *addr, size_t *addrlen
                                        fd = -1;
                                }
                        }
-               } else if (errno == ENOSYS || errno == ENOTSUP) {
-                       fd = accept(listenfd, addr, &len);
-                       sock_cloexec = 0;
+               }
+               else {
+                       switch (errno) {
+                       case ENOSYS:
+                       case ENOTSUP:
+                       case EPERM:
+                               fd = accept(listenfd, addr, &len);
+                               sock_cloexec = 0;
+                               break;
+                       default:
+                               break;
+                       }
                }
        }
        else {
Actions #5

Updated by gstrauss almost 5 years ago

  • Status changed from Patch Pending to Fixed
  • % Done changed from 0 to 100
Actions

Also available in: Atom