Skip to content

Commit 19e3c66

Browse files
author
Al Viro
committed
ipv6 equivalent of "ipv4: Avoid reading user iov twice after raw_probe_proto_opt"
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
1 parent b61e9dc commit 19e3c66

File tree

1 file changed

+56
-56
lines changed

1 file changed

+56
-56
lines changed

net/ipv6/raw.c

Lines changed: 56 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -672,65 +672,62 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
672672
return err;
673673
}
674674

675-
static int rawv6_probe_proto_opt(struct flowi6 *fl6, struct msghdr *msg)
675+
struct raw6_frag_vec {
676+
struct msghdr *msg;
677+
int hlen;
678+
char c[4];
679+
};
680+
681+
static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6)
676682
{
677-
struct iovec *iov;
678-
u8 __user *type = NULL;
679-
u8 __user *code = NULL;
680-
u8 len = 0;
681-
int probed = 0;
682-
int i;
683-
684-
if (!msg->msg_iov)
685-
return 0;
683+
int err = 0;
684+
switch (fl6->flowi6_proto) {
685+
case IPPROTO_ICMPV6:
686+
rfv->hlen = 2;
687+
err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
688+
if (!err) {
689+
fl6->fl6_icmp_type = rfv->c[0];
690+
fl6->fl6_icmp_code = rfv->c[1];
691+
}
692+
break;
693+
case IPPROTO_MH:
694+
rfv->hlen = 4;
695+
err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen);
696+
if (!err)
697+
fl6->fl6_mh_type = rfv->c[2];
698+
}
699+
return err;
700+
}
686701

687-
for (i = 0; i < msg->msg_iovlen; i++) {
688-
iov = &msg->msg_iov[i];
689-
if (!iov)
690-
continue;
702+
static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
703+
struct sk_buff *skb)
704+
{
705+
struct raw6_frag_vec *rfv = from;
691706

692-
switch (fl6->flowi6_proto) {
693-
case IPPROTO_ICMPV6:
694-
/* check if one-byte field is readable or not. */
695-
if (iov->iov_base && iov->iov_len < 1)
696-
break;
697-
698-
if (!type) {
699-
type = iov->iov_base;
700-
/* check if code field is readable or not. */
701-
if (iov->iov_len > 1)
702-
code = type + 1;
703-
} else if (!code)
704-
code = iov->iov_base;
705-
706-
if (type && code) {
707-
if (get_user(fl6->fl6_icmp_type, type) ||
708-
get_user(fl6->fl6_icmp_code, code))
709-
return -EFAULT;
710-
probed = 1;
711-
}
712-
break;
713-
case IPPROTO_MH:
714-
if (iov->iov_base && iov->iov_len < 1)
715-
break;
716-
/* check if type field is readable or not. */
717-
if (iov->iov_len > 2 - len) {
718-
u8 __user *p = iov->iov_base;
719-
if (get_user(fl6->fl6_mh_type, &p[2 - len]))
720-
return -EFAULT;
721-
probed = 1;
722-
} else
723-
len += iov->iov_len;
707+
if (offset < rfv->hlen) {
708+
int copy = min(rfv->hlen - offset, len);
724709

725-
break;
726-
default:
727-
probed = 1;
728-
break;
729-
}
730-
if (probed)
731-
break;
710+
if (skb->ip_summed == CHECKSUM_PARTIAL)
711+
memcpy(to, rfv->c + offset, copy);
712+
else
713+
skb->csum = csum_block_add(
714+
skb->csum,
715+
csum_partial_copy_nocheck(rfv->c + offset,
716+
to, copy, 0),
717+
odd);
718+
719+
odd = 0;
720+
offset += copy;
721+
to += copy;
722+
len -= copy;
723+
724+
if (!len)
725+
return 0;
732726
}
733-
return 0;
727+
728+
offset -= rfv->hlen;
729+
730+
return ip_generic_getfrag(rfv->msg->msg_iov, to, offset, len, odd, skb);
734731
}
735732

736733
static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
@@ -745,6 +742,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
745742
struct ipv6_txoptions *opt = NULL;
746743
struct ip6_flowlabel *flowlabel = NULL;
747744
struct dst_entry *dst = NULL;
745+
struct raw6_frag_vec rfv;
748746
struct flowi6 fl6;
749747
int addr_len = msg->msg_namelen;
750748
int hlimit = -1;
@@ -848,7 +846,9 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
848846
opt = ipv6_fixup_options(&opt_space, opt);
849847

850848
fl6.flowi6_proto = proto;
851-
err = rawv6_probe_proto_opt(&fl6, msg);
849+
rfv.msg = msg;
850+
rfv.hlen = 0;
851+
err = rawv6_probe_proto_opt(&rfv, &fl6);
852852
if (err)
853853
goto out;
854854

@@ -889,7 +889,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
889889
err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl6, &dst, msg->msg_flags);
890890
else {
891891
lock_sock(sk);
892-
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov,
892+
err = ip6_append_data(sk, raw6_getfrag, &rfv,
893893
len, 0, hlimit, tclass, opt, &fl6, (struct rt6_info *)dst,
894894
msg->msg_flags, dontfrag);
895895

0 commit comments

Comments
 (0)