Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

1) Don't flag SCTP heartbeat as invalid for re-used connections,
from Florian Westphal.

2) Bogus overlap report due to rbtree tree rotations, from Stefano Brivio.

3) Detect partial overlap with start end point match, also from Stefano.

4) Skip netlink dump of NFTA_SET_USERDATA is unset.

5) Incorrect nft_list_attributes enumeration definition.

6) Missing zeroing before memcpy to destination register, also
from Florian.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+92 -17
+2
include/linux/netfilter/nf_conntrack_sctp.h
··· 9 9 enum sctp_conntrack state; 10 10 11 11 __be32 vtag[IP_CT_DIR_MAX]; 12 + u8 last_dir; 13 + u8 flags; 12 14 }; 13 15 14 16 #endif /* _NF_CONNTRACK_SCTP_H */
+2
include/net/netfilter/nf_tables.h
··· 143 143 static inline void nft_data_copy(u32 *dst, const struct nft_data *src, 144 144 unsigned int len) 145 145 { 146 + if (len % NFT_REG32_SIZE) 147 + dst[len / NFT_REG32_SIZE] = 0; 146 148 memcpy(dst, src, len); 147 149 } 148 150
+1 -1
include/uapi/linux/netfilter/nf_tables.h
··· 133 133 * @NFTA_LIST_ELEM: list element (NLA_NESTED) 134 134 */ 135 135 enum nft_list_attributes { 136 - NFTA_LIST_UNPEC, 136 + NFTA_LIST_UNSPEC, 137 137 NFTA_LIST_ELEM, 138 138 __NFTA_LIST_MAX 139 139 };
+35 -4
net/netfilter/nf_conntrack_proto_sctp.c
··· 62 62 [SCTP_CONNTRACK_HEARTBEAT_ACKED] = 210 SECS, 63 63 }; 64 64 65 + #define SCTP_FLAG_HEARTBEAT_VTAG_FAILED 1 66 + 65 67 #define sNO SCTP_CONNTRACK_NONE 66 68 #define sCL SCTP_CONNTRACK_CLOSED 67 69 #define sCW SCTP_CONNTRACK_COOKIE_WAIT ··· 371 369 u_int32_t offset, count; 372 370 unsigned int *timeouts; 373 371 unsigned long map[256 / sizeof(unsigned long)] = { 0 }; 372 + bool ignore = false; 374 373 375 374 if (sctp_error(skb, dataoff, state)) 376 375 return -NF_ACCEPT; ··· 430 427 /* Sec 8.5.1 (D) */ 431 428 if (sh->vtag != ct->proto.sctp.vtag[dir]) 432 429 goto out_unlock; 433 - } else if (sch->type == SCTP_CID_HEARTBEAT || 434 - sch->type == SCTP_CID_HEARTBEAT_ACK) { 430 + } else if (sch->type == SCTP_CID_HEARTBEAT) { 431 + if (ct->proto.sctp.vtag[dir] == 0) { 432 + pr_debug("Setting %d vtag %x for dir %d\n", sch->type, sh->vtag, dir); 433 + ct->proto.sctp.vtag[dir] = sh->vtag; 434 + } else if (sh->vtag != ct->proto.sctp.vtag[dir]) { 435 + if (test_bit(SCTP_CID_DATA, map) || ignore) 436 + goto out_unlock; 437 + 438 + ct->proto.sctp.flags |= SCTP_FLAG_HEARTBEAT_VTAG_FAILED; 439 + ct->proto.sctp.last_dir = dir; 440 + ignore = true; 441 + continue; 442 + } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) { 443 + ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED; 444 + } 445 + } else if (sch->type == SCTP_CID_HEARTBEAT_ACK) { 435 446 if (ct->proto.sctp.vtag[dir] == 0) { 436 447 pr_debug("Setting vtag %x for dir %d\n", 437 448 sh->vtag, dir); 438 449 ct->proto.sctp.vtag[dir] = sh->vtag; 439 450 } else if (sh->vtag != ct->proto.sctp.vtag[dir]) { 440 - pr_debug("Verification tag check failed\n"); 441 - goto out_unlock; 451 + if (test_bit(SCTP_CID_DATA, map) || ignore) 452 + goto out_unlock; 453 + 454 + if ((ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) == 0 || 455 + ct->proto.sctp.last_dir == dir) 456 + goto out_unlock; 457 + 458 + ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED; 459 + ct->proto.sctp.vtag[dir] = sh->vtag; 460 + ct->proto.sctp.vtag[!dir] = 0; 461 + } else if (ct->proto.sctp.flags & SCTP_FLAG_HEARTBEAT_VTAG_FAILED) { 462 + ct->proto.sctp.flags &= ~SCTP_FLAG_HEARTBEAT_VTAG_FAILED; 442 463 } 443 464 } 444 465 ··· 496 469 nf_conntrack_event_cache(IPCT_PROTOINFO, ct); 497 470 } 498 471 spin_unlock_bh(&ct->lock); 472 + 473 + /* allow but do not refresh timeout */ 474 + if (ignore) 475 + return NF_ACCEPT; 499 476 500 477 timeouts = nf_ct_timeout_lookup(ct); 501 478 if (!timeouts)
+2 -1
net/netfilter/nf_tables_api.c
··· 3770 3770 goto nla_put_failure; 3771 3771 } 3772 3772 3773 - if (nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata)) 3773 + if (set->udata && 3774 + nla_put(skb, NFTA_SET_USERDATA, set->udlen, set->udata)) 3774 3775 goto nla_put_failure; 3775 3776 3776 3777 nest = nla_nest_start_noflag(skb, NFTA_SET_DESC);
+3 -1
net/netfilter/nft_payload.c
··· 87 87 u32 *dest = &regs->data[priv->dreg]; 88 88 int offset; 89 89 90 - dest[priv->len / NFT_REG32_SIZE] = 0; 90 + if (priv->len % NFT_REG32_SIZE) 91 + dest[priv->len / NFT_REG32_SIZE] = 0; 92 + 91 93 switch (priv->base) { 92 94 case NFT_PAYLOAD_LL_HEADER: 93 95 if (!skb_mac_header_was_set(skb))
+47 -10
net/netfilter/nft_set_rbtree.c
··· 218 218 struct nft_rbtree_elem *new, 219 219 struct nft_set_ext **ext) 220 220 { 221 + bool overlap = false, dup_end_left = false, dup_end_right = false; 221 222 struct nft_rbtree *priv = nft_set_priv(set); 222 223 u8 genmask = nft_genmask_next(net); 223 224 struct nft_rbtree_elem *rbe; 224 225 struct rb_node *parent, **p; 225 - bool overlap = false; 226 226 int d; 227 227 228 228 /* Detect overlaps as we descend the tree. Set the flag in these cases: ··· 238 238 * 239 239 * b1. _ _ __>| !_ _ __| (insert end before existing start) 240 240 * b2. _ _ ___| !_ _ _>| (insert end after existing start) 241 - * b3. _ _ ___! >|_ _ __| (insert start after existing end) 241 + * b3. _ _ ___! >|_ _ __| (insert start after existing end, as a leaf) 242 + * '--' no nodes falling in this range 243 + * b4. >|_ _ ! (insert start before existing start) 242 244 * 243 245 * Case a3. resolves to b3.: 244 246 * - if the inserted start element is the leftmost, because the '0' 245 247 * element in the tree serves as end element 246 - * - otherwise, if an existing end is found. Note that end elements are 247 - * always inserted after corresponding start elements. 248 + * - otherwise, if an existing end is found immediately to the left. If 249 + * there are existing nodes in between, we need to further descend the 250 + * tree before we can conclude the new start isn't causing an overlap 251 + * 252 + * or to b4., which, preceded by a3., means we already traversed one or 253 + * more existing intervals entirely, from the right. 248 254 * 249 255 * For a new, rightmost pair of elements, we'll hit cases b3. and b2., 250 256 * in that order. 251 257 * 252 258 * The flag is also cleared in two special cases: 253 259 * 254 - * b4. |__ _ _!|<_ _ _ (insert start right before existing end) 255 - * b5. |__ _ >|!__ _ _ (insert end right after existing start) 260 + * b5. |__ _ _!|<_ _ _ (insert start right before existing end) 261 + * b6. |__ _ >|!__ _ _ (insert end right after existing start) 256 262 * 257 263 * which always happen as last step and imply that no further 258 264 * overlapping is possible. 265 + * 266 + * Another special case comes from the fact that start elements matching 267 + * an already existing start element are allowed: insertion is not 268 + * performed but we return -EEXIST in that case, and the error will be 269 + * cleared by the caller if NLM_F_EXCL is not present in the request. 270 + * This way, request for insertion of an exact overlap isn't reported as 271 + * error to userspace if not desired. 272 + * 273 + * However, if the existing start matches a pre-existing start, but the 274 + * end element doesn't match the corresponding pre-existing end element, 275 + * we need to report a partial overlap. This is a local condition that 276 + * can be noticed without need for a tracking flag, by checking for a 277 + * local duplicated end for a corresponding start, from left and right, 278 + * separately. 259 279 */ 260 280 261 281 parent = NULL; ··· 292 272 if (nft_rbtree_interval_start(new)) { 293 273 if (nft_rbtree_interval_end(rbe) && 294 274 nft_set_elem_active(&rbe->ext, genmask) && 295 - !nft_set_elem_expired(&rbe->ext)) 275 + !nft_set_elem_expired(&rbe->ext) && !*p) 296 276 overlap = false; 297 277 } else { 278 + if (dup_end_left && !*p) 279 + return -ENOTEMPTY; 280 + 298 281 overlap = nft_rbtree_interval_end(rbe) && 299 282 nft_set_elem_active(&rbe->ext, 300 283 genmask) && 301 284 !nft_set_elem_expired(&rbe->ext); 285 + 286 + if (overlap) { 287 + dup_end_right = true; 288 + continue; 289 + } 302 290 } 303 291 } else if (d > 0) { 304 292 p = &parent->rb_right; 305 293 306 294 if (nft_rbtree_interval_end(new)) { 295 + if (dup_end_right && !*p) 296 + return -ENOTEMPTY; 297 + 307 298 overlap = nft_rbtree_interval_end(rbe) && 308 299 nft_set_elem_active(&rbe->ext, 309 300 genmask) && 310 301 !nft_set_elem_expired(&rbe->ext); 311 - } else if (nft_rbtree_interval_end(rbe) && 312 - nft_set_elem_active(&rbe->ext, genmask) && 302 + 303 + if (overlap) { 304 + dup_end_left = true; 305 + continue; 306 + } 307 + } else if (nft_set_elem_active(&rbe->ext, genmask) && 313 308 !nft_set_elem_expired(&rbe->ext)) { 314 - overlap = true; 309 + overlap = nft_rbtree_interval_end(rbe); 315 310 } 316 311 } else { 317 312 if (nft_rbtree_interval_end(rbe) && ··· 351 316 p = &parent->rb_left; 352 317 } 353 318 } 319 + 320 + dup_end_left = dup_end_right = false; 354 321 } 355 322 356 323 if (overlap)