Unverified Commit cea0a614 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!2867 netfilter: conntrack: dccp: copy entire header to stack buffer, not just basic one

parents 059ee86e f14a33b8
Loading
Loading
Loading
Loading
+49 −3
Original line number Diff line number Diff line
@@ -431,9 +431,19 @@ static bool dccp_error(const struct dccp_hdr *dh,
		       struct sk_buff *skb, unsigned int dataoff,
		       const struct nf_hook_state *state)
{
	static const unsigned long require_seq48 = 1 << DCCP_PKT_REQUEST |
						   1 << DCCP_PKT_RESPONSE |
						   1 << DCCP_PKT_CLOSEREQ |
						   1 << DCCP_PKT_CLOSE |
						   1 << DCCP_PKT_RESET |
						   1 << DCCP_PKT_SYNC |
						   1 << DCCP_PKT_SYNCACK;
	unsigned int dccp_len = skb->len - dataoff;
	unsigned int cscov;
	const char *msg;
	u8 type;

	BUILD_BUG_ON(DCCP_PKT_INVALID >= BITS_PER_LONG);

	if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) ||
	    dh->dccph_doff * 4 > dccp_len) {
@@ -458,10 +468,17 @@ static bool dccp_error(const struct dccp_hdr *dh,
		goto out_invalid;
	}

	if (dh->dccph_type >= DCCP_PKT_INVALID) {
	type = dh->dccph_type;
	if (type >= DCCP_PKT_INVALID) {
		msg = "nf_ct_dccp: reserved packet type ";
		goto out_invalid;
	}

	if (test_bit(type, &require_seq48) && !dh->dccph_x) {
		msg = "nf_ct_dccp: type lacks 48bit sequence numbers";
		goto out_invalid;
	}

	return false;
out_invalid:
	nf_l4proto_log_invalid(skb, state->net, state->pf,
@@ -469,24 +486,53 @@ static bool dccp_error(const struct dccp_hdr *dh,
	return true;
}

struct nf_conntrack_dccp_buf {
	struct dccp_hdr dh;	 /* generic header part */
	struct dccp_hdr_ext ext; /* optional depending dh->dccph_x */
	union {			 /* depends on header type */
		struct dccp_hdr_ack_bits ack;
		struct dccp_hdr_request req;
		struct dccp_hdr_response response;
		struct dccp_hdr_reset rst;
	} u;
};

static struct dccp_hdr *
dccp_header_pointer(const struct sk_buff *skb, int offset, const struct dccp_hdr *dh,
		    struct nf_conntrack_dccp_buf *buf)
{
	unsigned int hdrlen = __dccp_hdr_len(dh);

	if (hdrlen > sizeof(*buf))
		return NULL;

	return skb_header_pointer(skb, offset, hdrlen, buf);
}

int nf_conntrack_dccp_packet(struct nf_conn *ct, struct sk_buff *skb,
			     unsigned int dataoff,
			     enum ip_conntrack_info ctinfo,
			     const struct nf_hook_state *state)
{
	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
	struct dccp_hdr _dh, *dh;
	struct nf_conntrack_dccp_buf _dh;
	u_int8_t type, old_state, new_state;
	enum ct_dccp_roles role;
	unsigned int *timeouts;
	struct dccp_hdr *dh;

	dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &_dh);
	dh = skb_header_pointer(skb, dataoff, sizeof(*dh), &_dh.dh);
	if (!dh)
		return NF_DROP;

	if (dccp_error(dh, skb, dataoff, state))
		return -NF_ACCEPT;

	/* pull again, including possible 48 bit sequences and subtype header */
	dh = dccp_header_pointer(skb, dataoff, dh, &_dh);
	if (!dh)
		return NF_DROP;

	type = dh->dccph_type;
	if (!nf_ct_is_confirmed(ct) && !dccp_new(ct, skb, dh))
		return -NF_ACCEPT;