git: fcafa2453102 - releng/14.0 - timerfd: fix up a memory leak and missing locking
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 28 Sep 2023 22:28:14 UTC
The branch releng/14.0 has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=fcafa24531021555976b4945d9c58667c0f75ca2
commit fcafa24531021555976b4945d9c58667c0f75ca2
Author: Mateusz Guzik <mjg@FreeBSD.org>
AuthorDate: 2023-08-25 14:21:39 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2023-09-28 22:26:19 +0000
timerfd: fix up a memory leak and missing locking
timerfd01 from ltp passes (and some other don't), but none of the tests
crash the kernel.
This is a bare minimum patch to fix up the immediate regression.
Reported by: yasu
(cherry picked from commit 02f534b57f84d6f4f97c337b05b383c8b3aaf18c)
Approved by: re (cperciva@)
(cherry picked from commit 8c496b26641e3d86b0c9db0ed2b4598093df6d5a)
Approved-by: re (cperciva)
---
sys/kern/sys_timerfd.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/sys/kern/sys_timerfd.c b/sys/kern/sys_timerfd.c
index 6948fa059b8c..2bf2a05c443c 100644
--- a/sys/kern/sys_timerfd.c
+++ b/sys/kern/sys_timerfd.c
@@ -43,6 +43,7 @@
#include <sys/queue.h>
#include <sys/selinfo.h>
#include <sys/stat.h>
+#include <sys/sx.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
@@ -59,7 +60,11 @@
#endif
static MALLOC_DEFINE(M_TIMERFD, "timerfd", "timerfd structures");
-static LIST_HEAD(, timerfd) timerfd_head;
+
+static struct sx timerfd_list_lock;
+static LIST_HEAD(, timerfd) timerfd_list;
+SX_SYSINIT(timerfd, &timerfd_list_lock, "timerfd_list_lock");
+
static struct unrhdr64 tfdino_unr;
#define TFD_NOJUMP 0 /* Realtime clock has not jumped. */
@@ -125,7 +130,8 @@ timerfd_jumped(void)
struct timespec boottime, diff;
timerfd_getboottime(&boottime);
- LIST_FOREACH(tfd, &timerfd_head, entry) {
+ sx_xlock(&timerfd_list_lock);
+ LIST_FOREACH(tfd, &timerfd_list, entry) {
mtx_lock(&tfd->tfd_lock);
if (tfd->tfd_clockid != CLOCK_REALTIME ||
(tfd->tfd_timflags & TFD_TIMER_ABSTIME) == 0 ||
@@ -160,6 +166,7 @@ timerfd_jumped(void)
tfd->tfd_boottim = boottime;
mtx_unlock(&tfd->tfd_lock);
}
+ sx_xunlock(&timerfd_list_lock);
}
static int
@@ -314,11 +321,14 @@ timerfd_close(struct file *fp, struct thread *td)
{
struct timerfd *tfd = fp->f_data;
+ sx_xlock(&timerfd_list_lock);
+ LIST_REMOVE(tfd, entry);
+ sx_xunlock(&timerfd_list_lock);
+
callout_drain(&tfd->tfd_callout);
seldrain(&tfd->tfd_sel);
knlist_destroy(&tfd->tfd_sel.si_note);
mtx_destroy(&tfd->tfd_lock);
- LIST_REMOVE(tfd, entry);
free(tfd, M_TIMERFD);
fp->f_ops = &badfileops;
@@ -420,9 +430,11 @@ kern_timerfd_create(struct thread *td, int clockid, int flags)
if ((flags & TFD_CLOEXEC) != 0)
fflags |= O_CLOEXEC;
+ error = falloc(td, &fp, &fd, fflags);
+ if (error != 0)
+ return (error);
+
tfd = malloc(sizeof(*tfd), M_TIMERFD, M_WAITOK | M_ZERO);
- if (tfd == NULL)
- return (ENOMEM);
tfd->tfd_clockid = (clockid_t)clockid;
tfd->tfd_flags = flags;
tfd->tfd_ino = alloc_unr64(&tfdino_unr);
@@ -431,16 +443,15 @@ kern_timerfd_create(struct thread *td, int clockid, int flags)
knlist_init_mtx(&tfd->tfd_sel.si_note, &tfd->tfd_lock);
timerfd_getboottime(&tfd->tfd_boottim);
getnanotime(&tfd->tfd_birthtim);
- LIST_INSERT_HEAD(&timerfd_head, tfd, entry);
+ sx_xlock(&timerfd_list_lock);
+ LIST_INSERT_HEAD(&timerfd_list, tfd, entry);
+ sx_xunlock(&timerfd_list_lock);
- error = falloc(td, &fp, &fd, fflags);
- if (error != 0)
- return (error);
fflags = FREAD;
if ((flags & TFD_NONBLOCK) != 0)
fflags |= FNONBLOCK;
-
finit(fp, fflags, DTYPE_TIMERFD, tfd, &timerfdops);
+
fdrop(fp, td);
td->td_retval[0] = fd;