Compare commits

...

7 Commits

Author SHA1 Message Date
Daniel Béreš 1b93285ce0 nat: fix nat44 vrf handlers
Change of enums used in REPLY_MACRO() to appropriate one
for handlers:
-vl_api_nat44_ed_add_del_vrf_table_t_handler
-vl_api_nat44_ed_add_del_vrf_route_t_handler

Type: fix

Change-Id: I58e97817b1678da7c025c0d03a8b938a4e0f7b6c
Signed-off-by: Daniel Béreš <daniel.beres@pantheon.tech>
(cherry picked from commit 2c03879ce4)
2023-03-31 15:22:28 +00:00
Dave Wallace 57302fe52f misc: VPP 22.10.1 Release Notes
Type: docs
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
Change-Id: I70374ea376c895d92d5789debf4b437113e3d884
2023-02-10 19:20:28 -05:00
Dave Wallace 6d93d060a8 misc: VPP 22.06.1 Release Notes
Type: docs
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
Change-Id: I8770a35c801126ffd2de8f58d79e6616642709a9
(cherry picked from commit 1513b381d8)
2023-02-10 14:23:56 -05:00
Benoît Ganne 474f0ba2ab ipsec: fix AES CBC IV generation (CVE-2022-46397)
For AES-CBC, the IV must be unpredictable (see NIST SP800-38a Appendix
C). Chaining IVs like is done by ipsecmb and native backends for the
VNET_CRYPTO_OP_FLAG_INIT_IV is fully predictable.
Encrypt a counter as part of the message, making the (predictable)
counter-generated IV unpredictable.

Fixes: VPP-2037
Type: fix

Change-Id: If4f192d62bf97dda553e7573331c75efa11822ae
Signed-off-by: Benoît Ganne <bganne@cisco.com>
2023-02-03 21:04:11 -05:00
Vladimir Ratnikov b89dcf8241 dpdk: link DPDK with MLX4/MLX5 libraries again
Previously it was linked and worker properly. While rdma build
was simplified, link was lost so all encrypted data won't pass
via Mellanox interfaces(ipsec, ipip, ssh etc) and NetVSC taps
won't created the right way.

 Errors:
mlx5_common: Verbs device not found: 21a5:00:02.0
mlx5_common: Failed to initialize device context.
EAL: Requested device 21a5:00:02.0 cannot be used
 Tested on Azure. Same errors appears on physical machine with
Mellanox connect adapter

Type: fix

Signed-off-by: Vladimir Ratnikov <vratnikov@netgate.com>
Change-Id: Ib68976282e0ed91c016a7318db6b5eddf5510c47
(cherry picked from commit 413447451e)
2022-12-21 19:55:00 +00:00
Mauro Sardara 4b6fb593fb vapi: use the correct my_context_id when disconnecting API clients
While before the my_client_index variable was stored as global variable
in api_main_t, after commit 2ca88ff978
the my_client_index becomes part of vapi_ctx_t.

Each API client (internal/external) connected to VPP stores its
client index in vapi_ctx_t.

The issue is in the client disconnection. The vapi_disconnect is
untouched in patch 2ca88ff978,
so it keeps the behavior of using the my_client_index stored
in api_main_t.

Ticket: VPP-2069
Type: fix
Fixes: 2ca88ff978

Signed-off-by: Mauro Sardara <msardara@cisco.com>
Change-Id: Idf8c1d1056cbd631cc3057cf7acc486216fa8303
(cherry picked from commit 8c626b41ea)
2022-12-20 12:09:26 +00:00
Neale Ranns 267175fd04 ipsec: Failure at the start of the batch should not invalidate the rest of the batch
Type: fix

