watch_queue: prevent dangling pipe pointer
NULL the dangling pipe reference while clearing watch_queue. If not done, a reference to a freed pipe remains in the watch_queue, as this function is called before freeing a pipe in free_pipe_info() (see line 834 of fs/pipe.c). The sole use of wqueue->defunct is for checking if the watch queue has been cleared, but wqueue->pipe is also NULLed while clearing. Thus, wqueue->defunct is superfluous, as wqueue->pipe can be checked for NULL. Hence, the former can be removed. Tested with keyutils testsuite. Cc: stable@vger.kernel.org # 6.1 Signed-off-by: Siddh Raman Pant <code@siddh.me> Acked-by: David Howells <dhowells@redhat.com> Message-Id: <20230605143616.640517-1-code@siddh.me> Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
a7bc2e8ddf
commit
943211c874
|
@ -38,7 +38,7 @@ struct watch_filter {
|
|||
struct watch_queue {
|
||||
struct rcu_head rcu;
|
||||
struct watch_filter __rcu *filter;
|
||||
struct pipe_inode_info *pipe; /* The pipe we're using as a buffer */
|
||||
struct pipe_inode_info *pipe; /* Pipe we use as a buffer, NULL if queue closed */
|
||||
struct hlist_head watches; /* Contributory watches */
|
||||
struct page **notes; /* Preallocated notifications */
|
||||
unsigned long *notes_bitmap; /* Allocation bitmap for notes */
|
||||
|
@ -46,7 +46,6 @@ struct watch_queue {
|
|||
spinlock_t lock;
|
||||
unsigned int nr_notes; /* Number of notes */
|
||||
unsigned int nr_pages; /* Number of pages in notes[] */
|
||||
bool defunct; /* T when queues closed */
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -42,7 +42,7 @@ MODULE_AUTHOR("Red Hat, Inc.");
|
|||
static inline bool lock_wqueue(struct watch_queue *wqueue)
|
||||
{
|
||||
spin_lock_bh(&wqueue->lock);
|
||||
if (unlikely(wqueue->defunct)) {
|
||||
if (unlikely(!wqueue->pipe)) {
|
||||
spin_unlock_bh(&wqueue->lock);
|
||||
return false;
|
||||
}
|
||||
|
@ -104,9 +104,6 @@ static bool post_one_notification(struct watch_queue *wqueue,
|
|||
unsigned int head, tail, mask, note, offset, len;
|
||||
bool done = false;
|
||||
|
||||
if (!pipe)
|
||||
return false;
|
||||
|
||||
spin_lock_irq(&pipe->rd_wait.lock);
|
||||
|
||||
mask = pipe->ring_size - 1;
|
||||
|
@ -603,8 +600,11 @@ void watch_queue_clear(struct watch_queue *wqueue)
|
|||
rcu_read_lock();
|
||||
spin_lock_bh(&wqueue->lock);
|
||||
|
||||
/* Prevent new notifications from being stored. */
|
||||
wqueue->defunct = true;
|
||||
/*
|
||||
* This pipe can be freed by callers like free_pipe_info().
|
||||
* Removing this reference also prevents new notifications.
|
||||
*/
|
||||
wqueue->pipe = NULL;
|
||||
|
||||
while (!hlist_empty(&wqueue->watches)) {
|
||||
watch = hlist_entry(wqueue->watches.first, struct watch, queue_node);
|
||||
|
|
Loading…
Reference in New Issue