* EBADF returned from close() by FUSE
@ 2024-04-18 22:10 The 8472
2024-04-19 3:30 ` Antonio SJ Musumeci
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-18 22:10 UTC (permalink / raw)
To: linux-fsdevel
Hello, first time mailing the kernel mailing lists here, I hope got the right one.
I'm investigating a bug report against the Rust standard library about error handling
when closing file descriptors[0].
Testing shows that a FUSE flush request can be answered with a EBADF error
and this is surfaced to the close() call.
I am asking if it is intended behavior that filesystems can pass arbitrary error codes.
Specifically a EBADF returned from close() and other syscalls that only use that code
to indicate that it's not an open FD number is concerning since attempting to use
an incorrect FD number would normally indicate a double-drop or some other part
of the program trampling over file descriptors it is not supposed to touch.
But if FUSE or other filesystems can pass arbitrary error codes into syscall results
then it becomes impossible to distinguish fatally broken invariants (file descriptor ownership
within a program) from merely questionable fileystem behavior.
Since file descriptors are densely allocated (no equivalent to ASLR or guard pages)
there are very little guard rails against accidental ownership violations.
- The 8472
[0] https://github.com/rust-lang/rust/issues/124105
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-18 22:10 EBADF returned from close() by FUSE The 8472
@ 2024-04-19 3:30 ` Antonio SJ Musumeci
2024-04-19 6:55 ` The 8472
0 siblings, 1 reply; 15+ messages in thread
From: Antonio SJ Musumeci @ 2024-04-19 3:30 UTC (permalink / raw)
To: The 8472, linux-fsdevel
On 4/18/24 17:10, The 8472 wrote:
> Hello, first time mailing the kernel mailing lists here, I hope got the right one.
>
> I'm investigating a bug report against the Rust standard library about error handling
> when closing file descriptors[0].
> Testing shows that a FUSE flush request can be answered with a EBADF error
> and this is surfaced to the close() call.
>
> I am asking if it is intended behavior that filesystems can pass arbitrary error codes.
>
> Specifically a EBADF returned from close() and other syscalls that only use that code
> to indicate that it's not an open FD number is concerning since attempting to use
> an incorrect FD number would normally indicate a double-drop or some other part
> of the program trampling over file descriptors it is not supposed to touch.
>
> But if FUSE or other filesystems can pass arbitrary error codes into syscall results
> then it becomes impossible to distinguish fatally broken invariants (file descriptor ownership
> within a program) from merely questionable fileystem behavior.
> Since file descriptors are densely allocated (no equivalent to ASLR or guard pages)
> there are very little guard rails against accidental ownership violations.
>
>
> - The 8472
>
> [0] https://github.com/rust-lang/rust/issues/124105
I can't see how the kernel could meaningfully know of or limit errors
coming from the FUSE server without compromising the nature of the
technology. So in that sense... yes, it is intentional.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 3:30 ` Antonio SJ Musumeci
@ 2024-04-19 6:55 ` The 8472
[not found] ` <8c7552b1-f371-4a75-98cc-f2c89816becb@spawn.link>
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-19 6:55 UTC (permalink / raw)
To: Antonio SJ Musumeci, The 8472, linux-fsdevel
On 19-04-2024 05:30, Antonio SJ Musumeci wrote:
> On 4/18/24 17:10, The 8472 wrote:
>> Hello, first time mailing the kernel mailing lists here, I hope got the right one.
>>
>> I'm investigating a bug report against the Rust standard library about error handling
>> when closing file descriptors[0].
>> Testing shows that a FUSE flush request can be answered with a EBADF error
>> and this is surfaced to the close() call.
>>
>> I am asking if it is intended behavior that filesystems can pass arbitrary error codes.
>>
>> Specifically a EBADF returned from close() and other syscalls that only use that code
>> to indicate that it's not an open FD number is concerning since attempting to use
>> an incorrect FD number would normally indicate a double-drop or some other part
>> of the program trampling over file descriptors it is not supposed to touch.
>>
>> But if FUSE or other filesystems can pass arbitrary error codes into syscall results
>> then it becomes impossible to distinguish fatally broken invariants (file descriptor ownership
>> within a program) from merely questionable fileystem behavior.
>> Since file descriptors are densely allocated (no equivalent to ASLR or guard pages)
>> there are very little guard rails against accidental ownership violations.
>>
>>
>> - The 8472
>>
>> [0] https://github.com/rust-lang/rust/issues/124105
> I can't see how the kernel could meaningfully know of or limit errors
> coming from the FUSE server without compromising the nature of the
> technology. So in that sense... yes, it is intentional.
File descriptor numbers are not a FUSE-managed resource, so I was hoping
it would reserve error codes that are documented to signal incorrect
access to that resource and convert external errors to another code (e.g. EIO).
This would then signal that the file descriptor itself was valid but the underlying
resource encountered an error while performing the operation.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
[not found] ` <8c7552b1-f371-4a75-98cc-f2c89816becb@spawn.link>
@ 2024-04-19 18:18 ` The 8472
2024-04-19 20:07 ` Antonio SJ Musumeci
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-19 18:18 UTC (permalink / raw)
To: Antonio SJ Musumeci, The 8472, linux-fsdevel
On 19-04-2024 13:42, Antonio SJ Musumeci wrote:
> On 4/19/24 01:55, The 8472 wrote:
>> On 19-04-2024 05:30, Antonio SJ Musumeci wrote:
>>> I can't see how the kernel could meaningfully know of or limit errors
>>> coming from the FUSE server without compromising the nature of the
>>> technology. So in that sense... yes, it is intentional.
>> File descriptor numbers are not a FUSE-managed resource, so I was hoping
>> it would reserve error codes that are documented to signal incorrect
>> access to that resource and convert external errors to another code (e.g. EIO).
>> This would then signal that the file descriptor itself was valid but the underlying
>> resource encountered an error while performing the operation.
> Anything can be a FUSE managed resource by proxy. [...]
I'm referring to the slots in the file descriptor table of a process (A) that is opening
a file on a FUSE filesystem. Whether a slot (FD number) is occupied or not
is between the kernel and that process, not the server (S).
Imo the kernel should only return EBADF when the process accesses an FD
that is not in its table, which tends to be a fatal error in multithreaded
programs.
If S internally accesses invalid file descriptors that has no
bearing on the state of the FD table of A. From A's perspective
some sort of IO error occurred in the underlying storage system
while releasing the FD, but it did use a valid file descriptor.
> [...] There are a number of
> situations where FUSE itself return errors but the largest surface area
> for errors are from the FUSE server. And the server needs the ability to
> return nearly anything.
I'm not talking about what the server is allowed to return. I'm referring
to which errors from the server get bubbled up verbatim through syscalls on
files that are a FUSE mount.
Is it necessary to pass through arbitrary FUSE errors, especially EBADF,
when a processes closes a file that's backed by fuse?
This shouldn't happen:
|openat(AT_FDCWD, "./fuse-test/foo", O_RDONLY|O_CLOEXEC) = 5 close(5) = -1 EBADF (Bad file descriptor)|
> Errnos are not *really* standard. They vary by
> kernel release, different OSes, different libcs, different filesystems,
> etc. As I pointed out recently to someone the use of EPERM to mean a
> filesystem doesn't support "link" is not defined everywhere. Including
> POSIX IIRC. And given FUSE is a cross platform protocol it shouldn't,
> within reason, be interpreting any errors sent from the server (IMO).
FUSE can send any errnos it wants over its client-server protocol.
But the kernel could still translate them to error codes that don't
have a documented meaning for a specific syscall.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 18:18 ` The 8472
@ 2024-04-19 20:07 ` Antonio SJ Musumeci
2024-04-19 20:45 ` The 8472
0 siblings, 1 reply; 15+ messages in thread
From: Antonio SJ Musumeci @ 2024-04-19 20:07 UTC (permalink / raw)
To: The 8472, linux-fsdevel
On 4/19/24 13:18, The 8472 wrote:
>> Errnos are not *really* standard. They vary by
>> kernel release, different OSes, different libcs, different filesystems,
>> etc. As I pointed out recently to someone the use of EPERM to mean a
>> filesystem doesn't support "link" is not defined everywhere. Including
>> POSIX IIRC. And given FUSE is a cross platform protocol it shouldn't,
>> within reason, be interpreting any errors sent from the server (IMO).
> FUSE can send any errnos it wants over its client-server protocol.
> But the kernel could still translate them to error codes that don't
> have a documented meaning for a specific syscall.
No one is talking about or cares about the protocol error handling. That
is private to the protocol. What matters is what FUSE kernel side does.
And I'd disagree with you because as I tried to point out that
"documented meaning" is not set in stone. Things change over time.
Different systems, different filesystems, etc. treat situations
differently. Some platforms don't even have certain errno or conflate
others. Aren't there even differences in errno across some Linux archs?
This is just a fact of life. FUSE trying to make sense of that mess is
just going to lead to more of a mess. IMO EIO is no better than EBADF. A
lot of software don't handle handle EXDEV correctly let alone random
other errnos. For years Apple's SMB server would return EIO for just
about anything happening on the backend. If a FUSE server is sending
back EBADF in flush then it is likely a bug or bad decision. Ask them to
fix it.
And really... what is this translation table going to look like? `errno
--list | wc -l` returns 134. You going to have huge switch statements on
every single one of the couple dozen FUSE functions? Some of those
maybe with special checks against arguments for the function too since
many errno's are used to indicate multiple, sometimes entirely
different, errors? It'd be a mess. And as a cross platform technology
you'd need to define it as part of the protocol effectively. And it'd be
backwards incompatible therefore optional.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 20:07 ` Antonio SJ Musumeci
@ 2024-04-19 20:45 ` The 8472
2024-04-19 21:29 ` Antonio SJ Musumeci
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-19 20:45 UTC (permalink / raw)
To: Antonio SJ Musumeci, The 8472, linux-fsdevel
On 19-04-2024 22:07, Antonio SJ Musumeci wrote:
> And I'd disagree with you because as I tried to point out that
> "documented meaning" is not set in stone. Things change over time.
> Different systems, different filesystems, etc. treat situations
> differently. Some platforms don't even have certain errno or conflate
> others. Aren't there even differences in errno across some Linux archs?
Syscalls have documentation. Errors and their semantics are part
of the documentation. If the kernel cannot actually provide
the documented semantics because it passes errors through without
sanitizing them then this should at least be documented
for each affected syscall.
Proper API documentation and stability guarantees are important
so we can write robust software against them.
Note that write(2) documents
Other errors may occur, depending on the object connected to fd.
close(2) has no such note.
> This is just a fact of life. FUSE trying to make sense of that mess is
> just going to lead to more of a mess. IMO EIO is no better than EBADF. A
> lot of software don't handle handle EXDEV correctly let alone random
> other errnos. For years Apple's SMB server would return EIO for just
> about anything happening on the backend.
That does not mean userspace should be exposed to the entirety
of the mess. And in my opinion EIO is better than EBADF because
the former "merely" indicates that something went wrong relating
to a particular file. EBADF indicates that the file descriptor
table of the process may have been corrupted.
> If a FUSE server is sending
> back EBADF in flush then it is likely a bug or bad decision.
Agreed.
> Ask them to fix it.
Will try. But the kernel should imo also do its part fulfilling its API
contract.
> And really... what is this translation table going to look like? `errno
> --list | wc -l` returns 134. You going to have huge switch statements on
> every single one of the couple dozen FUSE functions? Some of those
> maybe with special checks against arguments for the function too since
> many errno's are used to indicate multiple, sometimes entirely
> different, errors? It'd be a mess. And as a cross platform technology
> you'd need to define it as part of the protocol effectively. And it'd be
> backwards incompatible therefore optional.
That it requires perhaps some thought to do it properly does not seem
sufficient to me to dismiss the request to provide a proper
abstraction boundary with reliable semantics that match its documentation.
Whitelisting or blacklisting errors that have guaranteed meanings in
individual syscalls and mapping those to a catchall is one possible approach.
But others are also thinkable.
That some symbolic lookup tables would be needed for this does not seem
insurmountable to me. We do something similar in the Rust standard library to
map OS-specific errors to a portable abstraction. We do have a catch-all
"Uncategorized" that's explicitly intended for currently-unrecognized codes
that may be moved to more meaningful variants later.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 20:45 ` The 8472
@ 2024-04-19 21:29 ` Antonio SJ Musumeci
2024-04-19 22:04 ` The 8472
0 siblings, 1 reply; 15+ messages in thread
From: Antonio SJ Musumeci @ 2024-04-19 21:29 UTC (permalink / raw)
To: The 8472, linux-fsdevel
On 4/19/24 15:45, The 8472 wrote:
> Syscalls have documentation. Errors and their semantics are part
> of the documentation. If the kernel cannot actually provide
> the documented semantics because it passes errors through without
> sanitizing them then this should at least be documented
> for each affected syscall.
And that documentation is *different* depending on the platform. The
clean vision you seem to have about errnos is not real. There are
conventions... not strong contracts. I had this exact debate days ago
about `link`. The claim that if link isn't supported by the OS FUSE
should return EPERM. But this just isn't standard the way people think
it is. Not on paper. And if a FUSE server wants to return EPERM then it
can. I don't see why the kernel needs to get in the business of reading
the mind of the server author.
>
> Proper API documentation and stability guarantees are important
> so we can write robust software against them.
>
> Note that write(2) documents
>
> Other errors may occur, depending on the object connected to fd.
>
> close(2) has no such note.
Your idea is laudable but not realistic. errnos are not even fully
consistent across devices or filesystem. Yes, there are norms and some
standards but they are not enforced by some central arbiter across all
forms of *nix.
> That does not mean userspace should be exposed to the entirety
> of the mess. And in my opinion EIO is better than EBADF because
> the former "merely" indicates that something went wrong relating
> to a particular file. EBADF indicates that the file descriptor
> table of the process may have been corrupted.
"should"... but it is exposed to it. *Most* software doesn't even
attempt to handle errors intelligently and just return the error up the
stack blindly. EIO is about as generic as can be and I've seen it used
many times as the "catch all" error making it meaningless. Further
incentivizing client software to behave as they do... not paying
attention. I will again point out that I've seen EXDEV treated like any
random other error several times in my career by important pieces of
software made by major vendors.
> Will try. But the kernel should imo also do its part fulfilling its API
> contract.
Then you are barking up the wrong tree. This isn't an issue unique to
FUSE. FUSE just makes it more obvious to you because anyone can write a
FUSE server and return (almost) anything they want.
> That it requires perhaps some thought to do it properly does not seem
> sufficient to me to dismiss the request to provide a proper
> abstraction boundary with reliable semantics that match its documentation.
I simply don't see what you could do to "do it properly." I am trying to
argue there is no such thing. And again it would require breaking every
single FUSE server.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 21:29 ` Antonio SJ Musumeci
@ 2024-04-19 22:04 ` The 8472
2024-04-19 22:47 ` Antonio SJ Musumeci
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-19 22:04 UTC (permalink / raw)
To: Antonio SJ Musumeci, The 8472, linux-fsdevel
On 19-04-2024 23:29, Antonio SJ Musumeci wrote:
>> Proper API documentation and stability guarantees are important
>> so we can write robust software against them.
>>
>> Note that write(2) documents
>>
>> Other errors may occur, depending on the object connected to fd.
>>
>> close(2) has no such note.
> Your idea is laudable but not realistic. errnos are not even fully
> consistent across devices or filesystem. Yes, there are norms and some
> standards but they are not enforced by some central arbiter across all
> forms of *nix.
I'm writing to a linux mailing list, am I not? And referring to linux-specific
manpages, not the POSIX ones. The way the linux kernel chooses to pass
what FUSE sends to userspace is under its control.
I would like linux to adhere more closely to its own API contract or improve its
documentation.
>> That does not mean userspace should be exposed to the entirety
>> of the mess. And in my opinion EIO is better than EBADF because
>> the former "merely" indicates that something went wrong relating
>> to a particular file. EBADF indicates that the file descriptor
>> table of the process may have been corrupted.
> "should"... but it is exposed to it. *Most* software doesn't even
> attempt to handle errors intelligently and just return the error up the
> stack blindly. EIO is about as generic as can be and I've seen it used
> many times as the "catch all" error making it meaningless. Further
> incentivizing client software to behave as they do... not paying
> attention. I will again point out that I've seen EXDEV treated like any
> random other error several times in my career by important pieces of
> software made by major vendors.
That seems hardly relevant to this case here.
>> Will try. But the kernel should imo also do its part fulfilling its API
>> contract.
> Then you are barking up the wrong tree. This isn't an issue unique to
> FUSE. FUSE just makes it more obvious to you because anyone can write a
> FUSE server and return (almost) anything they want.
If other things can cause this too, then yes of course, a more general
solution would be fine too for my purposes.
Should I have written to another list? Or filed a report on bugzilla instead?
>> That it requires perhaps some thought to do it properly does not seem
>> sufficient to me to dismiss the request to provide a proper
>> abstraction boundary with reliable semantics that match its documentation.
> I simply don't see what you could do to "do it properly." I am trying to
> argue there is no such thing. And again it would require breaking every
> single FUSE server.
I don't understand what would be broken here. In a previous mail you agreed
that FUSE servers have no business sending EBADF and should have a
bug filed against them. If that's the case then sanitizing problematic cases
should be ok.
The libfuse documentation even notes that servers should not assume errors
from flush get delivered to userspace.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 22:04 ` The 8472
@ 2024-04-19 22:47 ` Antonio SJ Musumeci
2024-04-19 23:04 ` The 8472
0 siblings, 1 reply; 15+ messages in thread
From: Antonio SJ Musumeci @ 2024-04-19 22:47 UTC (permalink / raw)
To: The 8472, linux-fsdevel
On 4/19/24 17:04, The 8472 wrote:
> I'm writing to a linux mailing list, am I not? And referring to linux-specific
> manpages, not the POSIX ones. The way the linux kernel chooses to pass
> what FUSE sends to userspace is under its control.
>
> I would like linux to adhere more closely to its own API contract or improve its
> documentation.
And you're talking about FUSE which is a cross platform (Linux, FreeBSD,
MacOS, Windows) protocol. And that protocol defacto includes what
happens when the FUSE server returns and error. If Linux suddenly
changes what happens when the server returns an error it will affect
everyone.
> I don't understand what would be broken here. In a previous mail you agreed
> that FUSE servers have no business sending EBADF and should have a
> bug filed against them. If that's the case then sanitizing problematic cases
> should be ok.
I said: "it is likely a bug or bad decision" but I don't claim to know
the mind of the author. I've seen FUSE filesystems designed for fuzzing
apps via filesystem APIs and they by their nature desire to return all
kinds of random errors. I've seen non-standard errors to indicate
special edge cases or more accurately indicate the underlying resource's
issue (like when interacting with remote system.) Or even uncommon
values used to indicate something to software which was written to know
it was dealing with a special filesystem. Filesystems are just not
uniform in behavior generally let alone errors.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 22:47 ` Antonio SJ Musumeci
@ 2024-04-19 23:04 ` The 8472
2024-04-23 12:46 ` Miklos Szeredi
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-19 23:04 UTC (permalink / raw)
To: Antonio SJ Musumeci, The 8472, linux-fsdevel
On 20-04-2024 00:47, Antonio SJ Musumeci wrote:
> On 4/19/24 17:04, The 8472 wrote:
>> I'm writing to a linux mailing list, am I not? And referring to linux-specific
>> manpages, not the POSIX ones. The way the linux kernel chooses to pass
>> what FUSE sends to userspace is under its control.
>>
>> I would like linux to adhere more closely to its own API contract or improve its
>> documentation.
> And you're talking about FUSE which is a cross platform (Linux, FreeBSD,
> MacOS, Windows) protocol. And that protocol defacto includes what
> happens when the FUSE server returns and error. If Linux suddenly
> changes what happens when the server returns an error it will affect
> everyone.
If it is the official position that the whims of FUSE servers have
primacy over current kernel API guarantees then please update
the documentation of all affected syscalls and relax those
guarantees, similar to the note on the write(2) manpage.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-19 23:04 ` The 8472
@ 2024-04-23 12:46 ` Miklos Szeredi
2024-04-23 13:24 ` Antonio SJ Musumeci
0 siblings, 1 reply; 15+ messages in thread
From: Miklos Szeredi @ 2024-04-23 12:46 UTC (permalink / raw)
To: The 8472; +Cc: Antonio SJ Musumeci, linux-fsdevel
On Sat, 20 Apr 2024 at 01:04, The 8472 <kernel@infinite-source.de> wrote:
> If it is the official position that the whims of FUSE servers have
> primacy over current kernel API guarantees then please update
> the documentation of all affected syscalls and relax those
> guarantees, similar to the note on the write(2) manpage.
Which note are you referring to?
I can see some merit to both sides.
If it's an issue that can be fixed in the fuse server ("Doctor, it
hurts when I do this." "Then don't do that!”) adding complexity to the
fuse client is not warranted.
Obviously most fuse servers don't want to actively confuse caller, but
if such behavior can be used to exploit a weakness in an application,
then it becomes more than just a correctness issue. If you came up
with such a scenario, then this would turn into a serious bug.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-23 12:46 ` Miklos Szeredi
@ 2024-04-23 13:24 ` Antonio SJ Musumeci
2024-04-23 13:38 ` Miklos Szeredi
0 siblings, 1 reply; 15+ messages in thread
From: Antonio SJ Musumeci @ 2024-04-23 13:24 UTC (permalink / raw)
To: Miklos Szeredi, The 8472; +Cc: linux-fsdevel
On 4/23/24 07:46, Miklos Szeredi wrote:
> On Sat, 20 Apr 2024 at 01:04, The 8472 <kernel@infinite-source.de> wrote:
>
>> If it is the official position that the whims of FUSE servers have
>> primacy over current kernel API guarantees then please update
>> the documentation of all affected syscalls and relax those
>> guarantees, similar to the note on the write(2) manpage.
> Which note are you referring to?
>
> I can see some merit to both sides.
>
> If it's an issue that can be fixed in the fuse server ("Doctor, it
> hurts when I do this." "Then don't do that!”) adding complexity to the
> fuse client is not warranted.
>
> Obviously most fuse servers don't want to actively confuse caller, but
> if such behavior can be used to exploit a weakness in an application,
> then it becomes more than just a correctness issue. If you came up
> with such a scenario, then this would turn into a serious bug.
>
> Thanks,
> Miklos
From the write(2) manpage (at least on Ubuntu):
"Other errors may occur, depending on the object connected to fd."
My argument has been that this note is defacto true generally.
The specifics of this thread stem from close() returning EBADF to the
client app while talking to a FUSE server after the open() succeeded
and, from the point of view of the client app, returned a valid file
descriptor. Sounds like a bug in the FUSE server rather than something
FUSE itself needs to worry about. Besides removing some classes of usage
of FUSE it would be rather complicated, if not impossible, to assume the
meaning of returned errors from the server and translate them into
"approved" values for the client. It will mask server bugs and/or
confuse server authors at best IMO. Error handling in FUSE is already a
bit difficult to manage.
This is not unlike a recent complaint that when link() is not
implemented libfuse returns ENOSYS rather than EPERM. As I pointed out
in that situation EPERM is not universally defined as meaning "not
implemented by filesystem" like used in Linux. Doesn't mean it isn't
used (I didn't check) but it isn't defined as such in docs.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-23 13:24 ` Antonio SJ Musumeci
@ 2024-04-23 13:38 ` Miklos Szeredi
[not found] ` <692a9f0b-9c2b-4850-b8bc-48f09fe41762@infinite-source.de>
0 siblings, 1 reply; 15+ messages in thread
From: Miklos Szeredi @ 2024-04-23 13:38 UTC (permalink / raw)
To: Antonio SJ Musumeci; +Cc: The 8472, linux-fsdevel
On Tue, 23 Apr 2024 at 15:24, Antonio SJ Musumeci <trapexit@spawn.link> wrote:
> From the write(2) manpage (at least on Ubuntu):
>
> "Other errors may occur, depending on the object connected to fd."
>
> My argument has been that this note is defacto true generally.
Yes.
>
> The specifics of this thread stem from close() returning EBADF to the
> client app while talking to a FUSE server after the open() succeeded
> and, from the point of view of the client app, returned a valid file
> descriptor. Sounds like a bug in the FUSE server rather than something
> FUSE itself needs to worry about.
Return value from close is ignored in 99% of cases. It is quite hard
to imagine this making real difference to an application. The basic
philosophy of the linux kernel is pragmatism: if it matters in a real
world use case, then we care, otherwise we don't. I don't think a
server returning EBADF matters in real life, but if it is, then we do
need to take care of it.
> This is not unlike a recent complaint that when link() is not
> implemented libfuse returns ENOSYS rather than EPERM. As I pointed out
> in that situation EPERM is not universally defined as meaning "not
> implemented by filesystem" like used in Linux. Doesn't mean it isn't
> used (I didn't check) but it isn't defined as such in docs.
ENOSYS is a good example where fuse does need to filter out errors,
since applications do interpret ENOSYS as "kernel doesn't implement
this syscall" and fuse actually uses ENOSYS for a different purpose.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
[not found] ` <692a9f0b-9c2b-4850-b8bc-48f09fe41762@infinite-source.de>
@ 2024-04-23 21:38 ` The 8472
2024-04-26 8:52 ` Miklos Szeredi
0 siblings, 1 reply; 15+ messages in thread
From: The 8472 @ 2024-04-23 21:38 UTC (permalink / raw)
To: The 8472, Miklos Szeredi, Antonio SJ Musumeci; +Cc: linux-fsdevel
On 23-04-2024 15:38, Miklos Szeredi wrote:
> On Tue, 23 Apr 2024 at 15:24, Antonio SJ Musumeci<trapexit@spawn.link> wrote:
>
>> From the write(2) manpage (at least on Ubuntu):
>>
>> "Other errors may occur, depending on the object connected to fd."
>>
>> My argument has been that this note is defacto true generally.
> Yes.
In some places we do rely on error codes having exactly the documented meaning
and no other. E.g. fcntl(..., F_GETFD) failing with EBADF is treated as fatal,
other codes are not.
Or openat(..., O_NOFOLLOW | O_DIRECTORY) returning ENOTDIR is trusted to mean
that the file is in fact not a directory and can be unlinked instead of rmdir'd
>> The specifics of this thread stem from close() returning EBADF to the
>> client app while talking to a FUSE server after the open() succeeded
>> and, from the point of view of the client app, returned a valid file
>> descriptor. Sounds like a bug in the FUSE server rather than something
>> FUSE itself needs to worry about.
> Return value from close is ignored in 99% of cases. It is quite hard
> to imagine this making real difference to an application. The basic
> philosophy of the linux kernel is pragmatism: if it matters in a real
> world use case, then we care, otherwise we don't. I don't think a
> server returning EBADF matters in real life, but if it is, then we do
> need to take care of it.
Current Rust versions unwind if closedir() is not successful since
directories aren't writable and aren't expected to have writeback
errors. That's what lead to this thread.
If that had returned an EIO that would have been annoying but
would clearly point at unreliable storage. If it returns
EBADF that is more concerning because it could be a double-close or
something similar within the process clobbering FDs.
>> This is not unlike a recent complaint that when link() is not
>> implemented libfuse returns ENOSYS rather than EPERM. As I pointed out
>> in that situation EPERM is not universally defined as meaning "not
>> implemented by filesystem" like used in Linux. Doesn't mean it isn't
>> used (I didn't check) but it isn't defined as such in docs.
> ENOSYS is a good example where fuse does need to filter out errors,
> since applications do interpret ENOSYS as "kernel doesn't implement
> this syscall" and fuse actually uses ENOSYS for a different purpose.
Yes, we use ENOSYS a lot for feature detection. Bogus ones would result
result in loss of performance and minor functionality.
Due to old docker seccomp filters returning EPERM instead of ENOSYS
on filtered syscalls we sometimes also have to treat EPERM like ENOSYS
on syscalls where EPERM is not documented as one of the valid return codes.
Also, "not universally defined" is not relevant, we consult a platform's
manpages to understand platform-specific behavior, not just the posix ones.
So if linux implements its fuse client in a way that propagates arbitrary
error codes to syscalls for which the linux-specific documentation says that only
a certain set of error codes with specific meanings would be returned then
either the documentation is wrong or those errors should be mangled before
they bubble up to the syscall.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: EBADF returned from close() by FUSE
2024-04-23 21:38 ` The 8472
@ 2024-04-26 8:52 ` Miklos Szeredi
0 siblings, 0 replies; 15+ messages in thread
From: Miklos Szeredi @ 2024-04-26 8:52 UTC (permalink / raw)
To: The 8472; +Cc: Antonio SJ Musumeci, linux-fsdevel
On Tue, 23 Apr 2024 at 23:38, The 8472 <kernel@infinite-source.de> wrote:
> In some places we do rely on error codes having exactly the documented meaning
> and no other. E.g. fcntl(..., F_GETFD) failing with EBADF is treated as fatal,
> other codes are not.
> Or openat(..., O_NOFOLLOW | O_DIRECTORY) returning ENOTDIR is trusted to mean
> that the file is in fact not a directory and can be unlinked instead of rmdir'd
There are lot of assumptions from applications. Fuse won't and can't
check them all. This applies to error codes as well.
> Current Rust versions unwind if closedir() is not successful since
> directories aren't writable and aren't expected to have writeback
> errors. That's what lead to this thread.
Is that bad? I mean can that lead to a security breach? If not, then
it's not interesting, lets just fix the bad filesystem.
> If that had returned an EIO that would have been annoying but
> would clearly point at unreliable storage. If it returns
> EBADF that is more concerning because it could be a double-close or
> something similar within the process clobbering FDs.
So the worst thing that can happen is that a bad fuse filesystem is
able to confuse the user of an application, believing the application
is at fault when in fact it's the filesystem that's acting up?
> So if linux implements its fuse client in a way that propagates arbitrary
> error codes to syscalls for which the linux-specific documentation says that only
> a certain set of error codes with specific meanings would be returned then
> either the documentation is wrong or those errors should be mangled before
> they bubble up to the syscall.
Man pages do not say that the error list is exhaustive. Other error
codes are almost always possible even without fuse.
Thanks,
Miklos
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2024-04-26 8:52 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-18 22:10 EBADF returned from close() by FUSE The 8472
2024-04-19 3:30 ` Antonio SJ Musumeci
2024-04-19 6:55 ` The 8472
[not found] ` <8c7552b1-f371-4a75-98cc-f2c89816becb@spawn.link>
2024-04-19 18:18 ` The 8472
2024-04-19 20:07 ` Antonio SJ Musumeci
2024-04-19 20:45 ` The 8472
2024-04-19 21:29 ` Antonio SJ Musumeci
2024-04-19 22:04 ` The 8472
2024-04-19 22:47 ` Antonio SJ Musumeci
2024-04-19 23:04 ` The 8472
2024-04-23 12:46 ` Miklos Szeredi
2024-04-23 13:24 ` Antonio SJ Musumeci
2024-04-23 13:38 ` Miklos Szeredi
[not found] ` <692a9f0b-9c2b-4850-b8bc-48f09fe41762@infinite-source.de>
2024-04-23 21:38 ` The 8472
2024-04-26 8:52 ` Miklos Szeredi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).