diff options
author | Jonathan Solnit <jsolnit@google.com> | 2018-02-12 15:03:16 -0800 |
---|---|---|
committer | SecurityBot <android-nexus-securitybot@system.gserviceaccount.com> | 2018-02-13 12:58:26 -0800 |
commit | 880265248e34f7a2af7c85959395e3991db25714 (patch) | |
tree | b0ef8b22efba6fca3ff595d20c051c09471ae157 | |
parent | 796a90d274918b1e33c604e4239a1a8e91cdb862 (diff) | |
download | tegra-880265248e34f7a2af7c85959395e3991db25714.tar.gz |
BACKPORT: net: ipv4: fix for a race condition in raw_sendmsg
[ Upstream commit 8f659a03a0ba9289b9aeb9b4470e6fb263d6f483 ]
inet->hdrincl is racy, and could lead to uninitialized stack pointer
usage, so its value should be read only once.
Bug: 71500434
Change-Id: I4a8394725f3ef893311121b18a0e5b2f44124b1f
Fixes: c008ba5bdc9f ("ipv4: Avoid reading user iov twice after raw_probe_proto_opt")
Signed-off-by: Mohamed Ghannam <simo.ghannam@gmail.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Jonathan Solnit <jsolnit@google.com>
-rw-r--r-- | net/ipv4/raw.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index e5fae6bafe6f..e3c25045947e 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -480,11 +480,16 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, u8 tos; int err; struct ip_options_data opt_copy; + 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. */ @@ -557,7 +562,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) @@ -579,12 +584,12 @@ 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) | - (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), + (hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), daddr, saddr, 0, 0, sk->sk_uid); - if (!inet->hdrincl) { + if (!hdrincl) { err = raw_probe_proto_opt(&fl4, msg); if (err) goto done; @@ -606,7 +611,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); |