From d11037a9a5646cfef454c51fc9cdbbddda73dc00 Mon Sep 17 00:00:00 2001 From: liangbotong Date: Mon, 28 Aug 2023 10:27:42 +0800 Subject: [PATCH] NewIP code security issue remediation 1.Resolve stack overflow issue in parsing ICMP packets in newip. 2.Resolve negative overflow issue in parsing UDP packets in newip. 3.Resolve unchecked data reception issue in nip_rcv. Signed-off-by: liangbotong --- newip/src/common/nip_addr.c | 17 +- newip/src/common/nip_addr.h | 16 +- newip/src/common/nip_hdr_decap.c | 167 ++++++++++-------- .../third_party/linux-5.10/include/net/nip.h | 5 +- newip/third_party/linux-5.10/net/newip/icmp.c | 11 +- .../linux-5.10/net/newip/nip_sockglue.c | 13 +- .../third_party/linux-5.10/net/newip/nndisc.c | 47 ++++- .../linux-5.10/net/newip/tcp_nip.c | 44 +++-- newip/third_party/linux-5.10/net/newip/udp.c | 21 ++- 9 files changed, 219 insertions(+), 122 deletions(-) diff --git a/newip/src/common/nip_addr.c b/newip/src/common/nip_addr.c index eb88a3c..31105bc 100644 --- a/newip/src/common/nip_addr.c +++ b/newip/src/common/nip_addr.c @@ -403,21 +403,26 @@ unsigned char *build_nip_addr(const struct nip_addr *addr, unsigned char *buf) return p; } -unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr) +unsigned char *decode_nip_addr(struct nip_buff *nbuf, struct nip_addr *addr) { int i; int ret; int addr_len; - unsigned char *p = buf; - addr->NIP_ADDR_FIELD8[0] = *p; + if (nbuf->remaining_len < sizeof(unsigned char)) + return 0; + + addr->NIP_ADDR_FIELD8[0] = *nbuf->data; addr_len = get_nip_addr_len(addr); if (addr_len == 0) return 0; + if (nbuf->remaining_len < addr_len) + return 0; + for (i = 0; i < addr_len; i++) { - addr->NIP_ADDR_FIELD8[i] = *p; - p++; + addr->NIP_ADDR_FIELD8[i] = *nbuf->data; + nip_buff_pull(nbuf, sizeof(unsigned char)); } addr->bitlen = addr_len * NIP_ADDR_BIT_LEN_8; @@ -425,6 +430,6 @@ unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr) if (ret) return 0; - return p; + return nbuf->data; } diff --git a/newip/src/common/nip_addr.h b/newip/src/common/nip_addr.h index 370007f..833202f 100644 --- a/newip/src/common/nip_addr.h +++ b/newip/src/common/nip_addr.h @@ -109,12 +109,26 @@ enum nip_index { extern const struct nip_addr nip_any_addr; extern const struct nip_addr nip_broadcast_addr_arp; +struct nip_buff { + unsigned char *data; + unsigned int remaining_len; +}; + +static inline void nip_buff_pull(struct nip_buff *nbuf, unsigned int len) +{ + if (len > nbuf->remaining_len) + return; + + nbuf->data += len; + nbuf->remaining_len -= len; +} + int nip_addr_invalid(const struct nip_addr *addr); int nip_addr_public(const struct nip_addr *addr); int nip_addr_any(const struct nip_addr *addr); int get_nip_addr_len(const struct nip_addr *addr); unsigned char *build_nip_addr(const struct nip_addr *addr, unsigned char *buf); -unsigned char *decode_nip_addr(unsigned char *buf, struct nip_addr *addr); +unsigned char *decode_nip_addr(struct nip_buff *nbuf, struct nip_addr *addr); int is_nip_local_addr(const struct nip_addr *addr); #endif /* _UAPI_NEWIP_ADDR_H */ diff --git a/newip/src/common/nip_hdr_decap.c b/newip/src/common/nip_hdr_decap.c index 21444c8..abec609 100644 --- a/newip/src/common/nip_hdr_decap.c +++ b/newip/src/common/nip_hdr_decap.c @@ -12,81 +12,98 @@ #include "nip_hdr.h" /* Must carry the current field */ -static int _get_nip_hdr_bitmap(unsigned char *buf, +static int _get_nip_hdr_bitmap(struct nip_buff *nbuf, unsigned char bitmap[], unsigned char bitmap_index_max) { int i = 0; - unsigned char *p = buf; - if (*p & NIP_BITMAP_INVALID_SET) + if (nbuf->remaining_len < sizeof(unsigned char)) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + + if (*nbuf->data & NIP_BITMAP_INVALID_SET) return -NIP_HDR_BITMAP_INVALID; do { if (i >= bitmap_index_max) return -NIP_HDR_BITMAP_NUM_OUT_RANGE; - bitmap[i] = *p; - p++; + if (nbuf->remaining_len < sizeof(unsigned char)) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + + bitmap[i] = *nbuf->data; + nip_buff_pull(nbuf, sizeof(unsigned char)); } while (bitmap[i++] & NIP_BITMAP_HAVE_MORE_BIT); return i; } /* Must carry the current field */ -static int _get_nip_hdr_ttl(const unsigned char *buf, +static int _get_nip_hdr_ttl(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { if (!(bitmap & NIP_BITMAP_INCLUDE_TTL)) return -NIP_HDR_NO_TTL; - niph->ttl = *buf; + if (nbuf->remaining_len < sizeof(niph->ttl)) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + + niph->ttl = *nbuf->data; niph->include_ttl = 1; + nip_buff_pull(nbuf, sizeof(niph->ttl)); - return sizeof(niph->ttl); + return 0; } /* Optional fields */ /* Communication between devices of the same version may not carry packet Header length, * but communication between devices of different versions must carry packet header length */ -static int _get_nip_hdr_len(const unsigned char *buf, +static int _get_nip_hdr_len(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { if (!(bitmap & NIP_BITMAP_INCLUDE_HDR_LEN)) return 0; + if (nbuf->remaining_len < sizeof(niph->hdr_len)) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + /* Total_len is a network sequence and cannot be * compared directly with the local sequence */ - niph->hdr_len = *buf; + niph->hdr_len = *nbuf->data; niph->include_hdr_len = 1; + nip_buff_pull(nbuf, sizeof(niph->hdr_len)); if (niph->include_total_len && niph->hdr_len >= niph->rcv_buf_len) return -NIP_HDR_LEN_OUT_RANGE; - return sizeof(niph->hdr_len); + return 0; } /* Must carry the current field */ -static int _get_nip_hdr_nexthdr(const unsigned char *buf, +static int _get_nip_hdr_nexthdr(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { if (!(bitmap & NIP_BITMAP_INCLUDE_NEXT_HDR)) return -NIP_HDR_NO_NEXT_HDR; - niph->nexthdr = *buf; + if (nbuf->remaining_len < sizeof(niph->nexthdr)) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + + niph->nexthdr = *nbuf->data; niph->include_nexthdr = 1; + nip_buff_pull(nbuf, sizeof(niph->nexthdr)); - return sizeof(niph->nexthdr); + return 0; } /* Must carry the current field */ /* Note: niph->saddr is network order.(big end) */ -static int _get_nip_hdr_daddr(unsigned char *buf, +static int _get_nip_hdr_daddr(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { @@ -95,7 +112,7 @@ static int _get_nip_hdr_daddr(unsigned char *buf, if (!(bitmap & NIP_BITMAP_INCLUDE_DADDR)) return -NIP_HDR_NO_DADDR; - p = decode_nip_addr(buf, &niph->daddr); + p = decode_nip_addr(nbuf, &niph->daddr); if (!p) return -NIP_HDR_DECAP_DADDR_ERR; @@ -103,12 +120,12 @@ static int _get_nip_hdr_daddr(unsigned char *buf, return -NIP_HDR_DADDR_INVALID; niph->include_daddr = 1; - return (niph->daddr.bitlen / NIP_ADDR_BIT_LEN_8); + return 0; } /* Optional fields */ /* Note: niph->daddr is network order.(big end) */ -static int _get_nip_hdr_saddr(unsigned char *buf, +static int _get_nip_hdr_saddr(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { @@ -117,7 +134,7 @@ static int _get_nip_hdr_saddr(unsigned char *buf, if (!(bitmap & NIP_BITMAP_INCLUDE_SADDR)) return 0; - p = decode_nip_addr(buf, &niph->saddr); + p = decode_nip_addr(nbuf, &niph->saddr); if (!p) return -NIP_HDR_DECAP_SADDR_ERR; @@ -125,84 +142,80 @@ static int _get_nip_hdr_saddr(unsigned char *buf, return -NIP_HDR_SADDR_INVALID; niph->include_saddr = 1; - return (niph->saddr.bitlen / NIP_ADDR_BIT_LEN_8); + return 0; } /* Optional fields: tcp/arp need, udp needless */ /* Note: niph->total_len is network order.(big end), need change to host order */ -static int _get_nip_total_len(unsigned char *buf, +static int _get_nip_total_len(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { if (!(bitmap & NIP_BITMAP_INCLUDE_TOTAL_LEN)) return 0; + if (nbuf->remaining_len < sizeof(niph->total_len)) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + /* Total_len is a network sequence and cannot be * compared directly with the local sequence */ - niph->total_len = *((unsigned short *)buf); + niph->total_len = *((unsigned short *)nbuf->data); niph->include_total_len = 1; + nip_buff_pull(nbuf, sizeof(niph->total_len)); - return sizeof(niph->total_len); + return 0; } -static int _nip_hdr_bitmap0_parse(unsigned char *buf, +static int _nip_hdr_bitmap0_parse(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { - int len; - int len_total = 0; + int err; - len = _get_nip_hdr_ttl(buf, bitmap, niph); - if (len < 0) - return len; - len_total += len; + err = _get_nip_hdr_ttl(nbuf, bitmap, niph); + if (err < 0) + return err; /* Optional fields */ - len = _get_nip_total_len(buf + len_total, bitmap, niph); - if (len < 0) - return len; - len_total += len; - - len = _get_nip_hdr_nexthdr(buf + len_total, bitmap, niph); - if (len < 0) - return len; - len_total += len; - - len = _get_nip_hdr_daddr(buf + len_total, bitmap, niph); - if (len < 0) - return len; - len_total += len; - - len = _get_nip_hdr_saddr(buf + len_total, bitmap, niph); - if (len < 0) - return len; - len_total += len; - - return len_total; + err = _get_nip_total_len(nbuf, bitmap, niph); + if (err < 0) + return err; + + err = _get_nip_hdr_nexthdr(nbuf, bitmap, niph); + if (err < 0) + return err; + + err = _get_nip_hdr_daddr(nbuf, bitmap, niph); + if (err < 0) + return err; + + err = _get_nip_hdr_saddr(nbuf, bitmap, niph); + if (err < 0) + return err; + + return 0; } -static int _nip_hdr_bitmap1_parse(unsigned char *buf, +static int _nip_hdr_bitmap1_parse(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { - int len; - int len_total = 0; + int err; /* If add new field needs to be modified with the macro definition */ if (bitmap & NIP_INVALID_BITMAP_2) niph->include_unknown_bit = 1; /* Optional fields */ - len = _get_nip_hdr_len(buf + len_total, bitmap, niph); - if (len < 0) - return len; - len_total += len; + err = _get_nip_hdr_len(nbuf, bitmap, niph); + if (err < 0) + return err; - return len_total; + return 0; } -static int _nip_hdr_unknown_bit_check(unsigned char *buf, +static int _nip_hdr_unknown_bit_check(struct nip_buff *nbuf, unsigned char bitmap, struct nip_hdr_decap *niph) { @@ -211,7 +224,7 @@ static int _nip_hdr_unknown_bit_check(unsigned char *buf, } #define FACTORY_NUM_MAX 3 -static int (*hdr_parse_factory[FACTORY_NUM_MAX])(unsigned char *, +static int (*hdr_parse_factory[FACTORY_NUM_MAX])(struct nip_buff *, unsigned char, struct nip_hdr_decap *) = { _nip_hdr_bitmap0_parse, @@ -242,33 +255,37 @@ int nip_hdr_parse(unsigned char *rcv_buf, unsigned int buf_len, struct nip_hdr_d { int i = 0; int ret; - unsigned char *buf = rcv_buf; unsigned char bitmap[BITMAP_MAX] = {0}; - int num = _get_nip_hdr_bitmap(buf, bitmap, BITMAP_MAX); + int num; + struct nip_buff nbuf; - if (num <= 0 || !rcv_buf) - return num; + nbuf.data = rcv_buf; + if (!nbuf.data) + return 0; - niph->hdr_real_len = num * sizeof(bitmap[0]); - buf += niph->hdr_real_len; + nbuf.remaining_len = buf_len; + num = _get_nip_hdr_bitmap(&nbuf, bitmap, BITMAP_MAX); + if (num <= 0) + return num; niph->rcv_buf_len = buf_len; while (i < num) { - int len; + int err; if (i >= FACTORY_NUM_MAX) break; - len = hdr_parse_factory[i](buf, bitmap[i], niph); - if (len < 0) - return len; - buf += len; - niph->hdr_real_len += len; - if (niph->hdr_real_len >= buf_len) - return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + err = hdr_parse_factory[i](&nbuf, bitmap[i], niph); + if (err < 0) + return err; + i++; } + if (buf_len < nbuf.remaining_len) + return -NIP_HDR_RCV_BUF_READ_OUT_RANGE; + + niph->hdr_real_len = buf_len - nbuf.remaining_len; ret = nip_hdr_check(niph); if (ret < 0) return ret; diff --git a/newip/third_party/linux-5.10/include/net/nip.h b/newip/third_party/linux-5.10/include/net/nip.h index 236ba3a..7880666 100644 --- a/newip/third_party/linux-5.10/include/net/nip.h +++ b/newip/third_party/linux-5.10/include/net/nip.h @@ -133,10 +133,9 @@ int nip_setsockopt(struct sock *sk, int level, int optname, sockptr_t optval, unsigned int optlen); int nip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); -void nip_sock_debug(const struct sock *sk, const char *name, int state); +void nip_sock_debug(const struct sock *sk, const char *name); void nip_sock_debug_output(const struct nip_addr *nip_daddr, const struct nip_addr *nip_saddr, - __be16 dport, __be16 sport, - const char *name, int state); + __be16 dport, __be16 sport, const char *name); /* functions defined in nip_addrconf.c */ int nip_addrconf_get_ifaddr(struct net *net, unsigned int cmd, void __user *arg); diff --git a/newip/third_party/linux-5.10/net/newip/icmp.c b/newip/third_party/linux-5.10/net/newip/icmp.c index 8202c37..39b1aa7 100644 --- a/newip/third_party/linux-5.10/net/newip/icmp.c +++ b/newip/third_party/linux-5.10/net/newip/icmp.c @@ -45,9 +45,16 @@ int nip_icmp_rcv(struct sk_buff *skb) { int ret = 0; - struct nip_icmp_hdr *hdr = nip_icmp_header(skb); - u8 type = hdr->nip_icmp_type; + struct nip_icmp_hdr *hdr; + u8 type; + if (!pskb_may_pull(skb, sizeof(struct nip_icmp_hdr))) { + nip_dbg("invalid ICMP packet"); + return -EINVAL; + } + + hdr = nip_icmp_header(skb); + type = hdr->nip_icmp_type; nip_dbg("rcv newip icmp packet. type=%u", type); switch (type) { case NIP_ARP_NS: diff --git a/newip/third_party/linux-5.10/net/newip/nip_sockglue.c b/newip/third_party/linux-5.10/net/newip/nip_sockglue.c index f3f7ac9..2080424 100644 --- a/newip/third_party/linux-5.10/net/newip/nip_sockglue.c +++ b/newip/third_party/linux-5.10/net/newip/nip_sockglue.c @@ -179,8 +179,7 @@ int nip_getsockopt(struct sock *sk, int level, } void nip_sock_debug_output(const struct nip_addr *nip_daddr, const struct nip_addr *nip_saddr, - __be16 dport, __be16 sport, - const char *name, int state) + __be16 dport, __be16 sport, const char *name) { if (get_nip_debug()) { char saddr[NIP_ADDR_BIT_LEN_MAX] = {0}; @@ -189,20 +188,18 @@ void nip_sock_debug_output(const struct nip_addr *nip_daddr, const struct nip_ad nip_addr_to_str(nip_daddr, daddr, NIP_ADDR_BIT_LEN_MAX); nip_addr_to_str(nip_saddr, saddr, NIP_ADDR_BIT_LEN_MAX); - nip_dbg("%s :%s (saddr=%s, daddr=%s, sport=%u, dport=%u)", - name, state ? "success" : "failed", saddr, daddr, - ntohs(sport), ntohs(dport)); + nip_dbg("%s (saddr=%s, daddr=%s, sport=%u, dport=%u)", + name, saddr, daddr, ntohs(sport), ntohs(dport)); } } -void nip_sock_debug(const struct sock *sk, const char *name, int state) +void nip_sock_debug(const struct sock *sk, const char *name) { if (sk) { struct inet_sock *inet = inet_sk(sk); nip_sock_debug_output(&sk->SK_NIP_DADDR, &sk->SK_NIP_RCV_SADDR, - inet->inet_dport, inet->inet_sport, - name, state); + inet->inet_dport, inet->inet_sport, name); } } diff --git a/newip/third_party/linux-5.10/net/newip/nndisc.c b/newip/third_party/linux-5.10/net/newip/nndisc.c index 6d1e4d2..27b48bc 100644 --- a/newip/third_party/linux-5.10/net/newip/nndisc.c +++ b/newip/third_party/linux-5.10/net/newip/nndisc.c @@ -495,16 +495,27 @@ out: int nndisc_rcv_ns(struct sk_buff *skb) { - struct nnd_msg *msg = (struct nnd_msg *)skb_transport_header(skb); - u_char *p = msg->data; + struct nnd_msg *msg; + u_char *p; u_char *lladdr; struct nip_addr addr = {0}; struct neighbour *neigh; struct ethhdr *eth; struct net_device *dev = skb->dev; int err = 0; + struct nip_buff nbuf; + + if (!pskb_may_pull(skb, sizeof(struct nnd_msg))) { + nip_dbg("invalid ns packet"); + err = -EFAULT; + goto out; + } + + msg = (struct nnd_msg *)skb->data; + nbuf.data = msg->data; + nbuf.remaining_len = skb->len - sizeof(struct nip_icmp_hdr); - p = decode_nip_addr(p, &addr); + p = decode_nip_addr(&nbuf, &addr); if (!p) { nip_dbg("failure when decode source address"); err = -EFAULT; @@ -526,7 +537,7 @@ int nndisc_rcv_ns(struct sk_buff *skb) lladdr = eth->h_source; /* checksum parse */ - if (!nip_get_nndisc_rcv_checksum(skb, p)) { + if (!nip_get_nndisc_rcv_checksum(skb, nbuf.data)) { nip_dbg("ns ICMP checksum failed, drop the packet"); err = -EINVAL; goto out; @@ -546,16 +557,40 @@ out: int nndisc_rcv_na(struct sk_buff *skb) { - struct nnd_msg *msg = (struct nnd_msg *)skb_transport_header(skb); - u_char *p = msg->data; + struct nnd_msg *msg; + u_char *p; u_char len; u8 lladdr[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; struct net_device *dev = skb->dev; struct neighbour *neigh; + if (!pskb_may_pull(skb, sizeof(struct nnd_msg))) { + nip_dbg("invalid na packet"); + kfree_skb(skb); + return -EINVAL; + } + + msg = (struct nnd_msg *)skb->data; + p = msg->data; + if (skb->len - sizeof(struct nip_icmp_hdr) < sizeof(unsigned char)) { + nip_dbg("invalid msg data"); + kfree_skb(skb); + return -EINVAL; + } len = *p; + if (len > MAX_ADDR_LEN) { + nip_dbg("Invalid length, drop the packet(len=%u)", len); + kfree_skb(skb); + return 0; + } + p++; memset(lladdr, 0, ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))); + if (skb->len - sizeof(struct nip_icmp_hdr) - sizeof(unsigned char) < len) { + nip_dbg("invalid msg data"); + kfree_skb(skb); + return -EINVAL; + } memcpy(lladdr, p, len); if (!nip_get_nndisc_rcv_checksum(skb, p + len)) { diff --git a/newip/third_party/linux-5.10/net/newip/tcp_nip.c b/newip/third_party/linux-5.10/net/newip/tcp_nip.c index f01eac4..2ca6bef 100644 --- a/newip/third_party/linux-5.10/net/newip/tcp_nip.c +++ b/newip/third_party/linux-5.10/net/newip/tcp_nip.c @@ -407,8 +407,6 @@ #define TCP_WINDOW_RAISE_THRESHOLD 2 #define TCP_BACKLOG_HEADROOM (64 * 1024) #define BYTES_PER_TCP_HEADER 4 -#define TRUE 1 -#define FALSE 0 static const struct inet_connection_sock_af_ops newip_specific; @@ -525,7 +523,7 @@ void tcp_nip_close(struct sock *sk, long timeout) if (data_was_unread) { tcp_set_state(sk, TCP_CLOSE); - nip_sock_debug(sk, __func__, TRUE); + nip_sock_debug(sk, __func__); tcp_nip_send_active_reset(sk, sk->sk_allocation); } else if (tcp_nip_close_state(sk)) { /* RED-PEN. Formally speaking, we have broken TCP state @@ -536,7 +534,7 @@ void tcp_nip_close(struct sock *sk, long timeout) * TCP_CLOSE_WAIT -> TCP_LAST_ACK */ nip_dbg("ready to send fin, sk_state=%d", sk->sk_state); - nip_sock_debug(sk, __func__, TRUE); + nip_sock_debug(sk, __func__); tcp_nip_send_fin(sk); } @@ -722,7 +720,7 @@ static int tcp_nip_connect(struct sock *sk, struct sockaddr *uaddr, err = __tcp_nip_connect(sk); if (err) goto late_failure; - nip_sock_debug(sk, __func__, TRUE); + nip_sock_debug(sk, __func__); return 0; /* failure after tcp_set_state(sk, TCP_SYN_SENT) */ @@ -730,8 +728,7 @@ late_failure: tcp_set_state(sk, TCP_CLOSE); failure: nip_sock_debug_output(&usin->sin_addr, &sk->SK_NIP_RCV_SADDR, - usin->sin_port, inet->inet_sport, - __func__, FALSE); + usin->sin_port, inet->inet_sport, __func__); sk->sk_route_caps = 0; inet->inet_dport = 0; return err; @@ -1710,6 +1707,26 @@ static bool tcp_nip_add_backlog(struct sock *sk, struct sk_buff *skb) return false; } +static int nip_skb_precheck(struct sk_buff *skb) +{ + if (!pskb_may_pull(skb, sizeof(struct tcphdr))) { + nip_dbg("invalid tcp packet length, drop the packet(skb->len=%u)", skb->len); + return -EINVAL; + } + + if (skb->pkt_type != PACKET_HOST) { + nip_dbg("unknown pkt-type(%u), drop skb", skb->pkt_type); + return -EINVAL; + } + + if (!nip_get_tcp_input_checksum(skb)) { + nip_dbg("checksum fail, drop skb"); + return -EINVAL; + } + + return 0; +} + /* Function * TCP is the gateway from the network layer to the transport layer * and receives data packets from the network layer @@ -1724,15 +1741,8 @@ static int tcp_nip_rcv(struct sk_buff *skb) int ret; int dif = skb->skb_iif; - if (skb->pkt_type != PACKET_HOST) { - nip_dbg("unknown pkt-type(%u), drop skb", skb->pkt_type); - goto discard_it; - } - - if (!nip_get_tcp_input_checksum(skb)) { - nip_dbg("checksum fail, drop skb"); + if (nip_skb_precheck(skb)) goto discard_it; - } th = (const struct tcphdr *)skb->data; @@ -1824,12 +1834,12 @@ no_tcp_socket: discard_it: kfree_skb(skb); - nip_sock_debug(sk, __func__, FALSE); + nip_sock_debug(sk, __func__); return 0; discard_and_relse: sk_drops_add(sk, skb); - nip_sock_debug(sk, __func__, FALSE); + nip_sock_debug(sk, __func__); if (refcounted) sock_put(sk); goto discard_it; diff --git a/newip/third_party/linux-5.10/net/newip/udp.c b/newip/third_party/linux-5.10/net/newip/udp.c index 5ff0c60..cd4a0b4 100644 --- a/newip/third_party/linux-5.10/net/newip/udp.c +++ b/newip/third_party/linux-5.10/net/newip/udp.c @@ -362,13 +362,27 @@ bool nip_get_udp_input_checksum(struct sk_buff *skb) int nip_udp_input(struct sk_buff *skb) { struct sock *sk; - int rc = 0; - struct udphdr *udphead = udp_hdr(skb); + int rc = -EINVAL; + struct udphdr *udphead; + + if (!pskb_may_pull(skb, sizeof(struct udphdr))) { + nip_dbg("invalid skb length, drop the packet(skb->len=%u)", skb->len); + kfree_skb(skb); + goto end; + } + + udphead = udp_hdr(skb); + if (ntohs(udphead->len) < sizeof(struct udphdr) || + ntohs(udphead->len) > skb->len) { + nip_dbg("invalid udp packet length, drop the packet(udphead->len=%u)", + ntohs(udphead->len)); + kfree_skb(skb); + goto end; + } if (!nip_get_udp_input_checksum(skb)) { nip_dbg("checksum failed, drop the packet"); kfree_skb(skb); - rc = -1; goto end; } @@ -378,7 +392,6 @@ int nip_udp_input(struct sk_buff *skb) nip_dbg("dport not match, drop the packet. sport=%u, dport=%u, data_len=%u", ntohs(udphead->source), ntohs(udphead->dest), ntohs(udphead->len)); kfree_skb(skb); - rc = -1; goto end; } -- Gitee