git: 3379d9b5de4c - main - umtx: Check for errors from suword32()

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 26 Dec 2023 02:04:27 UTC
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=3379d9b5de4c4876a317d25ca008e66b1111b701

commit 3379d9b5de4c4876a317d25ca008e66b1111b701
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-12-26 01:42:17 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-12-26 02:04:01 +0000

    umtx: Check for errors from suword32()
    
    This is in preparation for annotating copyin() and related functions
    with __result_use_check.
    
    Reviewed by:    kib
    MFC after:      2 weeks
    Differential Revision:  https://reviews.freebsd.org/D43144
---
 sys/kern/kern_umtx.c | 33 +++++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c
index ff9505b8e31d..57ff74f5421e 100644
--- a/sys/kern/kern_umtx.c
+++ b/sys/kern/kern_umtx.c
@@ -2960,7 +2960,14 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m,
 	 */
 	error = fueword32(&cv->c_has_waiters, &hasw);
 	if (error == 0 && hasw == 0)
-		suword32(&cv->c_has_waiters, 1);
+		error = suword32(&cv->c_has_waiters, 1);
+	if (error != 0) {
+		umtxq_lock(&uq->uq_key);
+		umtxq_remove(uq);
+		umtxq_unbusy(&uq->uq_key);
+		error = EFAULT;
+		goto out;
+	}
 
 	umtxq_unbusy_unlocked(&uq->uq_key);
 
@@ -2990,7 +2997,9 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m,
 			umtxq_remove(uq);
 			if (oldlen == 1) {
 				umtxq_unlock(&uq->uq_key);
-				suword32(&cv->c_has_waiters, 0);
+				if (suword32(&cv->c_has_waiters, 0) != 0 &&
+				    error == 0)
+					error = EFAULT;
 				umtxq_lock(&uq->uq_key);
 			}
 		}
@@ -2998,7 +3007,7 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m,
 		if (error == ERESTART)
 			error = EINTR;
 	}
-
+out:
 	umtxq_unlock(&uq->uq_key);
 	umtx_key_release(&uq->uq_key);
 	return (error);
@@ -3176,12 +3185,14 @@ sleep:
 		 */
 		rv = fueword32(&rwlock->rw_blocked_readers,
 		    &blocked_readers);
+		if (rv == 0)
+			rv = suword32(&rwlock->rw_blocked_readers,
+			    blocked_readers + 1);
 		if (rv == -1) {
 			umtxq_unbusy_unlocked(&uq->uq_key);
 			error = EFAULT;
 			break;
 		}
-		suword32(&rwlock->rw_blocked_readers, blocked_readers+1);
 
 		while (state & wrflags) {
 			umtxq_lock(&uq->uq_key);
@@ -3206,12 +3217,14 @@ sleep:
 		/* decrease read waiter count, and may clear read contention bit */
 		rv = fueword32(&rwlock->rw_blocked_readers,
 		    &blocked_readers);
+		if (rv == 0)
+			rv = suword32(&rwlock->rw_blocked_readers,
+			    blocked_readers - 1);
 		if (rv == -1) {
 			umtxq_unbusy_unlocked(&uq->uq_key);
 			error = EFAULT;
 			break;
 		}
-		suword32(&rwlock->rw_blocked_readers, blocked_readers-1);
 		if (blocked_readers == 1) {
 			rv = fueword32(&rwlock->rw_state, &state);
 			if (rv == -1) {
@@ -3360,12 +3373,14 @@ do_rw_wrlock(struct thread *td, struct urwlock *rwlock, struct _umtx_time *timeo
 sleep:
 		rv = fueword32(&rwlock->rw_blocked_writers,
 		    &blocked_writers);
+		if (rv == 0)
+			rv = suword32(&rwlock->rw_blocked_writers,
+			    blocked_writers + 1);
 		if (rv == -1) {
 			umtxq_unbusy_unlocked(&uq->uq_key);
 			error = EFAULT;
 			break;
 		}
-		suword32(&rwlock->rw_blocked_writers, blocked_writers + 1);
 
 		while ((state & URWLOCK_WRITE_OWNER) ||
 		    URWLOCK_READER_COUNT(state) != 0) {
@@ -3390,12 +3405,14 @@ sleep:
 
 		rv = fueword32(&rwlock->rw_blocked_writers,
 		    &blocked_writers);
+		if (rv == 0)
+			rv = suword32(&rwlock->rw_blocked_writers,
+			    blocked_writers - 1);
 		if (rv == -1) {
 			umtxq_unbusy_unlocked(&uq->uq_key);
 			error = EFAULT;
 			break;
 		}
-		suword32(&rwlock->rw_blocked_writers, blocked_writers-1);
 		if (blocked_writers == 1) {
 			rv = fueword32(&rwlock->rw_state, &state);
 			if (rv == -1) {
@@ -3574,7 +3591,7 @@ again:
 		rv1 = fueword32(&sem->_count, &count);
 	if (rv == -1 || rv1 == -1 || count != 0 || (rv == 1 && count1 == 0)) {
 		if (rv == 0)
-			suword32(&sem->_has_waiters, 0);
+			rv = suword32(&sem->_has_waiters, 0);
 		umtxq_lock(&uq->uq_key);
 		umtxq_unbusy(&uq->uq_key);
 		umtxq_remove(uq);