[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 1/2] xen/list: avoid UB in list iterators
The list_for_each_entry*() iterators are testing for having reached the end of the list in a way which relies on undefined behavior: the iterator (being a pointer to the struct of a list element) is advanced and only then tested to have reached not the next element, but the list head. This results in the list head being addressed via a list element pointer, which is undefined, in case the list elements have a higher alignment then the list head. Avoid that by testing for the end of the list before advancing the iterator. In case of having reached the end of the list, set the iterator to NULL and use that for stopping the loop. This has the additional advantage of not leaking the iterator pointing to something which isn't a list element past the loop. Reported-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Signed-off-by: Juergen Gross <jgross@xxxxxxxx> --- No proper Fixes: tag, as this bug predates Xen's git and mercurial history. --- xen/include/xen/list.h | 110 +++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 38 deletions(-) diff --git a/xen/include/xen/list.h b/xen/include/xen/list.h index 62169f4674..e6ece77225 100644 --- a/xen/include/xen/list.h +++ b/xen/include/xen/list.h @@ -291,6 +291,17 @@ static inline void list_move_tail(struct list_head *list, list_add_tail(list, head); } +/** + * list_is_first - tests whether @list is the first entry in list @head + * @list: the entry to test + * @head: the head of the list + */ +static inline int list_is_first(const struct list_head *list, + const struct list_head *head) +{ + return list->prev == head; +} + /** * list_is_last - tests whether @list is the last entry in list @head * @list: the entry to test @@ -440,7 +451,19 @@ static inline void list_splice_init(struct list_head *list, */ #define list_next_entry(pos, member) \ list_entry((pos)->member.next, typeof(*(pos)), member) - + +/** + * list_next_entry_or_null - get the next element in list + * @pos: the type * to cursor + * @member: the name of the struct list_head within the struct. + * + * Note that if the end of the list is reached, it returns NULL. + */ +#define list_next_entry_or_null(head, pos, member) \ + list_is_last(&(pos)->member, head) \ + ? NULL \ + : list_entry((pos)->member.next, typeof(*(pos)), member) + /** * list_prev_entry - get the prev element in list * @pos: the type * to cursor @@ -449,6 +472,18 @@ static inline void list_splice_init(struct list_head *list, #define list_prev_entry(pos, member) \ list_entry((pos)->member.prev, typeof(*(pos)), member) +/** + * list_prev_entry_or_null - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the struct list_head within the struct. + * + * Note that if the start of the list is reached, it returns NULL. + */ +#define list_prev_entry_or_null(head, pos, member) \ + list_is_first(&(pos)->member, head) \ + ? NULL \ + : list_entry((pos)->member.prev, typeof(*(pos)), member) + /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. @@ -492,10 +527,10 @@ 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(pos, head, member) \ - for ((pos) = list_entry((head)->next, typeof(*(pos)), member); \ - &(pos)->member != (head); \ - (pos) = list_entry((pos)->member.next, typeof(*(pos)), member)) +#define list_for_each_entry(pos, head, member) \ + for ( (pos) = list_first_entry_or_null(head, typeof(*(pos)), member); \ + pos; \ + (pos) = list_next_entry_or_null(head, pos, member) ) /** * list_for_each_entry_reverse - iterate backwards over list of given type. @@ -503,10 +538,10 @@ 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_reverse(pos, head, member) \ - for ((pos) = list_entry((head)->prev, typeof(*(pos)), member); \ - &(pos)->member != (head); \ - (pos) = list_entry((pos)->member.prev, typeof(*(pos)), member)) +#define list_for_each_entry_reverse(pos, head, member) \ + for ( (pos) = list_last_entry_or_null(head, typeof(*(pos)), member); \ + pos; \ + (pos) = list_prev_entry_or_null(head, pos, member) ) /** * list_prepare_entry - prepare a pos entry for use in @@ -530,10 +565,10 @@ static inline void list_splice_init(struct list_head *list, * Continue to iterate over list of given type, continuing after * the current position. */ -#define list_for_each_entry_continue(pos, head, member) \ - for ((pos) = list_entry((pos)->member.next, typeof(*(pos)), member); \ - &(pos)->member != (head); \ - (pos) = list_entry((pos)->member.next, typeof(*(pos)), member)) +#define list_for_each_entry_continue(pos, head, member) \ + for ( (pos) = list_next_entry_or_null(head, pos, member); \ + pos; \ + (pos) = list_next_entry_or_null(head, pos, member) ) /** * list_for_each_entry_from - iterate over list of given type from the @@ -544,9 +579,8 @@ static inline void list_splice_init(struct list_head *list, * * Iterate over list of given type, continuing from current position. */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &(pos)->member != (head); \ - (pos) = list_entry((pos)->member.next, typeof(*(pos)), member)) +#define list_for_each_entry_from(pos, head, member) \ + for ( ; pos; (pos) = list_next_entry_or_null(head, pos, member) ) /** * list_for_each_entry_safe - iterate over list of given type safe @@ -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; \ + pos; \ + (pos) = (n), (n) = list_next_entry_or_null(head, n, member) ) /** * list_for_each_entry_safe_continue @@ -572,11 +606,11 @@ static inline void list_splice_init(struct list_head *list, * Iterate over list of given type, continuing after current point, * safe against removal of list entry. */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for ((pos) = list_entry((pos)->member.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_continue(pos, n, head, member) \ + for ( (pos) = list_next_entry_or_null(head, pos, member), \ + (n) = (pos) ? list_next_entry_or_null(head, pos, member) : NULL; \ + pos; \ + (pos) = (n), (n) = list_next_entry_or_null(head, n, member) ) /** * list_for_each_entry_safe_from @@ -589,9 +623,9 @@ static inline void list_splice_init(struct list_head *list, * removal of list entry. */ #define list_for_each_entry_safe_from(pos, n, head, member) \ - for ((n) = list_entry((pos)->member.next, typeof(*(pos)), member); \ - &(pos)->member != (head); \ - (pos) = (n), (n) = list_entry((n)->member.next, typeof(*(n)), member)) + for ( (n) = list_next_entry_or_null(head, pos, member); \ + pos; \ + (pos) = (n), (n) = list_next_entry_or_null(head, n, member) ) /** * list_for_each_entry_safe_reverse @@ -603,11 +637,11 @@ static inline void list_splice_init(struct list_head *list, * Iterate backwards over list of given type, safe against removal * of list entry. */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for ((pos) = list_entry((head)->prev, typeof(*(pos)), member), \ - (n) = list_entry((pos)->member.prev, typeof(*(pos)), member); \ - &(pos)->member != (head); \ - (pos) = (n), (n) = list_entry((n)->member.prev, typeof(*(n)), member)) +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for ( (pos) = list_last_entry_or_null(head, typeof(*(pos)), member), \ + (n) = (pos) ? list_prev_entry_or_null(head, pos, member) : NULL; \ + pos; \ + (pos) = (n), (n) = list_prev_entry_or_null(head, n, member) ) /** * list_for_each_rcu - iterate over an rcu-protected list @@ -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) ) /** * list_for_each_continue_rcu -- 2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |