Message ID | 20220301110006.4033351-3-mmakassikis@freebox.fr (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [1/4] ksmbd-tools: Fix function name typo | expand |
Looks good to me. Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com> 2022년 3월 1일 (화) 오후 8:36, Marios Makassikis <mmakassikis@freebox.fr>님이 작성: > > Modify the ndr_read_* functions to check the payload is large enough to > read the requested bytes. Rather than returning the decoded value, > return 0 on success and -EINVAL if the buffer is too short. > This is the same pattern used in the kernel ksmbd code when dealing with > NDR encoded data. > > Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr> > --- > include/rpc.h | 18 ++--- > include/smbacl.h | 2 +- > mountd/rpc.c | 166 +++++++++++++++++++++++++++++++------------- > mountd/rpc_lsarpc.c | 77 +++++++++++++++----- > mountd/rpc_samr.c | 94 ++++++++++++++++++------- > mountd/rpc_srvsvc.c | 35 +++++++--- > mountd/rpc_wkssvc.c | 9 ++- > mountd/smbacl.c | 14 ++-- > 8 files changed, 291 insertions(+), 124 deletions(-) > > diff --git a/include/rpc.h b/include/rpc.h > index 63d79bc724c8..0fa99d41df35 100644 > --- a/include/rpc.h > +++ b/include/rpc.h > @@ -298,10 +298,10 @@ struct ksmbd_rpc_pipe { > int i); > }; > > -__u8 ndr_read_int8(struct ksmbd_dcerpc *dce); > -__u16 ndr_read_int16(struct ksmbd_dcerpc *dce); > -__u32 ndr_read_int32(struct ksmbd_dcerpc *dce); > -__u64 ndr_read_int64(struct ksmbd_dcerpc *dce); > +int ndr_read_int8(struct ksmbd_dcerpc *dce, __u8 *value); > +int ndr_read_int16(struct ksmbd_dcerpc *dce, __u16 *value); > +int ndr_read_int32(struct ksmbd_dcerpc *dce, __u32 *value); > +int ndr_read_int64(struct ksmbd_dcerpc *dce, __u64 *value); > > int ndr_write_int8(struct ksmbd_dcerpc *dce, __u8 value); > int ndr_write_int16(struct ksmbd_dcerpc *dce, __u16 value); > @@ -310,7 +310,7 @@ int ndr_write_int64(struct ksmbd_dcerpc *dce, __u64 value); > > int ndr_write_union_int16(struct ksmbd_dcerpc *dce, __u16 value); > int ndr_write_union_int32(struct ksmbd_dcerpc *dce, __u32 value); > -__u32 ndr_read_union_int32(struct ksmbd_dcerpc *dce); > +int ndr_read_union_int32(struct ksmbd_dcerpc *dce, __u32 *value); > > int ndr_write_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz); > int ndr_read_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz); > @@ -318,13 +318,13 @@ int ndr_write_vstring(struct ksmbd_dcerpc *dce, void *value); > int ndr_write_string(struct ksmbd_dcerpc *dce, char *str); > int ndr_write_lsa_string(struct ksmbd_dcerpc *dce, char *str); > char *ndr_read_vstring(struct ksmbd_dcerpc *dce); > -void ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr); > -void ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, > +int ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr); > +int ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, > struct ndr_uniq_char_ptr *ctr); > void ndr_free_vstring_ptr(struct ndr_char_ptr *ctr); > void ndr_free_uniq_vstring_ptr(struct ndr_uniq_char_ptr *ctr); > -void ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr); > -void ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr); > +int ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr); > +int ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr); > int __ndr_write_array_of_structs(struct ksmbd_rpc_pipe *pipe, int max_entry_nr); > int ndr_write_array_of_structs(struct ksmbd_rpc_pipe *pipe); > > diff --git a/include/smbacl.h b/include/smbacl.h > index 5be815447906..b0fe131c9fac 100644 > --- a/include/smbacl.h > +++ b/include/smbacl.h > @@ -72,7 +72,7 @@ struct smb_ace { > }; > > void smb_init_domain_sid(struct smb_sid *sid); > -void smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid); > +int smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid); > void smb_write_sid(struct ksmbd_dcerpc *dce, const struct smb_sid *src); > void smb_copy_sid(struct smb_sid *dst, const struct smb_sid *src); > int smb_compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid); > diff --git a/mountd/rpc.c b/mountd/rpc.c > index 4db422abe9b0..9d6402ba5281 100644 > --- a/mountd/rpc.c > +++ b/mountd/rpc.c > @@ -311,17 +311,22 @@ NDR_WRITE_INT(int32, __u32, htobe32, htole32); > NDR_WRITE_INT(int64, __u64, htobe64, htole64); > > #define NDR_READ_INT(name, type, be, le) \ > -type ndr_read_##name(struct ksmbd_dcerpc *dce) \ > +int ndr_read_##name(struct ksmbd_dcerpc *dce, type *value) \ > { \ > type ret; \ > \ > align_offset(dce, sizeof(type)); \ > + if (dce->offset + sizeof(type) > dce->payload_sz) \ > + return -EINVAL; \ > + \ > if (dce->flags & KSMBD_DCERPC_LITTLE_ENDIAN) \ > ret = le(*(type *)PAYLOAD_HEAD(dce)); \ > else \ > ret = be(*(type *)PAYLOAD_HEAD(dce)); \ > dce->offset += sizeof(type); \ > - return ret; \ > + if (value) \ > + *value = ret; \ > + return 0; \ > } > > NDR_READ_INT(int8, __u8, betoh_n, letoh_n); > @@ -350,15 +355,22 @@ NDR_WRITE_UNION(int16, __u16); > NDR_WRITE_UNION(int32, __u32); > > #define NDR_READ_UNION(name, type) \ > -type ndr_read_union_##name(struct ksmbd_dcerpc *dce) \ > +int ndr_read_union_##name(struct ksmbd_dcerpc *dce, type *value) \ > { \ > - type ret = ndr_read_##name(dce); \ > - if (ndr_read_##name(dce) != ret) { \ > + type val1, val2; \ > + \ > + if (ndr_read_##name(dce, &val1)) \ > + return -EINVAL; \ > + if (ndr_read_##name(dce, &val2)) \ > + return -EINVAL; \ > + if (val1 != val2) { \ > pr_err("NDR: union representation mismatch %lu\n", \ > - (unsigned long)ret); \ > - ret = -EINVAL; \ > + (unsigned long)val1); \ > + return -EINVAL; \ > } \ > - return ret; \ > + if (value) \ > + *value = val1; \ > + return 0; \ > } > > NDR_READ_UNION(int32, __u32); > @@ -377,6 +389,8 @@ int ndr_write_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz) > int ndr_read_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz) > { > align_offset(dce, 2); > + if (dce->offset + sz > dce->payload_sz) > + return -EINVAL; > memcpy(value, PAYLOAD_HEAD(dce), sz); > dce->offset += sz; > return 0; > @@ -503,12 +517,16 @@ char *ndr_read_vstring(struct ksmbd_dcerpc *dce) > gsize bytes_read = 0; > gsize bytes_written = 0; > > - size_t raw_len; > + int raw_len; > int charset = KSMBD_CHARSET_UTF16LE; > > - raw_len = ndr_read_int32(dce); > - ndr_read_int32(dce); /* read in offset */ > - ndr_read_int32(dce); > + if (ndr_read_int32(dce, &raw_len)) > + return NULL; > + /* read in offset */ > + if (ndr_read_int32(dce, NULL)) > + return NULL; > + if (ndr_read_int32(dce, NULL)) > + return NULL; > > if (!(dce->flags & KSMBD_DCERPC_LITTLE_ENDIAN)) > charset = KSMBD_CHARSET_UTF16BE; > @@ -521,6 +539,9 @@ char *ndr_read_vstring(struct ksmbd_dcerpc *dce) > return out; > } > > + if (dce->offset + 2 * raw_len > dce->payload_sz) > + return NULL; > + > out = ksmbd_gconvert(PAYLOAD_HEAD(dce), > raw_len * 2, > KSMBD_CHARSET_DEFAULT, > @@ -535,20 +556,28 @@ char *ndr_read_vstring(struct ksmbd_dcerpc *dce) > return out; > } > > -void ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr) > +int ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr) > { > ctr->ptr = ndr_read_vstring(dce); > + if (!ctr->ptr) > + return -EINVAL; > + return 0; > } > > -void ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, > +int ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, > struct ndr_uniq_char_ptr *ctr) > { > - ctr->ref_id = ndr_read_int32(dce); > + if (ndr_read_int32(dce, &ctr->ref_id)) > + return -EINVAL; > + > if (ctr->ref_id == 0) { > - ctr->ptr = 0; > - return; > + ctr->ptr = NULL; > + return 0; > } > ctr->ptr = ndr_read_vstring(dce); > + if (!ctr->ptr) > + return -EINVAL; > + return 0; > } > > void ndr_free_vstring_ptr(struct ndr_char_ptr *ctr) > @@ -564,19 +593,24 @@ void ndr_free_uniq_vstring_ptr(struct ndr_uniq_char_ptr *ctr) > ctr->ptr = NULL; > } > > -void ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr) > +int ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr) > { > - ctr->ptr = ndr_read_int32(dce); > + if (ndr_read_int32(dce, &ctr->ptr)) > + return -EINVAL; > + return 0; > } > > -void ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr) > +int ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr) > { > - ctr->ref_id = ndr_read_int32(dce); > + if (ndr_read_int32(dce, &ctr->ref_id)) > + return -EINVAL; > if (ctr->ref_id == 0) { > ctr->ptr = 0; > - return; > + return 0; > } > - ctr->ptr = ndr_read_int32(dce); > + if (ndr_read_int32(dce, &ctr->ptr)) > + return -EINVAL; > + return 0; > } > > static int __max_entries(struct ksmbd_dcerpc *dce, struct ksmbd_rpc_pipe *pipe) > @@ -731,10 +765,14 @@ static int dcerpc_hdr_read(struct ksmbd_dcerpc *dce, > { > /* Common Type Header for the Serialization Stream */ > > - hdr->rpc_vers = ndr_read_int8(dce); > - hdr->rpc_vers_minor = ndr_read_int8(dce); > - hdr->ptype = ndr_read_int8(dce); > - hdr->pfc_flags = ndr_read_int8(dce); > + if (ndr_read_int8(dce, &hdr->rpc_vers)) > + return -EINVAL; > + if (ndr_read_int8(dce, &hdr->rpc_vers_minor)) > + return -EINVAL; > + if (ndr_read_int8(dce, &hdr->ptype)) > + return -EINVAL; > + if (ndr_read_int8(dce, &hdr->pfc_flags)) > + return -EINVAL; > /* > * This common type header MUST be presented by using > * little-endian format in the octet stream. The first > @@ -746,16 +784,20 @@ static int dcerpc_hdr_read(struct ksmbd_dcerpc *dce, > * MUST use the IEEE floating-point format representation and > * ASCII character format. > */ > - ndr_read_bytes(dce, &hdr->packed_drep, sizeof(hdr->packed_drep)); > + if (ndr_read_bytes(dce, &hdr->packed_drep, sizeof(hdr->packed_drep))) > + return -EINVAL; > > dce->flags |= KSMBD_DCERPC_ALIGN4; > dce->flags |= KSMBD_DCERPC_LITTLE_ENDIAN; > if (hdr->packed_drep[0] != DCERPC_SERIALIZATION_LITTLE_ENDIAN) > dce->flags &= ~KSMBD_DCERPC_LITTLE_ENDIAN; > > - hdr->frag_length = ndr_read_int16(dce); > - hdr->auth_length = ndr_read_int16(dce); > - hdr->call_id = ndr_read_int32(dce); > + if (ndr_read_int16(dce, &hdr->frag_length)) > + return -EINVAL; > + if (ndr_read_int16(dce, &hdr->auth_length)) > + return -EINVAL; > + if (ndr_read_int32(dce, &hdr->call_id)) > + return -EINVAL; > return 0; > } > > @@ -772,9 +814,12 @@ static int dcerpc_response_hdr_write(struct ksmbd_dcerpc *dce, > static int dcerpc_request_hdr_read(struct ksmbd_dcerpc *dce, > struct dcerpc_request_header *hdr) > { > - hdr->alloc_hint = ndr_read_int32(dce); > - hdr->context_id = ndr_read_int16(dce); > - hdr->opnum = ndr_read_int16(dce); > + if (ndr_read_int32(dce, &hdr->alloc_hint)) > + return -EINVAL; > + if (ndr_read_int16(dce, &hdr->context_id)) > + return -EINVAL; > + if (ndr_read_int16(dce, &hdr->opnum)) > + return -EINVAL; > return 0; > } > > @@ -805,13 +850,21 @@ int dcerpc_write_headers(struct ksmbd_dcerpc *dce, int method_status) > static int __dcerpc_read_syntax(struct ksmbd_dcerpc *dce, > struct dcerpc_syntax *syn) > { > - syn->uuid.time_low = ndr_read_int32(dce); > - syn->uuid.time_mid = ndr_read_int16(dce); > - syn->uuid.time_hi_and_version = ndr_read_int16(dce); > - ndr_read_bytes(dce, syn->uuid.clock_seq, sizeof(syn->uuid.clock_seq)); > - ndr_read_bytes(dce, syn->uuid.node, sizeof(syn->uuid.node)); > - syn->ver_major = ndr_read_int16(dce); > - syn->ver_minor = ndr_read_int16(dce); > + if (ndr_read_int32(dce, &syn->uuid.time_low)) > + return -EINVAL; > + if (ndr_read_int16(dce, &syn->uuid.time_mid)) > + return -EINVAL; > + if (ndr_read_int16(dce, &syn->uuid.time_hi_and_version)) > + return -EINVAL; > + if (ndr_read_bytes(dce, syn->uuid.clock_seq, > + sizeof(syn->uuid.clock_seq))) > + return -EINVAL; > + if (ndr_read_bytes(dce, syn->uuid.node, sizeof(syn->uuid.node))) > + return -EINVAL; > + if (ndr_read_int16(dce, &syn->ver_major)) > + return -EINVAL; > + if (ndr_read_int16(dce, &syn->ver_minor)) > + return -EINVAL; > return 0; > } > > @@ -843,13 +896,18 @@ static int dcerpc_parse_bind_req(struct ksmbd_dcerpc *dce, > struct dcerpc_bind_request *hdr) > { > int i, j; > + int ret = -EINVAL; > > hdr->flags = dce->rpc_req->flags; > - hdr->max_xmit_frag_sz = ndr_read_int16(dce); > - hdr->max_recv_frag_sz = ndr_read_int16(dce); > - hdr->assoc_group_id = ndr_read_int32(dce); > + if (ndr_read_int16(dce, &hdr->max_xmit_frag_sz)) > + return -EINVAL; > + if (ndr_read_int16(dce, &hdr->max_recv_frag_sz)) > + return -EINVAL; > + if (ndr_read_int32(dce, &hdr->assoc_group_id)) > + return -EINVAL; > + if (ndr_read_int8(dce, &hdr->num_contexts)) > + return -EINVAL; > hdr->list = NULL; > - hdr->num_contexts = ndr_read_int8(dce); > auto_align_offset(dce); > > if (!hdr->num_contexts) > @@ -862,24 +920,32 @@ static int dcerpc_parse_bind_req(struct ksmbd_dcerpc *dce, > for (i = 0; i < hdr->num_contexts; i++) { > struct dcerpc_context *ctx = &hdr->list[i]; > > - ctx->id = ndr_read_int16(dce); > - ctx->num_syntaxes = ndr_read_int8(dce); > + if (ndr_read_int16(dce, &ctx->id)) > + goto fail; > + if (ndr_read_int8(dce, &ctx->num_syntaxes)) > + goto fail; > if (!ctx->num_syntaxes) { > pr_err("BIND: zero syntaxes provided\n"); > - return -EINVAL; > + goto fail; > } > > __dcerpc_read_syntax(dce, &ctx->abstract_syntax); > > ctx->transfer_syntaxes = calloc(ctx->num_syntaxes, > sizeof(struct dcerpc_syntax)); > - if (!ctx->transfer_syntaxes) > - return -ENOMEM; > + if (!ctx->transfer_syntaxes) { > + ret = -ENOMEM; > + goto fail; > + } > > for (j = 0; j < ctx->num_syntaxes; j++) > __dcerpc_read_syntax(dce, &ctx->transfer_syntaxes[j]); > } > return KSMBD_RPC_OK; > + > +fail: > + free(hdr->list); > + return ret; > } > > static int dcerpc_bind_invoke(struct ksmbd_rpc_pipe *pipe) > diff --git a/mountd/rpc_lsarpc.c b/mountd/rpc_lsarpc.c > index b9088950c46e..6aab08dd7223 100644 > --- a/mountd/rpc_lsarpc.c > +++ b/mountd/rpc_lsarpc.c > @@ -105,8 +105,12 @@ static int lsa_domain_account_data(struct ksmbd_dcerpc *dce, char *domain_name, > static int lsarpc_get_primary_domain_info_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > + __u16 val; > > - dce->lr_req.level = ndr_read_int16(dce); > + if (ndr_read_int16(dce, &val)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + > + dce->lr_req.level = val; > > return KSMBD_RPC_OK; > } > @@ -158,9 +162,15 @@ static int lsarpc_open_policy2_return(struct ksmbd_rpc_pipe *pipe) > static int lsarpc_query_info_policy_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > + __u16 val; > > - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); > - dce->lr_req.level = ndr_read_int16(dce); // level > + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // level > + if (ndr_read_int16(dce, &val)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + > + dce->lr_req.level = val; > > return KSMBD_RPC_OK; > } > @@ -206,19 +216,26 @@ static int __lsarpc_entry_processed(struct ksmbd_rpc_pipe *pipe, int i) > static int lsarpc_lookup_sid2_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > + struct lsarpc_names_info *ni = NULL; > unsigned int num_sid, i; > > - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) > + goto fail; > > - num_sid = ndr_read_int32(dce); > - ndr_read_int32(dce); // ref pointer > - ndr_read_int32(dce); // max count > + if (ndr_read_int32(dce, &num_sid)) > + goto fail; > + // ref pointer > + if (ndr_read_int32(dce, NULL)) > + goto fail; > + // max count > + if (ndr_read_int32(dce, NULL)) > + goto fail; > > for (i = 0; i < num_sid; i++) > - ndr_read_int32(dce); // ref pointer > + if (ndr_read_int32(dce, NULL)) // ref pointer > + goto fail; > > for (i = 0; i < num_sid; i++) { > - struct lsarpc_names_info *ni; > struct passwd *passwd; > int rid; > > @@ -226,8 +243,12 @@ static int lsarpc_lookup_sid2_invoke(struct ksmbd_rpc_pipe *pipe) > if (!ni) > break; > > - ndr_read_int32(dce); // max count > - smb_read_sid(dce, &ni->sid); // sid > + // max count > + if (ndr_read_int32(dce, NULL)) > + goto fail; > + // sid > + if (smb_read_sid(dce, &ni->sid)) > + goto fail; > ni->sid.num_subauth--; > rid = ni->sid.sub_auth[ni->sid.num_subauth]; > passwd = getpwuid(rid); > @@ -244,6 +265,9 @@ static int lsarpc_lookup_sid2_invoke(struct ksmbd_rpc_pipe *pipe) > > pipe->entry_processed = __lsarpc_entry_processed; > return KSMBD_RPC_OK; > +fail: > + free(ni); > + return KSMBD_RPC_EINVALID_PARAMETER; > } > > static int lsarpc_lookup_sid2_return(struct ksmbd_rpc_pipe *pipe) > @@ -333,24 +357,34 @@ static int lsarpc_lookup_sid2_return(struct ksmbd_rpc_pipe *pipe) > static int lsarpc_lookup_names3_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > + struct lsarpc_names_info *ni = NULL; > struct ndr_uniq_char_ptr username; > int num_names, i; > > - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) > + goto fail; > > - num_names = ndr_read_int32(dce); // num names > - ndr_read_int32(dce); // max count > + // num names > + if (ndr_read_int32(dce, &num_names)) > + goto fail; > + // max count > + if (ndr_read_int32(dce, NULL)) > + goto fail; > > for (i = 0; i < num_names; i++) { > - struct lsarpc_names_info *ni; > char *name = NULL; > > ni = malloc(sizeof(struct lsarpc_names_info)); > if (!ni) > break; > - ndr_read_int16(dce); // length > - ndr_read_int16(dce); // size > - ndr_read_uniq_vstring_ptr(dce, &username); > + // length > + if (ndr_read_int16(dce, NULL)) > + goto fail; > + // size > + if (ndr_read_int16(dce, NULL)) > + goto fail; > + if (ndr_read_uniq_vstring_ptr(dce, &username)) > + goto fail; > if (strstr(STR_VAL(username), "\\")) { > strtok(STR_VAL(username), "\\"); > name = strtok(NULL, "\\"); > @@ -368,6 +402,10 @@ static int lsarpc_lookup_names3_invoke(struct ksmbd_rpc_pipe *pipe) > pipe->entry_processed = __lsarpc_entry_processed; > > return KSMBD_RPC_OK; > + > +fail: > + free(ni); > + return KSMBD_RPC_EINVALID_PARAMETER; > } > > static int lsarpc_lookup_names3_return(struct ksmbd_rpc_pipe *pipe) > @@ -433,7 +471,8 @@ static int lsarpc_close_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > diff --git a/mountd/rpc_samr.c b/mountd/rpc_samr.c > index 6425215f6d34..5a9afd3000a2 100644 > --- a/mountd/rpc_samr.c > +++ b/mountd/rpc_samr.c > @@ -84,11 +84,19 @@ static int samr_connect5_invoke(struct ksmbd_rpc_pipe *pipe) > struct ksmbd_dcerpc *dce = pipe->dce; > struct ndr_uniq_char_ptr server_name; > > - ndr_read_uniq_vstring_ptr(dce, &server_name); > - ndr_read_int32(dce); // Access mask > - dce->sm_req.level = ndr_read_int32(dce); // level in > - ndr_read_int32(dce); // Info in > - dce->sm_req.client_version = ndr_read_int32(dce); > + if (ndr_read_uniq_vstring_ptr(dce, &server_name)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // Access mask > + if (ndr_read_int32(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // level in > + if (ndr_read_int32(dce, &dce->sm_req.level)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // Info in > + if (ndr_read_int32(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + if (ndr_read_int32(dce, &dce->sm_req.client_version)) > + return KSMBD_RPC_EINVALID_PARAMETER; > return 0; > } > > @@ -115,7 +123,8 @@ static int samr_enum_domain_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -181,10 +190,17 @@ static int samr_lookup_domain_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > - ndr_read_int16(dce); // name len > - ndr_read_int16(dce); // name size > - ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name); // domain name > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // name len > + if (ndr_read_int16(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // name size > + if (ndr_read_int16(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // domain name > + if (ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -221,7 +237,8 @@ static int samr_open_domain_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -245,16 +262,30 @@ static int samr_lookup_names_invoke(struct ksmbd_rpc_pipe *pipe) > struct ksmbd_dcerpc *dce = pipe->dce; > int user_num; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > - user_num = ndr_read_int32(dce); > - ndr_read_int32(dce); // max count > - ndr_read_int32(dce); // offset > - ndr_read_int32(dce); // actual count > - ndr_read_int16(dce); // name len > - ndr_read_int16(dce); // name size > + if (ndr_read_int32(dce, &user_num)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // max count > + if (ndr_read_int32(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // offset > + if (ndr_read_int32(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // actual count > + if (ndr_read_int32(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // name len > + if (ndr_read_int16(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // name size > + if (ndr_read_int16(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > - ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name); // names > + // names > + if (ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -291,10 +322,14 @@ static int samr_open_user_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > - ndr_read_int32(dce); > - dce->sm_req.rid = ndr_read_int32(dce); // RID > + if (ndr_read_int32(dce, NULL)) > + return KSMBD_RPC_EINVALID_PARAMETER; > + // RID > + if (ndr_read_int32(dce, &dce->sm_req.rid)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -321,7 +356,8 @@ static int samr_query_user_info_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -481,7 +517,8 @@ static int samr_query_security_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -519,7 +556,8 @@ static int samr_get_group_for_user_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EINVALID_PARAMETER; > > return KSMBD_RPC_OK; > } > @@ -549,7 +587,8 @@ static int samr_get_alias_membership_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EACCESS_DENIED; > > return KSMBD_RPC_OK; > } > @@ -575,7 +614,8 @@ static int samr_close_invoke(struct ksmbd_rpc_pipe *pipe) > { > struct ksmbd_dcerpc *dce = pipe->dce; > > - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); > + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) > + return KSMBD_RPC_EACCESS_DENIED; > > return KSMBD_RPC_OK; > } > diff --git a/mountd/rpc_srvsvc.c b/mountd/rpc_srvsvc.c > index 7e9fa675d34a..38b984b3a269 100644 > --- a/mountd/rpc_srvsvc.c > +++ b/mountd/rpc_srvsvc.c > @@ -272,32 +272,45 @@ static int srvsvc_share_get_info_return(struct ksmbd_rpc_pipe *pipe) > static int srvsvc_parse_share_info_req(struct ksmbd_dcerpc *dce, > struct srvsvc_share_info_request *hdr) > { > - ndr_read_uniq_vstring_ptr(dce, &hdr->server_name); > + if (ndr_read_uniq_vstring_ptr(dce, &hdr->server_name)) > + return -EINVAL; > > if (dce->req_hdr.opnum == SRVSVC_OPNUM_SHARE_ENUM_ALL) { > int ptr; > + __u32 val; > > /* Read union switch selector */ > - hdr->level = ndr_read_union_int32(dce); > - if (hdr->level == -EINVAL) > + if (ndr_read_union_int32(dce, &val)) > return -EINVAL; > - ndr_read_int32(dce); // read container pointer ref id > - ndr_read_int32(dce); // read container array size > - ptr = ndr_read_int32(dce); // read container array pointer > - // it should be null > + hdr->level = val; > + // read container pointer ref id > + if (ndr_read_int32(dce, NULL)) > + return -EINVAL; > + // read container array size > + if (ndr_read_int32(dce, NULL)) > + return -EINVAL; > + // read container array pointer > + if (ndr_read_int32(dce, &ptr)) > + return -EINVAL; > + // it should be null > if (ptr != 0x00) { > pr_err("SRVSVC: container array pointer is %x\n", > ptr); > return -EINVAL; > } > - hdr->max_size = ndr_read_int32(dce); > - ndr_read_uniq_ptr(dce, &hdr->payload_handle); > + if (ndr_read_int32(dce, &val)) > + return -EINVAL; > + hdr->max_size = val; > + if (ndr_read_uniq_ptr(dce, &hdr->payload_handle)) > + return -EINVAL; > return 0; > } > > if (dce->req_hdr.opnum == SRVSVC_OPNUM_GET_SHARE_INFO) { > - ndr_read_vstring_ptr(dce, &hdr->share_name); > - hdr->level = ndr_read_int32(dce); > + if (ndr_read_vstring_ptr(dce, &hdr->share_name)) > + return -EINVAL; > + if (ndr_read_int32(dce, &hdr->level)) > + return -EINVAL; > return 0; > } > > diff --git a/mountd/rpc_wkssvc.c b/mountd/rpc_wkssvc.c > index ba7f9a841e3d..124078fd38b4 100644 > --- a/mountd/rpc_wkssvc.c > +++ b/mountd/rpc_wkssvc.c > @@ -141,8 +141,13 @@ static int > wkssvc_parse_netwksta_info_req(struct ksmbd_dcerpc *dce, > struct wkssvc_netwksta_info_request *hdr) > { > - ndr_read_uniq_vstring_ptr(dce, &hdr->server_name); > - hdr->level = ndr_read_int32(dce); > + int val; > + > + if (ndr_read_uniq_vstring_ptr(dce, &hdr->server_name)) > + return -EINVAL; > + if (ndr_read_int32(dce, &val)) > + return -EINVAL; > + hdr->level = val; > return 0; > } > > diff --git a/mountd/smbacl.c b/mountd/smbacl.c > index 66531c3bebea..cc043ea59c2c 100644 > --- a/mountd/smbacl.c > +++ b/mountd/smbacl.c > @@ -30,16 +30,20 @@ static const struct smb_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, > static const struct smb_sid sid_local_group = { > 1, 1, {0, 0, 0, 0, 0, 5}, {32} }; > > -void smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid) > +int smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid) > { > int i; > > - sid->revision = ndr_read_int8(dce); > - sid->num_subauth = ndr_read_int8(dce); > + if (ndr_read_int8(dce, &sid->revision)) > + return -EINVAL; > + if (ndr_read_int8(dce, &sid->num_subauth)) > + return -EINVAL; > for (i = 0; i < NUM_AUTHS; ++i) > - sid->authority[i] = ndr_read_int8(dce); > + if (ndr_read_int8(dce, &sid->authority[i])) > + return -EINVAL; > for (i = 0; i < sid->num_subauth; ++i) > - sid->sub_auth[i] = ndr_read_int32(dce); > + if (ndr_read_int32(dce, &sid->sub_auth[i])) > + return -EINVAL; > } > > void smb_write_sid(struct ksmbd_dcerpc *dce, const struct smb_sid *src) > -- > 2.25.1 >
diff --git a/include/rpc.h b/include/rpc.h index 63d79bc724c8..0fa99d41df35 100644 --- a/include/rpc.h +++ b/include/rpc.h @@ -298,10 +298,10 @@ struct ksmbd_rpc_pipe { int i); }; -__u8 ndr_read_int8(struct ksmbd_dcerpc *dce); -__u16 ndr_read_int16(struct ksmbd_dcerpc *dce); -__u32 ndr_read_int32(struct ksmbd_dcerpc *dce); -__u64 ndr_read_int64(struct ksmbd_dcerpc *dce); +int ndr_read_int8(struct ksmbd_dcerpc *dce, __u8 *value); +int ndr_read_int16(struct ksmbd_dcerpc *dce, __u16 *value); +int ndr_read_int32(struct ksmbd_dcerpc *dce, __u32 *value); +int ndr_read_int64(struct ksmbd_dcerpc *dce, __u64 *value); int ndr_write_int8(struct ksmbd_dcerpc *dce, __u8 value); int ndr_write_int16(struct ksmbd_dcerpc *dce, __u16 value); @@ -310,7 +310,7 @@ int ndr_write_int64(struct ksmbd_dcerpc *dce, __u64 value); int ndr_write_union_int16(struct ksmbd_dcerpc *dce, __u16 value); int ndr_write_union_int32(struct ksmbd_dcerpc *dce, __u32 value); -__u32 ndr_read_union_int32(struct ksmbd_dcerpc *dce); +int ndr_read_union_int32(struct ksmbd_dcerpc *dce, __u32 *value); int ndr_write_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz); int ndr_read_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz); @@ -318,13 +318,13 @@ int ndr_write_vstring(struct ksmbd_dcerpc *dce, void *value); int ndr_write_string(struct ksmbd_dcerpc *dce, char *str); int ndr_write_lsa_string(struct ksmbd_dcerpc *dce, char *str); char *ndr_read_vstring(struct ksmbd_dcerpc *dce); -void ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr); -void ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, +int ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr); +int ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_char_ptr *ctr); void ndr_free_vstring_ptr(struct ndr_char_ptr *ctr); void ndr_free_uniq_vstring_ptr(struct ndr_uniq_char_ptr *ctr); -void ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr); -void ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr); +int ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr); +int ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr); int __ndr_write_array_of_structs(struct ksmbd_rpc_pipe *pipe, int max_entry_nr); int ndr_write_array_of_structs(struct ksmbd_rpc_pipe *pipe); diff --git a/include/smbacl.h b/include/smbacl.h index 5be815447906..b0fe131c9fac 100644 --- a/include/smbacl.h +++ b/include/smbacl.h @@ -72,7 +72,7 @@ struct smb_ace { }; void smb_init_domain_sid(struct smb_sid *sid); -void smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid); +int smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid); void smb_write_sid(struct ksmbd_dcerpc *dce, const struct smb_sid *src); void smb_copy_sid(struct smb_sid *dst, const struct smb_sid *src); int smb_compare_sids(const struct smb_sid *ctsid, const struct smb_sid *cwsid); diff --git a/mountd/rpc.c b/mountd/rpc.c index 4db422abe9b0..9d6402ba5281 100644 --- a/mountd/rpc.c +++ b/mountd/rpc.c @@ -311,17 +311,22 @@ NDR_WRITE_INT(int32, __u32, htobe32, htole32); NDR_WRITE_INT(int64, __u64, htobe64, htole64); #define NDR_READ_INT(name, type, be, le) \ -type ndr_read_##name(struct ksmbd_dcerpc *dce) \ +int ndr_read_##name(struct ksmbd_dcerpc *dce, type *value) \ { \ type ret; \ \ align_offset(dce, sizeof(type)); \ + if (dce->offset + sizeof(type) > dce->payload_sz) \ + return -EINVAL; \ + \ if (dce->flags & KSMBD_DCERPC_LITTLE_ENDIAN) \ ret = le(*(type *)PAYLOAD_HEAD(dce)); \ else \ ret = be(*(type *)PAYLOAD_HEAD(dce)); \ dce->offset += sizeof(type); \ - return ret; \ + if (value) \ + *value = ret; \ + return 0; \ } NDR_READ_INT(int8, __u8, betoh_n, letoh_n); @@ -350,15 +355,22 @@ NDR_WRITE_UNION(int16, __u16); NDR_WRITE_UNION(int32, __u32); #define NDR_READ_UNION(name, type) \ -type ndr_read_union_##name(struct ksmbd_dcerpc *dce) \ +int ndr_read_union_##name(struct ksmbd_dcerpc *dce, type *value) \ { \ - type ret = ndr_read_##name(dce); \ - if (ndr_read_##name(dce) != ret) { \ + type val1, val2; \ + \ + if (ndr_read_##name(dce, &val1)) \ + return -EINVAL; \ + if (ndr_read_##name(dce, &val2)) \ + return -EINVAL; \ + if (val1 != val2) { \ pr_err("NDR: union representation mismatch %lu\n", \ - (unsigned long)ret); \ - ret = -EINVAL; \ + (unsigned long)val1); \ + return -EINVAL; \ } \ - return ret; \ + if (value) \ + *value = val1; \ + return 0; \ } NDR_READ_UNION(int32, __u32); @@ -377,6 +389,8 @@ int ndr_write_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz) int ndr_read_bytes(struct ksmbd_dcerpc *dce, void *value, size_t sz) { align_offset(dce, 2); + if (dce->offset + sz > dce->payload_sz) + return -EINVAL; memcpy(value, PAYLOAD_HEAD(dce), sz); dce->offset += sz; return 0; @@ -503,12 +517,16 @@ char *ndr_read_vstring(struct ksmbd_dcerpc *dce) gsize bytes_read = 0; gsize bytes_written = 0; - size_t raw_len; + int raw_len; int charset = KSMBD_CHARSET_UTF16LE; - raw_len = ndr_read_int32(dce); - ndr_read_int32(dce); /* read in offset */ - ndr_read_int32(dce); + if (ndr_read_int32(dce, &raw_len)) + return NULL; + /* read in offset */ + if (ndr_read_int32(dce, NULL)) + return NULL; + if (ndr_read_int32(dce, NULL)) + return NULL; if (!(dce->flags & KSMBD_DCERPC_LITTLE_ENDIAN)) charset = KSMBD_CHARSET_UTF16BE; @@ -521,6 +539,9 @@ char *ndr_read_vstring(struct ksmbd_dcerpc *dce) return out; } + if (dce->offset + 2 * raw_len > dce->payload_sz) + return NULL; + out = ksmbd_gconvert(PAYLOAD_HEAD(dce), raw_len * 2, KSMBD_CHARSET_DEFAULT, @@ -535,20 +556,28 @@ char *ndr_read_vstring(struct ksmbd_dcerpc *dce) return out; } -void ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr) +int ndr_read_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_char_ptr *ctr) { ctr->ptr = ndr_read_vstring(dce); + if (!ctr->ptr) + return -EINVAL; + return 0; } -void ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, +int ndr_read_uniq_vstring_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_char_ptr *ctr) { - ctr->ref_id = ndr_read_int32(dce); + if (ndr_read_int32(dce, &ctr->ref_id)) + return -EINVAL; + if (ctr->ref_id == 0) { - ctr->ptr = 0; - return; + ctr->ptr = NULL; + return 0; } ctr->ptr = ndr_read_vstring(dce); + if (!ctr->ptr) + return -EINVAL; + return 0; } void ndr_free_vstring_ptr(struct ndr_char_ptr *ctr) @@ -564,19 +593,24 @@ void ndr_free_uniq_vstring_ptr(struct ndr_uniq_char_ptr *ctr) ctr->ptr = NULL; } -void ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr) +int ndr_read_ptr(struct ksmbd_dcerpc *dce, struct ndr_ptr *ctr) { - ctr->ptr = ndr_read_int32(dce); + if (ndr_read_int32(dce, &ctr->ptr)) + return -EINVAL; + return 0; } -void ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr) +int ndr_read_uniq_ptr(struct ksmbd_dcerpc *dce, struct ndr_uniq_ptr *ctr) { - ctr->ref_id = ndr_read_int32(dce); + if (ndr_read_int32(dce, &ctr->ref_id)) + return -EINVAL; if (ctr->ref_id == 0) { ctr->ptr = 0; - return; + return 0; } - ctr->ptr = ndr_read_int32(dce); + if (ndr_read_int32(dce, &ctr->ptr)) + return -EINVAL; + return 0; } static int __max_entries(struct ksmbd_dcerpc *dce, struct ksmbd_rpc_pipe *pipe) @@ -731,10 +765,14 @@ static int dcerpc_hdr_read(struct ksmbd_dcerpc *dce, { /* Common Type Header for the Serialization Stream */ - hdr->rpc_vers = ndr_read_int8(dce); - hdr->rpc_vers_minor = ndr_read_int8(dce); - hdr->ptype = ndr_read_int8(dce); - hdr->pfc_flags = ndr_read_int8(dce); + if (ndr_read_int8(dce, &hdr->rpc_vers)) + return -EINVAL; + if (ndr_read_int8(dce, &hdr->rpc_vers_minor)) + return -EINVAL; + if (ndr_read_int8(dce, &hdr->ptype)) + return -EINVAL; + if (ndr_read_int8(dce, &hdr->pfc_flags)) + return -EINVAL; /* * This common type header MUST be presented by using * little-endian format in the octet stream. The first @@ -746,16 +784,20 @@ static int dcerpc_hdr_read(struct ksmbd_dcerpc *dce, * MUST use the IEEE floating-point format representation and * ASCII character format. */ - ndr_read_bytes(dce, &hdr->packed_drep, sizeof(hdr->packed_drep)); + if (ndr_read_bytes(dce, &hdr->packed_drep, sizeof(hdr->packed_drep))) + return -EINVAL; dce->flags |= KSMBD_DCERPC_ALIGN4; dce->flags |= KSMBD_DCERPC_LITTLE_ENDIAN; if (hdr->packed_drep[0] != DCERPC_SERIALIZATION_LITTLE_ENDIAN) dce->flags &= ~KSMBD_DCERPC_LITTLE_ENDIAN; - hdr->frag_length = ndr_read_int16(dce); - hdr->auth_length = ndr_read_int16(dce); - hdr->call_id = ndr_read_int32(dce); + if (ndr_read_int16(dce, &hdr->frag_length)) + return -EINVAL; + if (ndr_read_int16(dce, &hdr->auth_length)) + return -EINVAL; + if (ndr_read_int32(dce, &hdr->call_id)) + return -EINVAL; return 0; } @@ -772,9 +814,12 @@ static int dcerpc_response_hdr_write(struct ksmbd_dcerpc *dce, static int dcerpc_request_hdr_read(struct ksmbd_dcerpc *dce, struct dcerpc_request_header *hdr) { - hdr->alloc_hint = ndr_read_int32(dce); - hdr->context_id = ndr_read_int16(dce); - hdr->opnum = ndr_read_int16(dce); + if (ndr_read_int32(dce, &hdr->alloc_hint)) + return -EINVAL; + if (ndr_read_int16(dce, &hdr->context_id)) + return -EINVAL; + if (ndr_read_int16(dce, &hdr->opnum)) + return -EINVAL; return 0; } @@ -805,13 +850,21 @@ int dcerpc_write_headers(struct ksmbd_dcerpc *dce, int method_status) static int __dcerpc_read_syntax(struct ksmbd_dcerpc *dce, struct dcerpc_syntax *syn) { - syn->uuid.time_low = ndr_read_int32(dce); - syn->uuid.time_mid = ndr_read_int16(dce); - syn->uuid.time_hi_and_version = ndr_read_int16(dce); - ndr_read_bytes(dce, syn->uuid.clock_seq, sizeof(syn->uuid.clock_seq)); - ndr_read_bytes(dce, syn->uuid.node, sizeof(syn->uuid.node)); - syn->ver_major = ndr_read_int16(dce); - syn->ver_minor = ndr_read_int16(dce); + if (ndr_read_int32(dce, &syn->uuid.time_low)) + return -EINVAL; + if (ndr_read_int16(dce, &syn->uuid.time_mid)) + return -EINVAL; + if (ndr_read_int16(dce, &syn->uuid.time_hi_and_version)) + return -EINVAL; + if (ndr_read_bytes(dce, syn->uuid.clock_seq, + sizeof(syn->uuid.clock_seq))) + return -EINVAL; + if (ndr_read_bytes(dce, syn->uuid.node, sizeof(syn->uuid.node))) + return -EINVAL; + if (ndr_read_int16(dce, &syn->ver_major)) + return -EINVAL; + if (ndr_read_int16(dce, &syn->ver_minor)) + return -EINVAL; return 0; } @@ -843,13 +896,18 @@ static int dcerpc_parse_bind_req(struct ksmbd_dcerpc *dce, struct dcerpc_bind_request *hdr) { int i, j; + int ret = -EINVAL; hdr->flags = dce->rpc_req->flags; - hdr->max_xmit_frag_sz = ndr_read_int16(dce); - hdr->max_recv_frag_sz = ndr_read_int16(dce); - hdr->assoc_group_id = ndr_read_int32(dce); + if (ndr_read_int16(dce, &hdr->max_xmit_frag_sz)) + return -EINVAL; + if (ndr_read_int16(dce, &hdr->max_recv_frag_sz)) + return -EINVAL; + if (ndr_read_int32(dce, &hdr->assoc_group_id)) + return -EINVAL; + if (ndr_read_int8(dce, &hdr->num_contexts)) + return -EINVAL; hdr->list = NULL; - hdr->num_contexts = ndr_read_int8(dce); auto_align_offset(dce); if (!hdr->num_contexts) @@ -862,24 +920,32 @@ static int dcerpc_parse_bind_req(struct ksmbd_dcerpc *dce, for (i = 0; i < hdr->num_contexts; i++) { struct dcerpc_context *ctx = &hdr->list[i]; - ctx->id = ndr_read_int16(dce); - ctx->num_syntaxes = ndr_read_int8(dce); + if (ndr_read_int16(dce, &ctx->id)) + goto fail; + if (ndr_read_int8(dce, &ctx->num_syntaxes)) + goto fail; if (!ctx->num_syntaxes) { pr_err("BIND: zero syntaxes provided\n"); - return -EINVAL; + goto fail; } __dcerpc_read_syntax(dce, &ctx->abstract_syntax); ctx->transfer_syntaxes = calloc(ctx->num_syntaxes, sizeof(struct dcerpc_syntax)); - if (!ctx->transfer_syntaxes) - return -ENOMEM; + if (!ctx->transfer_syntaxes) { + ret = -ENOMEM; + goto fail; + } for (j = 0; j < ctx->num_syntaxes; j++) __dcerpc_read_syntax(dce, &ctx->transfer_syntaxes[j]); } return KSMBD_RPC_OK; + +fail: + free(hdr->list); + return ret; } static int dcerpc_bind_invoke(struct ksmbd_rpc_pipe *pipe) diff --git a/mountd/rpc_lsarpc.c b/mountd/rpc_lsarpc.c index b9088950c46e..6aab08dd7223 100644 --- a/mountd/rpc_lsarpc.c +++ b/mountd/rpc_lsarpc.c @@ -105,8 +105,12 @@ static int lsa_domain_account_data(struct ksmbd_dcerpc *dce, char *domain_name, static int lsarpc_get_primary_domain_info_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; + __u16 val; - dce->lr_req.level = ndr_read_int16(dce); + if (ndr_read_int16(dce, &val)) + return KSMBD_RPC_EINVALID_PARAMETER; + + dce->lr_req.level = val; return KSMBD_RPC_OK; } @@ -158,9 +162,15 @@ static int lsarpc_open_policy2_return(struct ksmbd_rpc_pipe *pipe) static int lsarpc_query_info_policy_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; + __u16 val; - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); - dce->lr_req.level = ndr_read_int16(dce); // level + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; + // level + if (ndr_read_int16(dce, &val)) + return KSMBD_RPC_EINVALID_PARAMETER; + + dce->lr_req.level = val; return KSMBD_RPC_OK; } @@ -206,19 +216,26 @@ static int __lsarpc_entry_processed(struct ksmbd_rpc_pipe *pipe, int i) static int lsarpc_lookup_sid2_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; + struct lsarpc_names_info *ni = NULL; unsigned int num_sid, i; - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) + goto fail; - num_sid = ndr_read_int32(dce); - ndr_read_int32(dce); // ref pointer - ndr_read_int32(dce); // max count + if (ndr_read_int32(dce, &num_sid)) + goto fail; + // ref pointer + if (ndr_read_int32(dce, NULL)) + goto fail; + // max count + if (ndr_read_int32(dce, NULL)) + goto fail; for (i = 0; i < num_sid; i++) - ndr_read_int32(dce); // ref pointer + if (ndr_read_int32(dce, NULL)) // ref pointer + goto fail; for (i = 0; i < num_sid; i++) { - struct lsarpc_names_info *ni; struct passwd *passwd; int rid; @@ -226,8 +243,12 @@ static int lsarpc_lookup_sid2_invoke(struct ksmbd_rpc_pipe *pipe) if (!ni) break; - ndr_read_int32(dce); // max count - smb_read_sid(dce, &ni->sid); // sid + // max count + if (ndr_read_int32(dce, NULL)) + goto fail; + // sid + if (smb_read_sid(dce, &ni->sid)) + goto fail; ni->sid.num_subauth--; rid = ni->sid.sub_auth[ni->sid.num_subauth]; passwd = getpwuid(rid); @@ -244,6 +265,9 @@ static int lsarpc_lookup_sid2_invoke(struct ksmbd_rpc_pipe *pipe) pipe->entry_processed = __lsarpc_entry_processed; return KSMBD_RPC_OK; +fail: + free(ni); + return KSMBD_RPC_EINVALID_PARAMETER; } static int lsarpc_lookup_sid2_return(struct ksmbd_rpc_pipe *pipe) @@ -333,24 +357,34 @@ static int lsarpc_lookup_sid2_return(struct ksmbd_rpc_pipe *pipe) static int lsarpc_lookup_names3_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; + struct lsarpc_names_info *ni = NULL; struct ndr_uniq_char_ptr username; int num_names, i; - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) + goto fail; - num_names = ndr_read_int32(dce); // num names - ndr_read_int32(dce); // max count + // num names + if (ndr_read_int32(dce, &num_names)) + goto fail; + // max count + if (ndr_read_int32(dce, NULL)) + goto fail; for (i = 0; i < num_names; i++) { - struct lsarpc_names_info *ni; char *name = NULL; ni = malloc(sizeof(struct lsarpc_names_info)); if (!ni) break; - ndr_read_int16(dce); // length - ndr_read_int16(dce); // size - ndr_read_uniq_vstring_ptr(dce, &username); + // length + if (ndr_read_int16(dce, NULL)) + goto fail; + // size + if (ndr_read_int16(dce, NULL)) + goto fail; + if (ndr_read_uniq_vstring_ptr(dce, &username)) + goto fail; if (strstr(STR_VAL(username), "\\")) { strtok(STR_VAL(username), "\\"); name = strtok(NULL, "\\"); @@ -368,6 +402,10 @@ static int lsarpc_lookup_names3_invoke(struct ksmbd_rpc_pipe *pipe) pipe->entry_processed = __lsarpc_entry_processed; return KSMBD_RPC_OK; + +fail: + free(ni); + return KSMBD_RPC_EINVALID_PARAMETER; } static int lsarpc_lookup_names3_return(struct ksmbd_rpc_pipe *pipe) @@ -433,7 +471,8 @@ static int lsarpc_close_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->lr_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } diff --git a/mountd/rpc_samr.c b/mountd/rpc_samr.c index 6425215f6d34..5a9afd3000a2 100644 --- a/mountd/rpc_samr.c +++ b/mountd/rpc_samr.c @@ -84,11 +84,19 @@ static int samr_connect5_invoke(struct ksmbd_rpc_pipe *pipe) struct ksmbd_dcerpc *dce = pipe->dce; struct ndr_uniq_char_ptr server_name; - ndr_read_uniq_vstring_ptr(dce, &server_name); - ndr_read_int32(dce); // Access mask - dce->sm_req.level = ndr_read_int32(dce); // level in - ndr_read_int32(dce); // Info in - dce->sm_req.client_version = ndr_read_int32(dce); + if (ndr_read_uniq_vstring_ptr(dce, &server_name)) + return KSMBD_RPC_EINVALID_PARAMETER; + // Access mask + if (ndr_read_int32(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // level in + if (ndr_read_int32(dce, &dce->sm_req.level)) + return KSMBD_RPC_EINVALID_PARAMETER; + // Info in + if (ndr_read_int32(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + if (ndr_read_int32(dce, &dce->sm_req.client_version)) + return KSMBD_RPC_EINVALID_PARAMETER; return 0; } @@ -115,7 +123,8 @@ static int samr_enum_domain_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -181,10 +190,17 @@ static int samr_lookup_domain_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); - ndr_read_int16(dce); // name len - ndr_read_int16(dce); // name size - ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name); // domain name + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; + // name len + if (ndr_read_int16(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // name size + if (ndr_read_int16(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // domain name + if (ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -221,7 +237,8 @@ static int samr_open_domain_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -245,16 +262,30 @@ static int samr_lookup_names_invoke(struct ksmbd_rpc_pipe *pipe) struct ksmbd_dcerpc *dce = pipe->dce; int user_num; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; - user_num = ndr_read_int32(dce); - ndr_read_int32(dce); // max count - ndr_read_int32(dce); // offset - ndr_read_int32(dce); // actual count - ndr_read_int16(dce); // name len - ndr_read_int16(dce); // name size + if (ndr_read_int32(dce, &user_num)) + return KSMBD_RPC_EINVALID_PARAMETER; + // max count + if (ndr_read_int32(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // offset + if (ndr_read_int32(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // actual count + if (ndr_read_int32(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // name len + if (ndr_read_int16(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // name size + if (ndr_read_int16(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; - ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name); // names + // names + if (ndr_read_uniq_vstring_ptr(dce, &dce->sm_req.name)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -291,10 +322,14 @@ static int samr_open_user_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; - ndr_read_int32(dce); - dce->sm_req.rid = ndr_read_int32(dce); // RID + if (ndr_read_int32(dce, NULL)) + return KSMBD_RPC_EINVALID_PARAMETER; + // RID + if (ndr_read_int32(dce, &dce->sm_req.rid)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -321,7 +356,8 @@ static int samr_query_user_info_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -481,7 +517,8 @@ static int samr_query_security_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -519,7 +556,8 @@ static int samr_get_group_for_user_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EINVALID_PARAMETER; return KSMBD_RPC_OK; } @@ -549,7 +587,8 @@ static int samr_get_alias_membership_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EACCESS_DENIED; return KSMBD_RPC_OK; } @@ -575,7 +614,8 @@ static int samr_close_invoke(struct ksmbd_rpc_pipe *pipe) { struct ksmbd_dcerpc *dce = pipe->dce; - ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE); + if (ndr_read_bytes(dce, dce->sm_req.handle, HANDLE_SIZE)) + return KSMBD_RPC_EACCESS_DENIED; return KSMBD_RPC_OK; } diff --git a/mountd/rpc_srvsvc.c b/mountd/rpc_srvsvc.c index 7e9fa675d34a..38b984b3a269 100644 --- a/mountd/rpc_srvsvc.c +++ b/mountd/rpc_srvsvc.c @@ -272,32 +272,45 @@ static int srvsvc_share_get_info_return(struct ksmbd_rpc_pipe *pipe) static int srvsvc_parse_share_info_req(struct ksmbd_dcerpc *dce, struct srvsvc_share_info_request *hdr) { - ndr_read_uniq_vstring_ptr(dce, &hdr->server_name); + if (ndr_read_uniq_vstring_ptr(dce, &hdr->server_name)) + return -EINVAL; if (dce->req_hdr.opnum == SRVSVC_OPNUM_SHARE_ENUM_ALL) { int ptr; + __u32 val; /* Read union switch selector */ - hdr->level = ndr_read_union_int32(dce); - if (hdr->level == -EINVAL) + if (ndr_read_union_int32(dce, &val)) return -EINVAL; - ndr_read_int32(dce); // read container pointer ref id - ndr_read_int32(dce); // read container array size - ptr = ndr_read_int32(dce); // read container array pointer - // it should be null + hdr->level = val; + // read container pointer ref id + if (ndr_read_int32(dce, NULL)) + return -EINVAL; + // read container array size + if (ndr_read_int32(dce, NULL)) + return -EINVAL; + // read container array pointer + if (ndr_read_int32(dce, &ptr)) + return -EINVAL; + // it should be null if (ptr != 0x00) { pr_err("SRVSVC: container array pointer is %x\n", ptr); return -EINVAL; } - hdr->max_size = ndr_read_int32(dce); - ndr_read_uniq_ptr(dce, &hdr->payload_handle); + if (ndr_read_int32(dce, &val)) + return -EINVAL; + hdr->max_size = val; + if (ndr_read_uniq_ptr(dce, &hdr->payload_handle)) + return -EINVAL; return 0; } if (dce->req_hdr.opnum == SRVSVC_OPNUM_GET_SHARE_INFO) { - ndr_read_vstring_ptr(dce, &hdr->share_name); - hdr->level = ndr_read_int32(dce); + if (ndr_read_vstring_ptr(dce, &hdr->share_name)) + return -EINVAL; + if (ndr_read_int32(dce, &hdr->level)) + return -EINVAL; return 0; } diff --git a/mountd/rpc_wkssvc.c b/mountd/rpc_wkssvc.c index ba7f9a841e3d..124078fd38b4 100644 --- a/mountd/rpc_wkssvc.c +++ b/mountd/rpc_wkssvc.c @@ -141,8 +141,13 @@ static int wkssvc_parse_netwksta_info_req(struct ksmbd_dcerpc *dce, struct wkssvc_netwksta_info_request *hdr) { - ndr_read_uniq_vstring_ptr(dce, &hdr->server_name); - hdr->level = ndr_read_int32(dce); + int val; + + if (ndr_read_uniq_vstring_ptr(dce, &hdr->server_name)) + return -EINVAL; + if (ndr_read_int32(dce, &val)) + return -EINVAL; + hdr->level = val; return 0; } diff --git a/mountd/smbacl.c b/mountd/smbacl.c index 66531c3bebea..cc043ea59c2c 100644 --- a/mountd/smbacl.c +++ b/mountd/smbacl.c @@ -30,16 +30,20 @@ static const struct smb_sid sid_unix_groups = { 1, 1, {0, 0, 0, 0, 0, 22}, static const struct smb_sid sid_local_group = { 1, 1, {0, 0, 0, 0, 0, 5}, {32} }; -void smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid) +int smb_read_sid(struct ksmbd_dcerpc *dce, struct smb_sid *sid) { int i; - sid->revision = ndr_read_int8(dce); - sid->num_subauth = ndr_read_int8(dce); + if (ndr_read_int8(dce, &sid->revision)) + return -EINVAL; + if (ndr_read_int8(dce, &sid->num_subauth)) + return -EINVAL; for (i = 0; i < NUM_AUTHS; ++i) - sid->authority[i] = ndr_read_int8(dce); + if (ndr_read_int8(dce, &sid->authority[i])) + return -EINVAL; for (i = 0; i < sid->num_subauth; ++i) - sid->sub_auth[i] = ndr_read_int32(dce); + if (ndr_read_int32(dce, &sid->sub_auth[i])) + return -EINVAL; } void smb_write_sid(struct ksmbd_dcerpc *dce, const struct smb_sid *src)
Modify the ndr_read_* functions to check the payload is large enough to read the requested bytes. Rather than returning the decoded value, return 0 on success and -EINVAL if the buffer is too short. This is the same pattern used in the kernel ksmbd code when dealing with NDR encoded data. Signed-off-by: Marios Makassikis <mmakassikis@freebox.fr> --- include/rpc.h | 18 ++--- include/smbacl.h | 2 +- mountd/rpc.c | 166 +++++++++++++++++++++++++++++++------------- mountd/rpc_lsarpc.c | 77 +++++++++++++++----- mountd/rpc_samr.c | 94 ++++++++++++++++++------- mountd/rpc_srvsvc.c | 35 +++++++--- mountd/rpc_wkssvc.c | 9 ++- mountd/smbacl.c | 14 ++-- 8 files changed, 291 insertions(+), 124 deletions(-)