summaryrefslogtreecommitdiff
path: root/drivers/ptp/ptp_chardev.c
diff options
context:
space:
mode:
authorEdward Adam Davis <eadavis@qq.com>2023-11-07 11:00:41 +0300
committerJakub Kicinski <kuba@kernel.org>2023-11-09 05:47:07 +0300
commit1bea2c3e6df8caf45d18384abfb707f47e9ff993 (patch)
tree247a0999ede72aabbdd2c4acf9ada9a843947ebd /drivers/ptp/ptp_chardev.c
parentb714ca2ccf6a90733f6ceb14abb6ce914f8832c3 (diff)
downloadlinux-1bea2c3e6df8caf45d18384abfb707f47e9ff993.tar.xz
ptp: fix corrupted list in ptp_open
There is no lock protection when writing ptp->tsevqs in ptp_open() and ptp_release(), which can cause data corruption, use spin lock to avoid this issue. Moreover, ptp_release() should not be used to release the queue in ptp_read(), and it should be deleted altogether. Acked-by: Richard Cochran <richardcochran@gmail.com> Reported-and-tested-by: syzbot+df3f3ef31f60781fa911@syzkaller.appspotmail.com Fixes: 8f5de6fb2453 ("ptp: support multiple timestamp event readers") Signed-off-by: Edward Adam Davis <eadavis@qq.com> Link: https://lore.kernel.org/r/tencent_CD19564FFE8DA8A5918DFE92325D92DD8107@qq.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers/ptp/ptp_chardev.c')
-rw-r--r--drivers/ptp/ptp_chardev.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index 27c1ef493617..3f7a74788802 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -108,6 +108,7 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)
container_of(pccontext->clk, struct ptp_clock, clock);
struct timestamp_event_queue *queue;
char debugfsname[32];
+ unsigned long flags;
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
if (!queue)
@@ -119,7 +120,9 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)
}
bitmap_set(queue->mask, 0, PTP_MAX_CHANNELS);
spin_lock_init(&queue->lock);
+ spin_lock_irqsave(&ptp->tsevqs_lock, flags);
list_add_tail(&queue->qlist, &ptp->tsevqs);
+ spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
pccontext->private_clkdata = queue;
/* Debugfs contents */
@@ -139,16 +142,16 @@ int ptp_release(struct posix_clock_context *pccontext)
{
struct timestamp_event_queue *queue = pccontext->private_clkdata;
unsigned long flags;
+ struct ptp_clock *ptp =
+ container_of(pccontext->clk, struct ptp_clock, clock);
- if (queue) {
- debugfs_remove(queue->debugfs_instance);
- pccontext->private_clkdata = NULL;
- spin_lock_irqsave(&queue->lock, flags);
- list_del(&queue->qlist);
- spin_unlock_irqrestore(&queue->lock, flags);
- bitmap_free(queue->mask);
- kfree(queue);
- }
+ debugfs_remove(queue->debugfs_instance);
+ pccontext->private_clkdata = NULL;
+ spin_lock_irqsave(&ptp->tsevqs_lock, flags);
+ list_del(&queue->qlist);
+ spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
+ bitmap_free(queue->mask);
+ kfree(queue);
return 0;
}