Skip to content

Commit 1bea2c3

Browse files
ea1daviskuba-moo
authored andcommitted
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 <[email protected]> Reported-and-tested-by: [email protected] Fixes: 8f5de6f ("ptp: support multiple timestamp event readers") Signed-off-by: Edward Adam Davis <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent b714ca2 commit 1bea2c3

File tree

3 files changed

+19
-11
lines changed

3 files changed

+19
-11
lines changed

drivers/ptp/ptp_chardev.c

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)
108108
container_of(pccontext->clk, struct ptp_clock, clock);
109109
struct timestamp_event_queue *queue;
110110
char debugfsname[32];
111+
unsigned long flags;
111112

112113
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
113114
if (!queue)
@@ -119,7 +120,9 @@ int ptp_open(struct posix_clock_context *pccontext, fmode_t fmode)
119120
}
120121
bitmap_set(queue->mask, 0, PTP_MAX_CHANNELS);
121122
spin_lock_init(&queue->lock);
123+
spin_lock_irqsave(&ptp->tsevqs_lock, flags);
122124
list_add_tail(&queue->qlist, &ptp->tsevqs);
125+
spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
123126
pccontext->private_clkdata = queue;
124127

125128
/* Debugfs contents */
@@ -139,16 +142,16 @@ int ptp_release(struct posix_clock_context *pccontext)
139142
{
140143
struct timestamp_event_queue *queue = pccontext->private_clkdata;
141144
unsigned long flags;
145+
struct ptp_clock *ptp =
146+
container_of(pccontext->clk, struct ptp_clock, clock);
142147

143-
if (queue) {
144-
debugfs_remove(queue->debugfs_instance);
145-
pccontext->private_clkdata = NULL;
146-
spin_lock_irqsave(&queue->lock, flags);
147-
list_del(&queue->qlist);
148-
spin_unlock_irqrestore(&queue->lock, flags);
149-
bitmap_free(queue->mask);
150-
kfree(queue);
151-
}
148+
debugfs_remove(queue->debugfs_instance);
149+
pccontext->private_clkdata = NULL;
150+
spin_lock_irqsave(&ptp->tsevqs_lock, flags);
151+
list_del(&queue->qlist);
152+
spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
153+
bitmap_free(queue->mask);
154+
kfree(queue);
152155
return 0;
153156
}
154157

drivers/ptp/ptp_clock.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,11 +179,11 @@ static void ptp_clock_release(struct device *dev)
179179
mutex_destroy(&ptp->pincfg_mux);
180180
mutex_destroy(&ptp->n_vclocks_mux);
181181
/* Delete first entry */
182+
spin_lock_irqsave(&ptp->tsevqs_lock, flags);
182183
tsevq = list_first_entry(&ptp->tsevqs, struct timestamp_event_queue,
183184
qlist);
184-
spin_lock_irqsave(&tsevq->lock, flags);
185185
list_del(&tsevq->qlist);
186-
spin_unlock_irqrestore(&tsevq->lock, flags);
186+
spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
187187
bitmap_free(tsevq->mask);
188188
kfree(tsevq);
189189
debugfs_remove(ptp->debugfs_root);
@@ -247,6 +247,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info,
247247
if (!queue)
248248
goto no_memory_queue;
249249
list_add_tail(&queue->qlist, &ptp->tsevqs);
250+
spin_lock_init(&ptp->tsevqs_lock);
250251
queue->mask = bitmap_alloc(PTP_MAX_CHANNELS, GFP_KERNEL);
251252
if (!queue->mask)
252253
goto no_memory_bitmap;
@@ -407,6 +408,7 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
407408
{
408409
struct timestamp_event_queue *tsevq;
409410
struct pps_event_time evt;
411+
unsigned long flags;
410412

411413
switch (event->type) {
412414

@@ -415,10 +417,12 @@ void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
415417

416418
case PTP_CLOCK_EXTTS:
417419
/* Enqueue timestamp on selected queues */
420+
spin_lock_irqsave(&ptp->tsevqs_lock, flags);
418421
list_for_each_entry(tsevq, &ptp->tsevqs, qlist) {
419422
if (test_bit((unsigned int)event->index, tsevq->mask))
420423
enqueue_external_timestamp(tsevq, event);
421424
}
425+
spin_unlock_irqrestore(&ptp->tsevqs_lock, flags);
422426
wake_up_interruptible(&ptp->tsev_wq);
423427
break;
424428

drivers/ptp/ptp_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct ptp_clock {
4444
struct pps_device *pps_source;
4545
long dialed_frequency; /* remembers the frequency adjustment */
4646
struct list_head tsevqs; /* timestamp fifo list */
47+
spinlock_t tsevqs_lock; /* protects tsevqs from concurrent access */
4748
struct mutex pincfg_mux; /* protect concurrent info->pin_config access */
4849
wait_queue_head_t tsev_wq;
4950
int defunct; /* tells readers to go away when clock is being removed */

0 commit comments

Comments
 (0)