From: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>

Current code has a race condition between inbound traffic and creation
of new SA. It is possible for inbound traffic to trigger partially
created SA using SA_LOOKUP option (or INLINE mode). Add separate
(RESERVED) stage for SA which is in process of being created.

Fixes: https://bugs.linaro.org/show_bug.cgi?id=3594
Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>
---
/** Email created from pull request 427 (lumag:ipsec-fix-sad)
 ** https://github.com/Linaro/odp/pull/427
 ** Patch: https://github.com/Linaro/odp/pull/427.patch
 ** Base sha: 27480d82bd93a881ae683a3c314c11042a68ce29
 ** Merge commit sha: 67c9dbf28c41ea7a53782ba841276b03f154c4ef
 **/
 platform/linux-generic/odp_ipsec_sad.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/platform/linux-generic/odp_ipsec_sad.c 
b/platform/linux-generic/odp_ipsec_sad.c
index 845a73dea..bb984db38 100644
--- a/platform/linux-generic/odp_ipsec_sad.c
+++ b/platform/linux-generic/odp_ipsec_sad.c
@@ -17,7 +17,8 @@
 #include <string.h>
 
 #define IPSEC_SA_STATE_DISABLE 0x40000000
-#define IPSEC_SA_STATE_FREE    0xc0000000 /* This includes disable !!! */
+#define IPSEC_SA_STATE_FREE    0xc0000000
+#define IPSEC_SA_STATE_RESERVED        0x80000000
 
 typedef struct ipsec_sa_table_t {
        ipsec_sa_t ipsec_sa[ODP_CONFIG_IPSEC_SAS];
@@ -108,7 +109,8 @@ static ipsec_sa_t *ipsec_sa_reserve(void)
 
                ipsec_sa = ipsec_sa_entry(i);
 
-               if (odp_atomic_cas_acq_u32(&ipsec_sa->state, &state, 0))
+               if (odp_atomic_cas_acq_u32(&ipsec_sa->state, &state,
+                                          IPSEC_SA_STATE_RESERVED))
                        return ipsec_sa;
        }
 
@@ -120,6 +122,12 @@ static void ipsec_sa_release(ipsec_sa_t *ipsec_sa)
        odp_atomic_store_rel_u32(&ipsec_sa->state, IPSEC_SA_STATE_FREE);
 }
 
+/* Mark reserved SA as available now */
+static void ipsec_sa_publish(ipsec_sa_t *ipsec_sa)
+{
+       odp_atomic_store_rel_u32(&ipsec_sa->state, 0);
+}
+
 static int ipsec_sa_lock(ipsec_sa_t *ipsec_sa)
 {
        int cas = 0;
@@ -128,9 +136,11 @@ static int ipsec_sa_lock(ipsec_sa_t *ipsec_sa)
        while (0 == cas) {
                /*
                 * This can be called from lookup path, so we really need this
-                * check
+                * check. Thanks to the way flags are defined we actually test
+                * that the SA is not DISABLED, FREE or RESERVED using just one
+                * condition.
                 */
-               if (state & IPSEC_SA_STATE_DISABLE)
+               if (state & IPSEC_SA_STATE_FREE)
                        return -1;
 
                cas = odp_atomic_cas_acq_u32(&ipsec_sa->state, &state,
@@ -438,6 +448,8 @@ odp_ipsec_sa_t odp_ipsec_sa_create(const 
odp_ipsec_sa_param_t *param)
                                      &ses_create_rc))
                goto error;
 
+       ipsec_sa_publish(ipsec_sa);
+
        return ipsec_sa->ipsec_sa_hdl;
 
 error:

Reply via email to