From 2132acb4d99d01834f1ed8900f1db45bb1253922 Mon Sep 17 00:00:00 2001 From: Christof Schmitt Date: Thu, 14 Aug 2014 22:04:33 -0700 Subject: [PATCH] smbd: Add padding byte to readx response MS-CIFS 2.2.4.42.2 states: "Pad (1 byte): This field is optional. When using the NT LAN Manager dialect, this field can be used to align the Data field to a 16-bit boundary relative to the start of the SMB Header. If Unicode strings are being used, this field MUST be present. When used, this field MUST be one padding byte long." Always add the padding byte to all readx responses to avoid additional complexity. Signed-off-by: Christof Schmitt Reviewed-by: Jeremy Allison --- source3/smbd/aio.c | 11 +++++++---- source3/smbd/pipes.c | 11 +++++++---- source3/smbd/process.c | 3 ++- source3/smbd/reply.c | 21 +++++++++++++-------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c index 2235c32eefc..f5e4cc68377 100644 --- a/source3/smbd/aio.c +++ b/source3/smbd/aio.c @@ -196,7 +196,7 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn, /* The following is safe from integer wrap as we've already checked smb_maxcnt is 128k or less. Wct is 12 for read replies */ - bufsize = smb_size + 12 * 2 + smb_maxcnt; + bufsize = smb_size + 12 * 2 + smb_maxcnt + 1 /* padding byte */; if ((aio_ex = create_aio_extra(NULL, fsp, bufsize)) == NULL) { DEBUG(10,("schedule_aio_read_and_X: malloc fail.\n")); @@ -206,6 +206,7 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn, construct_reply_common_req(smbreq, (char *)aio_ex->outbuf.data); srv_set_message((char *)aio_ex->outbuf.data, 12, 0, True); SCVAL(aio_ex->outbuf.data,smb_vwv0,0xFF); /* Never a chained reply. */ + SCVAL(smb_buf(aio_ex->outbuf.data), 0, 0); /* padding byte */ init_strict_lock_struct(fsp, (uint64_t)smbreq->smbpid, (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK, @@ -221,7 +222,8 @@ NTSTATUS schedule_aio_read_and_X(connection_struct *conn, aio_ex->offset = startpos; req = SMB_VFS_PREAD_SEND(aio_ex, fsp->conn->sconn->ev_ctx, - fsp, smb_buf(aio_ex->outbuf.data), + fsp, + smb_buf(aio_ex->outbuf.data) + 1 /* pad */, smb_maxcnt, startpos); if (req == NULL) { DEBUG(0,("schedule_aio_read_and_X: aio_read failed. " @@ -256,7 +258,7 @@ static void aio_pread_smb1_done(struct tevent_req *req) files_struct *fsp = aio_ex->fsp; int outsize; char *outbuf = (char *)aio_ex->outbuf.data; - char *data = smb_buf(outbuf); + char *data = smb_buf(outbuf) + 1 /* padding byte */; ssize_t nread; int err; @@ -285,7 +287,8 @@ static void aio_pread_smb1_done(struct tevent_req *req) ERROR_NT(map_nt_error_from_unix(err)); outsize = srv_set_message(outbuf,0,0,true); } else { - outsize = srv_set_message(outbuf, 12, nread, False); + outsize = srv_set_message(outbuf, 12, + nread + 1 /* padding byte */, false); SSVAL(outbuf,smb_vwv2, 0xFFFF); /* Remaining - must be * -1. */ SSVAL(outbuf,smb_vwv5, nread); SSVAL(outbuf,smb_vwv6, smb_offset(data,outbuf)); diff --git a/source3/smbd/pipes.c b/source3/smbd/pipes.c index f1f61bbc5b8..110951ca67c 100644 --- a/source3/smbd/pipes.c +++ b/source3/smbd/pipes.c @@ -422,11 +422,12 @@ void reply_pipe_read_and_X(struct smb_request *req) state->smb_maxcnt = SVAL(req->vwv+5, 0); state->smb_mincnt = SVAL(req->vwv+6, 0); - reply_outbuf(req, 12, state->smb_maxcnt); + reply_outbuf(req, 12, state->smb_maxcnt + 1 /* padding byte */); SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ + SCVAL(smb_buf(req->outbuf), 0, 0); /* padding byte */ - data = (uint8_t *)smb_buf(req->outbuf); + data = (uint8_t *)smb_buf(req->outbuf) + 1 /* padding byte */; /* * We have to tell the upper layers that we're async. @@ -467,7 +468,8 @@ static void pipe_read_andx_done(struct tevent_req *subreq) req->outbuf = state->outbuf; state->outbuf = NULL; - srv_set_message((char *)req->outbuf, 12, nread, False); + srv_set_message((char *)req->outbuf, 12, nread + 1 /* padding byte */, + false); #if 0 /* @@ -488,7 +490,8 @@ static void pipe_read_andx_done(struct tevent_req *subreq) (smb_wct - 4) /* offset from smb header to wct */ + 1 /* the wct field */ + 12 * sizeof(uint16_t) /* vwv */ - + 2); /* the buflen field */ + + 2 /* the buflen field */ + + 1); /* padding byte */ SSVAL(req->outbuf,smb_vwv11,state->smb_maxcnt); DEBUG(3,("readX-IPC min=%d max=%d nread=%d\n", diff --git a/source3/smbd/process.c b/source3/smbd/process.c index 7148462d716..207a4dd9968 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -2144,7 +2144,8 @@ static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf) bytes_addr = outbuf + ofs /* vwv start */ + sizeof(uint16_t) * wct /* vwv array */ - + sizeof(uint16_t); /* bcc */ + + sizeof(uint16_t) /* bcc */ + + 1; /* padding byte */ SSVAL(outbuf + ofs, 6 * sizeof(uint16_t), bytes_addr - outbuf - 4); diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index 4cb446fb23e..2cc174fce42 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3682,7 +3682,8 @@ static int setup_readX_header(struct smb_request *req, char *outbuf, { int outsize; - outsize = srv_set_message(outbuf,12,smb_maxcnt,False); + outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */, + False); memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */ @@ -3693,11 +3694,14 @@ static int setup_readX_header(struct smb_request *req, char *outbuf, (smb_wct - 4) /* offset from smb header to wct */ + 1 /* the wct field */ + 12 * sizeof(uint16_t) /* vwv */ - + 2); /* the buflen field */ + + 2 /* the buflen field */ + + 1); /* padding byte */ SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16)); SSVAL(outbuf,smb_vwv11,smb_maxcnt); + SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */ /* Reset the outgoing length, set_message truncates at 0x1FFFF. */ - _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4)); + _smb_setlen_large(outbuf, + smb_size + 12*2 + smb_maxcnt - 4 + 1 /* pad */); return outsize; } @@ -3734,7 +3738,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, (fsp->base_fsp == NULL) && (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn), xconn->smb1.signing_state) ) { - uint8 headerbuf[smb_size + 12 * 2]; + uint8 headerbuf[smb_size + 12 * 2 + 1 /* padding byte */]; DATA_BLOB header; if(fsp_stat(fsp) == -1) { @@ -3848,7 +3852,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req, normal_read: if ((smb_maxcnt & 0xFF0000) > 0x10000) { - uint8 headerbuf[smb_size + 2*12]; + uint8 headerbuf[smb_size + 2*12 + 1 /* padding byte */]; ssize_t ret; construct_reply_common_req(req, (char *)headerbuf); @@ -3887,11 +3891,12 @@ normal_read: nosendfile_read: - reply_outbuf(req, 12, smb_maxcnt); + reply_outbuf(req, 12, smb_maxcnt + 1 /* padding byte */); SSVAL(req->outbuf, smb_vwv0, 0xff); /* andx chain ends */ SSVAL(req->outbuf, smb_vwv1, 0); /* no andx offset */ - nread = read_file(fsp, smb_buf(req->outbuf), startpos, smb_maxcnt); + nread = read_file(fsp, smb_buf(req->outbuf) + 1 /* padding byte */, + startpos, smb_maxcnt); saved_errno = errno; SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock); @@ -3969,7 +3974,7 @@ static size_t calc_read_size(const struct smb_request *req, size_t max_pdu = calc_max_read_pdu(req); size_t total_size = 0; size_t hdr_len = MIN_SMB_SIZE + VWV(12); - size_t max_len = max_pdu - hdr_len; + size_t max_len = max_pdu - hdr_len - 1 /* padding byte */; /* * Windows explicitly ignores upper size of 0xFFFF. -- 2.11.4.GIT