Skip to content

Commit

Permalink
Merge tag '4.18-fixes-smb3' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
Pull cifs fixes from Steve French:

 - one smb3 (ACL related) fix for stable

 - one SMB3 security enhancement (when mounting -t smb3 forbid less
   secure dialects)

 - some RDMA and compounding fixes

* tag '4.18-fixes-smb3' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: fix a buffer leak in smb2_query_symlink
  smb3: do not allow insecure cifs mounts when using smb3
  CIFS: Fix NULL ptr deref
  CIFS: fix encryption in SMB3.1.1
  CIFS: Pass page offset for encrypting
  CIFS: Pass page offset for calculating signature
  CIFS: SMBD: Support page offset in memory registration
  CIFS: SMBD: Support page offset in RDMA recv
  CIFS: SMBD: Support page offset in RDMA send
  CIFS: When sending data on socket, pass the correct page offset
  CIFS: Introduce helper function to get page offset and length in smb_rqst
  CIFS: Calculate the correct request length based on page offset and tail size
  cifs: For SMB2 security informaion query, check for minimum sized security descriptor instead of sizeof FileAllInformation class
  CIFS: Fix signing for SMB2/3
  • Loading branch information
Linus Torvalds committed Jun 10, 2018
2 parents bbaa101 + 9d874c3 commit 0c14e43
Show file tree
Hide file tree
Showing 18 changed files with 261 additions and 138 deletions.
14 changes: 14 additions & 0 deletions fs/cifs/cifsacl.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,18 @@ struct cifs_ace {
struct cifs_sid sid; /* ie UUID of user or group who gets these perms */
} __attribute__((packed));

/*
* Minimum security identifier can be one for system defined Users
* and Groups such as NULL SID and World or Built-in accounts such
* as Administrator and Guest and consists of
* Revision + Num (Sub)Auths + Authority + Domain (one Subauthority)
*/
#define MIN_SID_LEN (1 + 1 + 6 + 4) /* in bytes */

/*
* Minimum security descriptor can be one without any SACL and DACL and can
* consist of revision, type, and two sids of minimum size for owner and group
*/
#define MIN_SEC_DESC_LEN (sizeof(struct cifs_ntsd) + (2 * MIN_SID_LEN))

#endif /* _CIFSACL_H */
17 changes: 8 additions & 9 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <crypto/aead.h>

