From: Mohamed Ghannam Date: Sun, 10 Dec 2017 03:50:58 +0000 (+0000) Subject: net: ipv4: fix for a race condition in raw_sendmsg X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=commitdiff_plain;h=8eec37d0e9039d5fbfc400324a06793b21ff24cd net: ipv4: fix for a race condition in raw_sendmsg commit 8f659a03a0ba9289b9aeb9b4470e6fb263d6f483 upstream. inet->hdrincl is racy, and could lead to uninitialized stack pointer usage, so its value should be read only once. Fixes: c008ba5bdc9f ("ipv4: Avoid reading user iov twice after raw_probe_proto_opt") Signed-off-by: Mohamed Ghannam Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller [bwh: Backported to 3.2: - flowi4 flags don't depend on hdrincl - Adjust context] Signed-off-by: Ben Hutchings --- diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index f250aa7bf5e9..a02d3cdd05e0 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -484,11 +484,16 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int err; struct ip_options_data opt_copy; struct raw_frag_vec rfv; + int hdrincl; err = -EMSGSIZE; if (len > 0xFFFF) goto out; + /* hdrincl should be READ_ONCE(inet->hdrincl) + * but READ_ONCE() doesn't work with bit fields + */ + hdrincl = inet->hdrincl; /* * Check the flags. */ @@ -564,7 +569,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, /* Linux does not mangle headers on raw sockets, * so that IP options + IP_HDRINCL is non-sense. */ - if (inet->hdrincl) + if (hdrincl) goto done; if (ipc.opt->opt.srr) { if (!daddr) @@ -585,11 +590,11 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, + hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); - if (!inet->hdrincl) { + if (!hdrincl) { rfv.iov = msg->msg_iov; rfv.hlen = 0; @@ -614,7 +619,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, goto do_confirm; back_from_confirm: - if (inet->hdrincl) + if (hdrincl) err = raw_send_hdrinc(sk, &fl4, msg->msg_iov, len, &rt, msg->msg_flags);