This exports the functionality needed by Binder to close file
descriptors.
When you send a fd over Binder, what happens is this:
1. The sending process turns the fd into a struct file and stores it in
the transaction object.
2. When the receiving process gets the message, the fd is installed as a
fd into the current process.
3. When the receiving process is done handling the message, it tells
Binder to clean up the transaction. As part of this, fds embedded in
the transaction are closed.
Note that it was not always implemented like this. Previously the
sending process would install the fd directly into the receiving proc in
step 1, but as discussed previously [1] this is not ideal and has since
been changed so that fd install happens during receive.
The functions being exported here are for closing the fd in step 3. They
are required because closing a fd from an ioctl is in general not safe.
This is to meet the requirements for using fdget(), which is used by the
ioctl framework code before calling into the driver's implementation of
the ioctl. Binder works around this with this sequence of operations:
1. file_close_fd()
2. get_file()
3. filp_close()
4. task_work_add(current, TWA_RESUME)
5. <binder returns from ioctl>
6. fput()
This ensures that when fput() is called in the task work, the fdget()
that the ioctl framework code uses has already been fdput(), so if the
fd being closed happens to be the same fd, then the fd is not closed
in violation of the fdget() rules.
Link: https://lore.kernel.org/all/20180730203633.GC12962@bombadil.infradead.org/ [1]
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
fs/file.c | 1 +
kernel/task_work.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/fs/file.c b/fs/file.c
index 0a4f3bdb2dec6284a0c7b9687213137f2eecb250..0046d0034bf16270cdea7e30a86866ebea3a5a81 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -881,6 +881,7 @@ struct file *file_close_fd(unsigned int fd)
return file;
}
+EXPORT_SYMBOL(file_close_fd);
void do_close_on_exec(struct files_struct *files)
{
diff --git a/kernel/task_work.c b/kernel/task_work.c
index 0f7519f8e7c93f9a4536c26a341255799c320432..08eb29abaea6b98cc443d1087ddb1d0f1a38c9ae 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -102,6 +102,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
return 0;
}
+EXPORT_SYMBOL(task_work_add);
/**
* task_work_cancel_match - cancel a pending work added by task_work_add()
--
2.53.0.rc2.204.g2597b5adb4-goog
On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote:
> This exports the functionality needed by Binder to close file
> descriptors.
>
> When you send a fd over Binder, what happens is this:
>
> 1. The sending process turns the fd into a struct file and stores it in
> the transaction object.
> 2. When the receiving process gets the message, the fd is installed as a
> fd into the current process.
> 3. When the receiving process is done handling the message, it tells
> Binder to clean up the transaction. As part of this, fds embedded in
> the transaction are closed.
>
> Note that it was not always implemented like this. Previously the
> sending process would install the fd directly into the receiving proc in
> step 1, but as discussed previously [1] this is not ideal and has since
> been changed so that fd install happens during receive.
>
> The functions being exported here are for closing the fd in step 3. They
> are required because closing a fd from an ioctl is in general not safe.
> This is to meet the requirements for using fdget(), which is used by the
> ioctl framework code before calling into the driver's implementation of
> the ioctl. Binder works around this with this sequence of operations:
>
> 1. file_close_fd()
> 2. get_file()
> 3. filp_close()
> 4. task_work_add(current, TWA_RESUME)
> 5. <binder returns from ioctl>
> 6. fput()
>
> This ensures that when fput() is called in the task work, the fdget()
> that the ioctl framework code uses has already been fdput(), so if the
> fd being closed happens to be the same fd, then the fd is not closed
> in violation of the fdget() rules.
>
> Link: https://lore.kernel.org/all/20180730203633.GC12962@bombadil.infradead.org/ [1]
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> fs/file.c | 1 +
> kernel/task_work.c | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/fs/file.c b/fs/file.c
> index 0a4f3bdb2dec6284a0c7b9687213137f2eecb250..0046d0034bf16270cdea7e30a86866ebea3a5a81 100644
> --- a/fs/file.c
> +++ b/fs/file.c
> @@ -881,6 +881,7 @@ struct file *file_close_fd(unsigned int fd)
>
> return file;
> }
> +EXPORT_SYMBOL(file_close_fd);
>
> void do_close_on_exec(struct files_struct *files)
> {
> diff --git a/kernel/task_work.c b/kernel/task_work.c
> index 0f7519f8e7c93f9a4536c26a341255799c320432..08eb29abaea6b98cc443d1087ddb1d0f1a38c9ae 100644
> --- a/kernel/task_work.c
> +++ b/kernel/task_work.c
> @@ -102,6 +102,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
>
> return 0;
> }
> +EXPORT_SYMBOL(task_work_add);
Uhm, no. We're not going to export task_work_add() to let random drivers
queue up work for a task when it returns to userspace. That just screams
bugs and deadlocks at full capacity. Sorry, no.
On Thu 05-02-26 12:38:22, Christian Brauner wrote:
> On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote:
> > This exports the functionality needed by Binder to close file
> > descriptors.
> >
> > When you send a fd over Binder, what happens is this:
> >
> > 1. The sending process turns the fd into a struct file and stores it in
> > the transaction object.
> > 2. When the receiving process gets the message, the fd is installed as a
> > fd into the current process.
> > 3. When the receiving process is done handling the message, it tells
> > Binder to clean up the transaction. As part of this, fds embedded in
> > the transaction are closed.
> >
> > Note that it was not always implemented like this. Previously the
> > sending process would install the fd directly into the receiving proc in
> > step 1, but as discussed previously [1] this is not ideal and has since
> > been changed so that fd install happens during receive.
> >
> > The functions being exported here are for closing the fd in step 3. They
> > are required because closing a fd from an ioctl is in general not safe.
> > This is to meet the requirements for using fdget(), which is used by the
> > ioctl framework code before calling into the driver's implementation of
> > the ioctl. Binder works around this with this sequence of operations:
> >
> > 1. file_close_fd()
> > 2. get_file()
> > 3. filp_close()
> > 4. task_work_add(current, TWA_RESUME)
> > 5. <binder returns from ioctl>
> > 6. fput()
> >
> > This ensures that when fput() is called in the task work, the fdget()
> > that the ioctl framework code uses has already been fdput(), so if the
> > fd being closed happens to be the same fd, then the fd is not closed
> > in violation of the fdget() rules.
> >
> > Link: https://lore.kernel.org/all/20180730203633.GC12962@bombadil.infradead.org/ [1]
> > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> > ---
> > fs/file.c | 1 +
> > kernel/task_work.c | 1 +
> > 2 files changed, 2 insertions(+)
> >
> > diff --git a/fs/file.c b/fs/file.c
> > index 0a4f3bdb2dec6284a0c7b9687213137f2eecb250..0046d0034bf16270cdea7e30a86866ebea3a5a81 100644
> > --- a/fs/file.c
> > +++ b/fs/file.c
> > @@ -881,6 +881,7 @@ struct file *file_close_fd(unsigned int fd)
> >
> > return file;
> > }
> > +EXPORT_SYMBOL(file_close_fd);
> >
> > void do_close_on_exec(struct files_struct *files)
> > {
> > diff --git a/kernel/task_work.c b/kernel/task_work.c
> > index 0f7519f8e7c93f9a4536c26a341255799c320432..08eb29abaea6b98cc443d1087ddb1d0f1a38c9ae 100644
> > --- a/kernel/task_work.c
> > +++ b/kernel/task_work.c
> > @@ -102,6 +102,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
> >
> > return 0;
> > }
> > +EXPORT_SYMBOL(task_work_add);
>
> Uhm, no. We're not going to export task_work_add() to let random drivers
> queue up work for a task when it returns to userspace. That just screams
> bugs and deadlocks at full capacity. Sorry, no.
Agreed. And just to demonstrate the point binder's use would become the
first of such bugs because it is prone to the module being removed while
the task work is in flight and thus do_close_fd() code can be freed by the
time it gets executed.
Generally, making some code modular usually requires more effort than just
flipping the Kconfig to tristate. You usually need to make sure all objects
and queued work is flushed before the module can be removed. Not sure how
much of this is taken care of by Rust though...
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
On Thu, Feb 05, 2026 at 12:52:37PM +0100, Jan Kara wrote: > > Agreed. And just to demonstrate the point binder's use would become the > first of such bugs because it is prone to the module being removed while > the task work is in flight and thus do_close_fd() code can be freed by the > time it gets executed. Good point ... > Generally, making some code modular usually requires more effort than just > flipping the Kconfig to tristate. You usually need to make sure all objects > and queued work is flushed before the module can be removed. Not sure how > much of this is taken care of by Rust though... > > Honza > -- > Jan Kara <jack@suse.com> > SUSE Labs, CR
On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote:
> This exports the functionality needed by Binder to close file
> descriptors.
>
> When you send a fd over Binder, what happens is this:
>
> 1. The sending process turns the fd into a struct file and stores it in
> the transaction object.
> 2. When the receiving process gets the message, the fd is installed as a
> fd into the current process.
> 3. When the receiving process is done handling the message, it tells
> Binder to clean up the transaction. As part of this, fds embedded in
> the transaction are closed.
>
> Note that it was not always implemented like this. Previously the
> sending process would install the fd directly into the receiving proc in
> step 1, but as discussed previously [1] this is not ideal and has since
> been changed so that fd install happens during receive.
>
> The functions being exported here are for closing the fd in step 3. They
> are required because closing a fd from an ioctl is in general not safe.
> This is to meet the requirements for using fdget(), which is used by the
> ioctl framework code before calling into the driver's implementation of
> the ioctl. Binder works around this with this sequence of operations:
>
> 1. file_close_fd()
> 2. get_file()
> 3. filp_close()
> 4. task_work_add(current, TWA_RESUME)
> 5. <binder returns from ioctl>
> 6. fput()
>
> This ensures that when fput() is called in the task work, the fdget()
> that the ioctl framework code uses has already been fdput(), so if the
> fd being closed happens to be the same fd, then the fd is not closed
> in violation of the fdget() rules.
I'm not really familiar with this mechanism but you're already talking about
this being a workaround so strikes me the correct thing to do is to find a way
to do this in the kernel sensibly rather than exporting internal implementation
details and doing it in binder.
But on this I defer to Christian and Al.
>
> Link: https://lore.kernel.org/all/20180730203633.GC12962@bombadil.infradead.org/ [1]
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> fs/file.c | 1 +
> kernel/task_work.c | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/fs/file.c b/fs/file.c
> index 0a4f3bdb2dec6284a0c7b9687213137f2eecb250..0046d0034bf16270cdea7e30a86866ebea3a5a81 100644
> --- a/fs/file.c
> +++ b/fs/file.c
> @@ -881,6 +881,7 @@ struct file *file_close_fd(unsigned int fd)
>
> return file;
> }
> +EXPORT_SYMBOL(file_close_fd);
As a matter of policy we generally don't like to export without GPL like this
unless there's a _really_ good reason.
Christian or Al may have a different viewpoint but generally this should be an
EXPORT_SYMBOL_GPL() and also - there has to be a _really_ good reason to export
it.
>
> void do_close_on_exec(struct files_struct *files)
> {
> diff --git a/kernel/task_work.c b/kernel/task_work.c
> index 0f7519f8e7c93f9a4536c26a341255799c320432..08eb29abaea6b98cc443d1087ddb1d0f1a38c9ae 100644
> --- a/kernel/task_work.c
> +++ b/kernel/task_work.c
> @@ -102,6 +102,7 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
>
> return 0;
> }
> +EXPORT_SYMBOL(task_work_add);
Same here obviously.
There's nothing else exported here so this is even more questionable.
We want to export as little as possible, and I'm not modularising a driver,
_temporarily_ is a great justification for doing that.
Sadly the moment you export something people start using it :)
>
> /**
> * task_work_cancel_match - cancel a pending work added by task_work_add()
>
> --
> 2.53.0.rc2.204.g2597b5adb4-goog
>
Cheers, Lorenzo
On Thu, Feb 05, 2026 at 11:20:33AM +0000, Lorenzo Stoakes wrote: > On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote: > > This exports the functionality needed by Binder to close file > > descriptors. > > > > When you send a fd over Binder, what happens is this: > > > > 1. The sending process turns the fd into a struct file and stores it in > > the transaction object. > > 2. When the receiving process gets the message, the fd is installed as a > > fd into the current process. > > 3. When the receiving process is done handling the message, it tells > > Binder to clean up the transaction. As part of this, fds embedded in > > the transaction are closed. > > > > Note that it was not always implemented like this. Previously the > > sending process would install the fd directly into the receiving proc in > > step 1, but as discussed previously [1] this is not ideal and has since > > been changed so that fd install happens during receive. > > > > The functions being exported here are for closing the fd in step 3. They > > are required because closing a fd from an ioctl is in general not safe. > > This is to meet the requirements for using fdget(), which is used by the > > ioctl framework code before calling into the driver's implementation of > > the ioctl. Binder works around this with this sequence of operations: > > > > 1. file_close_fd() > > 2. get_file() > > 3. filp_close() > > 4. task_work_add(current, TWA_RESUME) > > 5. <binder returns from ioctl> > > 6. fput() > > > > This ensures that when fput() is called in the task work, the fdget() > > that the ioctl framework code uses has already been fdput(), so if the > > fd being closed happens to be the same fd, then the fd is not closed > > in violation of the fdget() rules. > > I'm not really familiar with this mechanism but you're already talking about > this being a workaround so strikes me the correct thing to do is to find a way > to do this in the kernel sensibly rather than exporting internal implementation > details and doing it in binder. I did previously submit a patch that implemented this logic outside of Binder, but I was advised to move it into Binder. But I'm happy to submit a patch to extract this logic into some sort of close_fd_safe() method that can be called even if said fd is currently held using fdget(). > > Link: https://lore.kernel.org/all/20180730203633.GC12962@bombadil.infradead.org/ [1] > > Signed-off-by: Alice Ryhl <aliceryhl@google.com> > > --- > > fs/file.c | 1 + > > kernel/task_work.c | 1 + > > 2 files changed, 2 insertions(+) > > > > diff --git a/fs/file.c b/fs/file.c > > index 0a4f3bdb2dec6284a0c7b9687213137f2eecb250..0046d0034bf16270cdea7e30a86866ebea3a5a81 100644 > > --- a/fs/file.c > > +++ b/fs/file.c > > @@ -881,6 +881,7 @@ struct file *file_close_fd(unsigned int fd) > > > > return file; > > } > > +EXPORT_SYMBOL(file_close_fd); > > As a matter of policy we generally don't like to export without GPL like this > unless there's a _really_ good reason. > > Christian or Al may have a different viewpoint but generally this should be an > EXPORT_SYMBOL_GPL() and also - there has to be a _really_ good reason to export > it. Sorry I should just have done _GPL from the beginning. My mistake. Alice
On Thu, Feb 05, 2026 at 11:42:46AM +0000, Alice Ryhl wrote: > On Thu, Feb 05, 2026 at 11:20:33AM +0000, Lorenzo Stoakes wrote: > > On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote: > > > This exports the functionality needed by Binder to close file > > > descriptors. > > > > > > When you send a fd over Binder, what happens is this: > > > > > > 1. The sending process turns the fd into a struct file and stores it in > > > the transaction object. > > > 2. When the receiving process gets the message, the fd is installed as a > > > fd into the current process. > > > 3. When the receiving process is done handling the message, it tells > > > Binder to clean up the transaction. As part of this, fds embedded in > > > the transaction are closed. > > > > > > Note that it was not always implemented like this. Previously the > > > sending process would install the fd directly into the receiving proc in > > > step 1, but as discussed previously [1] this is not ideal and has since > > > been changed so that fd install happens during receive. > > > > > > The functions being exported here are for closing the fd in step 3. They > > > are required because closing a fd from an ioctl is in general not safe. > > > This is to meet the requirements for using fdget(), which is used by the > > > ioctl framework code before calling into the driver's implementation of > > > the ioctl. Binder works around this with this sequence of operations: > > > > > > 1. file_close_fd() > > > 2. get_file() > > > 3. filp_close() > > > 4. task_work_add(current, TWA_RESUME) > > > 5. <binder returns from ioctl> > > > 6. fput() > > > > > > This ensures that when fput() is called in the task work, the fdget() > > > that the ioctl framework code uses has already been fdput(), so if the > > > fd being closed happens to be the same fd, then the fd is not closed > > > in violation of the fdget() rules. > > > > I'm not really familiar with this mechanism but you're already talking about > > this being a workaround so strikes me the correct thing to do is to find a way > > to do this in the kernel sensibly rather than exporting internal implementation > > details and doing it in binder. > > I did previously submit a patch that implemented this logic outside of > Binder, but I was advised to move it into Binder. Right yeah that's just odd to me, we really do not want to be adding internal implementation details to drivers. This is based on bitter experience of bugs being caused by drivers abusing every interface they get, which is basically exactly what always happens, sadly. And out-of-tree is heavily discouraged. Also can we use EXPORT_SYMBOL_FOR_MODULES() for anything we do need to export to make it explicitly only for binder, perhaps? > > But I'm happy to submit a patch to extract this logic into some sort of > close_fd_safe() method that can be called even if said fd is currently > held using fdget(). Yup, especially given Christian's view on the kernel task export here I think that's a more sensible approach. But obviously I defer the sensible-ness of this to him as I am but an mm dev :) > > > > Link: https://lore.kernel.org/all/20180730203633.GC12962@bombadil.infradead.org/ [1] > > > Signed-off-by: Alice Ryhl <aliceryhl@google.com> > > > --- > > > fs/file.c | 1 + > > > kernel/task_work.c | 1 + > > > 2 files changed, 2 insertions(+) > > > > > > diff --git a/fs/file.c b/fs/file.c > > > index 0a4f3bdb2dec6284a0c7b9687213137f2eecb250..0046d0034bf16270cdea7e30a86866ebea3a5a81 100644 > > > --- a/fs/file.c > > > +++ b/fs/file.c > > > @@ -881,6 +881,7 @@ struct file *file_close_fd(unsigned int fd) > > > > > > return file; > > > } > > > +EXPORT_SYMBOL(file_close_fd); > > > > As a matter of policy we generally don't like to export without GPL like this > > unless there's a _really_ good reason. > > > > Christian or Al may have a different viewpoint but generally this should be an > > EXPORT_SYMBOL_GPL() and also - there has to be a _really_ good reason to export > > it. > > Sorry I should just have done _GPL from the beginning. My mistake. Thanks! > > Alice Cheers, Lorenzo
On Thu, Feb 05, 2026 at 11:53:19AM +0000, Lorenzo Stoakes wrote:
> On Thu, Feb 05, 2026 at 11:42:46AM +0000, Alice Ryhl wrote:
> > On Thu, Feb 05, 2026 at 11:20:33AM +0000, Lorenzo Stoakes wrote:
> > > On Thu, Feb 05, 2026 at 10:51:26AM +0000, Alice Ryhl wrote:
> > > > This exports the functionality needed by Binder to close file
> > > > descriptors.
> > > >
> > > > When you send a fd over Binder, what happens is this:
> > > >
> > > > 1. The sending process turns the fd into a struct file and stores it in
> > > > the transaction object.
> > > > 2. When the receiving process gets the message, the fd is installed as a
> > > > fd into the current process.
> > > > 3. When the receiving process is done handling the message, it tells
> > > > Binder to clean up the transaction. As part of this, fds embedded in
> > > > the transaction are closed.
> > > >
> > > > Note that it was not always implemented like this. Previously the
> > > > sending process would install the fd directly into the receiving proc in
> > > > step 1, but as discussed previously [1] this is not ideal and has since
> > > > been changed so that fd install happens during receive.
> > > >
> > > > The functions being exported here are for closing the fd in step 3. They
> > > > are required because closing a fd from an ioctl is in general not safe.
> > > > This is to meet the requirements for using fdget(), which is used by the
> > > > ioctl framework code before calling into the driver's implementation of
> > > > the ioctl. Binder works around this with this sequence of operations:
> > > >
> > > > 1. file_close_fd()
> > > > 2. get_file()
> > > > 3. filp_close()
> > > > 4. task_work_add(current, TWA_RESUME)
> > > > 5. <binder returns from ioctl>
> > > > 6. fput()
> > > >
> > > > This ensures that when fput() is called in the task work, the fdget()
> > > > that the ioctl framework code uses has already been fdput(), so if the
> > > > fd being closed happens to be the same fd, then the fd is not closed
> > > > in violation of the fdget() rules.
> > >
> > > I'm not really familiar with this mechanism but you're already talking about
> > > this being a workaround so strikes me the correct thing to do is to find a way
> > > to do this in the kernel sensibly rather than exporting internal implementation
> > > details and doing it in binder.
> >
> > I did previously submit a patch that implemented this logic outside of
> > Binder, but I was advised to move it into Binder.
>
> Right yeah that's just odd to me, we really do not want to be adding internal
> implementation details to drivers.
>
> This is based on bitter experience of bugs being caused by drivers abusing every
> interface they get, which is basically exactly what always happens, sadly.
>
> And out-of-tree is heavily discouraged.
>
> Also can we use EXPORT_SYMBOL_FOR_MODULES() for anything we do need to export to
> make it explicitly only for binder, perhaps?
>
> >
> > But I'm happy to submit a patch to extract this logic into some sort of
> > close_fd_safe() method that can be called even if said fd is currently
> > held using fdget().
>
> Yup, especially given Christian's view on the kernel task export here I think
> that's a more sensible approach.
>
> But obviously I defer the sensible-ness of this to him as I am but an mm dev :)
Quick sketch of how this would look:
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index adde1e40cccd..6fb7175ff69b 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -64,7 +64,6 @@
#include <linux/spinlock.h>
#include <linux/ratelimit.h>
#include <linux/syscalls.h>
-#include <linux/task_work.h>
#include <linux/sizes.h>
#include <linux/ktime.h>
@@ -1962,68 +1961,6 @@ static bool binder_validate_fixup(struct binder_proc *proc,
return (fixup_offset >= last_min_offset);
}
-/**
- * struct binder_task_work_cb - for deferred close
- *
- * @twork: callback_head for task work
- * @file: file to close
- *
- * Structure to pass task work to be handled after
- * returning from binder_ioctl() via task_work_add().
- */
-struct binder_task_work_cb {
- struct callback_head twork;
- struct file *file;
-};
-
-/**
- * binder_do_fd_close() - close list of file descriptors
- * @twork: callback head for task work
- *
- * It is not safe to call ksys_close() during the binder_ioctl()
- * function if there is a chance that binder's own file descriptor
- * might be closed. This is to meet the requirements for using
- * fdget() (see comments for __fget_light()). Therefore use
- * task_work_add() to schedule the close operation once we have
- * returned from binder_ioctl(). This function is a callback
- * for that mechanism and does the actual ksys_close() on the
- * given file descriptor.
- */
-static void binder_do_fd_close(struct callback_head *twork)
-{
- struct binder_task_work_cb *twcb = container_of(twork,
- struct binder_task_work_cb, twork);
-
- fput(twcb->file);
- kfree(twcb);
-}
-
-/**
- * binder_deferred_fd_close() - schedule a close for the given file-descriptor
- * @fd: file-descriptor to close
- *
- * See comments in binder_do_fd_close(). This function is used to schedule
- * a file-descriptor to be closed after returning from binder_ioctl().
- */
-static void binder_deferred_fd_close(int fd)
-{
- struct binder_task_work_cb *twcb;
-
- twcb = kzalloc(sizeof(*twcb), GFP_KERNEL);
- if (!twcb)
- return;
- init_task_work(&twcb->twork, binder_do_fd_close);
- twcb->file = file_close_fd(fd);
- if (twcb->file) {
- // pin it until binder_do_fd_close(); see comments there
- get_file(twcb->file);
- filp_close(twcb->file, current->files);
- task_work_add(current, &twcb->twork, TWA_RESUME);
- } else {
- kfree(twcb);
- }
-}
-
static void binder_transaction_buffer_release(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_buffer *buffer,
@@ -2183,7 +2120,10 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
offset, sizeof(fd));
WARN_ON(err);
if (!err) {
- binder_deferred_fd_close(fd);
+ /*
+ * Intentionally ignore EBADF errors here.
+ */
+ close_fd_safe(fd, GFP_KERNEL | __GFP_NOFAIL);
/*
* Need to make sure the thread goes
* back to userspace to complete the
diff --git a/fs/file.c b/fs/file.c
index 0a4f3bdb2dec..58e3825e846c 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -21,6 +21,7 @@
#include <linux/rcupdate.h>
#include <linux/close_range.h>
#include <linux/file_ref.h>
+#include <linux/task_work.h>
#include <net/sock.h>
#include <linux/init_task.h>
@@ -1525,3 +1526,47 @@ int iterate_fd(struct files_struct *files, unsigned n,
return res;
}
EXPORT_SYMBOL(iterate_fd);
+
+struct close_fd_safe_task_work {
+ struct callback_head twork;
+ struct file *file;
+};
+
+static void close_fd_safe_callback(struct callback_head *twork)
+{
+ struct close_fd_safe_task_work *twcb = container_of(twork,
+ struct close_fd_safe_task_work, twork);
+
+ fput(twcb->file);
+ kfree(twcb);
+}
+
+/**
+ * close_fd_safe - close the given fd
+ * @fd: file descriptor to close
+ * @flags: gfp flags for allocation of task work
+ *
+ * This closes an fd. Unlike close_fd(), this may be used even if the fd is
+ * currently held with fdget().
+ *
+ * Returns: 0 or an error code
+ */
+int close_fd_safe(unsigned int fd, gfp_t flags)
+{
+ struct close_fd_safe_task_work *twcb;
+
+ twcb = kzalloc(sizeof(*twcb), flags);
+ if (!twcb)
+ return -ENOMEM;
+ init_task_work(&twcb->twork, close_fd_safe_callback);
+ twcb->file = file_close_fd(fd);
+ if (!twcb->file) {
+ kfree(twcb);
+ return -EBADF;
+ }
+
+ get_file(twcb->file);
+ filp_close(twcb->file, current->files);
+ task_work_add(current, &twcb->twork, TWA_RESUME);
+ return 0;
+}
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index c45306a9f007..1c99a56c0cdf 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -111,6 +111,7 @@ int iterate_fd(struct files_struct *, unsigned,
const void *);
extern int close_fd(unsigned int fd);
+extern int close_fd_safe(unsigned int fd, gfp_t flags);
extern struct file *file_close_fd(unsigned int fd);
extern struct kmem_cache *files_cachep;
© 2016 - 2026 Red Hat, Inc.