int __cifs_calc_signature(struct smb_rqst *rqst,
int start,
struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash)
{
Expand All @@ -45,10 +46,7 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
struct kvec *iov = rqst->rq_iov;
int n_vec = rqst->rq_nvec;

if (n_vec < 2 || iov[0].iov_len != 4)
return -EIO;

for (i = 1; i < n_vec; i++) {
for (i = start; i < n_vec; i++) {
if (iov[i].iov_len == 0)
continue;
if (iov[i].iov_base == NULL) {
Expand All @@ -68,11 +66,12 @@ int __cifs_calc_signature(struct smb_rqst *rqst,

/* now hash over the rq_pages array */
for (i = 0; i < rqst->rq_npages; i++) {
void *kaddr = kmap(rqst->rq_pages[i]);
size_t len = rqst->rq_pagesz;
void *kaddr;
unsigned int len, offset;

rqst_page_get_length(rqst, i, &len, &offset);

if (i == rqst->rq_npages - 1)
len = rqst->rq_tailsz;
kaddr = (char *) kmap(rqst->rq_pages[i]) + offset;

crypto_shash_update(shash, kaddr, len);

Expand Down Expand Up @@ -119,7 +118,7 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
return rc;
}

return __cifs_calc_signature(rqst, server, signature,
return __cifs_calc_signature(rqst, 1, server, signature,
&server->secmech.sdescmd5->shash);
}

Expand Down
22 changes: 18 additions & 4 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -698,8 +698,8 @@ static int cifs_set_super(struct super_block *sb, void *data)
}

static struct dentry *
cifs_do_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
cifs_smb3_do_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, bool is_smb3)
{
int rc;
struct super_block *sb;
Expand All @@ -710,7 +710,7 @@ cifs_do_mount(struct file_system_type *fs_type,

cifs_dbg(FYI, "Devname: %s flags: %d\n", dev_name, flags);

volume_info = cifs_get_volume_info((char *)data, dev_name);
volume_info = cifs_get_volume_info((char *)data, dev_name, is_smb3);
if (IS_ERR(volume_info))
return ERR_CAST(volume_info);

Expand Down Expand Up @@ -790,6 +790,20 @@ cifs_do_mount(struct file_system_type *fs_type,
goto out;
}

static struct dentry *
smb3_do_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return cifs_smb3_do_mount(fs_type, flags, dev_name, data, true);
}

static struct dentry *
cifs_do_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return cifs_smb3_do_mount(fs_type, flags, dev_name, data, false);
}

static ssize_t
cifs_loose_read_iter(struct kiocb *iocb, struct iov_iter *iter)
{
Expand Down Expand Up @@ -925,7 +939,7 @@ MODULE_ALIAS_FS("cifs");
static struct file_system_type smb3_fs_type = {
.owner = THIS_MODULE,
.name = "smb3",
.mount = cifs_do_mount,
.mount = smb3_do_mount,
.kill_sb = cifs_kill_sb,
/* .fs_flags */
};
Expand Down
6 changes: 6 additions & 0 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,12 @@ tlink_tcon(struct tcon_link *tlink)
return tlink->tl_tcon;
}

static inline struct tcon_link *
cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
{
return cifs_sb->master_tlink;
}

extern void cifs_put_tlink(struct tcon_link *tlink);

static inline struct tcon_link *
Expand Down
7 changes: 5 additions & 2 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ extern int cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
extern int cifs_match_super(struct super_block *, void *);
extern void cifs_cleanup_volume_info(struct smb_vol *pvolume_info);
extern struct smb_vol *cifs_get_volume_info(char *mount_data,
const char *devname);
const char *devname, bool is_smb3);
extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *);
extern void cifs_umount(struct cifs_sb_info *);
extern void cifs_mark_open_files_invalid(struct cifs_tcon *tcon);
Expand Down Expand Up @@ -544,7 +544,7 @@ int cifs_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb,
const unsigned char *path, char *pbuf,
unsigned int *pbytes_written);
int __cifs_calc_signature(struct smb_rqst *rqst,
int __cifs_calc_signature(struct smb_rqst *rqst, int start,
struct TCP_Server_Info *server, char *signature,
struct shash_desc *shash);
enum securityEnum cifs_select_sectype(struct TCP_Server_Info *,
Expand All @@ -557,4 +557,7 @@ int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
struct sdesc **sdesc);
void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);

extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset);

#endif /* _CIFSPROTO_H */
32 changes: 17 additions & 15 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ static int generic_ip_connect(struct TCP_Server_Info *server);
static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink);
static void cifs_prune_tlinks(struct work_struct *work);
static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
const char *devname);
const char *devname, bool is_smb3);

