2017-08-01 15:59:43

by Chuck Lever III

[permalink] [raw]
Subject: [PATCH v1 0/4] NFS server clean ups for v4.14

Hi Bruce-

Follow-on to Christoph's const-ification of the proc arrays, and a
clean-up suggested by Dan Carpenter. More to come.

---

Chuck Lever (4):
sunrpc: Const-ify instances of struct svc_xprt_ops
nfsd: Const-ify NFSv4 encoding and decoding ops arrays
sunrpc: Const-ify struct sv_serv_ops
svcrdma: Clean up svc_rdma_build_read_chunk()


fs/lockd/svc.c | 2 +-
fs/nfs/callback.c | 10 +++++-----
fs/nfsd/nfs4xdr.c | 4 ++--
fs/nfsd/nfssvc.c | 2 +-
include/linux/sunrpc/svc.h | 6 +++---
include/linux/sunrpc/svc_xprt.h | 4 ++--
net/sunrpc/svc.c | 6 +++---
net/sunrpc/svcsock.c | 6 +++---
net/sunrpc/xprtrdma/svc_rdma_rw.c | 8 +++++---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 4 ++--
10 files changed, 27 insertions(+), 25 deletions(-)

--
Chuck Lever


2017-08-01 16:00:16

by Chuck Lever III

[permalink] [raw]
Subject: [PATCH v1 4/4] svcrdma: Clean up svc_rdma_build_read_chunk()

Dan Carpenter <[email protected]> observed that the while()
loop in svc_rdma_build_read_chunk() does not document the assumption
that the loop interior is always executed at least once.

Defensive: the function now returns -EINVAL if this assumption
fails.

Suggested-by: Dan Carpenter <[email protected]>
Signed-off-by: Chuck Lever <[email protected]>
---
net/sunrpc/xprtrdma/svc_rdma_rw.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/xprtrdma/svc_rdma_rw.c b/net/sunrpc/xprtrdma/svc_rdma_rw.c
index 933f79b..1f34fae 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_rw.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_rw.c
@@ -660,19 +660,21 @@ static int svc_rdma_build_read_segment(struct svc_rdma_read_info *info,
return -EIO;
}

