When CONFIG_DEBUG_SG is set, sg_set_buf() will verify that the passed buffer is a valid virtual address (and not for example a stack address). This means that we are not allowed to pass buffers allocated from the stack into sg_set_buf() (when this configuration option is set). Go through and fix all the places (I could find) where we were passing a stack address into this function. Signed-off-by: Ronnie Sahlberg <lsahlber@xxxxxxxxxx> --- fs/cifs/smb2file.c | 19 +++++--- fs/cifs/smb2ops.c | 125 ++++++++++++++++++++++++++++++++++++----------------- fs/cifs/smb2pdu.c | 74 ++++++++++++++++++++----------- 3 files changed, 149 insertions(+), 69 deletions(-) diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c index 12af5dba742b..5f9d1171f41d 100644 --- a/fs/cifs/smb2file.c +++ b/fs/cifs/smb2file.c @@ -43,7 +43,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, struct smb2_file_all_info *smb2_data = NULL; __u8 smb2_oplock[17]; struct cifs_fid *fid = oparms->fid; - struct network_resiliency_req nr_ioctl_req; + struct network_resiliency_req *nr_ioctl_req; smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb); if (smb2_path == NULL) { @@ -69,14 +69,23 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms, goto out; - if (oparms->tcon->use_resilient) { - nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */ - nr_ioctl_req.Reserved = 0; + if (oparms->tcon->use_resilient) { + nr_ioctl_req = kzalloc(sizeof(struct network_resiliency_req), + GFP_KERNEL); + if (!nr_ioctl_req) { + cifs_dbg(VFS, "failed to allocate nr_ioctl_req\n"); + rc = -ENOMEM; + goto out; + } + nr_ioctl_req->Timeout = 0; /* use server default (120 seconds) */ + nr_ioctl_req->Reserved = 0; rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid, fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, true /* is_fsctl */, - (char *)&nr_ioctl_req, sizeof(nr_ioctl_req), + (char *)nr_ioctl_req, + sizeof(struct network_resiliency_req), NULL, NULL /* no return info */); + kfree(nr_ioctl_req); if (rc == -EOPNOTSUPP) { cifs_dbg(VFS, "resiliency not supported by server, disabling\n"); diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index eb68e2fcc500..af2df509292c 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -991,6 +991,7 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse) { struct cifsInodeInfo *cifsi; + __u8 *buf; int rc; cifsi = CIFS_I(inode); @@ -1015,10 +1016,17 @@ static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, if (tcon->broken_sparse_sup) return false; + buf = kzalloc(1, GFP_KERNEL); + if (!buf) { + cifs_dbg(VFS, "failed to allocate buf for set_sparse\n"); + return -ENOMEM; + } + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, FSCTL_SET_SPARSE, true /* is_fctl */, - &setsparse, 1, NULL, NULL); + buf, 1, NULL, NULL); + kfree(buf); if (rc) { tcon->broken_sparse_sup = true; cifs_dbg(FYI, "set sparse rc = %d\n", rc); @@ -1046,12 +1054,9 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, */ inode = d_inode(cfile->dentry); - if (!set_alloc && (size > inode->i_size + 8192)) { - __u8 set_sparse = 1; - - /* whether set sparse succeeds or not, extend the file */ - smb2_set_sparse(xid, tcon, cfile, inode, set_sparse); - } + /* whether set sparse succeeds or not, extend the file */ + if (!set_alloc && (size > inode->i_size + 8192)) + smb2_set_sparse(xid, tcon, cfile, inode, 1); return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, cfile->pid, &eof, false); @@ -1065,7 +1070,7 @@ smb2_duplicate_extents(const unsigned int xid, { int rc; unsigned int ret_data_len; - struct duplicate_extents_to_file dup_ext_buf; + struct duplicate_extents_to_file *dup_ext_buf; struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink); /* server fileays advertise duplicate extent support with this flag */ @@ -1073,11 +1078,17 @@ smb2_duplicate_extents(const unsigned int xid, FILE_SUPPORTS_BLOCK_REFCOUNTING) == 0) return -EOPNOTSUPP; - dup_ext_buf.VolatileFileHandle = srcfile->fid.volatile_fid; - dup_ext_buf.PersistentFileHandle = srcfile->fid.persistent_fid; - dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off); - dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off); - dup_ext_buf.ByteCount = cpu_to_le64(len); + dup_ext_buf = kzalloc(sizeof(struct duplicate_extents_to_file), + GFP_KERNEL); + if (!dup_ext_buf) { + cifs_dbg(VFS, "failed to allocate duplicate_extents_to_file\n"); + return -ENOMEM; + } + dup_ext_buf->VolatileFileHandle = srcfile->fid.volatile_fid; + dup_ext_buf->PersistentFileHandle = srcfile->fid.persistent_fid; + dup_ext_buf->SourceFileOffset = cpu_to_le64(src_off); + dup_ext_buf->TargetFileOffset = cpu_to_le64(dest_off); + dup_ext_buf->ByteCount = cpu_to_le64(len); cifs_dbg(FYI, "duplicate extents: src off %lld dst off %lld len %lld", src_off, dest_off, len); @@ -1089,7 +1100,7 @@ smb2_duplicate_extents(const unsigned int xid, trgtfile->fid.volatile_fid, FSCTL_DUPLICATE_EXTENTS_TO_FILE, true /* is_fsctl */, - (char *)&dup_ext_buf, + (char *)dup_ext_buf, sizeof(struct duplicate_extents_to_file), NULL, &ret_data_len); @@ -1098,6 +1109,7 @@ smb2_duplicate_extents(const unsigned int xid, cifs_dbg(FYI, "non-zero response length in duplicate extents"); duplicate_extents_out: + kfree(dup_ext_buf); return rc; } @@ -1113,22 +1125,30 @@ static int smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile) { - struct fsctl_set_integrity_information_req integr_info; + struct fsctl_set_integrity_information_req *integr_info; unsigned int ret_data_len; + int rc; - integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED); - integr_info.Flags = 0; - integr_info.Reserved = 0; + integr_info = kzalloc(sizeof(struct fsctl_set_integrity_information_req), + GFP_KERNEL); + if (!integr_info) { + cifs_dbg(VFS, "failed to allocate integr_info\n"); + return -ENOMEM; + } + integr_info->ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED); + integr_info->Flags = 0; + integr_info->Reserved = 0; - return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, FSCTL_SET_INTEGRITY_INFORMATION, true /* is_fsctl */, - (char *)&integr_info, + (char *)integr_info, sizeof(struct fsctl_set_integrity_information_req), NULL, &ret_data_len); - + kfree(integr_info); + return rc; } static int @@ -1682,7 +1702,7 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, struct inode *inode; struct cifsInodeInfo *cifsi; struct cifsFileInfo *cfile = file->private_data; - struct file_zero_data_information fsctl_buf; + struct file_zero_data_information *fsctl_buf; long rc; unsigned int xid; @@ -1710,18 +1730,29 @@ static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon, * which for a non sparse file would zero the newly extended range */ if (keep_size == false) - if (i_size_read(inode) < offset + len) - return -EOPNOTSUPP; + if (i_size_read(inode) < offset + len) { + rc = -EOPNOTSUPP; + goto out; + } cifs_dbg(FYI, "offset %lld len %lld", offset, len); - fsctl_buf.FileOffset = cpu_to_le64(offset); - fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len); + fsctl_buf = kzalloc(sizeof(struct file_zero_data_information), + GFP_KERNEL); + if (!fsctl_buf) { + cifs_dbg(VFS, "failed to allocate fsctl_buf\n"); + rc = -ENOMEM; + goto out; + } + fsctl_buf->FileOffset = cpu_to_le64(offset); + fsctl_buf->BeyondFinalZero = cpu_to_le64(offset + len); rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, - true /* is_fctl */, (char *)&fsctl_buf, + true /* is_fctl */, (char *)fsctl_buf, sizeof(struct file_zero_data_information), NULL, NULL); + kfree(fsctl_buf); +out: free_xid(xid); return rc; } @@ -1732,10 +1763,9 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, struct inode *inode; struct cifsInodeInfo *cifsi; struct cifsFileInfo *cfile = file->private_data; - struct file_zero_data_information fsctl_buf; + struct file_zero_data_information *fsctl_buf; long rc; unsigned int xid; - __u8 set_sparse = 1; xid = get_xid(); @@ -1744,18 +1774,27 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, /* Need to make file sparse, if not already, before freeing range. */ /* Consider adding equivalent for compressed since it could also work */ - if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) - return -EOPNOTSUPP; - + if (!smb2_set_sparse(xid, tcon, cfile, inode, 1)) { + rc = -EOPNOTSUPP; + goto out; + } cifs_dbg(FYI, "offset %lld len %lld", offset, len); - fsctl_buf.FileOffset = cpu_to_le64(offset); - fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len); + fsctl_buf = kzalloc(sizeof(struct file_zero_data_information), + GFP_KERNEL); + if (!fsctl_buf) { + cifs_dbg(VFS, "failed to allocate fsctl_buf\n"); + return -ENOMEM; + } + fsctl_buf->FileOffset = cpu_to_le64(offset); + fsctl_buf->BeyondFinalZero = cpu_to_le64(offset + len); rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, - true /* is_fctl */, (char *)&fsctl_buf, + true /* is_fctl */, (char *)fsctl_buf, sizeof(struct file_zero_data_information), NULL, NULL); + kfree(fsctl_buf); +out: free_xid(xid); return rc; } @@ -1808,7 +1847,7 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) return -EOPNOTSUPP; - rc = smb2_set_sparse(xid, tcon, cfile, inode, false); + rc = smb2_set_sparse(xid, tcon, cfile, inode, 0); } /* BB: else ... in future add code to extend file and set sparse */ @@ -2128,7 +2167,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 24; int rc = 0; struct scatterlist *sg; - u8 sign[SMB2_SIGNATURE_SIZE] = {}; + u8 *sign; u8 key[SMB3_SIGN_KEY_SIZE]; struct aead_request *req; char *iv; @@ -2143,7 +2182,6 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) enc ? "en" : "de"); return 0; } - rc = smb3_crypto_aead_allocate(server); if (rc) { cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__); @@ -2170,6 +2208,13 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) return -ENOMEM; } + sign = kzalloc(SMB2_SIGNATURE_SIZE, GFP_KERNEL); + if (!sign) { + cifs_dbg(VFS, "%s: Failed to kzalloc sign", __func__); + rc = -ENOMEM; + goto free_req; + } + if (!enc) { memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); crypt_len += SMB2_SIGNATURE_SIZE; @@ -2179,7 +2224,7 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) if (!sg) { cifs_dbg(VFS, "%s: Failed to init sg", __func__); rc = -ENOMEM; - goto free_req; + goto free_sign; } iv_len = crypto_aead_ivsize(tfm); @@ -2207,6 +2252,8 @@ crypt_message(struct TCP_Server_Info *server, struct smb_rqst *rqst, int enc) kfree(iv); free_sg: kfree(sg); +free_sign: + kfree(sign); free_req: kfree(req); return rc; diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 63778ac22fd9..eca036faa755 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -609,7 +609,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) { int rc = 0; - struct validate_negotiate_info_req vneg_inbuf; + struct validate_negotiate_info_req *vneg_inbuf; struct validate_negotiate_info_rsp *pneg_rsp = NULL; u32 rsplen; u32 inbuflen; /* max of 4 dialects */ @@ -639,50 +639,57 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) if (tcon->ses->session_flags & SMB2_SESSION_FLAG_IS_NULL) cifs_dbg(VFS, "Unexpected null user (anonymous) auth flag sent by server\n"); - vneg_inbuf.Capabilities = + vneg_inbuf = kzalloc(sizeof(struct validate_negotiate_info_req), + GFP_KERNEL); + if (!vneg_inbuf) { + cifs_dbg(VFS, "failed to allocate vneg_inbuf\n"); + return -ENOMEM; + } + + vneg_inbuf->Capabilities = cpu_to_le32(tcon->ses->server->vals->req_capabilities); - memcpy(vneg_inbuf.Guid, tcon->ses->server->client_guid, + memcpy(vneg_inbuf->Guid, tcon->ses->server->client_guid, SMB2_CLIENT_GUID_SIZE); if (tcon->ses->sign) - vneg_inbuf.SecurityMode = + vneg_inbuf->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED); else if (global_secflags & CIFSSEC_MAY_SIGN) - vneg_inbuf.SecurityMode = + vneg_inbuf->SecurityMode = cpu_to_le16(SMB2_NEGOTIATE_SIGNING_ENABLED); else - vneg_inbuf.SecurityMode = 0; + vneg_inbuf->SecurityMode = 0; if (strcmp(tcon->ses->server->vals->version_string, SMB3ANY_VERSION_STRING) == 0) { - vneg_inbuf.Dialects[0] = cpu_to_le16(SMB30_PROT_ID); - vneg_inbuf.Dialects[1] = cpu_to_le16(SMB302_PROT_ID); - vneg_inbuf.DialectCount = cpu_to_le16(2); + vneg_inbuf->Dialects[0] = cpu_to_le16(SMB30_PROT_ID); + vneg_inbuf->Dialects[1] = cpu_to_le16(SMB302_PROT_ID); + vneg_inbuf->DialectCount = cpu_to_le16(2); /* structure is big enough for 3 dialects, sending only 2 */ inbuflen = sizeof(struct validate_negotiate_info_req) - 2; } else if (strcmp(tcon->ses->server->vals->version_string, SMBDEFAULT_VERSION_STRING) == 0) { - vneg_inbuf.Dialects[0] = cpu_to_le16(SMB21_PROT_ID); - vneg_inbuf.Dialects[1] = cpu_to_le16(SMB30_PROT_ID); - vneg_inbuf.Dialects[2] = cpu_to_le16(SMB302_PROT_ID); - vneg_inbuf.DialectCount = cpu_to_le16(3); + vneg_inbuf->Dialects[0] = cpu_to_le16(SMB21_PROT_ID); + vneg_inbuf->Dialects[1] = cpu_to_le16(SMB30_PROT_ID); + vneg_inbuf->Dialects[2] = cpu_to_le16(SMB302_PROT_ID); + vneg_inbuf->DialectCount = cpu_to_le16(3); /* structure is big enough for 3 dialects */ inbuflen = sizeof(struct validate_negotiate_info_req); } else { /* otherwise specific dialect was requested */ - vneg_inbuf.Dialects[0] = + vneg_inbuf->Dialects[0] = cpu_to_le16(tcon->ses->server->vals->protocol_id); - vneg_inbuf.DialectCount = cpu_to_le16(1); + vneg_inbuf->DialectCount = cpu_to_le16(1); /* structure is big enough for 3 dialects, sending only 1 */ inbuflen = sizeof(struct validate_negotiate_info_req) - 4; } rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, - (char *)&vneg_inbuf, sizeof(struct validate_negotiate_info_req), + (char *)vneg_inbuf, sizeof(struct validate_negotiate_info_req), (char **)&pneg_rsp, &rsplen); - + kfree(vneg_inbuf); if (rc != 0) { cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); return -EIO; @@ -1997,16 +2004,24 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid) { int rc; - struct compress_ioctl fsctl_input; + struct compress_ioctl *fsctl_input; char *ret_data = NULL; - fsctl_input.CompressionState = + fsctl_input = kzalloc(sizeof(struct compress_ioctl), + GFP_KERNEL); + if (!fsctl_input) { + cifs_dbg(VFS, "failed to allocate fsctl_input\n"); + return -ENOMEM; + } + + fsctl_input->CompressionState = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT); rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid, FSCTL_SET_COMPRESSION, true /* is_fsctl */, (char *)&fsctl_input /* data input */, 2 /* in data len */, &ret_data /* out data */, NULL); + kfree(fsctl_input); cifs_dbg(FYI, "set compression rc %d\n", rc); @@ -3613,15 +3628,24 @@ SMB2_lock(const unsigned int xid, struct cifs_tcon *tcon, const __u64 length, const __u64 offset, const __u32 lock_flags, const bool wait) { - struct smb2_lock_element lock; + struct smb2_lock_element *lock; + int rc; - lock.Offset = cpu_to_le64(offset); - lock.Length = cpu_to_le64(length); - lock.Flags = cpu_to_le32(lock_flags); + lock = kzalloc(sizeof(struct smb2_lock_element), GFP_KERNEL); + if (!lock) { + cifs_dbg(VFS, "failed to allocate smb2_lock_element\n"); + return -ENOMEM; + } + lock->Offset = cpu_to_le64(offset); + lock->Length = cpu_to_le64(length); + lock->Flags = cpu_to_le32(lock_flags); if (!wait && lock_flags != SMB2_LOCKFLAG_UNLOCK) - lock.Flags |= cpu_to_le32(SMB2_LOCKFLAG_FAIL_IMMEDIATELY); + lock->Flags |= cpu_to_le32(SMB2_LOCKFLAG_FAIL_IMMEDIATELY); + + rc = smb2_lockv(xid, tcon, persist_fid, volatile_fid, pid, 1, lock); + kfree(lock); - return smb2_lockv(xid, tcon, persist_fid, volatile_fid, pid, 1, &lock); + return rc; } int -- 2.13.3 -- To unsubscribe from this list: send the line "unsubscribe linux-cifs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html