aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAllan Stephens <allan.stephens@windriver.com>2008-05-12 18:42:28 -0400
committerDavid S. Miller <davem@davemloft.net>2008-05-12 18:42:28 -0400
commit7ef43ebaa538e0cc9063cbf84593a05091bcace2 (patch)
treed2bac748f6620cc2f217672105918b2116f6c958
parent4e3e6dcb43c3669a8817cb3d0f920f91661afd98 (diff)
tipc: Fix race condition when creating socket or native port
This patch eliminates the (very remote) chance of a crash resulting from a partially initialized socket or native port unexpectedly receiving a message. Now, during the creation of a socket or native port, the underlying generic port's lock is not released until all initialization required to handle incoming messages has been done. Signed-off-by: Allan Stephens <allan.stephens@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/tipc/tipc_port.h3
-rw-r--r--net/tipc/port.c20
-rw-r--r--net/tipc/ref.c12
-rw-r--r--net/tipc/socket.c5
-rw-r--r--net/tipc/subscr.c1
5 files changed, 27 insertions, 14 deletions
diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h
index 11105bcc4457..9923e41a8215 100644
--- a/include/net/tipc/tipc_port.h
+++ b/include/net/tipc/tipc_port.h
@@ -84,7 +84,8 @@ struct tipc_port {
84u32 tipc_createport_raw(void *usr_handle, 84u32 tipc_createport_raw(void *usr_handle,
85 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), 85 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
86 void (*wakeup)(struct tipc_port *), 86 void (*wakeup)(struct tipc_port *),
87 const u32 importance); 87 const u32 importance,
88 struct tipc_port **tp_ptr);
88 89
89int tipc_reject_msg(struct sk_buff *buf, u32 err); 90int tipc_reject_msg(struct sk_buff *buf, u32 err);
90 91
diff --git a/net/tipc/port.c b/net/tipc/port.c
index 2f5806410c64..757de38fe6af 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -211,15 +211,18 @@ exit:
211} 211}
212 212
213/** 213/**
214 * tipc_createport_raw - create a native TIPC port 214 * tipc_createport_raw - create a generic TIPC port
215 * 215 *
216 * Returns local port reference 216 * Returns port reference, or 0 if unable to create it
217 *
218 * Note: The newly created port is returned in the locked state.
217 */ 219 */
218 220
219u32 tipc_createport_raw(void *usr_handle, 221u32 tipc_createport_raw(void *usr_handle,
220 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *), 222 u32 (*dispatcher)(struct tipc_port *, struct sk_buff *),
221 void (*wakeup)(struct tipc_port *), 223 void (*wakeup)(struct tipc_port *),
222 const u32 importance) 224 const u32 importance,
225 struct tipc_port **tp_ptr)
223{ 226{
224 struct port *p_ptr; 227 struct port *p_ptr;
225 struct tipc_msg *msg; 228 struct tipc_msg *msg;
@@ -237,7 +240,6 @@ u32 tipc_createport_raw(void *usr_handle,
237 return 0; 240 return 0;
238 } 241 }
239 242
240 tipc_port_lock(ref);
241 p_ptr->publ.usr_handle = usr_handle; 243 p_ptr->publ.usr_handle = usr_handle;
242 p_ptr->publ.max_pkt = MAX_PKT_DEFAULT; 244 p_ptr->publ.max_pkt = MAX_PKT_DEFAULT;
243 p_ptr->publ.ref = ref; 245 p_ptr->publ.ref = ref;
@@ -262,7 +264,7 @@ u32 tipc_createport_raw(void *usr_handle,
262 INIT_LIST_HEAD(&p_ptr->port_list); 264 INIT_LIST_HEAD(&p_ptr->port_list);
263 list_add_tail(&p_ptr->port_list, &ports); 265 list_add_tail(&p_ptr->port_list, &ports);
264 spin_unlock_bh(&tipc_port_list_lock); 266 spin_unlock_bh(&tipc_port_list_lock);
265 tipc_port_unlock(p_ptr); 267 *tp_ptr = &p_ptr->publ;
266 return ref; 268 return ref;
267} 269}
268 270
@@ -1053,6 +1055,7 @@ int tipc_createport(u32 user_ref,
1053{ 1055{
1054 struct user_port *up_ptr; 1056 struct user_port *up_ptr;
1055 struct port *p_ptr; 1057 struct port *p_ptr;
1058 struct tipc_port *tp_ptr;
1056 u32 ref; 1059 u32 ref;
1057 1060
1058 up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC); 1061 up_ptr = kmalloc(sizeof(*up_ptr), GFP_ATOMIC);
@@ -1060,12 +1063,13 @@ int tipc_createport(u32 user_ref,
1060 warn("Port creation failed, no memory\n"); 1063 warn("Port creation failed, no memory\n");
1061 return -ENOMEM; 1064 return -ENOMEM;
1062 } 1065 }
1063 ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup, importance); 1066 ref = tipc_createport_raw(NULL, port_dispatcher, port_wakeup,
1064 p_ptr = tipc_port_lock(ref); 1067 importance, &tp_ptr);
1065 if (!p_ptr) { 1068 if (ref == 0) {
1066 kfree(up_ptr); 1069 kfree(up_ptr);
1067 return -ENOMEM; 1070 return -ENOMEM;
1068 } 1071 }
1072 p_ptr = (struct port *)tp_ptr;
1069 1073
1070 p_ptr->user_port = up_ptr; 1074 p_ptr->user_port = up_ptr;
1071 up_ptr->user_ref = user_ref; 1075 up_ptr->user_ref = user_ref;
diff --git a/net/tipc/ref.c b/net/tipc/ref.c
index 89cbab24d08f..a101de86824d 100644
--- a/net/tipc/ref.c
+++ b/net/tipc/ref.c
@@ -142,9 +142,13 @@ void tipc_ref_table_stop(void)
142/** 142/**
143 * tipc_ref_acquire - create reference to an object 143 * tipc_ref_acquire - create reference to an object
144 * 144 *
145 * Return a unique reference value which can be translated back to the pointer 145 * Register an object pointer in reference table and lock the object.
146 * 'object' at a later time. Also, pass back a pointer to the lock protecting 146 * Returns a unique reference value that is used from then on to retrieve the
147 * the object, but without locking it. 147 * object pointer, or to determine that the object has been deregistered.
148 *
149 * Note: The object is returned in the locked state so that the caller can
150 * register a partially initialized object, without running the risk that
151 * the object will be accessed before initialization is complete.
148 */ 152 */
149 153
150u32 tipc_ref_acquire(void *object, spinlock_t **lock) 154u32 tipc_ref_acquire(void *object, spinlock_t **lock)
@@ -178,13 +182,13 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock)
178 ref = (next_plus_upper & ~index_mask) + index; 182 ref = (next_plus_upper & ~index_mask) + index;
179 entry->ref = ref; 183 entry->ref = ref;
180 entry->object = object; 184 entry->object = object;
181 spin_unlock_bh(&entry->lock);
182 *lock = &entry->lock; 185 *lock = &entry->lock;
183 } 186 }
184 else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { 187 else if (tipc_ref_table.init_point < tipc_ref_table.capacity) {
185 index = tipc_ref_table.init_point++; 188 index = tipc_ref_table.init_point++;
186 entry = &(tipc_ref_table.entries[index]); 189 entry = &(tipc_ref_table.entries[index]);
187 spin_lock_init(&entry->lock); 190 spin_lock_init(&entry->lock);
191 spin_lock_bh(&entry->lock);
188 ref = tipc_ref_table.start_mask + index; 192 ref = tipc_ref_table.start_mask + index;
189 entry->ref = ref; 193 entry->ref = ref;
190 entry->object = object; 194 entry->object = object;
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 230f9ca2ad6b..38f48795b40e 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -188,6 +188,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
188 const struct proto_ops *ops; 188 const struct proto_ops *ops;
189 socket_state state; 189 socket_state state;
190 struct sock *sk; 190 struct sock *sk;
191 struct tipc_port *tp_ptr;
191 u32 portref; 192 u32 portref;
192 193
193 /* Validate arguments */ 194 /* Validate arguments */
@@ -225,7 +226,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
225 /* Allocate TIPC port for socket to use */ 226 /* Allocate TIPC port for socket to use */
226 227
227 portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch, 228 portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch,
228 TIPC_LOW_IMPORTANCE); 229 TIPC_LOW_IMPORTANCE, &tp_ptr);
229 if (unlikely(portref == 0)) { 230 if (unlikely(portref == 0)) {
230 sk_free(sk); 231 sk_free(sk);
231 return -ENOMEM; 232 return -ENOMEM;
@@ -241,6 +242,8 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol)
241 sk->sk_backlog_rcv = backlog_rcv; 242 sk->sk_backlog_rcv = backlog_rcv;
242 tipc_sk(sk)->p = tipc_get_port(portref); 243 tipc_sk(sk)->p = tipc_get_port(portref);
243 244
245 spin_unlock_bh(tp_ptr->lock);
246
244 if (sock->state == SS_READY) { 247 if (sock->state == SS_READY) {
245 tipc_set_portunreturnable(portref, 1); 248 tipc_set_portunreturnable(portref, 1);
246 if (sock->type == SOCK_DGRAM) 249 if (sock->type == SOCK_DGRAM)
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index 8c01ccd3626c..8f8d0a6c1c16 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -474,6 +474,7 @@ static void subscr_named_msg_event(void *usr_handle,
474 kfree(subscriber); 474 kfree(subscriber);
475 return; 475 return;
476 } 476 }
477 spin_unlock_bh(subscriber->lock);
477 478
478 /* Establish a connection to subscriber */ 479 /* Establish a connection to subscriber */
479 480