diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 009cc77..2ae9b1d 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -529,8 +529,8 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4); for (i = 1; i < count; i += 3) { - /* i + 0 and i + 1 are always - * boilerplate. */ + /* i + 0 is always boilerplate and must + * be allocated with size OUTVEC_ALLOC_SIZE. */ outvec[i].iov_base = talloc_memdup(outvec, req->out.vector[i].iov_base, OUTVEC_ALLOC_SIZE); @@ -539,19 +539,14 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re } outvec[i].iov_len = SMB2_HDR_BODY; - outvec[i+1].iov_base = ((uint8_t *)outvec[i].iov_base) + - SMB2_HDR_BODY; - outvec[i+1].iov_len = 8; + /* i + 1 may have been realloc'ed and may have a length != 8 + * so use dup_smb2_vec(). */ - if (req->out.vector[i+2].iov_base == - ((uint8_t *)req->out.vector[i].iov_base) + - (OUTVEC_ALLOC_SIZE - 1) && - req->out.vector[i+2].iov_len == 1) { - /* Common SMB2 error packet case. */ - outvec[i+2].iov_base = ((uint8_t *)outvec[i].iov_base) + - (OUTVEC_ALLOC_SIZE - 1); - outvec[i+2].iov_len = 1; - } else if (!dup_smb2_vec(outvec, req->out.vector, i+2)) { + if (!dup_smb2_vec(outvec, req->out.vector, i+1)) { + break; + } + + if (!dup_smb2_vec(outvec, req->out.vector, i+2)) { break; } } @@ -821,10 +816,17 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, if (!outvec) { return NT_STATUS_NO_MEMORY; } + + /* 0 is always boilerplate and must + * be of size 4 for the length field. */ + outvec[0].iov_base = req->out.nbt_hdr; outvec[0].iov_len = 4; SIVAL(req->out.nbt_hdr, 0, 0); + /* i + 0 is always boilerplate and must + * be allocated with size OUTVEC_ALLOC_SIZE. */ + outvec[1].iov_base = talloc_memdup(outvec, req->out.vector[i].iov_base, OUTVEC_ALLOC_SIZE); @@ -833,9 +835,34 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req, } outvec[1].iov_len = SMB2_HDR_BODY; - outvec[2].iov_base = ((uint8_t *)outvec[1].iov_base) + - SMB2_HDR_BODY; - outvec[2].iov_len = 8; + /* + * If this is a "standard" i+1 vec of length 8, + * pointing to req->out.vector[i].iov_base + SMB2_HDR_BODY, + * then duplicate this. Else use talloc_memdup(). + */ + + if (req->out.vector[i+1].iov_len == 8 && + req->out.vector[i+1].iov_base == + ((uint8_t *)req->out.vector[i].iov_base) + + SMB2_HDR_BODY) { + outvec[2].iov_base = ((uint8_t *)outvec[1].iov_base) + + SMB2_HDR_BODY; + outvec[2].iov_len = 8; + } else { + outvec[2].iov_base = talloc_memdup(outvec, + req->out.vector[i+1].iov_base, + req->out.vector[i+1].iov_len); + if (!outvec[2].iov_base) { + return NT_STATUS_NO_MEMORY; + } + outvec[2].iov_len = req->out.vector[i+1].iov_len; + } + + /* + * If this is a "standard" i+2 vec of length 1, + * pointing to req->out.vector[i].iov_base + (OUTVEC_ALLOC_SIZE - 1) + * then duplicate this. Else use talloc_memdup(). + */ if (req->out.vector[i+2].iov_base && req->out.vector[i+2].iov_len) {