lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Ybc5aMFodXvDkT4f@hirez.programming.kicks-ass.net>
Date:   Mon, 13 Dec 2021 13:15:36 +0100
From:   Peter Zijlstra <peterz@...radead.org>
To:     will@...nel.org, boqun.feng@...il.com
Cc:     linux-kernel@...r.kernel.org, x86@...nel.org, mark.rutland@....com,
        elver@...gle.com, keescook@...omium.org, hch@...radead.org,
        torvalds@...ux-foundation.org, axboe@...nel.dk
Subject: [PATCH v2 10/9] atomic: Document the atomic_{}_overflow() functions


They're damn special, they're very likely to confuse people, write a
few words in a vain attempt to twart some of that confusion.

Signed-off-by: Peter Zijlstra (Intel) <peterz@...radead.org>
---
 Documentation/atomic_t.txt                     |   36 +++++++++++++++++
 include/linux/atomic/atomic-arch-fallback.h    |   52 ++++++++++++++++++++++++-
 scripts/atomic/fallbacks/dec_and_test_overflow |   10 ++++
 scripts/atomic/fallbacks/dec_overflow          |    9 ++++
 scripts/atomic/fallbacks/inc_overflow          |    9 ++++
 5 files changed, 115 insertions(+), 1 deletion(-)

--- a/Documentation/atomic_t.txt
+++ b/Documentation/atomic_t.txt
@@ -45,6 +45,14 @@ The 'full' API consists of (atomic64_ an
   atomic_sub_and_test(), atomic_dec_and_test()
 
 
+Reference count with overflow (as used by refcount_t):
+
+  atomic_inc_overflow(), atomic_dec_overflow()
+  atomic_dec_and_test_overflow()
+
+  ATOMIC_OVERFLOW_OFFSET
+
+
 Misc:
 
   atomic_inc_and_test(), atomic_add_negative()
@@ -157,6 +165,34 @@ atomic variable) can be fully ordered an
 visible.
 
 
+Overflow ops:
+
+The atomic_{}_overflow() ops are similar to their !_overflow() bretheren with
+two notable exceptions:
+
+ - they take a label as their final argument to to jump to when the atomic op
+   overflows;
+
+ - the actual value can be offset from 0 in order to allow architectures
+   to play games with condition flags in order to generate better code. This
+   offset is ATOMIC_OVERFLOW_OFFSET.
+
+The canonical overflow conditions are (ATOMIC_OVERFLOW_OFFSET == 0):
+
+  inc: zero or negative on the value pre increment
+  dec: zero or negative on the value post decrement
+  dec_and_test: negative on the value post decrement
+
+This gives an effective range of [0, INT_MIN] for the actual value. When an
+architecture uses ATOMIC_OVERFLOW_OFFSET == 1 (x86), the effective range
+becomes [-1, INT_MIN], or [0, INT_MIN+1] after correction.
+
+These semantics match the reference count use-case (for which they were
+created). Specifically incrementing from zero is a failure because zero means
+the object is freed (IOW use-after-free). Decrementing to zero is a failure
+because it goes undetected (see dec_and_test) and the object would leak.
+
+
 ORDERING  (go read memory-barriers.txt first)
 --------
 
--- a/include/linux/atomic/atomic-arch-fallback.h
+++ b/include/linux/atomic/atomic-arch-fallback.h
@@ -1251,6 +1251,14 @@ arch_atomic_dec_if_positive(atomic_t *v)
 #endif
 
 #ifndef arch_atomic_inc_overflow