Signed-off-by: Neale Ranns <neale@graphiant.com>
Change-Id: Icd1e43a5764496784c355c93066273435f16dd35
(cherry picked from commit fe2d23f916)
2022-11-21 01:02:29 +00:00
13 changed files with 224 additions and 53 deletions
+2
View File
@@ -6,7 +6,9 @@ Release notes
.. toctree::
:maxdepth: 2
v22.10.1
v22.10
v22.06.1
v22.06
v22.02
past
-1
View File
@@ -39,4 +39,3 @@ Past releases
v17.01
v16.09
v16.06
+12
View File
@@ -0,0 +1,12 @@
Release notes for VPP 22.06.1
=============================
This is bug fix release.
Of particular importance, this release contains the fix for
`JIRA VPP-2307: CVE-2022-46397 FD.io VPP (Vector Packet Processor) IPSec generates a predictable IV in AES-CBC mode <https://jira.fd.io/browse/VPP-2037>`__
For the full list of fixed issues please refer to:
- fd.io `JIRA <https://jira.fd.io>`__
- git `commit log <https://git.fd.io/vpp/log/?h=stable/2206>`__
+12
View File
@@ -0,0 +1,12 @@
Release notes for VPP 22.10.1
=============================
This is bug fix release.
Of particular importance, this release contains the fix for
`JIRA VPP-2307: CVE-2022-46397 FD.io VPP (Vector Packet Processor) IPSec generates a predictable IV in AES-CBC mode <https://jira.fd.io/browse/VPP-2037>`__
For the full list of fixed issues please refer to:
- fd.io `JIRA <https://jira.fd.io>`__
- git `commit log <https://git.fd.io/vpp/log/?h=stable/2210>`__
+24 -14
View File
@@ -260,17 +260,22 @@ process_ops (vlib_main_t * vm, vnet_crypto_async_frame_t * f,
n_fail = n_ops - vnet_crypto_process_ops (vm, op, n_ops);
while (n_fail)
/*
* If we had a failure in the ops then we need to walk all the ops
* and set the status in the corresponding frame. This status is
* not set in the case with no failures, as in that case the overall
* frame status is success.
*/
if (n_fail)
{
ASSERT (op - ops < n_ops);
if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
for (int i = 0; i < n_ops; i++)
{
ASSERT (op - ops < n_ops);
f->elts[op->user_data].status = op->status;
*state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
n_fail--;
op++;
}
op++;
*state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
}
}
@@ -287,17 +292,22 @@ process_chained_ops (vlib_main_t * vm, vnet_crypto_async_frame_t * f,
n_fail = n_ops - vnet_crypto_process_chained_ops (vm, op, chunks, n_ops);
while (n_fail)
/*
* If we had a failure in the ops then we need to walk all the ops
* and set the status in the corresponding frame. This status is
* not set in the case with no failures, as in that case the overall
* frame status is success.
*/
if (n_fail)
{
ASSERT (op - ops < n_ops);
if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
for (int i = 0; i < n_ops; i++)
{
ASSERT (op - ops < n_ops);
f->elts[op->user_data].status = op->status;
*state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
n_fail--;
op++;
}
op++;
*state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
}
}
+3 -1
View File
@@ -104,7 +104,9 @@ else()
else()
message(WARNING "EXPERIMENTAL: DPDK plugin without dlopen mode")
vpp_plugin_find_library(dpdk IBVERBS_LIB "libibverbs.a")
string_append(DPDK_LINK_FLAGS "${IBVERBS_LIB} -Wl,--exclude-libs,ALL")
vpp_plugin_find_library(dpdk MLX5_LIB "libmlx5.a")
vpp_plugin_find_library(dpdk MLX4_LIB "libmlx4.a")
string_append(DPDK_LINK_FLAGS "-Wl,--whole-archive,${IBVERBS_LIB},${MLX5_LIB},${MLX4_LIB} -Wl,--no-whole-archive,--exclude-libs,ALL")
endif()
endif()
endif()
+2 -2
View File
@@ -1202,7 +1202,7 @@ vl_api_nat44_ed_add_del_vrf_table_t_handler (
vl_api_nat44_ed_add_del_vrf_table_reply_t *rmp;
int rv = nat44_ed_add_del_vrf_table (clib_net_to_host_u32 (mp->table_vrf_id),
mp->is_add);
REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_TABLE);
REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_TABLE_REPLY);
}
static void
@@ -1214,7 +1214,7 @@ vl_api_nat44_ed_add_del_vrf_route_t_handler (
int rv =
nat44_ed_add_del_vrf_route (clib_net_to_host_u32 (mp->table_vrf_id),
clib_net_to_host_u32 (mp->vrf_id), mp->is_add);
REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_ROUTE);
REPLY_MACRO (VL_API_NAT44_ED_ADD_DEL_VRF_ROUTE_REPLY);
}
static void
+2 -2
View File
@@ -338,7 +338,7 @@ typedef struct
i16 crypto_start_offset; /* first buffer offset */
i16 integ_start_offset;
/* adj total_length for integ, e.g.4 bytes for IPSec ESN */
u16 integ_length_adj;
i16 integ_length_adj;
vnet_crypto_op_status_t status : 8;
u8 flags; /**< share same VNET_CRYPTO_OP_FLAG_* values */
} vnet_crypto_async_frame_elt_t;
@@ -628,7 +628,7 @@ static_always_inline void
vnet_crypto_async_add_to_frame (vlib_main_t *vm, vnet_crypto_async_frame_t *f,
u32 key_index, u32 crypto_len,
i16 integ_len_adj, i16 crypto_start_offset,
u16 integ_start_offset, u32 buffer_index,
i16 integ_start_offset, u32 buffer_index,
u16 next_node, u8 *iv, u8 *tag, u8 *aad,
u8 flags)
{
+1 -1
View File
@@ -1189,7 +1189,7 @@ esp_decrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node,
else
esp_decrypt_prepare_sync_op (
vm, node, ptd, &crypto_ops, &integ_ops, op, sa0, payload, len,
cpd.icv_sz, cpd.iv_sz, pd, pd2, b[0], sync_next, b - bufs);
cpd.icv_sz, cpd.iv_sz, pd, pd2, b[0], sync_next, n_sync);
/* next */
next:
if (ESP_DECRYPT_ERROR_RX_PKTS != err)
+62 -26
View File
@@ -215,6 +215,24 @@ esp_get_ip6_hdr_len (ip6_header_t * ip6, ip6_ext_header_t ** ext_hdr)
return len;
}
/* IPsec IV generation: IVs requirements differ depending of the
* encryption mode: IVs must be unpredictable for AES-CBC whereas it can
* be predictable but should never be reused with the same key material
* for CTR and GCM.
* We use a packet counter as the IV for CTR and GCM, and to ensure the
* IV is unpredictable for CBC, it is then encrypted using the same key
* as the message. You can refer to NIST SP800-38a and NIST SP800-38d
* for more details. */
static_always_inline void *
esp_generate_iv (ipsec_sa_t *sa, void *payload, int iv_sz)
{
ASSERT (iv_sz >= sizeof (u64));
u64 *iv = (u64 *) (payload - iv_sz);
clib_memset_u8 (iv, 0, iv_sz);
*iv = sa->iv_counter++;
return iv;
}
static_always_inline void
esp_process_chained_ops (vlib_main_t * vm, vlib_node_runtime_t * node,
vnet_crypto_op_t * ops, vlib_buffer_t * b[],
@@ -368,27 +386,29 @@ esp_prepare_sync_op (vlib_main_t *vm, ipsec_per_thread_data_t *ptd,
vnet_crypto_op_t *op;
vec_add2_aligned (crypto_ops[0], op, 1, CLIB_CACHE_LINE_BYTES);
vnet_crypto_op_init (op, sa0->crypto_enc_op_id);
u8 *crypto_start = payload;
/* esp_add_footer_and_icv() in esp_encrypt_inline() makes sure we always
* have enough space for ESP header and footer which includes ICV */
ASSERT (payload_len > icv_sz);
u16 crypto_len = payload_len - icv_sz;
/* generate the IV in front of the payload */
void *pkt_iv = esp_generate_iv (sa0, payload, iv_sz);
op->src = op->dst = payload;
op->key_index = sa0->crypto_key_index;
op->len = payload_len - icv_sz;
op->user_data = bi;
if (ipsec_sa_is_set_IS_CTR (sa0))
{
ASSERT (sizeof (u64) == iv_sz);
/* construct nonce in a scratch space in front of the IP header */
esp_ctr_nonce_t *nonce =
(esp_ctr_nonce_t *) (payload - sizeof (u64) - hdr_len -
sizeof (*nonce));
u64 *pkt_iv = (u64 *) (payload - sizeof (u64));
(esp_ctr_nonce_t *) (pkt_iv - hdr_len - sizeof (*nonce));
if (ipsec_sa_is_set_IS_AEAD (sa0))
{
/* constuct aad in a scratch space in front of the nonce */
op->aad = (u8 *) nonce - sizeof (esp_aead_t);
op->aad_len = esp_aad_fill (op->aad, esp, sa0, seq_hi);
op->tag = payload + op->len;
op->tag = payload + crypto_len;
op->tag_len = 16;
}
else
@@ -397,13 +417,17 @@ esp_prepare_sync_op (vlib_main_t *vm, ipsec_per_thread_data_t *ptd,
}
nonce->salt = sa0->salt;
nonce->iv = *pkt_iv = clib_host_to_net_u64 (sa0->ctr_iv_counter++);
nonce->iv = *(u64 *) pkt_iv;
op->iv = (u8 *) nonce;
}
else
{
op->iv = payload - iv_sz;
op->flags = VNET_CRYPTO_OP_FLAG_INIT_IV;
/* construct zero iv in front of the IP header */
op->iv = pkt_iv - hdr_len - iv_sz;
clib_memset_u8 (op->iv, 0, iv_sz);
/* include iv field in crypto */
crypto_start -= iv_sz;
crypto_len += iv_sz;
}
if (lb != b[0])
@@ -412,8 +436,15 @@ esp_prepare_sync_op (vlib_main_t *vm, ipsec_per_thread_data_t *ptd,
op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
op->chunk_index = vec_len (ptd->chunks);
op->tag = vlib_buffer_get_tail (lb) - icv_sz;
esp_encrypt_chain_crypto (vm, ptd, sa0, b[0], lb, icv_sz, payload,
payload_len, &op->n_chunks);
esp_encrypt_chain_crypto (vm, ptd, sa0, b[0], lb, icv_sz,
crypto_start, crypto_len + icv_sz,
&op->n_chunks);
}
else
{
/* not chained */
op->src = op->dst = crypto_start;
op->len = crypto_len;
}
}
@@ -463,26 +494,26 @@ esp_prepare_async_frame (vlib_main_t *vm, ipsec_per_thread_data_t *ptd,
u8 *tag, *iv, *aad = 0;
u8 flag = 0;
u32 key_index;
i16 crypto_start_offset, integ_start_offset = 0;
i16 crypto_start_offset, integ_start_offset;
u16 crypto_total_len, integ_total_len;
post->next_index = next;
/* crypto */
crypto_start_offset = payload - b->data;
crypto_start_offset = integ_start_offset = payload - b->data;
crypto_total_len = integ_total_len = payload_len - icv_sz;
tag = payload + crypto_total_len;
key_index = sa->linked_key_index;
/* generate the IV in front of the payload */
void *pkt_iv = esp_generate_iv (sa, payload, iv_sz);
if (ipsec_sa_is_set_IS_CTR (sa))
{
ASSERT (sizeof (u64) == iv_sz);
/* construct nonce in a scratch space in front of the IP header */
esp_ctr_nonce_t *nonce = (esp_ctr_nonce_t *) (payload - sizeof (u64) -
hdr_len - sizeof (*nonce));
u64 *pkt_iv = (u64 *) (payload - sizeof (u64));
esp_ctr_nonce_t *nonce =
(esp_ctr_nonce_t *) (pkt_iv - hdr_len - sizeof (*nonce));
if (ipsec_sa_is_set_IS_AEAD (sa))
{
/* constuct aad in a scratch space in front of the nonce */
@@ -496,13 +527,17 @@ esp_prepare_async_frame (vlib_main_t *vm, ipsec_per_thread_data_t *ptd,
}
nonce->salt = sa->salt;
nonce->iv = *pkt_iv = clib_host_to_net_u64 (sa->ctr_iv_counter++);
nonce->iv = *(u64 *) pkt_iv;
iv = (u8 *) nonce;
}
else
{
iv = payload - iv_sz;
flag |= VNET_CRYPTO_OP_FLAG_INIT_IV;
/* construct zero iv in front of the IP header */
iv = pkt_iv - hdr_len - iv_sz;
clib_memset_u8 (iv, 0, iv_sz);
/* include iv field in crypto */
crypto_start_offset -= iv_sz;
crypto_total_len += iv_sz;
}
if (lb != b)
@@ -510,13 +545,14 @@ esp_prepare_async_frame (vlib_main_t *vm, ipsec_per_thread_data_t *ptd,
/* chain */
flag |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
tag = vlib_buffer_get_tail (lb) - icv_sz;
crypto_total_len = esp_encrypt_chain_crypto (vm, ptd, sa, b, lb, icv_sz,
payload, payload_len, 0);
crypto_total_len = esp_encrypt_chain_crypto (
vm, ptd, sa, b, lb, icv_sz, b->data + crypto_start_offset,
crypto_total_len + icv_sz, 0);
}
if (sa->integ_op_id)
{
integ_start_offset = crypto_start_offset - iv_sz - sizeof (esp_header_t);
integ_start_offset -= iv_sz + sizeof (esp_header_t);
integ_total_len += iv_sz + sizeof (esp_header_t);
if (b != lb)
+1 -1
View File
@@ -137,7 +137,7 @@ typedef struct
u32 seq;
u32 seq_hi;
u64 replay_window;
u64 ctr_iv_counter;
u64 iv_counter;
dpo_id_t dpo;
vnet_crypto_key_index_t crypto_key_index;
+75 -5
View File
@@ -386,7 +386,7 @@ vapi_memclnt_delete_reply_t_handler (vapi_ctx_t ctx,
ctx->vl_input_queue = 0;
}
int
static int
vapi_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
int input_queue_size, bool keepalive)
{
@@ -462,6 +462,76 @@ vapi_client_connect (vapi_ctx_t ctx, const char *name, int ctx_quota,
return (rv);
}
static void
vapi_client_send_disconnect (vapi_ctx_t ctx, u8 do_cleanup)
{
vl_api_memclnt_delete_t *mp;
vl_shmem_hdr_t *shmem_hdr;
api_main_t *am = vlibapi_get_main ();
ASSERT (am->vlib_rp);
shmem_hdr = am->shmem_hdr;
ASSERT (shmem_hdr && shmem_hdr->vl_input_queue);
mp = vl_msg_api_alloc (sizeof (vl_api_memclnt_delete_t));
clib_memset (mp, 0, sizeof (*mp));
mp->_vl_msg_id = ntohs (VL_API_MEMCLNT_DELETE);
mp->index = ctx->my_client_index;
mp->do_cleanup = do_cleanup;
vl_msg_api_send_shmem (shmem_hdr->vl_input_queue, (u8 *) &mp);
}
static int
vapi_client_disconnect (vapi_ctx_t ctx)
{
vl_api_memclnt_delete_reply_t *rp;
svm_queue_t *vl_input_queue;
time_t begin;
msgbuf_t *msgbuf;
vl_input_queue = ctx->vl_input_queue;
vapi_client_send_disconnect (ctx, 0 /* wait for reply */);
/*
* Have to be careful here, in case the client is disconnecting
* because e.g. the vlib process died, or is unresponsive.
*/
begin = time (0);
while (1)
{
time_t now;
now = time (0);
if (now >= (begin + 2))
{
clib_warning ("peer unresponsive, give up");
ctx->my_client_index = ~0;
return -1;
}
if (svm_queue_sub (vl_input_queue, (u8 *) &rp, SVM_Q_NOWAIT, 0) < 0)
continue;
VL_MSG_API_UNPOISON (rp);
/* drain the queue */
if (ntohs (rp->_vl_msg_id) != VL_API_MEMCLNT_DELETE_REPLY)
{
clib_warning ("queue drain: %d", ntohs (rp->_vl_msg_id));
msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
continue;
}
msgbuf = (msgbuf_t *) ((u8 *) rp - offsetof (msgbuf_t, data));
vl_msg_api_handler ((void *) rp, ntohl (msgbuf->data_len));
break;
}
vapi_api_name_and_crc_free (ctx);
return 0;
}
u32
vapi_api_get_msg_index (vapi_ctx_t ctx, u8 *name_and_crc)
{
@@ -592,7 +662,7 @@ vapi_connect (vapi_ctx_t ctx, const char *name, const char *chroot_prefix,
}
return VAPI_OK;
fail:
vl_client_disconnect ();
vapi_client_disconnect (ctx);
vl_client_api_unmap ();
return rv;
}
@@ -689,7 +759,7 @@ vapi_connect_from_vpp (vapi_ctx_t ctx, const char *name,
}
return VAPI_OK;
fail:
vl_client_disconnect ();
vapi_client_disconnect (ctx);
return rv;
}
@@ -704,7 +774,7 @@ vapi_disconnect_from_vpp (vapi_ctx_t ctx)
svm_queue_t *vl_input_queue;
time_t begin;
vl_input_queue = ctx->vl_input_queue;
vl_client_send_disconnect (0 /* wait for reply */);
vapi_client_send_disconnect (ctx, 0 /* wait for reply */);
/*
* Have to be careful here, in case the client is disconnecting
@@ -760,7 +830,7 @@ vapi_disconnect (vapi_ctx_t ctx)
svm_queue_t *vl_input_queue;
time_t begin;
vl_input_queue = ctx->vl_input_queue;
vl_client_send_disconnect (0 /* wait for reply */);
vapi_client_send_disconnect (ctx, 0 /* wait for reply */);
/*
* Have to be careful here, in case the client is disconnecting
+28
View File
@@ -432,6 +432,34 @@ class IpsecTra4(object):
]
recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if)
# a replayed packet, then an out of window, then a legit
# tests that a early failure on the batch doesn't affect subsequent packets.
pkts = [
(
Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
/ p.scapy_tra_sa.encrypt(
IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
seq_num=203,
)
),
(
Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
/ p.scapy_tra_sa.encrypt(
IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
seq_num=81,
)
),
(
Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac)
/ p.scapy_tra_sa.encrypt(
IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(),
seq_num=204,
)
),
]
n_rx = 1 if ar_on else 3
recv_pkts = self.send_and_expect(self.tra_if, pkts, self.tra_if, n_rx=n_rx)
# move the window over half way to a wrap
pkts = [
(