Normally the DB layer handles duplicate syscalls, but in the case of
multiple architectures we can hit a scenario where we do have multiple
syscalls with the same syscall number and duplicate BPF hash values;
this can cause significant problems when trying to do the final BPF
generation/block-assembly.

This patch allows duplicate BPF blocks in certain cases - most
importantly syscalls - to resolve this problem.

Signed-off-by: Paul Moore <[email protected]>
---
 src/gen_bpf.c |   89 ++++++++++++++++++++-------------------------------------
 1 file changed, 32 insertions(+), 57 deletions(-)

diff --git a/src/gen_bpf.c b/src/gen_bpf.c
index 52d4a42..c82452f 100644
--- a/src/gen_bpf.c
+++ b/src/gen_bpf.c
@@ -100,8 +100,12 @@ struct bpf_blk {
        /* original db_arg_chain_tree node */
        const struct db_arg_chain_tree *node;
 
+       /* status flags */
+       unsigned int flag_hash;         /* added to the hash table */
+       unsigned int flag_dup;          /* duplicate block and in use */
+       unsigned int flag_unique;       /* ->blks is unique to this block */
+
        /* used during block assembly */
-       unsigned int hashed_flag;
        uint64_t hash;
        struct bpf_blk *hash_nxt;
        struct bpf_blk *prev, *next;
@@ -181,9 +185,10 @@ static void __blk_free(struct bpf_state *state, struct 
bpf_blk *blk)
        while (blk->hash_nxt != NULL) {
                b_tmp = blk->hash_nxt;
                blk->hash_nxt = b_tmp->hash_nxt;
-               free(b_tmp);
+               if (!b_tmp->flag_dup)
+                       free(b_tmp);
        }
-       if (blk->blks != NULL)
+       if (blk->blks != NULL && blk->flag_unique)
                free(blk->blks);
        free(blk);
 }
@@ -263,6 +268,7 @@ static struct bpf_blk *_blk_append(struct bpf_state *state,
                if (blk == NULL)
                        return NULL;
                memset(blk, 0, sizeof(*blk));
+               blk->flag_unique = 1;
        }
        if ((blk->blk_cnt + 1) > blk->blk_alloc) {
                blk->blk_alloc += AINC_BLK;
@@ -278,51 +284,6 @@ static struct bpf_blk *_blk_append(struct bpf_state *state,
        return blk;
 }
 
-#if 0 /* see NOTE in function description */
-/**
- * Append a BPF instruction block to another BPF instruction block
- * @param state the BPF state
- * @param dst the destination instruction block
- * @param src the source instruction block
- *
- * Append the source instruction block to the end of the destination block.
- * Returns a pointer to dst on success, NULL on failure, and in the case of
- * failure the destination block is free'd.
- *
- * NOTE: We're going to #if'def this function out and not simply remove it
- *      because the need for such a function does seem to reoccur from time
- *      to time and I don't feel like re-implementing it again in the near
- *      future.  Once we've given the BPF generator a good scrubbing we can
- *      remove this function if it still isn't used.
- *
- */
-static struct bpf_blk *_blk_append_blk(struct bpf_state *state,
-                                      struct bpf_blk *dst,
-                                      const struct bpf_blk *src)
-{
-       unsigned int size;
-       struct bpf_instr *new;
-
-       size = dst->blk_cnt + src->blk_cnt;
-       if (size > dst->blk_alloc) {
-               dst->blk_alloc = size;
-               new = realloc(dst->blks, dst->blk_alloc * sizeof(*(dst->blks)));
-               if (new == NULL) {
-                       _blk_free(state, dst);
-                       return NULL;
-               }
-               dst->blks = new;
-       }
-       memcpy(&dst->blks[dst->blk_cnt], src->blks,
-              src->blk_cnt * sizeof(*(src->blks)));
-       dst->blk_cnt += src->blk_cnt;
-       if (src->priority > dst->priority)
-               dst->priority = src->priority;
-
-       return dst;
-}
-#endif /* see NOTE in function description */
-
 /**
  * Append a block of BPF instructions to the final BPF program
  * @param prg the BPF program
@@ -470,7 +431,7 @@ static int _hsh_add(struct bpf_state *state, struct bpf_blk 
**blk_p,
        struct bpf_blk *blk = *blk_p;
        struct bpf_blk *b_iter;
 
-       if (blk->hashed_flag)
+       if (blk->flag_hash)
                return 0;
 
        h_new = malloc(sizeof(*h_new));
@@ -481,7 +442,7 @@ static int _hsh_add(struct bpf_state *state, struct bpf_blk 
**blk_p,
        /* generate the hash */
        h_val = jhash(blk->blks, _BLK_MSZE(blk), 0);
        blk->hash = h_val;
-       blk->hashed_flag = 1;
+       blk->flag_hash = 1;
        blk->node = NULL;
        h_new->blk = blk;
        h_new->found = (found ? 1 : 0);
@@ -497,6 +458,19 @@ static int _hsh_add(struct bpf_state *state, struct 
bpf_blk **blk_p,
                                /* duplicate block */
                                free(h_new);
 
+                               /* store the duplicate block */
+                               b_iter = h_iter->blk;
+                               while (b_iter->hash_nxt != NULL)
+                                       b_iter = b_iter->hash_nxt;
+                               b_iter->hash_nxt = blk;
+
+                               /* in some cases we want to return the
+                                * duplicate block */
+                               if (found) {
+                                       blk->flag_dup = 1;
+                                       return 0;
+                               }
+
                                /* update the priority if needed */
                                if (h_iter->blk->priority < blk->priority)
                                        h_iter->blk->priority = blk->priority;
@@ -504,19 +478,15 @@ static int _hsh_add(struct bpf_state *state, struct 
bpf_blk **blk_p,
                                /* try to save some memory */
                                free(blk->blks);
                                blk->blks = h_iter->blk->blks;
+                               blk->flag_unique = 0;
 
-                               /* store the duplicate block */
-                               b_iter = h_iter->blk;
-                               while (b_iter->hash_nxt != NULL)
-                                       b_iter = b_iter->hash_nxt;
-                               b_iter->hash_nxt = blk;
                                *blk_p = h_iter->blk;
                                return 0;
                        } else if (h_iter->blk->hash == h_val) {
                                /* hash collision */
                                if ((h_val >> 32) == 0xffffffff) {
                                        /* overflow */
-                                       blk->hashed_flag = 0;
+                                       blk->flag_hash = 0;
                                        blk->hash = 0;
                                        return -EFAULT;
                                }
@@ -816,7 +786,7 @@ static struct bpf_blk *_gen_bpf_chain_lvl_res(struct 
bpf_state *state,
        struct bpf_instr *i_iter;
        struct db_arg_chain_tree *node;
 
-       if (blk->hashed_flag)
+       if (blk->flag_hash)
                return blk;
 
        /* convert TGT_PTR_DB to TGT_PTR_HSH references */
@@ -1162,6 +1132,11 @@ static struct bpf_blk *_gen_bpf_arch(struct bpf_state 
*state,
                if (b_new == NULL)
                        goto arch_failure;
 
+#if 1
+               if (b_new->next != NULL)
+                       printf("PMD: spot #1\n");
+#endif
+
                /* add the filter to the list head */
                b_new->prev = NULL;
                b_new->next = b_head;


------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_jan
_______________________________________________
libseccomp-discuss mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libseccomp-discuss

Reply via email to