On Thu, Mar 21, 2024 at 02:28:15PM +0100, Alice Ryhl wrote: > On Wed, Mar 20, 2024 at 3:22 PM Christian Brauner <brauner@xxxxxxxxxx> wrote: > > > > On Fri, Feb 09, 2024 at 11:18:21AM +0000, Alice Ryhl wrote: > > > > > > +/// Helper used for closing file descriptors in a way that is safe even if the file is currently > > > +/// held using `fdget`. > > > +/// > > > +/// Additional motivation can be found in commit 80cd795630d6 ("binder: fix use-after-free due to > > > +/// ksys_close() during fdget()") and in the comments on `binder_do_fd_close`. > > > +pub struct DeferredFdCloser { > > > + inner: Box<DeferredFdCloserInner>, > > > +} > > > + > > > +/// SAFETY: This just holds an allocation with no real content, so there's no safety issue with > > > +/// moving it across threads. > > > +unsafe impl Send for DeferredFdCloser {} > > > +unsafe impl Sync for DeferredFdCloser {} > > > + > > > +/// # Invariants > > > +/// > > > +/// If the `file` pointer is non-null, then it points at a `struct file` and owns a refcount to > > > +/// that file. > > > +#[repr(C)] > > > +struct DeferredFdCloserInner { > > > + twork: mem::MaybeUninit<bindings::callback_head>, > > > + file: *mut bindings::file, > > > +} > > > + > > > +impl DeferredFdCloser { > > > > So the explicitly deferred close is due to how binder works so it's not > > much of a general purpose interface as I don't recall having other > > codepaths with similar problems. So this should live in the binder > > specific rust code imo. > > Hmm. Are there really no other ioctls that call ksys_close on a > user-provided fd? No, I don't think there are otherwise they would have the same bug that binder had. io_uring comes closest but they have their own task work and deferred close implementation. > > As far as I can tell, this kind of deferred API is the only way for us > to provide a fully safe Rust api for closing an fd. Directly calling > ksys_close must unsafely assert that the fd does not have an active > fdget call. So it makes sense to me as an API that others might want > to use. I'm sorry, I don't quite understand you here. What binder is doing iirc is that it's performing an ioctl() using a fd to /dev/binderfs/$device-node or similar. The fatal flaw is that binder now allows that fd to be closed during that ioctl - and by accident at that. It's effectively closing a file it's relying on to not go away. That's the original nonsense/creativity that necessitates this whole manual task work shenanigans binder is doing. Unless I misremember. But that's really frowned upon generally and absolutely not encouraged by providing a generic interface for this stuff. Sure, we have some users in the kernel that do stuff like call close_fd() on a file descriptor they just installed into their file descriptor table. That's usually bad design with maybe a few valid exceptions. One example where that's still done and should be fixed is e.g., cachefiles in fs/cachefiles/ondemand.c. The point is that they at least close a file descriptor that they just installed and that they don't rely on being valid. So really, I need more details why without this interface it would prevent Rust from implementing safe file descriptor closing because right now all I see is a design flaw in binder being promoted to a generic interface. And unless there's detailed reasons for it's existence we're not going to do it.