diff options
| author | J. Bruce Fields <bfields@redhat.com> | 2010-10-02 15:19:01 -0400 | 
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-10-25 22:19:41 -0400 | 
| commit | 43c2e885be25311e6289c7da52e8a03c4453ee03 (patch) | |
| tree | 68b32eda7198486a8fe720bb5ed91189a769d817 | |
| parent | 1c787096fce217b5fdd9806dbce96e738c9345c0 (diff) | |
nfs4: fix channel attribute sanity-checks
The sanity checks here are incorrect; in the worst case they allow
values that crash the client.
They're also over-reliant on the preprocessor.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
| -rw-r--r-- | fs/nfs/nfs4proc.c | 75 | 
1 files changed, 41 insertions, 34 deletions
| diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 7e14e991ddfa..32c8758c99fd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -4842,49 +4842,56 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | |||
| 4842 | args->bc_attrs.max_reqs); | 4842 | args->bc_attrs.max_reqs); | 
| 4843 | } | 4843 | } | 
| 4844 | 4844 | ||
| 4845 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | 4845 | static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session) | 
| 4846 | { | 4846 | { | 
| 4847 | if (rcvd <= sent) | 4847 | struct nfs4_channel_attrs *sent = &args->fc_attrs; | 
| 4848 | return 0; | 4848 | struct nfs4_channel_attrs *rcvd = &session->fc_attrs; | 
| 4849 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | 4849 | |
| 4850 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | 4850 | if (rcvd->headerpadsz > sent->headerpadsz) | 
| 4851 | return -EINVAL; | 4851 | return -EINVAL; | 
| 4852 | if (rcvd->max_resp_sz > sent->max_resp_sz) | ||
| 4853 | return -EINVAL; | ||
| 4854 | /* | ||
| 4855 | * Our requested max_ops is the minimum we need; we're not | ||
| 4856 | * prepared to break up compounds into smaller pieces than that. | ||
| 4857 | * So, no point even trying to continue if the server won't | ||
| 4858 | * cooperate: | ||
| 4859 | */ | ||
| 4860 | if (rcvd->max_ops < sent->max_ops) | ||
| 4861 | return -EINVAL; | ||
| 4862 | if (rcvd->max_reqs == 0) | ||
| 4863 | return -EINVAL; | ||
| 4864 | return 0; | ||
| 4852 | } | 4865 | } | 
| 4853 | 4866 | ||
| 4854 | #define _verify_fore_channel_attr(_name_) \ | 4867 | static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session) | 
| 4855 | _verify_channel_attr("fore", #_name_, \ | 4868 | { | 
| 4856 | args->fc_attrs._name_, \ | 4869 | struct nfs4_channel_attrs *sent = &args->bc_attrs; | 
| 4857 | session->fc_attrs._name_) | 4870 | struct nfs4_channel_attrs *rcvd = &session->bc_attrs; | 
| 4858 | 4871 | ||
| 4859 | #define _verify_back_channel_attr(_name_) \ | 4872 | if (rcvd->max_rqst_sz > sent->max_rqst_sz) | 
| 4860 | _verify_channel_attr("back", #_name_, \ | 4873 | return -EINVAL; | 
| 4861 | args->bc_attrs._name_, \ | 4874 | if (rcvd->max_resp_sz < sent->max_resp_sz) | 
| 4862 | session->bc_attrs._name_) | 4875 | return -EINVAL; | 
| 4876 | if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached) | ||
| 4877 | return -EINVAL; | ||
| 4878 | /* These would render the backchannel useless: */ | ||
| 4879 | if (rcvd->max_ops == 0) | ||
| 4880 | return -EINVAL; | ||
| 4881 | if (rcvd->max_reqs == 0) | ||
| 4882 | return -EINVAL; | ||
| 4883 | return 0; | ||
| 4884 | } | ||
| 4863 | 4885 | ||
| 4864 | /* | ||
| 4865 | * The server is not allowed to increase the fore channel header pad size, | ||
| 4866 | * maximum response size, or maximum number of operations. | ||
| 4867 | * | ||
| 4868 | * The back channel attributes are only negotiatied down: We send what the | ||
| 4869 | * (back channel) server insists upon. | ||
| 4870 | */ | ||
| 4871 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | 4886 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | 
| 4872 | struct nfs4_session *session) | 4887 | struct nfs4_session *session) | 
| 4873 | { | 4888 | { | 
| 4874 | int ret = 0; | 4889 | int ret; | 
| 4875 | |||
| 4876 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
| 4877 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
| 4878 | ret |= _verify_fore_channel_attr(max_ops); | ||
| 4879 | |||
| 4880 | ret |= _verify_back_channel_attr(headerpadsz); | ||
| 4881 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
| 4882 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
| 4883 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
| 4884 | ret |= _verify_back_channel_attr(max_ops); | ||
| 4885 | ret |= _verify_back_channel_attr(max_reqs); | ||
| 4886 | 4890 | ||
| 4887 | return ret; | 4891 | ret = nfs4_verify_fore_channel_attrs(args, session); | 
| 4892 | if (ret) | ||
| 4893 | return ret; | ||
| 4894 | return nfs4_verify_back_channel_attrs(args, session); | ||
| 4888 | } | 4895 | } | 
| 4889 | 4896 | ||
| 4890 | static int _nfs4_proc_create_session(struct nfs_client *clp) | 4897 | static int _nfs4_proc_create_session(struct nfs_client *clp) | 