/*
* cifs tcp session reconnection
Expand Down Expand Up @@ -1166,7 +1166,7 @@ cifs_parse_cache_flavor(char *value, struct smb_vol *vol)
}

static int
cifs_parse_smb_version(char *value, struct smb_vol *vol)
cifs_parse_smb_version(char *value, struct smb_vol *vol, bool is_smb3)
{
substring_t args[MAX_OPT_ARGS];

Expand All @@ -1176,6 +1176,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
cifs_dbg(VFS, "mount with legacy dialect disabled\n");
return 1;
}
if (is_smb3) {
cifs_dbg(VFS, "vers=1.0 (cifs) not permitted when mounting with smb3\n");
return 1;
}
vol->ops = &smb1_operations;
vol->vals = &smb1_values;
break;
Expand All @@ -1184,6 +1188,10 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
cifs_dbg(VFS, "mount with legacy dialect disabled\n");
return 1;
}
if (is_smb3) {
cifs_dbg(VFS, "vers=2.0 not permitted when mounting with smb3\n");
return 1;
}
vol->ops = &smb20_operations;
vol->vals = &smb20_values;
break;
Expand Down Expand Up @@ -1272,7 +1280,7 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol)

static int
cifs_parse_mount_options(const char *mountdata, const char *devname,
struct smb_vol *vol)
struct smb_vol *vol, bool is_smb3)
{
char *data, *end;
char *mountdata_copy = NULL, *options;
Expand Down Expand Up @@ -1985,7 +1993,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (string == NULL)
goto out_nomem;

if (cifs_parse_smb_version(string, vol) != 0)
if (cifs_parse_smb_version(string, vol, is_smb3) != 0)
goto cifs_parse_mount_err;
got_version = true;
break;
Expand Down Expand Up @@ -3116,12 +3124,6 @@ cifs_put_tlink(struct tcon_link *tlink)
return;
}

static inline struct tcon_link *
cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
{
return cifs_sb->master_tlink;
}

static int
compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data)
{
Expand Down Expand Up @@ -3803,7 +3805,7 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,
} else {
cleanup_volume_info_contents(volume_info);
rc = cifs_setup_volume_info(volume_info, mdata,
fake_devname);
fake_devname, false);
}
kfree(fake_devname);
kfree(cifs_sb->mountdata);
Expand All @@ -3816,11 +3818,11 @@ expand_dfs_referral(const unsigned int xid, struct cifs_ses *ses,

static int
cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
const char *devname)
const char *devname, bool is_smb3)
{
int rc = 0;

if (cifs_parse_mount_options(mount_data, devname, volume_info))
if (cifs_parse_mount_options(mount_data, devname, volume_info, is_smb3))
return -EINVAL;

if (volume_info->nullauth) {
Expand Down Expand Up @@ -3854,7 +3856,7 @@ cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data,
}

struct smb_vol *
cifs_get_volume_info(char *mount_data, const char *devname)
cifs_get_volume_info(char *mount_data, const char *devname, bool is_smb3)
{
int rc;
struct smb_vol *volume_info;
Expand All @@ -3863,7 +3865,7 @@ cifs_get_volume_info(char *mount_data, const char *devname)
if (!volume_info)
return ERR_PTR(-ENOMEM);

rc = cifs_setup_volume_info(volume_info, mount_data, devname);
rc = cifs_setup_volume_info(volume_info, mount_data, devname, is_smb3);
if (rc) {
cifs_cleanup_volume_info(volume_info);
volume_info = ERR_PTR(rc);
Expand Down
6 changes: 4 additions & 2 deletions fs/cifs/link.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,8 @@ smb3_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
return -ENOMEM;
}

rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL);
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, pfile_info, NULL,
NULL);
if (rc)
goto qmf_out_open_fail;

Expand Down Expand Up @@ -478,7 +479,8 @@ smb3_create_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
oparms.fid = &fid;
oparms.reconnect = false;

rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
NULL);
if (rc) {
kfree(utf16_path);
return rc;
Expand Down
17 changes: 17 additions & 0 deletions fs/cifs/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -905,3 +905,20 @@ cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
crypto_free_shash(*shash);
*shash = NULL;
}

/**
* rqst_page_get_length - obtain the length and offset for a page in smb_rqst
* Input: rqst - a smb_rqst, page - a page index for rqst
* Output: *len - the length for this page, *offset - the offset for this page
*/
void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset)
{
*len = rqst->rq_pagesz;
*offset = (page == 0) ? rqst->rq_offset : 0;

if (rqst->rq_npages == 1 || page == rqst->rq_npages-1)
*len = rqst->rq_tailsz;
else if (page == 0)
*len = rqst->rq_pagesz - rqst->rq_offset;
}
3 changes: 2 additions & 1 deletion fs/cifs/smb2file.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);

rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL);
rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL,
NULL);
if (rc)
goto out;

Expand Down
3 changes: 2 additions & 1 deletion fs/cifs/smb2inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
oparms.fid = &fid;
oparms.reconnect = false;

rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
NULL);
if (rc) {
kfree(utf16_path);
return rc;
Expand Down
4 changes: 3 additions & 1 deletion fs/cifs/smb2misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,10 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
start_of_path = from + 1;
#ifdef CONFIG_CIFS_SMB311
/* SMB311 POSIX extensions paths do not include leading slash */
else if (cifs_sb_master_tcon(cifs_sb)->posix_extensions)
else if (cifs_sb_master_tlink(cifs_sb) &&
cifs_sb_master_tcon(cifs_sb)->posix_extensions) {
start_of_path = from + 1;
}
#endif /* 311 */
else
start_of_path = from;
Expand Down
Loading

0 comments on commit 0c14e43

Please sign in to comment.