-
Notifications
You must be signed in to change notification settings - Fork 9
Accept FIOASYNC ioctl and F_SETOWN/F_GETOWN fcntl #81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Max042004
wants to merge
1
commit into
sysprog21:main
Choose a base branch
from
Max042004:ioctl-fioasync
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -801,6 +801,29 @@ int64_t sys_fcntl(guest_t *g, int fd, int cmd, uint64_t arg) | |
| host_fd_ref_close(&host_ref); | ||
| return 0; | ||
| } | ||
| case 8: /* F_SETOWN */ | ||
| case 15: /* F_SETOWN_EX */ | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: F_SETOWN_EX no-op path skips user-pointer read/validation, so bad guest pointers incorrectly succeed. Prompt for AI agents |
||
| /* SIGIO/SIGURG delivery owner. nginx's ngx_spawn_process pairs | ||
| * ioctl(FIOASYNC) with fcntl(F_SETOWN) on the channel socket before | ||
| * fork() and aborts the worker (NGX_INVALID_PID) if either fails. | ||
| * elfuse does not deliver host SIGIO into the guest (see LINUX_FIOASYNC | ||
| * in sys_ioctl), so no owner is tracked: accept the request as a | ||
| * no-op. */ | ||
| return 0; | ||
| case 9: /* F_GETOWN */ | ||
| /* No owner tracked; report none. */ | ||
| return 0; | ||
| case 16: { /* F_GETOWN_EX */ | ||
| /* glibc implements fcntl(F_GETOWN) on top of F_GETOWN_EX, so this must | ||
| * answer coherently with the F_SETOWN no-op above rather than EINVAL | ||
| * (which would make F_GETOWN fail under glibc). Report "owned by no | ||
| * specific process": struct f_owner_ex { int type; int pid; } with | ||
| * type=F_OWNER_PID(1), pid=0. */ | ||
| int32_t owner_ex[2] = {1 /* F_OWNER_PID */, 0 /* pid */}; | ||
| if (guest_write_small(g, arg, owner_ex, sizeof(owner_ex)) < 0) | ||
| return -LINUX_EFAULT; | ||
| return 0; | ||
| } | ||
| case 1024: /* F_GETPIPE_SZ */ | ||
| /* macOS does not support pipe size queries; return default 64KiB */ | ||
| return 65536; | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| /* FIOASYNC ioctl + F_SETOWN/F_GETOWN fcntl regression test | ||
| * | ||
| * Copyright 2026 elfuse contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| * | ||
| * nginx's ngx_spawn_process arms the master->worker channel socket with | ||
| * ioctl(FIOASYNC) immediately followed by fcntl(F_SETOWN), right before fork(), | ||
| * and treats a failure of EITHER as fatal: it logs an alert, ngx_close_channel, | ||
| * and returns NGX_INVALID_PID -- so it never forks the worker. elfuse used to | ||
| * answer FIOASYNC with ENOTTY and F_SETOWN with EINVAL, which silently left the | ||
| * master with zero workers: the listen socket still accepted connections at the | ||
| * host kernel, but nothing in the guest ever accept()ed them, so every request | ||
| * hung. This test pins the fix by replaying that pre-fork channel arming. | ||
| * | ||
| * elfuse does not forward host SIGIO into the guest, and nginx workers receive | ||
| * client I/O and channel commands via epoll rather than SIGIO, so both calls | ||
| * are accepted as no-ops that report success (F_GETOWN reports "no owner", 0). | ||
| * | ||
| * Syscalls exercised: socketpair(199), socket(198), ioctl(29) FIOASYNC, | ||
| * fcntl(25) F_SETOWN/F_GETOWN, getpid(172), close(57) | ||
| */ | ||
|
|
||
| #include <fcntl.h> | ||
| #include <sys/ioctl.h> | ||
| #include <sys/socket.h> | ||
| #include <unistd.h> | ||
|
|
||
| #include "test-harness.h" | ||
|
|
||
| #ifndef FIOASYNC | ||
| #define FIOASYNC 0x5452 | ||
| #endif | ||
|
|
||
| int passes = 0, fails = 0; | ||
|
|
||
| /* Replay nginx's ngx_spawn_process async/owner arming on a single fd. */ | ||
| static void check_async_owner(int fd, const char *what) | ||
| { | ||
| char label[80]; | ||
| int on = 1; | ||
|
|
||
| snprintf(label, sizeof(label), "%s: ioctl(FIOASYNC) enable -> 0", what); | ||
| TEST(label); | ||
| EXPECT_EQ(ioctl(fd, FIOASYNC, &on), 0, "FIOASYNC enable rejected"); | ||
|
|
||
| snprintf(label, sizeof(label), "%s: fcntl(F_SETOWN) -> 0", what); | ||
| TEST(label); | ||
| EXPECT_EQ(fcntl(fd, F_SETOWN, getpid()), 0, "F_SETOWN rejected"); | ||
|
|
||
| /* F_GETOWN reports the owner; elfuse tracks none, so 0 (no error). glibc | ||
| * may probe F_GETOWN_EX first and fall back to plain F_GETOWN on EINVAL -- | ||
| * either way the visible result must not be a failure. */ | ||
| snprintf(label, sizeof(label), "%s: fcntl(F_GETOWN) -> not an error", what); | ||
| TEST(label); | ||
| EXPECT_TRUE(fcntl(fd, F_GETOWN) >= 0, "F_GETOWN returned an error"); | ||
|
|
||
| on = 0; | ||
| snprintf(label, sizeof(label), "%s: ioctl(FIOASYNC) disable -> 0", what); | ||
| TEST(label); | ||
| EXPECT_EQ(ioctl(fd, FIOASYNC, &on), 0, "FIOASYNC disable rejected"); | ||
| } | ||
|
|
||
| int main(void) | ||
| { | ||
| printf("test-ioctl-fioasync: FIOASYNC ioctl + F_SETOWN/F_GETOWN fcntl\n"); | ||
|
|
||
| /* nginx's channel is an AF_UNIX SOCK_STREAM socketpair; FIOASYNC/F_SETOWN | ||
| * are applied to channel[0] (nginx also marks it non-blocking via FIONBIO | ||
| * first, which this test omits to stay focused on the calls added here). */ | ||
| int sp[2]; | ||
| TEST("socketpair(AF_UNIX, SOCK_STREAM)"); | ||
| EXPECT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sp), 0, "socketpair failed"); | ||
|
|
||
| check_async_owner(sp[0], "unix socketpair"); | ||
|
|
||
| close(sp[0]); | ||
| close(sp[1]); | ||
|
|
||
| /* A plain TCP socket too -- the same family as nginx's listen sockets. */ | ||
| int s = socket(AF_INET, SOCK_STREAM, 0); | ||
| TEST("socket(AF_INET, SOCK_STREAM)"); | ||
| EXPECT_TRUE(s >= 0, "socket failed"); | ||
| if (s >= 0) { | ||
| check_async_owner(s, "tcp socket"); | ||
| close(s); | ||
| } | ||
|
|
||
| SUMMARY("test-ioctl-fioasync"); | ||
| return fails > 0 ? 1 : 0; | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: New F_SETOWN/F_GETOWN handlers can return success for closed FDs because they skip closed-descriptor validation.
Prompt for AI agents