NAT44 segv on unknown proto on inside interface 53/12353/2
authorMatthew Smith <mgsmith@netgate.com>
Mon, 30 Apr 2018 21:39:13 +0000 (16:39 -0500)
committerDamjan Marion <dmarion.lists@gmail.com>
Thu, 3 May 2018 19:07:53 +0000 (19:07 +0000)
When a packet with an unknown proto arrives
on an inside interface and there are no existing sessions
for the source address, a segv occurs.

snat_in2out_unknown_proto() finds the head of the sessions
dlist, fetches the address of the next element using
head->next, and then dereferences the next element. On the
first packet received from a source address, head->next is
~0, so this results in a segv.

Check that the session list is not empty before trying to
traverse it.

Also removed unnecessary lookup against tsm->user_hash.
Prior call to nat_user_get_or_create() already performed
that lookup and added a user if one didn't exist.

Change-Id: If73e79aa2f8e3962ab7b876ecf55aea40d7a5472
Signed-off-by: Matthew Smith <mgsmith@netgate.com>
src/plugins/nat/in2out.c

index 786b6c6..3ec65e8 100755 (executable)
@@ -1217,34 +1217,37 @@ snat_in2out_unknown_proto (snat_main_t *sm,
       else
         {
           /* Choose same out address as for TCP/UDP session to same destination */
-          if (!clib_bihash_search_8_8 (&tsm->user_hash, &kv, &value))
+          head_index = u->sessions_per_user_list_head_index;
+          head = pool_elt_at_index (tsm->list_pool, head_index);
+          elt_index = head->next;
+         if (PREDICT_FALSE (elt_index == ~0))
+           ses_index = ~0;
+         else
+           {
+             elt = pool_elt_at_index (tsm->list_pool, elt_index);
+             ses_index = elt->value;
+           }
+
+          while (ses_index != ~0)
             {
-              head_index = u->sessions_per_user_list_head_index;
-              head = pool_elt_at_index (tsm->list_pool, head_index);
-              elt_index = head->next;
+              s =  pool_elt_at_index (tsm->sessions, ses_index);
+              elt_index = elt->next;
               elt = pool_elt_at_index (tsm->list_pool, elt_index);
               ses_index = elt->value;
-              while (ses_index != ~0)
-                {
-                  s =  pool_elt_at_index (tsm->sessions, ses_index);
-                  elt_index = elt->next;
-                  elt = pool_elt_at_index (tsm->list_pool, elt_index);
-                  ses_index = elt->value;
 
-                  if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
-                    {
-                      new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
-                      address_index = s->outside_address_index;
+              if (s->ext_host_addr.as_u32 == ip->dst_address.as_u32)
+                {
+                  new_addr = ip->src_address.as_u32 = s->out2in.addr.as_u32;
+                  address_index = s->outside_address_index;
 
-                      key.fib_index = sm->outside_fib_index;
-                      key.l_addr.as_u32 = new_addr;
-                      s_kv.key[0] = key.as_u64[0];
-                      s_kv.key[1] = key.as_u64[1];
-                      if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
-                        break;
+                  key.fib_index = sm->outside_fib_index;
+                  key.l_addr.as_u32 = new_addr;
+                  s_kv.key[0] = key.as_u64[0];
+                  s_kv.key[1] = key.as_u64[1];
+                  if (clib_bihash_search_16_8 (&sm->out2in_ed, &s_kv, &s_value))
+                    break;
 
-                      goto create_ses;
-                    }
+                  goto create_ses;
                 }
             }
           key.fib_index = sm->outside_fib_index;