Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[AF_IUCV]: Add lock when updating accept_q

The accept_queue of an af_iucv socket will be corrupted, if
adding and deleting of entries in this queue occurs at the
same time (connect request from one client, while accept call
is processed for another client).
Solution: add locking when updating accept_q

Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Acked-by: Frank Pavlic <fpavlic@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ursula Braun and committed by
David S. Miller
febca281 13fdc9a7

+15 -2
+1
include/net/iucv/af_iucv.h
··· 60 60 char dst_user_id[8]; 61 61 char dst_name[8]; 62 62 struct list_head accept_q; 63 + spinlock_t accept_q_lock; 63 64 struct sock *parent; 64 65 struct iucv_path *path; 65 66 struct sk_buff_head send_skb_q;
+14 -2
net/iucv/af_iucv.c
··· 219 219 220 220 sock_init_data(sock, sk); 221 221 INIT_LIST_HEAD(&iucv_sk(sk)->accept_q); 222 + spin_lock_init(&iucv_sk(sk)->accept_q_lock); 222 223 skb_queue_head_init(&iucv_sk(sk)->send_skb_q); 223 224 skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q); 224 225 iucv_sk(sk)->send_tag = 0; ··· 275 274 276 275 void iucv_accept_enqueue(struct sock *parent, struct sock *sk) 277 276 { 277 + unsigned long flags; 278 + struct iucv_sock *par = iucv_sk(parent); 279 + 278 280 sock_hold(sk); 279 - list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q); 281 + spin_lock_irqsave(&par->accept_q_lock, flags); 282 + list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q); 283 + spin_unlock_irqrestore(&par->accept_q_lock, flags); 280 284 iucv_sk(sk)->parent = parent; 281 285 parent->sk_ack_backlog++; 282 286 } 283 287 284 288 void iucv_accept_unlink(struct sock *sk) 285 289 { 290 + unsigned long flags; 291 + struct iucv_sock *par = iucv_sk(iucv_sk(sk)->parent); 292 + 293 + spin_lock_irqsave(&par->accept_q_lock, flags); 286 294 list_del_init(&iucv_sk(sk)->accept_q); 295 + spin_unlock_irqrestore(&par->accept_q_lock, flags); 287 296 iucv_sk(sk)->parent->sk_ack_backlog--; 288 297 iucv_sk(sk)->parent = NULL; 289 298 sock_put(sk); ··· 309 298 lock_sock(sk); 310 299 311 300 if (sk->sk_state == IUCV_CLOSED) { 312 - release_sock(sk); 313 301 iucv_accept_unlink(sk); 302 + release_sock(sk); 314 303 continue; 315 304 } 316 305 ··· 890 879 /* Find out if this path belongs to af_iucv. */ 891 880 read_lock(&iucv_sk_list.lock); 892 881 iucv = NULL; 882 + sk = NULL; 893 883 sk_for_each(sk, node, &iucv_sk_list.head) 894 884 if (sk->sk_state == IUCV_LISTEN && 895 885 !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {