aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/inet_diag.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/inet_diag.c')
-rw-r--r--net/ipv4/inet_diag.c90
1 files changed, 33 insertions, 57 deletions
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 5df71cd08da8..dbeacd8b0f90 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -27,6 +27,7 @@
27#include <net/inet_hashtables.h> 27#include <net/inet_hashtables.h>
28#include <net/inet_timewait_sock.h> 28#include <net/inet_timewait_sock.h>
29#include <net/inet6_hashtables.h> 29#include <net/inet6_hashtables.h>
30#include <net/netlink.h>
30 31
31#include <linux/inet.h> 32#include <linux/inet.h>
32#include <linux/stddef.h> 33#include <linux/stddef.h>
@@ -60,7 +61,7 @@ static int inet_csk_diag_fill(struct sock *sk,
60 struct nlmsghdr *nlh; 61 struct nlmsghdr *nlh;
61 void *info = NULL; 62 void *info = NULL;
62 struct inet_diag_meminfo *minfo = NULL; 63 struct inet_diag_meminfo *minfo = NULL;
63 unsigned char *b = skb->tail; 64 unsigned char *b = skb_tail_pointer(skb);
64 const struct inet_diag_handler *handler; 65 const struct inet_diag_handler *handler;
65 66
66 handler = inet_diag_table[unlh->nlmsg_type]; 67 handler = inet_diag_table[unlh->nlmsg_type];
@@ -147,12 +148,12 @@ static int inet_csk_diag_fill(struct sock *sk,
147 icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info) 148 icsk->icsk_ca_ops && icsk->icsk_ca_ops->get_info)
148 icsk->icsk_ca_ops->get_info(sk, ext, skb); 149 icsk->icsk_ca_ops->get_info(sk, ext, skb);
149 150
150 nlh->nlmsg_len = skb->tail - b; 151 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
151 return skb->len; 152 return skb->len;
152 153
153rtattr_failure: 154rtattr_failure:
154nlmsg_failure: 155nlmsg_failure:
155 skb_trim(skb, b - skb->data); 156 nlmsg_trim(skb, b);
156 return -EMSGSIZE; 157 return -EMSGSIZE;
157} 158}
158 159
@@ -163,7 +164,7 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
163{ 164{
164 long tmo; 165 long tmo;
165 struct inet_diag_msg *r; 166 struct inet_diag_msg *r;
166 const unsigned char *previous_tail = skb->tail; 167 const unsigned char *previous_tail = skb_tail_pointer(skb);
167 struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq, 168 struct nlmsghdr *nlh = NLMSG_PUT(skb, pid, seq,
168 unlh->nlmsg_type, sizeof(*r)); 169 unlh->nlmsg_type, sizeof(*r));
169 170
@@ -205,10 +206,10 @@ static int inet_twsk_diag_fill(struct inet_timewait_sock *tw,
205 &tw6->tw_v6_daddr); 206 &tw6->tw_v6_daddr);
206 } 207 }
207#endif 208#endif
208 nlh->nlmsg_len = skb->tail - previous_tail; 209 nlh->nlmsg_len = skb_tail_pointer(skb) - previous_tail;
209 return skb->len; 210 return skb->len;
210nlmsg_failure: 211nlmsg_failure:
211 skb_trim(skb, previous_tail - skb->data); 212 nlmsg_trim(skb, previous_tail);
212 return -EMSGSIZE; 213 return -EMSGSIZE;
213} 214}
214 215
@@ -535,7 +536,7 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
535{ 536{
536 const struct inet_request_sock *ireq = inet_rsk(req); 537 const struct inet_request_sock *ireq = inet_rsk(req);
537 struct inet_sock *inet = inet_sk(sk); 538 struct inet_sock *inet = inet_sk(sk);
538 unsigned char *b = skb->tail; 539 unsigned char *b = skb_tail_pointer(skb);
539 struct inet_diag_msg *r; 540 struct inet_diag_msg *r;
540 struct nlmsghdr *nlh; 541 struct nlmsghdr *nlh;
541 long tmo; 542 long tmo;
@@ -574,12 +575,12 @@ static int inet_diag_fill_req(struct sk_buff *skb, struct sock *sk,
574 &inet6_rsk(req)->rmt_addr); 575 &inet6_rsk(req)->rmt_addr);
575 } 576 }
576#endif 577#endif
577 nlh->nlmsg_len = skb->tail - b; 578 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
578 579
579 return skb->len; 580 return skb->len;
580 581
581nlmsg_failure: 582nlmsg_failure:
582 skb_trim(skb, b - skb->data); 583 nlmsg_trim(skb, b);
583 return -1; 584 return -1;
584} 585}
585 586
@@ -805,68 +806,43 @@ done:
805 return skb->len; 806 return skb->len;
806} 807}
807 808
808static inline int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 809static int inet_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
809{ 810{
810 if (!(nlh->nlmsg_flags&NLM_F_REQUEST)) 811 int hdrlen = sizeof(struct inet_diag_req);
811 return 0;
812 812
813 if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX) 813 if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX ||
814 goto err_inval; 814 nlmsg_len(nlh) < hdrlen)
815 return -EINVAL;
815 816
816 if (inet_diag_table[nlh->nlmsg_type] == NULL) 817 if (inet_diag_table[nlh->nlmsg_type] == NULL)
817 return -ENOENT; 818 return -ENOENT;
818 819
819 if (NLMSG_LENGTH(sizeof(struct inet_diag_req)) > skb->len) 820 if (nlh->nlmsg_flags & NLM_F_DUMP) {
820 goto err_inval; 821 if (nlmsg_attrlen(nlh, hdrlen)) {
821 822 struct nlattr *attr;
822 if (nlh->nlmsg_flags&NLM_F_DUMP) { 823
823 if (nlh->nlmsg_len > 824 attr = nlmsg_find_attr(nlh, hdrlen,
824 (4 + NLMSG_SPACE(sizeof(struct inet_diag_req)))) { 825 INET_DIAG_REQ_BYTECODE);
825 struct rtattr *rta = (void *)(NLMSG_DATA(nlh) + 826 if (attr == NULL ||
826 sizeof(struct inet_diag_req)); 827 nla_len(attr) < sizeof(struct inet_diag_bc_op) ||
827 if (rta->rta_type != INET_DIAG_REQ_BYTECODE || 828 inet_diag_bc_audit(nla_data(attr), nla_len(attr)))
828 rta->rta_len < 8 || 829 return -EINVAL;
829 rta->rta_len >
830 (nlh->nlmsg_len -
831 NLMSG_SPACE(sizeof(struct inet_diag_req))))
832 goto err_inval;
833 if (inet_diag_bc_audit(RTA_DATA(rta), RTA_PAYLOAD(rta)))
834 goto err_inval;
835 } 830 }
831
836 return netlink_dump_start(idiagnl, skb, nlh, 832 return netlink_dump_start(idiagnl, skb, nlh,
837 inet_diag_dump, NULL); 833 inet_diag_dump, NULL);
838 } else
839 return inet_diag_get_exact(skb, nlh);
840
841err_inval:
842 return -EINVAL;
843}
844
845
846static inline void inet_diag_rcv_skb(struct sk_buff *skb)
847{
848 if (skb->len >= NLMSG_SPACE(0)) {
849 int err;
850 struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
851
852 if (nlh->nlmsg_len < sizeof(*nlh) ||
853 skb->len < nlh->nlmsg_len)
854 return;
855 err = inet_diag_rcv_msg(skb, nlh);
856 if (err || nlh->nlmsg_flags & NLM_F_ACK)
857 netlink_ack(skb, nlh, err);
858 } 834 }
835
836 return inet_diag_get_exact(skb, nlh);
859} 837}
860 838
861static void inet_diag_rcv(struct sock *sk, int len) 839static void inet_diag_rcv(struct sock *sk, int len)
862{ 840{
863 struct sk_buff *skb; 841 unsigned int qlen = 0;
864 unsigned int qlen = skb_queue_len(&sk->sk_receive_queue);
865 842
866 while (qlen-- && (skb = skb_dequeue(&sk->sk_receive_queue))) { 843 do {
867 inet_diag_rcv_skb(skb); 844 netlink_run_queue(sk, &qlen, &inet_diag_rcv_msg);
868 kfree_skb(skb); 845 } while (qlen);
869 }
870} 846}
871 847
872static DEFINE_SPINLOCK(inet_diag_register_lock); 848static DEFINE_SPINLOCK(inet_diag_register_lock);
@@ -917,7 +893,7 @@ static int __init inet_diag_init(void)
917 goto out; 893 goto out;
918 894
919 idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, 0, inet_diag_rcv, 895 idiagnl = netlink_kernel_create(NETLINK_INET_DIAG, 0, inet_diag_rcv,
920 THIS_MODULE); 896 NULL, THIS_MODULE);
921 if (idiagnl == NULL) 897 if (idiagnl == NULL)
922 goto out_free_table; 898 goto out_free_table;
923 err = 0; 899 err = 0;