-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Add fchmodat
fallback on Linux when flags
is nonzero.
#17954
Conversation
Dang, I have no idea why this new test is flaky. This shouldn't even throw an error given that we're not try os.fchmodat(tmp.dir.fd, "regfile", 0o600, os.AT.SYMLINK_NOFOLLOW); |
I think I understand what's happening. CI is failing when linking with glibc, and the version being used is int
fchmodat (int fd, const char *file, mode_t mode, int flag)
{
if (flag & ~AT_SYMLINK_NOFOLLOW)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
#ifndef __NR_lchmod /* Linux so far has no lchmod syscall. */
if (flag & AT_SYMLINK_NOFOLLOW)
return INLINE_SYSCALL_ERROR_RETURN_VALUE (ENOTSUP);
#endif
return INLINE_SYSCALL (fchmodat, 3, fd, file, mode);
}
|
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.
I've got some minor comments and suggestions. Looks like a good direction to me. That said, this is just a drive-by review, I'm not a Zig maintainer or anything (so feel free to ignore me).
return syscall3(.fchmodat, @bitCast(@as(isize, fd)), @intFromPtr(path), mode); | ||
} | ||
|
||
pub fn fchmodat2(fd: i32, path: [*:0]const u8, mode: mode_t, flags: u32) usize { |
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.
Might be worth adding a comment about this fchmod vs the other one? (And maybe note which Linux versions they came in on?)
// Fallback to changing permissions using procfs: | ||
// | ||
// 1. Open `path` as an `O.PATH` descriptor. | ||
// 2. Stat the fd and check if it isn't a symbolic link. | ||
// 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`. | ||
// 4. Pass the procfs path to `chmod` with the `mode`. |
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.
Maybe factor this implementation out into a fn fchmodat_fallback(..)
function?
I've rebased this PR atop of master due to the recent |
FYI: I authored a similar patch that was merged into Cosmopolitan a while ago. The difference was that atomic booleans aren't used, instead relying on |
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.
Thank you, this is nice work.
I have one very specific request: please take advantage of inline
to make it so that when flags is comptime-known to be 0, the fallback code is not compiled.
Inside the body of the inline function it should compute the value of use_c
and then call the appropriate function.
I don't quite follow, do you mean to split the fallback code into an inline function, or to mark |
I was going to link you to the relevant section of the language reference but I realized that the section was missing, so I created it: aba8d4f Hopefully it should be clear after reading these new docs. |
Not really? If |
I am not suggesting to inline all the logic, only the use_c calculation. |
This syscall was added to simplify the the libc implementations of fchmodat, as the original syscall does not take a `flags` argument. Another syscall, `map_shadow_stack`, was also added for x86_64.
The check for determining whether to use the fallback code has been moved into an inline function as per Andrew's comments in #17954.
Based on the Linux kernel fchmodat2 test
I think I understand now, is this acceptable? BTW #18131 gives a similar improvement to a function used here, might be worth adding to the review pile ;). |
No, there is too much logic in the inline function. Do you want me to show you? |
Yes please. Edit: Unless you mean something like: inline fn skipFchmodatFallback(flags: u32) bool {
return flags == 0;
} Honestly I'm more confused. Is there a way for me to verify that either of these approaches? |
The check for determining whether to use the fallback code has been moved into an inline function as per Andrew's comments in #17954.
It looks like you've unchecked the box "allow maintainers to push commits to this branch" so I moved the PR here: #18547 Have a look and let me know if it is satisfactory |
The check for determining whether to use the fallback code has been moved into an inline function as per Andrew's comments in ziglang#17954.
After updating the syscall list, I researched why
fchmodat2
was introduced. Thefchmodat
syscall doesn't take aflags
argument, meaning this wrapper has been subtly broken since its introduction. This pr changesfchmodat
to:fchmodat
ifflags
is zero.fchmodat2
if available.The procfs workaround is what glibc and musl do. This pr copies the glibc logic as it requires the least amount of syscalls.
I've also replaced the
fchmodat
tests to check for this case and ensured they passed on Linux and other systems (FreeBSD 13, NetBSD 10).