From 4adbf1dd9b48aa65037abc73f43c21dca868a25f Mon Sep 17 00:00:00 2001 From: Aykhan Hagverdili Date: Sun, 11 Aug 2024 21:52:05 +0200 Subject: [PATCH] Fix: blocking O_NONBLOCK process bug in sleep.c There is a subtle bug that if the atomic flag changes between the time it was checked and the second time it was checked, sleep.c would potentially block a process that had specified O_NONBLOCK. This fixes the bug by using atomic_cmpxchg instead of atomic_read. --- examples/sleep.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/sleep.c b/examples/sleep.c index 8ce7ff9..520a3e0 100644 --- a/examples/sleep.c +++ b/examples/sleep.c @@ -92,12 +92,18 @@ static DECLARE_WAIT_QUEUE_HEAD(waitq); /* Called when the /proc file is opened */ static int module_open(struct inode *inode, struct file *file) { + /* Try to get without blocking */ + if (!atomic_cmpxchg(&already_open, 0, 1)) { + /* Success without blocking, allow the access */ + try_module_get(THIS_MODULE); + return 0; + } /* If the file's flags include O_NONBLOCK, it means the process does not - * want to wait for the file. In this case, if the file is already open, + * want to wait for the file. In this case, because the file is already open, * we should fail with -EAGAIN, meaning "you will have to try again", * instead of blocking a process which would rather stay awake. */ - if ((file->f_flags & O_NONBLOCK) && atomic_read(&already_open)) + if (file->f_flags & O_NONBLOCK) return -EAGAIN; /* This is the correct place for try_module_get(THIS_MODULE) because if