ソースを参照

madwifi: fix ACL race condition (patch by Sebastian Gottschall)

SVN-Revision: 13097
Felix Fietkau 17 年 前
コミット
f44a4a0b00
1 ファイル変更116 行追加0 行削除
  1. 116 0
      package/madwifi/patches/386-acl_crashfix.patch

+ 116 - 0
package/madwifi/patches/386-acl_crashfix.patch

@@ -0,0 +1,116 @@
+fixes ACL race condition caused by acl list modifications at run time
+
+Signed-off-by: Sebastian Gottschall <[email protected]>
+
+--- a/net80211/ieee80211_acl.c
++++ b/net80211/ieee80211_acl.c
+@@ -112,9 +112,9 @@ acl_detach(struct ieee80211vap *vap)
+ {
+ 	struct aclstate *as = vap->iv_as;
+ 
+-	ACL_LOCK(as);
++	ACL_LOCK_IRQ(as);
+ 	acl_free_all_locked(as);
+-	ACL_UNLOCK(as);
++	ACL_UNLOCK_IRQ(as);
+ 	vap->iv_as = NULL;
+ 	ACL_LOCK_DESTROY(as);
+ 	FREE(as, M_DEVBUF);
+@@ -128,11 +128,18 @@ _find_acl(struct aclstate *as, const u_i
+ 	struct acl *acl;
+ 	int hash;
+ 
++	/* locking needed, as inserts are not atomic */
++	ACL_LOCK_IRQ(as);
+ 	hash = ACL_HASH(macaddr);
+ 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
+-		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
+-			return acl;
++		if (!IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
++			continue;
++
++		ACL_UNLOCK_IRQ_EARLY(as);
++		return acl;
+ 	}
++	ACL_UNLOCK_IRQ(as);
++
+ 	return NULL;
+ }
+ 
+@@ -176,11 +183,11 @@ acl_add(struct ieee80211vap *vap, const 
+ 		return -ENOMEM;
+ 	}
+ 
+-	ACL_LOCK(as);
++	ACL_LOCK_IRQ(as);
+ 	hash = ACL_HASH(mac);
+ 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
+ 		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
+-			ACL_UNLOCK_EARLY(as);
++			ACL_UNLOCK_IRQ_EARLY(as);
+ 			FREE(new, M_80211_ACL);
+ 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
+ 				"ACL: add " MAC_FMT " failed, already present\n",
+@@ -191,7 +198,7 @@ acl_add(struct ieee80211vap *vap, const 
+ 	IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
+ 	TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
+ 	LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
+-	ACL_UNLOCK(as);
++	ACL_UNLOCK_IRQ(as);
+ 
+ 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
+ 		"ACL: add " MAC_FMT "\n", MAC_ADDR(mac));
+@@ -204,11 +211,11 @@ acl_remove(struct ieee80211vap *vap, con
+ 	struct aclstate *as = vap->iv_as;
+ 	struct acl *acl;
+ 
+-	ACL_LOCK(as);
++	ACL_LOCK_IRQ(as);
+ 	acl = _find_acl(as, mac);
+ 	if (acl != NULL)
+ 		_acl_free(as, acl);
+-	ACL_UNLOCK(as);
++	ACL_UNLOCK_IRQ(as);
+ 
+ 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
+ 		"ACL: remove " MAC_FMT "%s\n", MAC_ADDR(mac),
+@@ -235,9 +242,9 @@ acl_free_all(struct ieee80211vap *vap)
+ 
+ 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
+ 
+-	ACL_LOCK(as);
++	ACL_LOCK_IRQ(as);
+ 	acl_free_all_locked(vap->iv_as);
+-	ACL_UNLOCK(as);
++	ACL_UNLOCK_IRQ(as);
+ 
+ 	return 0;
+ }
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -311,16 +311,15 @@ typedef spinlock_t ieee80211_scan_lock_t
+ typedef spinlock_t acl_lock_t;
+ #define	ACL_LOCK_INIT(_as, _name)	spin_lock_init(&(_as)->as_lock)
+ #define	ACL_LOCK_DESTROY(_as)
+-#define	ACL_LOCK(_as)			do { 	\
+-	ACL_LOCK_CHECK(_as); 		\
+-	spin_lock(&(_as)->as_lock);
+-#define	ACL_UNLOCK(_as)				\
+-	ACL_LOCK_ASSERT(_as); 			\
+-	spin_unlock(&(_as)->as_lock); 		\
+-} while(0)
+-#define ACL_UNLOCK_EARLY(_as)			\
+-	ACL_LOCK_ASSERT(_as); 			\
+-	spin_unlock(&(_as)->as_lock);
++#define	ACL_LOCK_IRQ(_as)	do {	\
++	unsigned long __acl_lockflags;		\
++	spin_lock_irqsave(&(_as)->as_lock, __acl_lockflags);
++#define	ACL_UNLOCK_IRQ(_as) \
++	spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
++} while (0)
++#define	ACL_UNLOCK_IRQ_EARLY(_as)	do { \
++	spin_unlock_irqrestore(&(_as)->as_lock, __acl_lockflags); \
++} while (0)
+ 
+ #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
+ #define	ACL_LOCK_ASSERT(_as) \