+/**
+ * arch_atomic_inc_overflow - increment with overflow exception
+ * @_v: pointer of type atomic_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically increments @_v and goto @_label when the old
+ * value (+ATOMIC_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_atomic_inc_overflow(_v, _label)				\
 do {									\
 	int __old = arch_atomic_fetch_inc(_v);			\
@@ -1260,6 +1268,14 @@ do {									\
 #endif
 
 #ifndef arch_atomic_dec_overflow
+/**
+ * arch_atomic_dec_overflow - decrement with overflow exception
+ * @_v: pointer of type atomic_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically decrements @_v and goto @_label when the
+ * result (+ATOMIC_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_atomic_dec_overflow(_v, _label)				\
 do {									\
 	int __new = arch_atomic_dec_return(_v);			\
@@ -1269,6 +1285,15 @@ do {									\
 #endif
 
 #ifndef arch_atomic_dec_and_test_overflow
+/**
+ * arch_atomic_dec_and_test_overflow - decrement and test if zero with overflow exception
+ * @_v: pointer of type atomic_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically decrements @_v and returns true if the result
+ * (+ATOMIC_OVERFLOW_OFFSET) is zero or goto @_label when the
+ * result (+ATOMIC_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_atomic_dec_and_test_overflow(_v, _label)		\
 ({									\
 	bool __ret = false;						\
@@ -2389,6 +2414,14 @@ arch_atomic64_dec_if_positive(atomic64_t
 #endif
 
 #ifndef arch_atomic64_inc_overflow
+/**
+ * arch_atomic64_inc_overflow - increment with overflow exception
+ * @_v: pointer of type atomic64_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically increments @_v and goto @_label when the old
+ * value (+ATOMIC64_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_atomic64_inc_overflow(_v, _label)				\
 do {									\
 	s64 __old = arch_atomic64_fetch_inc(_v);			\
@@ -2398,6 +2431,14 @@ do {									\
 #endif
 
 #ifndef arch_atomic64_dec_overflow
+/**
+ * arch_atomic64_dec_overflow - decrement with overflow exception
+ * @_v: pointer of type atomic64_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically decrements @_v and goto @_label when the
+ * result (+ATOMIC64_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_atomic64_dec_overflow(_v, _label)				\
 do {									\
 	s64 __new = arch_atomic64_dec_return(_v);			\
@@ -2407,6 +2448,15 @@ do {									\
 #endif
 
 #ifndef arch_atomic64_dec_and_test_overflow
+/**
+ * arch_atomic64_dec_and_test_overflow - decrement and test if zero with overflow exception
+ * @_v: pointer of type atomic64_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically decrements @_v and returns true if the result
+ * (+ATOMIC64_OVERFLOW_OFFSET) is zero or goto @_label when the
+ * result (+ATOMIC64_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_atomic64_dec_and_test_overflow(_v, _label)		\
 ({									\
 	bool __ret = false;						\
@@ -2420,4 +2470,4 @@ do {									\
 #endif
 
 #endif /* _LINUX_ATOMIC_FALLBACK_H */
-// e4c677b23b3fd5e8dc4bce9d6c055103666cfc4a
+// ccccab23ad71e0523949b969f68b40fe6812fc15
--- a/scripts/atomic/fallbacks/dec_and_test_overflow
+++ b/scripts/atomic/fallbacks/dec_and_test_overflow
@@ -1,4 +1,14 @@
+ATOMIC=`echo ${atomic} | tr '[:lower:]' '[:upper:]'`
 cat << EOF
+/**
+ * arch_${atomic}_dec_and_test_overflow - decrement and test if zero with overflow exception
+ * @_v: pointer of type ${atomic}_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically decrements @_v and returns true if the result
+ * (+${ATOMIC}_OVERFLOW_OFFSET) is zero or goto @_label when the
+ * result (+${ATOMIC}_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_${atomic}_dec_and_test_overflow(_v, _label)		\\
 ({									\\
 	bool __ret = false;						\\
--- a/scripts/atomic/fallbacks/dec_overflow
+++ b/scripts/atomic/fallbacks/dec_overflow
@@ -1,4 +1,13 @@
+ATOMIC=`echo ${atomic} | tr '[:lower:]' '[:upper:]'`
 cat << EOF
+/**
+ * arch_${atomic}_dec_overflow - decrement with overflow exception
+ * @_v: pointer of type ${atomic}_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically decrements @_v and goto @_label when the
+ * result (+${ATOMIC}_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_${atomic}_dec_overflow(_v, _label)				\\
 do {									\\
 	${int} __new = arch_${atomic}_dec_return(_v);			\\
--- a/scripts/atomic/fallbacks/inc_overflow
+++ b/scripts/atomic/fallbacks/inc_overflow
@@ -1,4 +1,13 @@
+ATOMIC=`echo ${atomic} | tr '[:lower:]' '[:upper:]'`
 cat << EOF
+/**
+ * arch_${atomic}_inc_overflow - increment with overflow exception
+ * @_v: pointer of type ${atomic}_t
+ * @_label: label to goto on overflow
+ *
+ * Atomically increments @_v and goto @_label when the old
+ * value (+${ATOMIC}_OVERFLOW_OFFSET) is negative.
+ */
 #define arch_${atomic}_inc_overflow(_v, _label)				\\
 do {									\\
 	${int} __old = arch_${atomic}_fetch_inc(_v);			\\

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