Message ID | 1518188432-9245-8-git-send-email-jchapman@katalix.com |
---|---|
State | Superseded, archived |
Delegated to: | David Miller |
Headers | show |
Series | l2tp: fix API races discovered by syzbot | expand |
Hi James,
I love your patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/James-Chapman/l2tp-fix-API-races-discovered-by-syzbot/20180212-102613
config: i386-randconfig-x079-201806 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
Note: the linux-review/James-Chapman/l2tp-fix-API-races-discovered-by-syzbot/20180212-102613 HEAD 0b6885922178c50183cc441ee2b0e2346292de81 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
net/l2tp/l2tp_core.c: In function 'l2tp_tunnel_closeall':
>> net/l2tp/l2tp_core.c:1266:36: error: 'struct l2tp_session' has no member named 'dead'
if (test_and_set_bit(0, &session->dead))
^~
vim +1266 net/l2tp/l2tp_core.c
fd558d18 James Chapman 2010-04-02 1240
fd558d18 James Chapman 2010-04-02 1241 /* When the tunnel is closed, all the attached sessions need to go too.
fd558d18 James Chapman 2010-04-02 1242 */
e34f4c70 Tom Parkin 2013-03-19 1243 void l2tp_tunnel_closeall(struct l2tp_tunnel *tunnel)
fd558d18 James Chapman 2010-04-02 1244 {
fd558d18 James Chapman 2010-04-02 1245 int hash;
fd558d18 James Chapman 2010-04-02 1246 struct hlist_node *walk;
fd558d18 James Chapman 2010-04-02 1247 struct hlist_node *tmp;
fd558d18 James Chapman 2010-04-02 1248 struct l2tp_session *session;
fd558d18 James Chapman 2010-04-02 1249
fd558d18 James Chapman 2010-04-02 1250 BUG_ON(tunnel == NULL);
fd558d18 James Chapman 2010-04-02 1251
a4ca44fa Joe Perches 2012-05-16 1252 l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing all sessions...\n",
a4ca44fa Joe Perches 2012-05-16 1253 tunnel->name);
fd558d18 James Chapman 2010-04-02 1254
fd558d18 James Chapman 2010-04-02 1255 write_lock_bh(&tunnel->hlist_lock);
fd558d18 James Chapman 2010-04-02 1256 for (hash = 0; hash < L2TP_HASH_SIZE; hash++) {
fd558d18 James Chapman 2010-04-02 1257 again:
fd558d18 James Chapman 2010-04-02 1258 hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
fd558d18 James Chapman 2010-04-02 1259 session = hlist_entry(walk, struct l2tp_session, hlist);
fd558d18 James Chapman 2010-04-02 1260
a4ca44fa Joe Perches 2012-05-16 1261 l2tp_info(session, L2TP_MSG_CONTROL,
fd558d18 James Chapman 2010-04-02 1262 "%s: closing session\n", session->name);
fd558d18 James Chapman 2010-04-02 1263
fd558d18 James Chapman 2010-04-02 1264 hlist_del_init(&session->hlist);
fd558d18 James Chapman 2010-04-02 1265
b228a940 Guillaume Nault 2017-09-22 @1266 if (test_and_set_bit(0, &session->dead))
b228a940 Guillaume Nault 2017-09-22 1267 goto again;
b228a940 Guillaume Nault 2017-09-22 1268
fd558d18 James Chapman 2010-04-02 1269 write_unlock_bh(&tunnel->hlist_lock);
fd558d18 James Chapman 2010-04-02 1270
f6e16b29 Tom Parkin 2013-03-19 1271 __l2tp_session_unhash(session);
4c6e2fd3 Tom Parkin 2013-03-19 1272 l2tp_session_queue_purge(session);
4c6e2fd3 Tom Parkin 2013-03-19 1273
fd558d18 James Chapman 2010-04-02 1274 if (session->session_close != NULL)
fd558d18 James Chapman 2010-04-02 1275 (*session->session_close)(session);
fd558d18 James Chapman 2010-04-02 1276
9980d001 Tom Parkin 2013-03-19 1277 l2tp_session_dec_refcount(session);
9980d001 Tom Parkin 2013-03-19 1278
fd558d18 James Chapman 2010-04-02 1279 write_lock_bh(&tunnel->hlist_lock);
fd558d18 James Chapman 2010-04-02 1280
fd558d18 James Chapman 2010-04-02 1281 /* Now restart from the beginning of this hash
fd558d18 James Chapman 2010-04-02 1282 * chain. We always remove a session from the
fd558d18 James Chapman 2010-04-02 1283 * list so we are guaranteed to make forward
fd558d18 James Chapman 2010-04-02 1284 * progress.
fd558d18 James Chapman 2010-04-02 1285 */
fd558d18 James Chapman 2010-04-02 1286 goto again;
fd558d18 James Chapman 2010-04-02 1287 }
fd558d18 James Chapman 2010-04-02 1288 }
fd558d18 James Chapman 2010-04-02 1289 write_unlock_bh(&tunnel->hlist_lock);
fd558d18 James Chapman 2010-04-02 1290 }
e34f4c70 Tom Parkin 2013-03-19 1291 EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall);
fd558d18 James Chapman 2010-04-02 1292
:::::: The code at line 1266 was first introduced by commit
:::::: b228a94066406b6c456321d69643b0d7ce11cfa6 l2tp: fix race between l2tp_session_delete() and l2tp_tunnel_closeall()
:::::: TO: Guillaume Nault <g.nault@alphalink.fr>
:::::: CC: David S. Miller <davem@davemloft.net>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 477b96cf8ab3..869dec89ff0f 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -198,7 +198,14 @@ struct l2tp_session *l2tp_session_get(const struct net *net, rcu_read_lock_bh(); hlist_for_each_entry_rcu(session, session_list, global_hlist) { if (session->session_id == session_id) { + spin_lock_bh(&session->lock); + if (session->closing) { + spin_unlock_bh(&session->lock); + rcu_read_unlock_bh(); + return NULL; + } l2tp_session_inc_refcount(session); + spin_unlock_bh(&session->lock); rcu_read_unlock_bh(); return session; @@ -213,7 +220,14 @@ struct l2tp_session *l2tp_session_get(const struct net *net, read_lock_bh(&tunnel->hlist_lock); hlist_for_each_entry(session, session_list, hlist) { if (session->session_id == session_id) { + spin_lock_bh(&session->lock); + if (session->closing) { + spin_unlock_bh(&session->lock); + read_unlock_bh(&tunnel->hlist_lock); + return NULL; + } l2tp_session_inc_refcount(session); + spin_unlock_bh(&session->lock); read_unlock_bh(&tunnel->hlist_lock); return session; @@ -234,6 +248,12 @@ struct l2tp_session *l2tp_session_get_nth(struct l2tp_tunnel *tunnel, int nth) read_lock_bh(&tunnel->hlist_lock); for (hash = 0; hash < L2TP_HASH_SIZE; hash++) { hlist_for_each_entry(session, &tunnel->session_hlist[hash], hlist) { + spin_lock_bh(&session->lock); + if (session->closing) { + spin_unlock_bh(&session->lock); + continue; + } + spin_unlock_bh(&session->lock); if (++count > nth) { l2tp_session_inc_refcount(session); read_unlock_bh(&tunnel->hlist_lock); @@ -261,6 +281,12 @@ struct l2tp_session *l2tp_session_get_by_ifname(const struct net *net, rcu_read_lock_bh(); for (hash = 0; hash < L2TP_HASH_SIZE_2; hash++) { hlist_for_each_entry_rcu(session, &pn->l2tp_session_hlist[hash], global_hlist) { + spin_lock_bh(&session->lock); + if (session->closing) { + spin_unlock_bh(&session->lock); + continue; + } + spin_unlock_bh(&session->lock); if (!strcmp(session->ifname, ifname)) { l2tp_session_inc_refcount(session); rcu_read_unlock_bh(); @@ -1678,8 +1704,13 @@ void __l2tp_session_unhash(struct l2tp_session *session) */ int l2tp_session_delete(struct l2tp_session *session) { - if (test_and_set_bit(0, &session->dead)) + spin_lock_bh(&session->lock); + if (session->closing) { + spin_unlock_bh(&session->lock); return 0; + } + session->closing = true; + spin_unlock_bh(&session->lock); __l2tp_session_unhash(session); l2tp_session_queue_purge(session); @@ -1747,6 +1778,7 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn INIT_HLIST_NODE(&session->hlist); INIT_HLIST_NODE(&session->global_hlist); + spin_lock_init(&session->lock); /* Inherit debug options from tunnel */ session->debug = tunnel->debug; diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h index 4e098c822cd1..98709086fe84 100644 --- a/net/l2tp/l2tp_core.h +++ b/net/l2tp/l2tp_core.h @@ -74,7 +74,8 @@ struct l2tp_session_cfg { struct l2tp_session { int magic; /* should be * L2TP_SESSION_MAGIC */ - long dead; + bool closing; + spinlock_t lock; /* protect closing */ struct l2tp_tunnel *tunnel; /* back pointer to tunnel * context */
Replace the dead flag in the session context with a closing flag and spinlock. Check it in session lookup functions such that we don't try to access session data while it is being destroyed. Signed-off-by: James Chapman <jchapman@katalix.com> --- net/l2tp/l2tp_core.c | 34 +++++++++++++++++++++++++++++++++- net/l2tp/l2tp_core.h | 3 ++- 2 files changed, 35 insertions(+), 2 deletions(-)