wireguard: move buffer when insufficient pre_data left 04/38004/3
authorAlexander Skorichenko <askorichenko@netgate.com>
Thu, 19 Jan 2023 13:26:47 +0000 (14:26 +0100)
committerMatthew Smith <mgsmith@netgate.com>
Thu, 16 Feb 2023 15:01:07 +0000 (15:01 +0000)
Currently wg-output-tun() doesn't check if a buffer has enough space for
prepending an ethernet header (wg header over ipv6 vxlan header case
leaves only 8 bytes free).

In such a case move buffer's content.

Type: fix

Change-Id: Iad18860e6b86a3d81f3d96d782de7c59556152d0
Signed-off-by: Alexander Skorichenko <askorichenko@netgate.com>
src/plugins/wireguard/wireguard_output_tun.c

index f613d6c..c009d0c 100644 (file)
@@ -423,20 +423,7 @@ wg_output_tun_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
          goto out;
        }
 
-      is_ip4_out = ip46_address_is_ip4 (&peer->src.addr);
-      if (is_ip4_out)
-       {
-         hdr4_out = vlib_buffer_get_current (b[0]);
-         message_data_wg = &hdr4_out->wg;
-       }
-      else
-       {
-         hdr6_out = vlib_buffer_get_current (b[0]);
-         message_data_wg = &hdr6_out->wg;
-       }
-
       iph_offset = vnet_buffer (b[0])->ip.save_rewrite_length;
-      plain_data = vlib_buffer_get_current (b[0]) + iph_offset;
       plain_data_len = vlib_buffer_length_in_chain (vm, b[0]) - iph_offset;
       u8 *iv_data = b[0]->pre_data;
 
@@ -447,13 +434,36 @@ wg_output_tun_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
        * into the packet
        */
       if (PREDICT_FALSE (encrypted_packet_len >= WG_DEFAULT_DATA_SIZE) ||
-         PREDICT_FALSE ((b[0]->current_data + encrypted_packet_len) >=
+         PREDICT_FALSE ((iph_offset + encrypted_packet_len) >=
                         vlib_buffer_get_default_data_size (vm)))
        {
          b[0]->error = node->errors[WG_OUTPUT_ERROR_TOO_BIG];
          goto out;
        }
 
+      /*
+       * Move the buffer to fit ethernet header
+       */
+      if (b[0]->current_data + VLIB_BUFFER_PRE_DATA_SIZE <
+         sizeof (ethernet_header_t))
+       {
+         vlib_buffer_move (vm, b[0], 0);
+       }
+
+      plain_data = vlib_buffer_get_current (b[0]) + iph_offset;
+
+      is_ip4_out = ip46_address_is_ip4 (&peer->src.addr);
+      if (is_ip4_out)
+       {
+         hdr4_out = vlib_buffer_get_current (b[0]);
+         message_data_wg = &hdr4_out->wg;
+       }
+      else
+       {
+         hdr6_out = vlib_buffer_get_current (b[0]);
+         message_data_wg = &hdr6_out->wg;
+       }
+
       if (PREDICT_FALSE (last_adj_index != adj_index))
        {
          wg_timers_any_authenticated_packet_sent_opt (peer, time);