[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/2] xen/list: avoid UB in list iterators


  • To: Jan Beulich <jbeulich@xxxxxxxx>
  • From: Jürgen Groß <jgross@xxxxxxxx>
  • Date: Mon, 17 Feb 2025 12:58:10 +0100
  • Autocrypt: addr=jgross@xxxxxxxx; keydata= xsBNBFOMcBYBCACgGjqjoGvbEouQZw/ToiBg9W98AlM2QHV+iNHsEs7kxWhKMjrioyspZKOB ycWxw3ie3j9uvg9EOB3aN4xiTv4qbnGiTr3oJhkB1gsb6ToJQZ8uxGq2kaV2KL9650I1SJve dYm8Of8Zd621lSmoKOwlNClALZNew72NjJLEzTalU1OdT7/i1TXkH09XSSI8mEQ/ouNcMvIJ NwQpd369y9bfIhWUiVXEK7MlRgUG6MvIj6Y3Am/BBLUVbDa4+gmzDC9ezlZkTZG2t14zWPvx XP3FAp2pkW0xqG7/377qptDmrk42GlSKN4z76ELnLxussxc7I2hx18NUcbP8+uty4bMxABEB AAHNH0p1ZXJnZW4gR3Jvc3MgPGpncm9zc0BzdXNlLmNvbT7CwHkEEwECACMFAlOMcK8CGwMH CwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRCw3p3WKL8TL8eZB/9G0juS/kDY9LhEXseh mE9U+iA1VsLhgDqVbsOtZ/S14LRFHczNd/Lqkn7souCSoyWsBs3/wO+OjPvxf7m+Ef+sMtr0 G5lCWEWa9wa0IXx5HRPW/ScL+e4AVUbL7rurYMfwCzco+7TfjhMEOkC+va5gzi1KrErgNRHH kg3PhlnRY0Udyqx++UYkAsN4TQuEhNN32MvN0Np3WlBJOgKcuXpIElmMM5f1BBzJSKBkW0Jc Wy3h2Wy912vHKpPV/Xv7ZwVJ27v7KcuZcErtptDevAljxJtE7aJG6WiBzm+v9EswyWxwMCIO RoVBYuiocc51872tRGywc03xaQydB+9R7BHPzsBNBFOMcBYBCADLMfoA44MwGOB9YT1V4KCy vAfd7E0BTfaAurbG+Olacciz3yd09QOmejFZC6AnoykydyvTFLAWYcSCdISMr88COmmCbJzn sHAogjexXiif6ANUUlHpjxlHCCcELmZUzomNDnEOTxZFeWMTFF9Rf2k2F0Tl4E5kmsNGgtSa aMO0rNZoOEiD/7UfPP3dfh8JCQ1VtUUsQtT1sxos8Eb/HmriJhnaTZ7Hp3jtgTVkV0ybpgFg w6WMaRkrBh17mV0z2ajjmabB7SJxcouSkR0hcpNl4oM74d2/VqoW4BxxxOD1FcNCObCELfIS auZx+XT6s+CE7Qi/c44ibBMR7hyjdzWbABEBAAHCwF8EGAECAAkFAlOMcBYCGwwACgkQsN6d 1ii/Ey9D+Af/WFr3q+bg/8v5tCknCtn92d5lyYTBNt7xgWzDZX8G6/pngzKyWfedArllp0Pn fgIXtMNV+3t8Li1Tg843EXkP7+2+CQ98MB8XvvPLYAfW8nNDV85TyVgWlldNcgdv7nn1Sq8g HwB2BHdIAkYce3hEoDQXt/mKlgEGsLpzJcnLKimtPXQQy9TxUaLBe9PInPd+Ohix0XOlY+Uk QFEx50Ki3rSDl2Zt2tnkNYKUCvTJq7jvOlaPd6d/W0tZqpyy7KVay+K4aMobDsodB3dvEAs6 ScCnh03dDAFgIq5nsB11j3KPKdVoPlfucX2c7kGNH+LUMbzqV6beIENfNexkOfxHfw==
  • Cc: oleksii.kurochko@xxxxxxxxx, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Julien Grall <julien@xxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxxx
  • Delivery-date: Mon, 17 Feb 2025 11:58:20 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

On 17.02.25 12:39, Jan Beulich wrote:
On 17.02.2025 12:16, Juergen Gross wrote:
On 17.02.25 10:47, Jan Beulich wrote:
On 16.02.2025 11:23, Juergen Gross wrote:
@@ -556,11 +590,11 @@ static inline void list_splice_init(struct list_head 
*list,
    * @head:   the head for your list.
    * @member: the name of the list_struct within the struct.
    */
-#define list_for_each_entry_safe(pos, n, head, member)                  \
-    for ((pos) = list_entry((head)->next, typeof(*(pos)), member),      \
-         (n) = list_entry((pos)->member.next, typeof(*(pos)), member);  \
-         &(pos)->member != (head);                                      \
-         (pos) = (n), (n) = list_entry((n)->member.next, typeof(*(n)), member))
+#define list_for_each_entry_safe(pos, n, head, member)                     \
+    for ( (pos) = list_first_entry_or_null(head, typeof(*(pos)), member),  \
+          (n) = (pos) ? list_next_entry_or_null(head, pos, member) : NULL; \

n can end up being NULL here even if pos isn't. Then ...

+          pos;                                                             \
+          (pos) = (n), (n) = list_next_entry_or_null(head, n, member) )

... you can't use list_next_entry_or_null() on it.

Ah, indeed.

What would you prefer? Handling that in the *_safe() iterator macros, or
allowing the *_entry_or_null() macros to be called with a NULL parameter?

I'd prefer the former, but I probably wouldn't mind the latter.

@@ -655,10 +689,10 @@ static inline void list_splice_init(struct list_head 
*list,
    * the _rcu list-mutation primitives such as list_add_rcu()
    * as long as the traversal is guarded by rcu_read_lock().
    */
-#define list_for_each_entry_rcu(pos, head, member)                      \
-    for ((pos) = list_entry((head)->next, typeof(*(pos)), member);      \
-         &rcu_dereference(pos)->member != (head);                       \
-         (pos) = list_entry((pos)->member.next, typeof(*(pos)), member))
+#define list_for_each_entry_rcu(pos, head, member)                        \
+    for ( (pos) = list_first_entry_or_null(head, typeof(*(pos)), member); \
+          rcu_dereference(pos);                                           \
+          (pos) = list_next_entry_or_null(head, pos, member) )

Don't you need a list_next_entry_or_null_rcu() flavor here, using
rcu_dereference() on the passed in pos for the (pos)->member.next deref?

Isn't the "rcu_dereference(pos);" all what is needed for the current iteration?

Reading Linux'es rcu_dereference.rst, my understanding is that one of them
would suffice if then we used its result rather than the original pointer.
Then again RCU has been somewhat opaque to me for all the years ...

Otherwise today's implementation would suffer from the same problem IMHO.

That's the impression I'm (now) having.

The rcu_dereference() is basically just for documentation purposes. If needed
by an arch, it can add barriers, too, but according to the comments those would
be needed on alpha only. The returned value is always the original pointer
value. See the comment block in xen/include/xen/rcupdate.h


Juergen

Attachment: OpenPGP_0xB0DE9DD628BF132F.asc
Description: OpenPGP public key

Attachment: OpenPGP_signature.asc
Description: OpenPGP digital signature


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.