X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fraw.c;h=d73ccfa2d825e235d1a25181c0672f6bf8f007cc;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=e378ddcd8bd40e9fc3b575e56c7958a11cda85fd;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index e378ddcd8..d73ccfa2d 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -104,34 +104,23 @@ static void raw_v4_unhash(struct sock *sk) /* - Check if an address is in the list -*/ -static inline int raw_addr_in_list ( - u32 rcv_saddr1, - u32 rcv_saddr2, - u32 loc_addr, - struct nx_info *nx_info) -{ - int ret = 0; - if (loc_addr != 0 && - (rcv_saddr1 == loc_addr || rcv_saddr2 == loc_addr)) - ret = 1; - else if (rcv_saddr1 == 0) { - /* Accept any address or only the one in the list */ - if (nx_info == NULL) - ret = 1; - else { - int n = nx_info->nbipv4; - int i; - for (i=0; iipv4[i] == loc_addr) { - ret = 1; - break; - } - } - } - } - return ret; + * Check if a given address matches for a socket + * + * nxi: the socket's nx_info if any + * addr: to be verified address + * saddr/baddr: socket addresses + */ +static inline int raw_addr_match ( + struct nx_info *nxi, + uint32_t addr, + uint32_t saddr, + uint32_t baddr) +{ + if (addr && (saddr == addr || baddr == addr)) + return 1; + if (!saddr) + return addr_in_nx_info(nxi, addr); + return 0; } struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, @@ -145,8 +134,8 @@ struct sock *__raw_v4_lookup(struct sock *sk, unsigned short num, if (inet->num == num && !(inet->daddr && inet->daddr != raddr) && - raw_addr_in_list(inet->rcv_saddr, inet->rcv_saddr2, - laddr, sk->sk_nx_info) && + raw_addr_match(sk->sk_nx_info, laddr, + inet->rcv_saddr, inet->rcv_saddr2) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) goto found; /* gotcha */ } @@ -340,7 +329,7 @@ static int raw_send_hdrinc(struct sock *sk, void *from, int length, } err = -EPERM; if (!vx_check(0, VX_ADMIN) && !capable(CAP_NET_RAW) - && (!raw_addr_in_list(0, 0, iph->saddr, sk->sk_nx_info))) + && (!addr_in_nx_info(sk->sk_nx_info, iph->saddr))) goto error; err = NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, @@ -360,6 +349,51 @@ error: return err; } +static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) +{ + struct iovec *iov; + u8 __user *type = NULL; + u8 __user *code = NULL; + int probed = 0; + int i; + + if (!msg->msg_iov) + return; + + for (i = 0; i < msg->msg_iovlen; i++) { + iov = &msg->msg_iov[i]; + if (!iov) + continue; + + switch (fl->proto) { + case IPPROTO_ICMP: + /* check if one-byte field is readable or not. */ + if (iov->iov_base && iov->iov_len < 1) + break; + + 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; + + if (type && code) { + get_user(fl->fl_icmp_type, type); + __get_user(fl->fl_icmp_code, code); + probed = 1; + } + break; + default: + probed = 1; + break; + } + if (probed) + break; + } +} + static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { @@ -466,7 +500,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, .proto = inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, }; - + if (!inet->hdrincl) + raw_probe_proto_opt(&fl, msg); + if (sk->sk_nx_info) { err = ip_find_src(sk->sk_nx_info, &rt, &fl); @@ -715,6 +751,7 @@ struct proto raw_prot = { .backlog_rcv = raw_rcv_skb, .hash = raw_v4_hash, .unhash = raw_v4_unhash, + .slab_obj_size = sizeof(struct raw_sock), }; #ifdef CONFIG_PROC_FS