Hi,

On Tue,  2 Jan 2018 17:30:20 +0100
Nicolai Stange <nsta...@suse.de> wrote:

> [...]
>
> diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
> index 5b9bd5c33d9d..e84290c28c0c 100644
> --- a/net/ipv4/raw.c
> +++ b/net/ipv4/raw.c
> @@ -513,16 +513,18 @@ static int raw_sendmsg(struct sock *sk, struct msghdr 
> *msg, size_t len)
>       int err;
>       struct ip_options_data opt_copy;
>       struct raw_frag_vec rfv;
> -     int hdrincl;
> +     int hdrincl, __hdrincl;
>  
>       err = -EMSGSIZE;
>       if (len > 0xFFFF)
>               goto out;
>  
>       /* hdrincl should be READ_ONCE(inet->hdrincl)
> -      * but READ_ONCE() doesn't work with bit fields
> +      * but READ_ONCE() doesn't work with bit fields.
> +      * Emulate it by doing the READ_ONCE() from an intermediate int.
>        */
> -     hdrincl = inet->hdrincl;
> +     __hdrincl = inet->hdrincl;
> +     hdrincl = READ_ONCE(__hdrincl);

I guess you don't actually need to use a third variable. What about
doing READ_ONCE() on hdrincl itself after the first assignment?

Perhaps something like the patch below -- applies to net.git, yields
same binary output as your version with gcc 6, looks IMHO more
straightforward:

diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 125c1eab3eaa..8c2f783a95fc 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -519,10 +519,12 @@ static int raw_sendmsg(struct sock *sk, struct msghdr 
*msg, size_t len)
        if (len > 0xFFFF)
                goto out;
 
-       /* hdrincl should be READ_ONCE(inet->hdrincl)
-        * but READ_ONCE() doesn't work with bit fields
+       /* hdrincl should be READ_ONCE(inet->hdrincl) but READ_ONCE() doesn't
+        * work with bit fields. Emulate it by adding a further sequence point.
         */
        hdrincl = inet->hdrincl;
+       hdrincl = READ_ONCE(hdrincl);
+
        /*
         *      Check the flags.
         */


-- 
Stefano

Reply via email to