[2/4] batman-adv: fix kernel crash due to missing NULL checks

Message ID 1438779107-12665-3-git-send-email-antonio@meshcoding.com (mailing list archive)
State Not Applicable, archived
Headers

Commit Message

Antonio Quartulli Aug. 5, 2015, 12:51 p.m. UTC
  From: Marek Lindner <mareklindner@neomailbox.ch>

batadv_softif_vlan_get() may return NULL which has to be verified
by the caller.

Fixes: 35df3b298fc8 ("batman-adv: fix TT VLAN inconsistency on VLAN re-add")
Reported-by: Ryan Thompson <ryan@eero.com>
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
---
 net/batman-adv/soft-interface.c    |  3 +++
 net/batman-adv/translation-table.c | 18 ++++++++++++++----
 2 files changed, 17 insertions(+), 4 deletions(-)
  

Comments

David Laight Aug. 5, 2015, 1:15 p.m. UTC | #1
From: Of Antonio Quartulli
> Sent: 05 August 2015 13:52
> From: Marek Lindner <mareklindner@neomailbox.ch>
> 
> batadv_softif_vlan_get() may return NULL which has to be verified
> by the caller.
> 
...
> diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
> index c002961..a2fc843 100644
> --- a/net/batman-adv/soft-interface.c
> +++ b/net/batman-adv/soft-interface.c
> @@ -479,6 +479,9 @@ out:
>   */
>  void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
>  {
> +	if (!vlan)
> +		return;
> +

This bit doesn't look necessary.
You've added checks to some callers, the others probably don't need the check.

> @@ -1066,6 +1069,9 @@ uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
> 
>  	/* decrease the reference held for this vlan */
>  	vlan = batadv_softif_vlan_get(bat_priv, vid);
> +	if (!vlan)
> +		goto out;
> +
>  	batadv_softif_vlan_free_ref(vlan);
>  	batadv_softif_vlan_free_ref(vlan);

That code is ringing alarm bells.
If you expect to have a reference count the object better exist.
If you can remove a reference count from a 'random' object then
you can break the reference counting of objects.

So is this test just hiding anoter bug somewhere??

	David
  
Antonio Quartulli Aug. 11, 2015, 4:42 p.m. UTC | #2
On 05/08/15 15:15, David Laight wrote:
> So is this test just hiding anoter bug somewhere??

Hi David and thanks for your feedback.

The point is that we got several bug reports of kernel crashes due to
NULL pointer deferences in these lines and fter having debugged this
problem for quite a while we preferred to move on and propose this patch.

Still, I am personally debugging this part of the code to understand if
we really have something wrong or if this NULL pointer is something we
should expect (and therefore check).

For the time being we think this patch is better than having horrible
kernel crashes, but I hope to come to a definitive conclusion soon.

Cheers,
  
David Laight Aug. 12, 2015, 8:44 a.m. UTC | #3
From: Antonio Quartulli
> Sent: 11 August 2015 17:43
> On 05/08/15 15:15, David Laight wrote:
> > So is this test just hiding anoter bug somewhere??
> 
> Hi David and thanks for your feedback.
> 
> The point is that we got several bug reports of kernel crashes due to
> NULL pointer deferences in these lines and after having debugged this
> problem for quite a while we preferred to move on and propose this patch.

That is what I thought.

> Still, I am personally debugging this part of the code to understand if
> we really have something wrong or if this NULL pointer is something we
> should expect (and therefore check).
> 
> For the time being we think this patch is better than having horrible
> kernel crashes, but I hope to come to a definitive conclusion soon.

If you don't know why you are seeing the NULL pointer then you are
just papering over some cracks and it is likely that something
is really badly wrong somewhere (ie missing locking).
This could easily mean that there are some much harder to find
bugs lurking there.

	David
  

Patch

diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c
index c002961..a2fc843 100644
--- a/net/batman-adv/soft-interface.c
+++ b/net/batman-adv/soft-interface.c
@@ -479,6 +479,9 @@  out:
  */
 void batadv_softif_vlan_free_ref(struct batadv_softif_vlan *vlan)
 {
+	if (!vlan)
+		return;
+
 	if (atomic_dec_and_test(&vlan->refcount)) {
 		spin_lock_bh(&vlan->bat_priv->softif_vlan_list_lock);
 		hlist_del_rcu(&vlan->list);
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index b482495..38b83c5 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -594,6 +594,9 @@  bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr,
 
 	/* increase the refcounter of the related vlan */
 	vlan = batadv_softif_vlan_get(bat_priv, vid);
+	if (WARN(!vlan, "adding TT local entry %pM to non-existent VLAN %d",
+		 addr, BATADV_PRINT_VID(vid)))
+		goto out;
 
 	batadv_dbg(BATADV_DBG_TT, bat_priv,
 		   "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n",
@@ -1066,6 +1069,9 @@  uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv,
 
 	/* decrease the reference held for this vlan */
 	vlan = batadv_softif_vlan_get(bat_priv, vid);
+	if (!vlan)
+		goto out;
+
 	batadv_softif_vlan_free_ref(vlan);
 	batadv_softif_vlan_free_ref(vlan);
 
@@ -1166,8 +1172,10 @@  static void batadv_tt_local_table_free(struct batadv_priv *bat_priv)
 			/* decrease the reference held for this vlan */
 			vlan = batadv_softif_vlan_get(bat_priv,
 						      tt_common_entry->vid);
-			batadv_softif_vlan_free_ref(vlan);
-			batadv_softif_vlan_free_ref(vlan);
+			if (vlan) {
+				batadv_softif_vlan_free_ref(vlan);
+				batadv_softif_vlan_free_ref(vlan);
+			}
 
 			batadv_tt_local_entry_free_ref(tt_local);
 		}
@@ -3207,8 +3215,10 @@  static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv)
 
 			/* decrease the reference held for this vlan */
 			vlan = batadv_softif_vlan_get(bat_priv, tt_common->vid);
-			batadv_softif_vlan_free_ref(vlan);
-			batadv_softif_vlan_free_ref(vlan);
+			if (vlan) {
+				batadv_softif_vlan_free_ref(vlan);
+				batadv_softif_vlan_free_ref(vlan);
+			}
 
 			batadv_tt_local_entry_free_ref(tt_local);
 		}