+/* Walk the segments in the Read chunk starting at @p and construct
+ * RDMA Read operations to pull the chunk to the server.
+ */
static int svc_rdma_build_read_chunk(struct svc_rqst *rqstp,
struct svc_rdma_read_info *info,
__be32 *p)
{
int ret;

+ ret = -EINVAL;
info->ri_chunklen = 0;
- while (*p++ != xdr_zero) {
+ while (*p++ != xdr_zero && be32_to_cpup(p++) == info->ri_position) {
u32 rs_handle, rs_length;
u64 rs_offset;

- if (be32_to_cpup(p++) != info->ri_position)
- break;
rs_handle = be32_to_cpup(p++);
rs_length = be32_to_cpup(p++);
p = xdr_decode_hyper(p, &rs_offset);


2017-08-01 15:59:51

by Chuck Lever III

[permalink] [raw]
Subject: [PATCH v1 1/4] sunrpc: Const-ify instances of struct svc_xprt_ops

Close an attack vector by moving the arrays of server-side transport
methods to read-only memory.

Signed-off-by: Chuck Lever <[email protected]>
---
include/linux/sunrpc/svc_xprt.h | 4 ++--
net/sunrpc/svcsock.c | 6 +++---
net/sunrpc/xprtrdma/svc_rdma_transport.c | 4 ++--
3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h
index ddb7f94..6a2ad38 100644
--- a/include/linux/sunrpc/svc_xprt.h
+++ b/include/linux/sunrpc/svc_xprt.h
@@ -31,7 +31,7 @@ struct svc_xprt_ops {
struct svc_xprt_class {
const char *xcl_name;
struct module *xcl_owner;
- struct svc_xprt_ops *xcl_ops;
+ const struct svc_xprt_ops *xcl_ops;
struct list_head xcl_list;
u32 xcl_max_payload;
int xcl_ident;
@@ -49,7 +49,7 @@ struct svc_xpt_user {

struct svc_xprt {
struct svc_xprt_class *xpt_class;
- struct svc_xprt_ops *xpt_ops;
+ const struct svc_xprt_ops *xpt_ops;
struct kref xpt_ref;
struct list_head xpt_list;
struct list_head xpt_ready;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 2b720fa..b434f52 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -687,7 +687,7 @@ static struct svc_xprt *svc_udp_create(struct svc_serv *serv,
return svc_create_socket(serv, IPPROTO_UDP, net, sa, salen, flags);
}

-static struct svc_xprt_ops svc_udp_ops = {
+static const struct svc_xprt_ops svc_udp_ops = {
.xpo_create = svc_udp_create,
.xpo_recvfrom = svc_udp_recvfrom,
.xpo_sendto = svc_udp_sendto,
@@ -1229,7 +1229,7 @@ static void svc_bc_tcp_sock_detach(struct svc_xprt *xprt)
{
}

-static struct svc_xprt_ops svc_tcp_bc_ops = {
+static const struct svc_xprt_ops svc_tcp_bc_ops = {
.xpo_create = svc_bc_tcp_create,
.xpo_detach = svc_bc_tcp_sock_detach,
.xpo_free = svc_bc_sock_free,
@@ -1263,7 +1263,7 @@ static void svc_cleanup_bc_xprt_sock(void)
}
#endif /* CONFIG_SUNRPC_BACKCHANNEL */

-static struct svc_xprt_ops svc_tcp_ops = {
+static const struct svc_xprt_ops svc_tcp_ops = {
.xpo_create = svc_tcp_create,
.xpo_recvfrom = svc_tcp_recvfrom,
.xpo_sendto = svc_tcp_sendto,
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index e660d49..2aa8473 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -70,7 +70,7 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
static int svc_rdma_secure_port(struct svc_rqst *);
static void svc_rdma_kill_temp_xprt(struct svc_xprt *);

-static struct svc_xprt_ops svc_rdma_ops = {
+static const struct svc_xprt_ops svc_rdma_ops = {
.xpo_create = svc_rdma_create,
.xpo_recvfrom = svc_rdma_recvfrom,
.xpo_sendto = svc_rdma_sendto,
@@ -98,7 +98,7 @@ static struct svc_xprt *svc_rdma_bc_create(struct svc_serv *, struct net *,
static void svc_rdma_bc_detach(struct svc_xprt *);
static void svc_rdma_bc_free(struct svc_xprt *);

-static struct svc_xprt_ops svc_rdma_bc_ops = {
+static const struct svc_xprt_ops svc_rdma_bc_ops = {
.xpo_create = svc_rdma_bc_create,
.xpo_detach = svc_rdma_bc_detach,
.xpo_free = svc_rdma_bc_free,


2017-08-01 16:00:08

by Chuck Lever III

[permalink] [raw]
Subject: [PATCH v1 3/4] sunrpc: Const-ify struct sv_serv_ops

Close an attack vector by moving the arrays of per-server methods to
read-only memory.

Signed-off-by: Chuck Lever <[email protected]>
---
fs/lockd/svc.c | 2 +-
fs/nfs/callback.c | 10 +++++-----
fs/nfsd/nfssvc.c | 2 +-
include/linux/sunrpc/svc.h | 6 +++---
net/sunrpc/svc.c | 6 +++---
5 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 726b6ce..b995bdc 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -396,7 +396,7 @@ static int lockd_start_svc(struct svc_serv *serv)
return error;
}

-static struct svc_serv_ops lockd_sv_ops = {
+static const struct svc_serv_ops lockd_sv_ops = {
.svo_shutdown = svc_rpcb_cleanup,
.svo_enqueue_xprt = svc_xprt_do_enqueue,
};
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 3432387..2cddf7f 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -226,26 +226,26 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
return ret;
}

-static struct svc_serv_ops nfs40_cb_sv_ops = {
+static const struct svc_serv_ops nfs40_cb_sv_ops = {
.svo_function = nfs4_callback_svc,
.svo_enqueue_xprt = svc_xprt_do_enqueue,
.svo_setup = svc_set_num_threads_sync,
.svo_module = THIS_MODULE,
};
#if defined(CONFIG_NFS_V4_1)
-static struct svc_serv_ops nfs41_cb_sv_ops = {
+static const struct svc_serv_ops nfs41_cb_sv_ops = {
.svo_function = nfs41_callback_svc,
.svo_enqueue_xprt = svc_xprt_do_enqueue,
.svo_setup = svc_set_num_threads_sync,
.svo_module = THIS_MODULE,
};

-static struct svc_serv_ops *nfs4_cb_sv_ops[] = {
+static const struct svc_serv_ops *nfs4_cb_sv_ops[] = {
[0] = &nfs40_cb_sv_ops,
[1] = &nfs41_cb_sv_ops,
};
#else
-static struct svc_serv_ops *nfs4_cb_sv_ops[] = {
+static const struct svc_serv_ops *nfs4_cb_sv_ops[] = {
[0] = &nfs40_cb_sv_ops,
[1] = NULL,
};
@@ -254,8 +254,8 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
static struct svc_serv *nfs_callback_create_svc(int minorversion)
{
struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion];
+ const struct svc_serv_ops *sv_ops;
struct svc_serv *serv;
- struct svc_serv_ops *sv_ops;

/*
* Check whether we're already up and running.
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 063ae7d..7e3af3e 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -475,7 +475,7 @@ static int nfsd_get_default_max_blksize(void)
return ret;
}

-static struct svc_serv_ops nfsd_thread_sv_ops = {
+static const struct svc_serv_ops nfsd_thread_sv_ops = {
.svo_shutdown = nfsd_last_thread,
.svo_function = nfsd,
.svo_enqueue_xprt = svc_xprt_do_enqueue,
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index a3f8af9..38f561b 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -99,7 +99,7 @@ struct svc_serv {

unsigned int sv_nrpools; /* number of thread pools */
struct svc_pool * sv_pools; /* array of thread pools */
- struct svc_serv_ops *sv_ops; /* server operations */
+ const struct svc_serv_ops *sv_ops; /* server operations */
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
struct list_head sv_cb_list; /* queue for callback requests
* that arrive over the same
@@ -465,7 +465,7 @@ struct svc_pool_map {
void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
int svc_bind(struct svc_serv *serv, struct net *net);
struct svc_serv *svc_create(struct svc_program *, unsigned int,
- struct svc_serv_ops *);
+ const struct svc_serv_ops *);
struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv,
struct svc_pool *pool, int node);
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
@@ -475,7 +475,7 @@ struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
unsigned int svc_pool_map_get(void);
void svc_pool_map_put(void);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
- struct svc_serv_ops *);
+ const struct svc_serv_ops *);
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
int svc_set_num_threads_sync(struct svc_serv *, struct svc_pool *, int);
int svc_pool_stats_open(struct svc_serv *serv, struct file *file);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 85ce0db..aa04666 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -421,7 +421,7 @@ int svc_bind(struct svc_serv *serv, struct net *net)
*/
static struct svc_serv *
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
- struct svc_serv_ops *ops)
+ const struct svc_serv_ops *ops)
{
struct svc_serv *serv;
unsigned int vers;
@@ -486,7 +486,7 @@ int svc_bind(struct svc_serv *serv, struct net *net)

struct svc_serv *
svc_create(struct svc_program *prog, unsigned int bufsize,
- struct svc_serv_ops *ops)
+ const struct svc_serv_ops *ops)
{
return __svc_create(prog, bufsize, /*npools*/1, ops);
}
@@ -494,7 +494,7 @@ struct svc_serv *

struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
- struct svc_serv_ops *ops)
+ const struct svc_serv_ops *ops)
{
struct svc_serv *serv;
unsigned int npools = svc_pool_map_get();


2017-08-01 15:59:59

by Chuck Lever III

[permalink] [raw]
Subject: [PATCH v1 2/4] nfsd: Const-ify NFSv4 encoding and decoding ops arrays

Close an attack vector by moving the arrays of encoding and decoding
methods to read-only memory.

Signed-off-by: Chuck Lever <[email protected]>
---
fs/nfsd/nfs4xdr.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 20fbcab..51e729a 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1780,7 +1780,7 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, str

typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *);

-static nfsd4_dec nfsd4_dec_ops[] = {
+static const nfsd4_dec nfsd4_dec_ops[] = {
[OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access,
[OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close,
[OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit,
@@ -4332,7 +4332,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
* since we don't need to filter out obsolete ops as this is
* done in the decoding phase.
*/
-static nfsd4_enc nfsd4_enc_ops[] = {
+static const nfsd4_enc nfsd4_enc_ops[] = {
[OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access,
[OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close,
[OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit,


2017-08-01 21:37:30

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH v1 0/4] NFS server clean ups for v4.14

On Tue, Aug 01, 2017 at 11:59:41AM -0400, Chuck Lever wrote:
> Follow-on to Christoph's const-ification of the proc arrays, and a
> clean-up suggested by Dan Carpenter. More to come.

Those look good, thanks!

--b.

>
> ---
>
> Chuck Lever (4):
> sunrpc: Const-ify instances of struct svc_xprt_ops
> nfsd: Const-ify NFSv4 encoding and decoding ops arrays
> sunrpc: Const-ify struct sv_serv_ops
> svcrdma: Clean up svc_rdma_build_read_chunk()
>
>
> fs/lockd/svc.c | 2 +-
> fs/nfs/callback.c | 10 +++++-----
> fs/nfsd/nfs4xdr.c | 4 ++--
> fs/nfsd/nfssvc.c | 2 +-
> include/linux/sunrpc/svc.h | 6 +++---
> include/linux/sunrpc/svc_xprt.h | 4 ++--
> net/sunrpc/svc.c | 6 +++---
> net/sunrpc/svcsock.c | 6 +++---
> net/sunrpc/xprtrdma/svc_rdma_rw.c | 8 +++++---
> net/sunrpc/xprtrdma/svc_rdma_transport.c | 4 ++--
> 10 files changed, 27 insertions(+), 25 deletions(-)
>
> --
> Chuck Lever