From 803bd0af2c4842f440c58a8ab2c7b52f4171145d Mon Sep 17 00:00:00 2001 From: Gordon Ross Date: Mon, 12 Aug 2013 18:46:56 -0400 Subject: [PATCH] SMB-48 Panic with smbtorture raw.scan-eamax --- .../common/fs/smbsrv/smb_common_transact.c | 251 +++++++++++------- usr/src/uts/common/fs/smbsrv/smb_kutil.c | 6 - .../common/fs/smbsrv/smb_mbuf_marshaling.c | 128 ++++++++- usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c | 4 +- usr/src/uts/common/fs/smbsrv/smb_session.c | 17 +- usr/src/uts/common/smbsrv/smb_kproto.h | 2 + usr/src/uts/common/smbsrv/smb_ktypes.h | 4 + 7 files changed, 296 insertions(+), 116 deletions(-) diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c index 7d534665fdfe..4c3666bc0270 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_transact.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_transact.c @@ -107,18 +107,18 @@ smb_com_transaction(smb_request_t *sr) xa->req_disp_param = pscnt; xa->req_disp_data = dscnt; - if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv, + if (smb_mbc_copy(&xa->req_setup_mb, &sr->smb_vwv, sr->smb_vwv.chain_offset, suwcnt * 2)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) { + if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { + if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); @@ -192,18 +192,43 @@ smb_com_transaction_secondary(smb_request_t *sr) return (SDRC_ERROR); mutex_enter(&xa->xa_mutex); - xa->smb_tpscnt = tpscnt; /* might have shrunk */ - xa->smb_tdscnt = tdscnt; /* might have shrunk */ - xa->req_disp_param = psdisp+pscnt; - xa->req_disp_data = dsdisp+dscnt; + if (xa->smb_tpscnt > tpscnt) + xa->smb_tpscnt = tpscnt; + if (xa->smb_tdscnt > tdscnt) + xa->smb_tdscnt = tdscnt; + xa->req_disp_param = psdisp + pscnt; + xa->req_disp_data = dsdisp + dscnt; + + /* + * The words psdisp, dsdisp, tell us what displacement + * into the entire trans parameter and data buffers + * where we should put the params & data that are + * delivered by this request. [MS-CIFS] says all the + * parameters and data SHOULD be sent sequentially, so + * so we can normally reassemble by simply appending. + * However, the components MAY come out of order, so + * check and set the current offset. This is rare, + * and we might like to know when this happens, so + * fire some static dtrace probes when it does. + */ + if (xa->req_param_mb.chain_offset != psdisp) { + DTRACE_SMB_2(op__Trans_param_disp, + smb_xa_t *, xa, uint16_t, psdisp); + xa->req_param_mb.chain_offset = psdisp; + } + if (xa->req_data_mb.chain_offset != dsdisp) { + DTRACE_SMB_2(op__Trans_data_disp, + smb_xa_t *, xa, uint16_t, dsdisp); + xa->req_data_mb.chain_offset = dsdisp; + } - if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) { + if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) { mutex_exit(&xa->xa_mutex); smb_xa_close(xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { + if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { mutex_exit(&xa->xa_mutex); smb_xa_close(xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); @@ -294,18 +319,18 @@ smb_com_transaction2(struct smb_request *sr) xa->req_disp_param = pscnt; xa->req_disp_data = dscnt; - if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv, + if (smb_mbc_copy(&xa->req_setup_mb, &sr->smb_vwv, sr->smb_vwv.chain_offset, suwcnt*2)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) { + if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { + if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); @@ -379,19 +404,36 @@ smb_com_transaction2_secondary(smb_request_t *sr) return (SDRC_ERROR); mutex_enter(&xa->xa_mutex); - xa->smb_tpscnt = tpscnt; /* might have shrunk */ - xa->smb_tdscnt = tdscnt; /* might have shrunk */ - xa->xa_smb_fid = fid; /* overwrite rules? */ + if (xa->smb_tpscnt > tpscnt) + xa->smb_tpscnt = tpscnt; + if (xa->smb_tdscnt > tdscnt) + xa->smb_tdscnt = tdscnt; + if (fid != 0xFFFF) + xa->xa_smb_fid = fid; xa->req_disp_param = psdisp + pscnt; xa->req_disp_data = dsdisp + dscnt; - if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) { + /* + * See comment in smb_com_transaction_secondary + */ + if (xa->req_param_mb.chain_offset != psdisp) { + DTRACE_SMB_2(op__Trans2_param_disp, + smb_xa_t *, xa, uint16_t, psdisp); + xa->req_param_mb.chain_offset = psdisp; + } + if (xa->req_data_mb.chain_offset != dsdisp) { + DTRACE_SMB_2(op__Trans2_data_disp, + smb_xa_t *, xa, uint16_t, dsdisp); + xa->req_data_mb.chain_offset = dsdisp; + } + + if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) { mutex_exit(&xa->xa_mutex); smb_xa_close(xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { + if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { mutex_exit(&xa->xa_mutex); smb_xa_close(xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); @@ -415,19 +457,6 @@ smb_nt_trans_dispatch(struct smb_request *sr, struct smb_xa *xa) int total_bytes, n_setup, n_param, n_data; int param_off, param_pad, data_off, data_pad; - n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200; - n_setup++; - n_setup = n_setup & ~0x0001; - n_param = (xa->smb_mprcnt < smb_maxbufsize) - ? xa->smb_mprcnt : smb_maxbufsize; - n_param++; - n_param = n_param & ~0x0001; - rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param); - n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc; - MBC_INIT(&xa->rep_setup_mb, n_setup * 2); - MBC_INIT(&xa->rep_param_mb, n_param); - MBC_INIT(&xa->rep_data_mb, n_data); - switch (xa->smb_func) { case NT_TRANSACT_CREATE: if ((rc = smb_pre_nt_transact_create(sr, xa)) == 0) @@ -566,18 +595,18 @@ smb_com_nt_transact(struct smb_request *sr) xa->req_disp_param = pscnt; xa->req_disp_data = dscnt; - if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv, + if (smb_mbc_copy(&xa->req_setup_mb, &sr->smb_vwv, sr->smb_vwv.chain_offset, SetupCount * 2)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) { + if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { + if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { smb_xa_rele(sr->session, xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); @@ -651,19 +680,36 @@ smb_com_nt_transact_secondary(struct smb_request *sr) return (SDRC_ERROR); mutex_enter(&xa->xa_mutex); - xa->smb_tpscnt = tpscnt; /* might have shrunk */ - xa->smb_tdscnt = tdscnt; /* might have shrunk */ - xa->xa_smb_fid = fid; /* overwrite rules? */ - xa->req_disp_param = psdisp+pscnt; - xa->req_disp_data = dsdisp+dscnt; + if (xa->smb_tpscnt > tpscnt) + xa->smb_tpscnt = tpscnt; + if (xa->smb_tdscnt > tdscnt) + xa->smb_tdscnt = tdscnt; + if (fid != 0xFFFF) + xa->xa_smb_fid = fid; + xa->req_disp_param = psdisp + pscnt; + xa->req_disp_data = dsdisp + dscnt; + + /* + * See comment in smb_com_transaction_secondary + */ + if (xa->req_param_mb.chain_offset != psdisp) { + DTRACE_SMB_2(op__NtTrans_param_disp, + smb_xa_t *, xa, uint16_t, psdisp); + xa->req_param_mb.chain_offset = psdisp; + } + if (xa->req_data_mb.chain_offset != dsdisp) { + DTRACE_SMB_2(op__NtTrans_data_disp, + smb_xa_t *, xa, uint16_t, dsdisp); + xa->req_data_mb.chain_offset = dsdisp; + } - if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) { + if (smb_mbc_copy(&xa->req_param_mb, &sr->command, psoff, pscnt)) { mutex_exit(&xa->xa_mutex); smb_xa_close(xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); return (SDRC_ERROR); } - if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { + if (smb_mbc_copy(&xa->req_data_mb, &sr->command, dsoff, dscnt)) { mutex_exit(&xa->xa_mutex); smb_xa_close(xa); smbsr_error(sr, 0, ERRDOS, ERRbadformat); @@ -774,12 +820,6 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) ASSERT(sr->uid_user); - /* - * Initialize the mbuf chain of reply to zero. If it is not - * zero, code inside the while loop will try to free the chain. - */ - bzero(&reply, sizeof (struct mbuf_chain)); - if (smb_mbc_decodef(&xa->req_param_mb, "ww", &level, &esi.es_bufsize) != 0) return (SDRC_NOT_IMPLEMENTED); @@ -806,6 +846,12 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) return (SDRC_SUCCESS); } + /* + * Initialize the reply mbuf chain. Note that we re-initialize + * this on each pass through the loop below. + */ + MBC_SETUP(&reply, smb_maxbufsize); + /* * The rep_setup_mb is already initialized in smb_trans_dispatch(). * Calling MBC_INIT() will initialized the structure and so the @@ -813,8 +859,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) * to free the resources before calling MBC_INIT() again. */ n_setup = 0; /* Setup count for NetShareEnum SMB is 0 */ - m_freem(xa->rep_setup_mb.chain); - MBC_INIT(&xa->rep_setup_mb, n_setup * 2); + MBC_FLUSH(&xa->rep_setup_mb); n_param = 8; pkt_bufsize = sr->session->smb_msg_size - @@ -828,8 +873,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) data_scnt = esi.es_datasize - tot_data_scnt; if (data_scnt > pkt_bufsize) data_scnt = pkt_bufsize; - m_freem(xa->rep_data_mb.chain); - MBC_INIT(&xa->rep_data_mb, data_scnt); + MBC_FLUSH(&xa->rep_data_mb); (void) sprintf(fmt, "%dc", data_scnt); (void) smb_mbc_encodef(&xa->rep_data_mb, fmt, sent_buf); @@ -843,8 +887,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) param_off = SMB_HEADER_ED_LEN + RESP_HEADER_LEN; param_disp = (first_resp) ? 0 : n_param; - m_freem(xa->rep_param_mb.chain); - MBC_INIT(&xa->rep_param_mb, param_scnt); + MBC_FLUSH(&xa->rep_param_mb); if (first_resp) { first_resp = B_FALSE; @@ -862,19 +905,7 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) tot_packet_bytes = param_pad + param_scnt + data_pad + data_scnt; - /* - * Calling MBC_INIT() will initialized the structure and so the - * pointer to the mbuf chains will be lost. Therefore, we need - * to free the resources if any before calling MBC_INIT(). - */ - m_freem(reply.chain); - MBC_INIT(&reply, SMB_HEADER_ED_LEN - + sizeof (uint8_t) /* word parameters count */ - + 10*sizeof (uint16_t) /* word parameters */ - + n_setup*sizeof (uint16_t) /* setup parameters */ - + sizeof (uint16_t) /* total data byte count */ - + tot_packet_bytes); - + MBC_FLUSH(&reply); (void) smb_mbc_encodef(&reply, SMB_HEADER_ED_FMT, sr->first_smb_com, sr->smb_rcls, @@ -912,8 +943,11 @@ smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa) smb_sign_reply(sr, &reply); (void) smb_session_send(sr->session, 0, &reply); + } + m_freem(reply.chain); + return (SDRC_NO_REPLY); } @@ -1373,19 +1407,6 @@ smb_trans_dispatch(smb_request_t *sr, smb_xa_t *xa) char *rep_fmt; smb_vdb_t vdb; - n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200; - n_setup++; - n_setup = n_setup & ~0x0001; - n_param = (xa->smb_mprcnt < smb_maxbufsize) - ? xa->smb_mprcnt : smb_maxbufsize; - n_param++; - n_param = n_param & ~0x0001; - rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param); - n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc; - MBC_INIT(&xa->rep_setup_mb, n_setup * 2); - MBC_INIT(&xa->rep_param_mb, n_param); - MBC_INIT(&xa->rep_data_mb, n_data); - if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) { rc = smb_mbc_decodef(&xa->req_setup_mb, "ww", &opcode, &sr->smb_fid); @@ -1553,18 +1574,7 @@ smb_trans2_dispatch(smb_request_t *sr, smb_xa_t *xa) uint16_t nt_unknown_secret = 0x0100; char *fmt; - n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200; - n_setup++; - n_setup = n_setup & ~0x0001; - n_param = (xa->smb_mprcnt < smb_maxbufsize) - ? xa->smb_mprcnt : smb_maxbufsize; - n_param++; - n_param = n_param & ~0x0001; - rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param); - n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc; - MBC_INIT(&xa->rep_setup_mb, n_setup * 2); - MBC_INIT(&xa->rep_param_mb, n_param); - MBC_INIT(&xa->rep_data_mb, n_data); + n_data = xa->smb_mdrcnt; if (smb_mbc_decodef(&xa->req_setup_mb, "w", &opcode) != 0) goto trans_err_not_supported; @@ -1768,6 +1778,10 @@ smb_trans2_dispatch(smb_request_t *sr, smb_xa_t *xa) return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } +static uint32_t smb_xa_max_setup_count = 200; +static uint32_t smb_xa_max_param_count = 32 * 1024; +static uint32_t smb_xa_max_data_count = 64 * 1024; + smb_xa_t * smb_xa_create( smb_session_t *session, @@ -1782,6 +1796,28 @@ smb_xa_create( smb_xa_t *xa, *nxa; smb_llist_t *xlist; + /* + * Sanity check what the client says it will send. + * Caller handles NULL return as ERRnoroom. + */ + if (setup_word_count > smb_xa_max_setup_count) + return (NULL); + if (total_parameter_count > smb_xa_max_param_count) + return (NULL); + if (total_data_count > smb_xa_max_data_count) + return (NULL); + + /* + * Limit what the client asks us to allocate for + * returned setup, params, data. + */ + if (max_setup_count > smb_xa_max_setup_count) + max_setup_count = smb_xa_max_setup_count; + if (max_parameter_count > smb_xa_max_param_count) + max_parameter_count = smb_xa_max_param_count; + if (max_data_count > smb_xa_max_data_count) + max_data_count = smb_xa_max_data_count; + xa = kmem_zalloc(sizeof (smb_xa_t), KM_SLEEP); xa->xa_refcnt = 1; xa->smb_com = sr->smb_com; @@ -1791,6 +1827,7 @@ smb_xa_create( xa->smb_pid = sr->smb_pid; xa->smb_uid = sr->smb_uid; xa->xa_smb_mid = sr->smb_mid; + xa->xa_smb_fid = 0xFFFF; xa->reply_seqnum = sr->reply_seqnum; xa->smb_tpscnt = total_parameter_count; xa->smb_tdscnt = total_data_count; @@ -1801,6 +1838,16 @@ smb_xa_create( xa->xa_session = session; xa->xa_magic = SMB_XA_MAGIC; + /* request parts */ + xa->req_setup_mb.max_bytes = setup_word_count * 2; + xa->req_param_mb.max_bytes = total_parameter_count; + xa->req_data_mb.max_bytes = total_data_count; + + /* reply parts */ + xa->rep_setup_mb.max_bytes = max_setup_count * 2; + xa->rep_param_mb.max_bytes = max_parameter_count; + xa->rep_data_mb.max_bytes = max_data_count; + /* * The new xa structure is checked against the current list to see * if it exists already. @@ -1834,6 +1881,15 @@ smb_xa_delete(smb_xa_t *xa) if (xa->xa_pipe_name) smb_mem_free(xa->xa_pipe_name); + /* request parts */ + if (xa->req_setup_mb.chain != NULL) + m_freem(xa->req_setup_mb.chain); + if (xa->req_param_mb.chain != NULL) + m_freem(xa->req_param_mb.chain); + if (xa->req_data_mb.chain != NULL) + m_freem(xa->req_data_mb.chain); + + /* reply parts */ if (xa->rep_setup_mb.chain != NULL) m_freem(xa->rep_setup_mb.chain); if (xa->rep_param_mb.chain != NULL) @@ -1919,11 +1975,22 @@ smb_xa_complete(smb_xa_t *xa) mutex_enter(&xa->xa_mutex); if (xa->xa_flags & (SMB_XA_FLAG_COMPLETE | SMB_XA_FLAG_CLOSE)) { - rc = 0; + rc = 0; /* error ("not complete") */ } else { - rc = 1; + rc = 1; /* Yes, "complete" */ xa->xa_flags |= SMB_XA_FLAG_COMPLETE; + + /* + * During trans & trans-secondary processing, + * we copied the request data into these. + * Now we want to parse them, so we need to + * move the "finger" back to the beginning. + */ + xa->req_setup_mb.chain_offset = 0; + xa->req_param_mb.chain_offset = 0; + xa->req_data_mb.chain_offset = 0; } + mutex_exit(&xa->xa_mutex); return (rc); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_kutil.c b/usr/src/uts/common/fs/smbsrv/smb_kutil.c index aed58277beb3..abfbdea701cf 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_kutil.c +++ b/usr/src/uts/common/fs/smbsrv/smb_kutil.c @@ -199,12 +199,6 @@ clock_get_milli_uptime() return (TICK_TO_MSEC(ddi_get_lbolt())); } -int /*ARGSUSED*/ -smb_noop(void *p, size_t size, int foo) -{ - return (0); -} - /* * smb_idpool_increment * diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c index 31e1baa77aa3..a9b787f461ae 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c +++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c @@ -752,6 +752,128 @@ smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...) return (xx); } +/* + * Copy data from the src mbuf chain to the dst mbuf chain, + * at the given offset in the src and current offset in dst, + * for copy_len bytes. Does NOT update src->chain_offset. + */ +int +smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc, + int copy_offset, int copy_len) +{ + mbuf_t *src_m; + int offset, len; + int rc; + + if (copy_len <= 0) + return (0); + if (copy_offset < 0) + return (EINVAL); + if ((copy_offset + copy_len) > src_mbc->max_bytes) + return (EMSGSIZE); + + /* + * Advance to the src mbuf where we start copying. + */ + offset = copy_offset; + src_m = src_mbc->chain; + while (src_m && offset >= src_m->m_len) { + offset -= src_m->m_len; + src_m = src_m->m_next; + } + if (src_m == NULL) + return (EFAULT); + + /* + * Copy the first part, which may start somewhere past + * the beginning of the current mbuf. + */ + len = src_m->m_len - offset; + if (len > copy_len) + len = copy_len; + rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len); + if (rc != 0) + return (rc); + copy_len -= len; + + /* + * Copy remaining mbufs... + */ + while (copy_len > 0) { + src_m = src_m->m_next; + if (src_m == NULL) + break; + len = src_m->m_len; + if (len > copy_len) + len = copy_len; + rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len); + copy_len -= len; + } + + return (0); +} + +/* + * Copy data from the passed memory buffer into the mbuf chain + * at the current offset. + */ +int +smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len) +{ + caddr_t mem = vmem; + mbuf_t *m; + int32_t offset, tlen; + int rc; + + if (mem_len <= 0) + return (0); + + if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0) + return (rc); + + /* + * Advance to the dst mbuf where we start copying. + * Allocations were done by _make_room(). + */ + offset = mbc->chain_offset; + m = mbc->chain; + while (offset >= m->m_len) { + ASSERT(m->m_len > 0); + offset -= m->m_len; + m = m->m_next; + } + + /* + * Copy the first part, which may start somewhere past + * the beginning of the current mbuf. + */ + tlen = m->m_len - offset; + if (tlen > mem_len) + tlen = mem_len; + bcopy(mem, m->m_data + offset, tlen); + mbc->chain_offset += tlen; + mem += tlen; + mem_len -= tlen; + + /* + * Copy remaining mem into mbufs. These all start + * at the beginning of each mbuf, and the last may + * end somewhere short of m_len. + */ + while (mem_len > 0) { + m = m->m_next; + tlen = m->m_len; + if (tlen > mem_len) + tlen = mem_len; + bcopy(mem, m->m_data, tlen); + mbc->chain_offset += tlen; + mem += tlen; + mem_len -= tlen; + } + + return (0); +} + /* * Put data into mbuf chain allocating as needed. * Adds room to end of mbuf chain if needed. @@ -991,7 +1113,7 @@ mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio) for (i = 0; i < iov_cnt; i++) { MGET(m, M_WAIT, MT_DATA); m->m_ext.ext_buf = iov->iov_base; - m->m_ext.ext_ref = smb_noop; + m->m_ext.ext_ref = mclrefnoop; m->m_data = m->m_ext.ext_buf; m->m_flags |= M_EXT; m->m_len = m->m_ext.ext_size = iov->iov_len; @@ -1304,11 +1426,13 @@ done: *ch = 0; static int /*ARGSUSED*/ mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m) { + *m = NULL; if (MBC_ROOM_FOR(mbc, bytes) == 0) { /* Data will never be available */ return (DECODE_NO_MORE_DATA); } - return (0); + /* not yet implemented */ + return (-1); } static int diff --git a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c index 76d468eebe96..278bb7699a23 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c +++ b/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c @@ -236,7 +236,7 @@ void MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes) { bzero((MBC), sizeof (struct mbuf_chain)); - (MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize; + (MBC)->max_bytes = max_bytes; } void @@ -306,7 +306,7 @@ MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN) (MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF); (MBC)->chain->m_len = (LEN); (MBC)->chain->m_ext.ext_size = (LEN); - (MBC)->chain->m_ext.ext_ref = smb_noop; + (MBC)->chain->m_ext.ext_ref = mclrefnoop; (MBC)->max_bytes = (LEN); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c index 4a1e52859968..f8f4dd809d93 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c @@ -338,25 +338,14 @@ smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr, static void smb_request_init_command_mbuf(smb_request_t *sr) { - MGET(sr->command.chain, 0, MT_DATA); /* - * Setup mbuf, mimic MCLGET but use the complete packet buffer. + * Setup mbuf using the buffer we allocated. */ - sr->command.chain->m_ext.ext_buf = sr->sr_request_buf; - sr->command.chain->m_data = sr->command.chain->m_ext.ext_buf; - sr->command.chain->m_len = sr->sr_req_length; - sr->command.chain->m_flags |= M_EXT; - sr->command.chain->m_ext.ext_size = sr->sr_req_length; - sr->command.chain->m_ext.ext_ref = &mclrefnoop; + MBC_ATTACH_BUF(&sr->command, sr->sr_request_buf, sr->sr_req_length); - /* - * Initialize the rest of the mbuf_chain fields - */ sr->command.flags = 0; - sr->command.shadow_of = 0; - sr->command.max_bytes = sr->sr_req_length; - sr->command.chain_offset = 0; + sr->command.shadow_of = NULL; } /* diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h index aa24dc2caec2..cb6d02ebcec8 100644 --- a/usr/src/uts/common/smbsrv/smb_kproto.h +++ b/usr/src/uts/common/smbsrv/smb_kproto.h @@ -301,6 +301,8 @@ int smb_mbc_decodef(mbuf_chain_t *, char *, ...); int smb_mbc_encodef(mbuf_chain_t *, char *, ...); int smb_mbc_peek(mbuf_chain_t *, int, char *, ...); int smb_mbc_poke(mbuf_chain_t *, int, char *, ...); +int smb_mbc_put_mem(mbuf_chain_t *, void *, int); +int smb_mbc_copy(mbuf_chain_t *, const mbuf_chain_t *, int, int); void smbsr_encode_header(smb_request_t *sr, int wct, int bcc, char *fmt, ...); diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h index f55eaa130a1b..493e7130a79e 100644 --- a/usr/src/uts/common/smbsrv/smb_ktypes.h +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h @@ -1724,6 +1724,10 @@ typedef struct smb_xa { char *xa_pipe_name; + /* + * These are the param and data count received so far, + * used to decide if the whole trans is here yet. + */ int req_disp_param; int req_disp_data;