]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'nfsd-4.13-2' of git://linux-nfs.org/~bfields/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Aug 2017 00:27:26 +0000 (17:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 26 Aug 2017 00:27:26 +0000 (17:27 -0700)
Pull nfsd fixes from Bruce Fields:
 "Two nfsd bugfixes, neither 4.13 regressions, but both potentially
  serious"

* tag 'nfsd-4.13-2' of git://linux-nfs.org/~bfields/linux:
  net: sunrpc: svcsock: fix NULL-pointer exception
  nfsd: Limit end of page list when decoding NFSv4 WRITE

fs/nfsd/nfs4xdr.c
net/sunrpc/svcsock.c

index 20fbcab977531bee75501a9403f4c8f60ee404d4..5f940d2a136b72a8e5ffcbff2f094b9f0ebfdaa3 100644 (file)
@@ -144,7 +144,7 @@ static void next_decode_page(struct nfsd4_compoundargs *argp)
        argp->p = page_address(argp->pagelist[0]);
        argp->pagelist++;
        if (argp->pagelen < PAGE_SIZE) {
-               argp->end = argp->p + (argp->pagelen>>2);
+               argp->end = argp->p + XDR_QUADLEN(argp->pagelen);
                argp->pagelen = 0;
        } else {
                argp->end = argp->p + (PAGE_SIZE>>2);
@@ -1279,9 +1279,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
                argp->pagelen -= pages * PAGE_SIZE;
                len -= pages * PAGE_SIZE;
 
-               argp->p = (__be32 *)page_address(argp->pagelist[0]);
-               argp->pagelist++;
-               argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE);
+               next_decode_page(argp);
        }
        argp->p += XDR_QUADLEN(len);
 
index 2b720fa35c4ff7c2ae906e9e76d13d27a2b2f008..e18500151236ed3b162cebcf24966957e58be484 100644 (file)
@@ -421,6 +421,9 @@ static void svc_data_ready(struct sock *sk)
                dprintk("svc: socket %p(inet %p), busy=%d\n",
                        svsk, sk,
                        test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+
+               /* Refer to svc_setup_socket() for details. */
+               rmb();
                svsk->sk_odata(sk);
                if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
                        svc_xprt_enqueue(&svsk->sk_xprt);
@@ -437,6 +440,9 @@ static void svc_write_space(struct sock *sk)
        if (svsk) {
                dprintk("svc: socket %p(inet %p), write_space busy=%d\n",
                        svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags));
+
+               /* Refer to svc_setup_socket() for details. */
+               rmb();
                svsk->sk_owspace(sk);
                svc_xprt_enqueue(&svsk->sk_xprt);
        }
@@ -760,8 +766,12 @@ static void svc_tcp_listen_data_ready(struct sock *sk)
        dprintk("svc: socket %p TCP (listen) state change %d\n",
                sk, sk->sk_state);
 
-       if (svsk)
+       if (svsk) {
+               /* Refer to svc_setup_socket() for details. */
+               rmb();
                svsk->sk_odata(sk);
+       }
+
        /*
         * This callback may called twice when a new connection
         * is established as a child socket inherits everything
@@ -794,6 +804,8 @@ static void svc_tcp_state_change(struct sock *sk)
        if (!svsk)
                printk("svc: socket %p: no user data\n", sk);
        else {
+               /* Refer to svc_setup_socket() for details. */
+               rmb();
                svsk->sk_ostate(sk);
                if (sk->sk_state != TCP_ESTABLISHED) {
                        set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
@@ -1381,12 +1393,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
                return ERR_PTR(err);
        }
 
-       inet->sk_user_data = svsk;
        svsk->sk_sock = sock;
        svsk->sk_sk = inet;
        svsk->sk_ostate = inet->sk_state_change;
        svsk->sk_odata = inet->sk_data_ready;
        svsk->sk_owspace = inet->sk_write_space;
+       /*
+        * This barrier is necessary in order to prevent race condition
+        * with svc_data_ready(), svc_listen_data_ready() and others
+        * when calling callbacks above.
+        */
+       wmb();
+       inet->sk_user_data = svsk;
 
        /* Initialize the socket */
        if (sock->type == SOCK_DGRAM)