@@ -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");
@@ -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,18 @@ 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;
+ }
+
+ *buf = setsparse;
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 +1055,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 +1071,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 +1079,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 +1101,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 +1110,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 +1126,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 +1703,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 +1731,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 +1764,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 +1775,28 @@ 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");
+ 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;
}
@@ -1808,7 +1849,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 +2169,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 +2184,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 +2210,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 +2226,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 +2254,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;
@@ -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
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@redhat.com> --- fs/cifs/smb2file.c | 19 +++++--- fs/cifs/smb2ops.c | 127 +++++++++++++++++++++++++++++++++++++---------------- fs/cifs/smb2pdu.c | 74 ++++++++++++++++++++----------- 3 files changed, 151 insertions(+), 69 deletions(-)