!40 NewIP code security issue remediation

Merge pull request !40 from liangbotong/master
This commit is contained in:
openharmony_ci
2023-08-28 08:24:49 +00:00
committed by Gitee
9 changed files with 217 additions and 120 deletions
+11 -6
View File
@@ -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;
}
+15 -1
View File
@@ -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 */
+90 -73
View File
@@ -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;
niph->include_ttl = 1;
if (nbuf->remaining_len < sizeof(niph->ttl))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
return sizeof(niph->ttl);
niph->ttl = *nbuf->data;
niph->include_ttl = 1;
nip_buff_pull(nbuf, 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;
niph->include_nexthdr = 1;
if (nbuf->remaining_len < sizeof(niph->nexthdr))
return -NIP_HDR_RCV_BUF_READ_OUT_RANGE;
return sizeof(niph->nexthdr);
niph->nexthdr = *nbuf->data;
niph->include_nexthdr = 1;
nip_buff_pull(nbuf, 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;
err = _get_nip_total_len(nbuf, bitmap, niph);
if (err < 0)
return err;
len = _get_nip_hdr_nexthdr(buf + len_total, bitmap, niph);
if (len < 0)
return len;
len_total += len;
err = _get_nip_hdr_nexthdr(nbuf, bitmap, niph);
if (err < 0)
return err;
len = _get_nip_hdr_daddr(buf + len_total, bitmap, niph);
if (len < 0)
return len;
len_total += len;
err = _get_nip_hdr_daddr(nbuf, bitmap, niph);
if (err < 0)
return err;
len = _get_nip_hdr_saddr(buf + len_total, bitmap, niph);
if (len < 0)
return len;
len_total += len;
err = _get_nip_hdr_saddr(nbuf, bitmap, niph);
if (err < 0)
return err;
return len_total;
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)
nbuf.data = rcv_buf;
if (!nbuf.data)
return 0;
nbuf.remaining_len = buf_len;
num = _get_nip_hdr_bitmap(&nbuf, bitmap, BITMAP_MAX);
if (num <= 0)
return num;
niph->hdr_real_len = num * sizeof(bitmap[0]);
buf += niph->hdr_real_len;
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;
+2 -3
View File
@@ -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);
+9 -2
View File
@@ -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:
+5 -8
View File
@@ -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);
}
}
+41 -6
View File
@@ -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;
p = decode_nip_addr(p, &addr);
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(&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)) {
+27 -17
View File
@@ -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);
if (nip_skb_precheck(skb))
goto discard_it;
}
if (!nip_get_tcp_input_checksum(skb)) {
nip_dbg("checksum fail, drop 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;
+17 -4
View File
@@ -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;
}