mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
Merge branch 'raw_probe_proto_opt'
Herbert Xu says: ==================== ipv4: Simplify raw_probe_proto_opt and avoid reading user iov twice This series rewrites the function raw_probe_proto_opt in a more readable fasion, and then fixes the long-standing bug where we read the probed bytes twice which means that what we're using to probe may in fact be invalid. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
e344458fc0
@ -79,6 +79,16 @@
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter_ipv4.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/uio.h>
|
||||
|
||||
struct raw_frag_vec {
|
||||
struct iovec *iov;
|
||||
union {
|
||||
struct icmphdr icmph;
|
||||
char c[1];
|
||||
} hdr;
|
||||
int hlen;
|
||||
};
|
||||
|
||||
static struct raw_hashinfo raw_v4_hashinfo = {
|
||||
.lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock),
|
||||
@ -420,53 +430,57 @@ error:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int raw_probe_proto_opt(struct flowi4 *fl4, struct msghdr *msg)
|
||||
static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4)
|
||||
{
|
||||
struct iovec *iov;
|
||||
u8 __user *type = NULL;
|
||||
u8 __user *code = NULL;
|
||||
int probed = 0;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
if (!msg->msg_iov)
|
||||
if (fl4->flowi4_proto != IPPROTO_ICMP)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < msg->msg_iovlen; i++) {
|
||||
iov = &msg->msg_iov[i];
|
||||
if (!iov)
|
||||
continue;
|
||||
/* We only need the first two bytes. */
|
||||
rfv->hlen = 2;
|
||||
|
||||
switch (fl4->flowi4_proto) {
|
||||
case IPPROTO_ICMP:
|
||||
/* check if one-byte field is readable or not. */
|
||||
if (iov->iov_base && iov->iov_len < 1)
|
||||
break;
|
||||
err = memcpy_fromiovec(rfv->hdr.c, rfv->iov, rfv->hlen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!type) {
|
||||
type = iov->iov_base;
|
||||
/* check if code field is readable or not. */
|
||||
if (iov->iov_len > 1)
|
||||
code = type + 1;
|
||||
} else if (!code)
|
||||
code = iov->iov_base;
|
||||
fl4->fl4_icmp_type = rfv->hdr.icmph.type;
|
||||
fl4->fl4_icmp_code = rfv->hdr.icmph.code;
|
||||
|
||||
if (type && code) {
|
||||
if (get_user(fl4->fl4_icmp_type, type) ||
|
||||
get_user(fl4->fl4_icmp_code, code))
|
||||
return -EFAULT;
|
||||
probed = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
probed = 1;
|
||||
break;
|
||||
}
|
||||
if (probed)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_getfrag(void *from, char *to, int offset, int len, int odd,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct raw_frag_vec *rfv = from;
|
||||
|
||||
if (offset < rfv->hlen) {
|
||||
int copy = min(rfv->hlen - offset, len);
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||
memcpy(to, rfv->hdr.c + offset, copy);
|
||||
else
|
||||
skb->csum = csum_block_add(
|
||||
skb->csum,
|
||||
csum_partial_copy_nocheck(rfv->hdr.c + offset,
|
||||
to, copy, 0),
|
||||
odd);
|
||||
|
||||
odd = 0;
|
||||
offset += copy;
|
||||
to += copy;
|
||||
len -= copy;
|
||||
|
||||
if (!len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
offset -= rfv->hlen;
|
||||
|
||||
return ip_generic_getfrag(rfv->iov, to, offset, len, odd, skb);
|
||||
}
|
||||
|
||||
static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
size_t len)
|
||||
{
|
||||
@ -480,6 +494,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
u8 tos;
|
||||
int err;
|
||||
struct ip_options_data opt_copy;
|
||||
struct raw_frag_vec rfv;
|
||||
|
||||
err = -EMSGSIZE;
|
||||
if (len > 0xFFFF)
|
||||
@ -585,7 +600,10 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
daddr, saddr, 0, 0);
|
||||
|
||||
if (!inet->hdrincl) {
|
||||
err = raw_probe_proto_opt(&fl4, msg);
|
||||
rfv.iov = msg->msg_iov;
|
||||
rfv.hlen = 0;
|
||||
|
||||
err = raw_probe_proto_opt(&rfv, &fl4);
|
||||
if (err)
|
||||
goto done;
|
||||
}
|
||||
@ -616,8 +634,8 @@ back_from_confirm:
|
||||
if (!ipc.addr)
|
||||
ipc.addr = fl4.daddr;
|
||||
lock_sock(sk);
|
||||
err = ip_append_data(sk, &fl4, ip_generic_getfrag,
|
||||
msg->msg_iov, len, 0,
|
||||
err = ip_append_data(sk, &fl4, raw_getfrag,
|
||||
&rfv, len, 0,
|
||||
&ipc, &rt, msg->msg_flags);
|
||||
if (err)
|
||||
ip_flush_pending_frames(sk);
|
||||
|
Loading…
x
Reference in New Issue
Block a user