netfilter: bridge: ebt_among: add more missing match size checks
[pandora-kernel.git] / net / bridge / netfilter / ebt_among.c
index 83c775c..06db707 100644 (file)
@@ -177,6 +177,28 @@ static bool poolsize_invalid(const struct ebt_mac_wormhash *w)
        return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
 }
 
        return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
 }
 
+static bool wormhash_offset_invalid(int off, unsigned int len)
+{
+       if (off == 0) /* not present */
+               return false;
+
+       if (off < (int)sizeof(struct ebt_among_info) ||
+           off % __alignof__(struct ebt_mac_wormhash))
+               return true;
+
+       off += sizeof(struct ebt_mac_wormhash);
+
+       return off > len;
+}
+
+static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b)
+{
+       if (a == 0)
+               a = sizeof(struct ebt_among_info);
+
+       return ebt_mac_wormhash_size(wh) + a == b;
+}
+
 static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_among_info *info = par->matchinfo;
 static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_among_info *info = par->matchinfo;
@@ -189,6 +211,10 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par)
        if (expected_length > em->match_size)
                return -EINVAL;
 
        if (expected_length > em->match_size)
                return -EINVAL;
 
+       if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) ||
+           wormhash_offset_invalid(info->wh_src_ofs, em->match_size))
+               return -EINVAL;
+
        wh_dst = ebt_among_wh_dst(info);
        if (poolsize_invalid(wh_dst))
                return -EINVAL;
        wh_dst = ebt_among_wh_dst(info);
        if (poolsize_invalid(wh_dst))
                return -EINVAL;
@@ -201,6 +227,14 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par)
        if (poolsize_invalid(wh_src))
                return -EINVAL;
 
        if (poolsize_invalid(wh_src))
                return -EINVAL;
 
+       if (info->wh_src_ofs < info->wh_dst_ofs) {
+               if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs))
+                       return -EINVAL;
+       } else {
+               if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs))
+                       return -EINVAL;
+       }
+
        expected_length += ebt_mac_wormhash_size(wh_src);
 
        if (em->match_size != EBT_ALIGN(expected_length)) {
        expected_length += ebt_mac_wormhash_size(wh_src);
 
        if (em->match_size != EBT_ALIGN(expected_length)) {