diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-08-25 20:27:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-08-25 20:27:26 -0400 |
commit | 105065c3f7164d756ee5495b8670e57f2bcf65c3 (patch) | |
tree | d0cf33dfc3f01f8dc596329844dcc695f4d079b5 | |
parent | 8c7932a32e1ebf6e845bd32a5399cce442d2e745 (diff) | |
parent | eebe53e87f97975ee58a21693e44797608bf679c (diff) |
Merge tag 'nfsd-4.13-2' of git://linux-nfs.org/~bfields/linux
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
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 6 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 22 |
2 files changed, 22 insertions, 6 deletions
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 20fbcab97753..5f940d2a136b 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -144,7 +144,7 @@ static void next_decode_page(struct nfsd4_compoundargs *argp) | |||
144 | argp->p = page_address(argp->pagelist[0]); | 144 | argp->p = page_address(argp->pagelist[0]); |
145 | argp->pagelist++; | 145 | argp->pagelist++; |
146 | if (argp->pagelen < PAGE_SIZE) { | 146 | if (argp->pagelen < PAGE_SIZE) { |
147 | argp->end = argp->p + (argp->pagelen>>2); | 147 | argp->end = argp->p + XDR_QUADLEN(argp->pagelen); |
148 | argp->pagelen = 0; | 148 | argp->pagelen = 0; |
149 | } else { | 149 | } else { |
150 | argp->end = argp->p + (PAGE_SIZE>>2); | 150 | argp->end = argp->p + (PAGE_SIZE>>2); |
@@ -1279,9 +1279,7 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) | |||
1279 | argp->pagelen -= pages * PAGE_SIZE; | 1279 | argp->pagelen -= pages * PAGE_SIZE; |
1280 | len -= pages * PAGE_SIZE; | 1280 | len -= pages * PAGE_SIZE; |
1281 | 1281 | ||
1282 | argp->p = (__be32 *)page_address(argp->pagelist[0]); | 1282 | next_decode_page(argp); |
1283 | argp->pagelist++; | ||
1284 | argp->end = argp->p + XDR_QUADLEN(PAGE_SIZE); | ||
1285 | } | 1283 | } |
1286 | argp->p += XDR_QUADLEN(len); | 1284 | argp->p += XDR_QUADLEN(len); |
1287 | 1285 | ||
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 2b720fa35c4f..e18500151236 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -421,6 +421,9 @@ static void svc_data_ready(struct sock *sk) | |||
421 | dprintk("svc: socket %p(inet %p), busy=%d\n", | 421 | dprintk("svc: socket %p(inet %p), busy=%d\n", |
422 | svsk, sk, | 422 | svsk, sk, |
423 | test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags)); | 423 | test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags)); |
424 | |||
425 | /* Refer to svc_setup_socket() for details. */ | ||
426 | rmb(); | ||
424 | svsk->sk_odata(sk); | 427 | svsk->sk_odata(sk); |
425 | if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags)) | 428 | if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags)) |
426 | svc_xprt_enqueue(&svsk->sk_xprt); | 429 | svc_xprt_enqueue(&svsk->sk_xprt); |
@@ -437,6 +440,9 @@ static void svc_write_space(struct sock *sk) | |||
437 | if (svsk) { | 440 | if (svsk) { |
438 | dprintk("svc: socket %p(inet %p), write_space busy=%d\n", | 441 | dprintk("svc: socket %p(inet %p), write_space busy=%d\n", |
439 | svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags)); | 442 | svsk, sk, test_bit(XPT_BUSY, &svsk->sk_xprt.xpt_flags)); |
443 | |||
444 | /* Refer to svc_setup_socket() for details. */ | ||
445 | rmb(); | ||
440 | svsk->sk_owspace(sk); | 446 | svsk->sk_owspace(sk); |
441 | svc_xprt_enqueue(&svsk->sk_xprt); | 447 | svc_xprt_enqueue(&svsk->sk_xprt); |
442 | } | 448 | } |
@@ -760,8 +766,12 @@ static void svc_tcp_listen_data_ready(struct sock *sk) | |||
760 | dprintk("svc: socket %p TCP (listen) state change %d\n", | 766 | dprintk("svc: socket %p TCP (listen) state change %d\n", |
761 | sk, sk->sk_state); | 767 | sk, sk->sk_state); |
762 | 768 | ||
763 | if (svsk) | 769 | if (svsk) { |
770 | /* Refer to svc_setup_socket() for details. */ | ||
771 | rmb(); | ||
764 | svsk->sk_odata(sk); | 772 | svsk->sk_odata(sk); |
773 | } | ||
774 | |||
765 | /* | 775 | /* |
766 | * This callback may called twice when a new connection | 776 | * This callback may called twice when a new connection |
767 | * is established as a child socket inherits everything | 777 | * is established as a child socket inherits everything |
@@ -794,6 +804,8 @@ static void svc_tcp_state_change(struct sock *sk) | |||
794 | if (!svsk) | 804 | if (!svsk) |
795 | printk("svc: socket %p: no user data\n", sk); | 805 | printk("svc: socket %p: no user data\n", sk); |
796 | else { | 806 | else { |
807 | /* Refer to svc_setup_socket() for details. */ | ||
808 | rmb(); | ||
797 | svsk->sk_ostate(sk); | 809 | svsk->sk_ostate(sk); |
798 | if (sk->sk_state != TCP_ESTABLISHED) { | 810 | if (sk->sk_state != TCP_ESTABLISHED) { |
799 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); | 811 | set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags); |
@@ -1381,12 +1393,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, | |||
1381 | return ERR_PTR(err); | 1393 | return ERR_PTR(err); |
1382 | } | 1394 | } |
1383 | 1395 | ||
1384 | inet->sk_user_data = svsk; | ||
1385 | svsk->sk_sock = sock; | 1396 | svsk->sk_sock = sock; |
1386 | svsk->sk_sk = inet; | 1397 | svsk->sk_sk = inet; |
1387 | svsk->sk_ostate = inet->sk_state_change; | 1398 | svsk->sk_ostate = inet->sk_state_change; |
1388 | svsk->sk_odata = inet->sk_data_ready; | 1399 | svsk->sk_odata = inet->sk_data_ready; |
1389 | svsk->sk_owspace = inet->sk_write_space; | 1400 | svsk->sk_owspace = inet->sk_write_space; |
1401 | /* | ||
1402 | * This barrier is necessary in order to prevent race condition | ||
1403 | * with svc_data_ready(), svc_listen_data_ready() and others | ||
1404 | * when calling callbacks above. | ||
1405 | */ | ||
1406 | wmb(); | ||
1407 | inet->sk_user_data = svsk; | ||
1390 | 1408 | ||
1391 | /* Initialize the socket */ | 1409 | /* Initialize the socket */ |
1392 | if (sock->type == SOCK_DGRAM) | 1410 | if (sock->type == SOCK_DGRAM) |