summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorGeorge Wilson <[email protected]>2021-07-10 20:00:37 -0500
committerTony Hutter <[email protected]>2021-09-14 12:37:38 -0700
commit8415c3c1705ec64ea34a2e90d6810e6fe5232cce (patch)
treeff2cd96eb21a4c13a4d95e5987a615beee255aae /lib
parent04ebe29188032c9d2b0fd80b2571a82aa3013134 (diff)
file reference counts can get corrupted
Callers of zfs_file_get and zfs_file_put can corrupt the reference counts for the file structure resulting in a panic or a soft lockup. When zfs send/recv runs, it will add a reference count to the open file, and begin to send or recv the stream. If the file descriptor is closed, then when dmu_recv_stream() or dmu_send() return we will call zfs_file_put to remove the reference we placed on the file structure. Unfortunately, because zfs_file_put() uses the file descriptor to lookup the file structure, it may end up finding that the file descriptor table no longer contains the file struct, thus leaking the file structure. Or it might end up finding a file descriptor for a different file and blindly updating its reference counts. Other failure modes probably exists. This change reworks the zfs_file_[get|put] interface to not rely on the file descriptor but instead pass the zfs_file_t pointer around. Reviewed-by: Matthew Ahrens <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Mark Maybee <[email protected]> Reviewed-by: Ryan Moeller <[email protected]> Co-authored-by: Allan Jude <[email protected]> Signed-off-by: George Wilson <[email protected]> External-issue: DLPX-76119 Closes #12299
Diffstat (limited to 'lib')
-rw-r--r--lib/libzpool/kernel.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index 09812dece..5f4740261 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -936,16 +936,16 @@ kmem_asprintf(const char *fmt, ...)
}
/* ARGSUSED */
-int
+zfs_file_t *
zfs_onexit_fd_hold(int fd, minor_t *minorp)
{
*minorp = 0;
- return (0);
+ return (NULL);
}
/* ARGSUSED */
void
-zfs_onexit_fd_rele(int fd)
+zfs_onexit_fd_rele(zfs_file_t *fp)
{
}
@@ -1355,28 +1355,26 @@ zfs_file_unlink(const char *path)
* Get reference to file pointer
*
* fd - input file descriptor
- * fpp - pointer to file pointer
*
- * Returns 0 on success EBADF on failure.
+ * Returns pointer to file struct or NULL.
* Unsupported in user space.
*/
-int
-zfs_file_get(int fd, zfs_file_t **fpp)
+zfs_file_t *
+zfs_file_get(int fd)
{
abort();
- return (EOPNOTSUPP);
+ return (NULL);
}
-
/*
* Drop reference to file pointer
*
- * fd - input file descriptor
+ * fp - pointer to file struct
*
* Unsupported in user space.
*/
void
-zfs_file_put(int fd)
+zfs_file_put(zfs_file_t *fp)
{
abort();
}