mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
Merge tag '6.13-rc-part1-SMB3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client updates from Steve French: - Fix two SMB3.1.1 POSIX Extensions problems - Fixes for special file handling (symlinks and FIFOs) - Improve compounding - Four cleanup patches - Fix use after free in signing - Add support for handling namespaces for reconnect related upcalls (e.g. for DNS names resolution and auth) - Fix various directory lease problems (directory entry caching), including some important potential use after frees * tag '6.13-rc-part1-SMB3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: prevent use-after-free due to open_cached_dir error paths smb: Don't leak cfid when reconnect races with open_cached_dir smb: client: handle max length for SMB symlinks smb: client: get rid of bounds check in SMB2_ioctl_init() smb: client: improve compound padding in encryption smb3: request handle caching when caching directories cifs: Recognize SFU char/block devices created by Windows NFS server on Windows Server <<2012 CIFS: New mount option for cifs.upcall namespace resolution smb/client: Prevent error pointer dereference fs/smb/client: implement chmod() for SMB3 POSIX Extensions smb: cached directories can be more than root file handle smb: client: fix use-after-free of signing key smb: client: Use str_yes_no() helper function smb: client: memcpy() with surrounding object base address cifs: Remove pre-historic unused CIFSSMBCopy
This commit is contained in:
@@ -59,6 +59,16 @@ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
|
||||
list_add(&cfid->entry, &cfids->entries);
|
||||
cfid->on_list = true;
|
||||
kref_get(&cfid->refcount);
|
||||
/*
|
||||
* Set @cfid->has_lease to true during construction so that the lease
|
||||
* reference can be put in cached_dir_lease_break() due to a potential
|
||||
* lease break right after the request is sent or while @cfid is still
|
||||
* being cached, or if a reconnection is triggered during construction.
|
||||
* Concurrent processes won't be to use it yet due to @cfid->time being
|
||||
* zero.
|
||||
*/
|
||||
cfid->has_lease = true;
|
||||
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
return cfid;
|
||||
}
|
||||
@@ -176,12 +186,12 @@ replay_again:
|
||||
return -ENOENT;
|
||||
}
|
||||
/*
|
||||
* Return cached fid if it has a lease. Otherwise, it is either a new
|
||||
* entry or laundromat worker removed it from @cfids->entries. Caller
|
||||
* will put last reference if the latter.
|
||||
* Return cached fid if it is valid (has a lease and has a time).
|
||||
* Otherwise, it is either a new entry or laundromat worker removed it
|
||||
* from @cfids->entries. Caller will put last reference if the latter.
|
||||
*/
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
if (cfid->has_lease) {
|
||||
if (cfid->has_lease && cfid->time) {
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
*ret_cfid = cfid;
|
||||
kfree(utf16_path);
|
||||
@@ -267,15 +277,6 @@ replay_again:
|
||||
|
||||
smb2_set_related(&rqst[1]);
|
||||
|
||||
/*
|
||||
* Set @cfid->has_lease to true before sending out compounded request so
|
||||
* its lease reference can be put in cached_dir_lease_break() due to a
|
||||
* potential lease break right after the request is sent or while @cfid
|
||||
* is still being cached. Concurrent processes won't be to use it yet
|
||||
* due to @cfid->time being zero.
|
||||
*/
|
||||
cfid->has_lease = true;
|
||||
|
||||
if (retries) {
|
||||
smb2_set_replay(server, &rqst[0]);
|
||||
smb2_set_replay(server, &rqst[1]);
|
||||
@@ -347,6 +348,7 @@ oshr_free:
|
||||
SMB2_query_info_free(&rqst[1]);
|
||||
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
||||
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
||||
out:
|
||||
if (rc) {
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
if (cfid->on_list) {
|
||||
@@ -358,23 +360,14 @@ oshr_free:
|
||||
/*
|
||||
* We are guaranteed to have two references at this
|
||||
* point. One for the caller and one for a potential
|
||||
* lease. Release the Lease-ref so that the directory
|
||||
* will be closed when the caller closes the cached
|
||||
* handle.
|
||||
* lease. Release one here, and the second below.
|
||||
*/
|
||||
cfid->has_lease = false;
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
goto out;
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
}
|
||||
out:
|
||||
if (rc) {
|
||||
if (cfid->is_open)
|
||||
SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
|
||||
cfid->fid.volatile_fid);
|
||||
free_cached_dir(cfid);
|
||||
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
} else {
|
||||
*ret_cfid = cfid;
|
||||
atomic_inc(&tcon->num_remote_opens);
|
||||
@@ -401,7 +394,7 @@ int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
list_for_each_entry(cfid, &cfids->entries, entry) {
|
||||
if (dentry && cfid->dentry == dentry) {
|
||||
cifs_dbg(FYI, "found a cached root file handle by dentry\n");
|
||||
cifs_dbg(FYI, "found a cached file handle by dentry\n");
|
||||
kref_get(&cfid->refcount);
|
||||
*ret_cfid = cfid;
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
@@ -512,25 +505,24 @@ void invalidate_all_cached_dirs(struct cifs_tcon *tcon)
|
||||
cfids->num_entries--;
|
||||
cfid->is_open = false;
|
||||
cfid->on_list = false;
|
||||
/* To prevent race with smb2_cached_lease_break() */
|
||||
kref_get(&cfid->refcount);
|
||||
if (cfid->has_lease) {
|
||||
/*
|
||||
* The lease was never cancelled from the server,
|
||||
* so steal that reference.
|
||||
*/
|
||||
cfid->has_lease = false;
|
||||
} else
|
||||
kref_get(&cfid->refcount);
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
|
||||
list_for_each_entry_safe(cfid, q, &entry, entry) {
|
||||
list_del(&cfid->entry);
|
||||
cancel_work_sync(&cfid->lease_break);
|
||||
if (cfid->has_lease) {
|
||||
/*
|
||||
* We lease was never cancelled from the server so we
|
||||
* need to drop the reference.
|
||||
*/
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
cfid->has_lease = false;
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
/* Drop the extra reference opened above*/
|
||||
/*
|
||||
* Drop the ref-count from above, either the lease-ref (if there
|
||||
* was one) or the extra one acquired.
|
||||
*/
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
}
|
||||
@@ -541,9 +533,6 @@ smb2_cached_lease_break(struct work_struct *work)
|
||||
struct cached_fid *cfid = container_of(work,
|
||||
struct cached_fid, lease_break);
|
||||
|
||||
spin_lock(&cfid->cfids->cfid_list_lock);
|
||||
cfid->has_lease = false;
|
||||
spin_unlock(&cfid->cfids->cfid_list_lock);
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
|
||||
@@ -561,6 +550,7 @@ int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16])
|
||||
!memcmp(lease_key,
|
||||
cfid->fid.lease_key,
|
||||
SMB2_LEASE_KEY_SIZE)) {
|
||||
cfid->has_lease = false;
|
||||
cfid->time = 0;
|
||||
/*
|
||||
* We found a lease remove it from the list
|
||||
@@ -638,8 +628,14 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
||||
cfid->on_list = false;
|
||||
list_move(&cfid->entry, &entry);
|
||||
cfids->num_entries--;
|
||||
/* To prevent race with smb2_cached_lease_break() */
|
||||
kref_get(&cfid->refcount);
|
||||
if (cfid->has_lease) {
|
||||
/*
|
||||
* Our lease has not yet been cancelled from the
|
||||
* server. Steal that reference.
|
||||
*/
|
||||
cfid->has_lease = false;
|
||||
} else
|
||||
kref_get(&cfid->refcount);
|
||||
}
|
||||
}
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
@@ -651,17 +647,10 @@ static void cfids_laundromat_worker(struct work_struct *work)
|
||||
* with it.
|
||||
*/
|
||||
cancel_work_sync(&cfid->lease_break);
|
||||
if (cfid->has_lease) {
|
||||
/*
|
||||
* Our lease has not yet been cancelled from the server
|
||||
* so we need to drop the reference.
|
||||
*/
|
||||
spin_lock(&cfids->cfid_list_lock);
|
||||
cfid->has_lease = false;
|
||||
spin_unlock(&cfids->cfid_list_lock);
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
/* Drop the extra reference opened above */
|
||||
/*
|
||||
* Drop the ref-count from above, either the lease-ref (if there
|
||||
* was one) or the extra one acquired.
|
||||
*/
|
||||
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
||||
}
|
||||
queue_delayed_work(cifsiod_wq, &cfids->laundromat_work,
|
||||
|
||||
@@ -82,6 +82,9 @@ struct key_type cifs_spnego_key_type = {
|
||||
/* strlen of ";pid=0x" */
|
||||
#define PID_KEY_LEN 7
|
||||
|
||||
/* strlen of ";upcall_target=" */
|
||||
#define UPCALL_TARGET_KEY_LEN 15
|
||||
|
||||
/* get a key struct with a SPNEGO security blob, suitable for session setup */
|
||||
struct key *
|
||||
cifs_get_spnego_key(struct cifs_ses *sesInfo,
|
||||
@@ -108,6 +111,11 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
|
||||
if (sesInfo->user_name)
|
||||
desc_len += USER_KEY_LEN + strlen(sesInfo->user_name);
|
||||
|
||||
if (sesInfo->upcall_target == UPTARGET_MOUNT)
|
||||
desc_len += UPCALL_TARGET_KEY_LEN + 5; // strlen("mount")
|
||||
else
|
||||
desc_len += UPCALL_TARGET_KEY_LEN + 3; // strlen("app")
|
||||
|
||||
spnego_key = ERR_PTR(-ENOMEM);
|
||||
description = kzalloc(desc_len, GFP_KERNEL);
|
||||
if (description == NULL)
|
||||
@@ -156,6 +164,14 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo,
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";pid=0x%x", current->pid);
|
||||
|
||||
if (sesInfo->upcall_target == UPTARGET_MOUNT) {
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";upcall_target=mount");
|
||||
} else {
|
||||
dp = description + strlen(description);
|
||||
sprintf(dp, ";upcall_target=app");
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "key description = %s\n", description);
|
||||
saved_cred = override_creds(spnego_cred);
|
||||
spnego_key = request_key(&cifs_spnego_key_type, description, "");
|
||||
|
||||
@@ -885,12 +885,17 @@ unsigned int setup_authusers_ACE(struct smb_ace *pntace)
|
||||
* Fill in the special SID based on the mode. See
|
||||
* https://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
|
||||
*/
|
||||
unsigned int setup_special_mode_ACE(struct smb_ace *pntace, __u64 nmode)
|
||||
unsigned int setup_special_mode_ACE(struct smb_ace *pntace,
|
||||
bool posix,
|
||||
__u64 nmode)
|
||||
{
|
||||
int i;
|
||||
unsigned int ace_size = 28;
|
||||
|
||||
pntace->type = ACCESS_DENIED_ACE_TYPE;
|
||||
if (posix)
|
||||
pntace->type = ACCESS_ALLOWED_ACE_TYPE;
|
||||
else
|
||||
pntace->type = ACCESS_DENIED_ACE_TYPE;
|
||||
pntace->flags = 0x0;
|
||||
pntace->access_req = 0;
|
||||
pntace->sid.num_subauth = 3;
|
||||
@@ -933,7 +938,8 @@ static void populate_new_aces(char *nacl_base,
|
||||
struct smb_sid *pownersid,
|
||||
struct smb_sid *pgrpsid,
|
||||
__u64 *pnmode, u32 *pnum_aces, u16 *pnsize,
|
||||
bool modefromsid)
|
||||
bool modefromsid,
|
||||
bool posix)
|
||||
{
|
||||
__u64 nmode;
|
||||
u32 num_aces = 0;
|
||||
@@ -950,13 +956,15 @@ static void populate_new_aces(char *nacl_base,
|
||||
num_aces = *pnum_aces;
|
||||
nsize = *pnsize;
|
||||
|
||||
if (modefromsid) {
|
||||
if (modefromsid || posix) {
|
||||
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
||||
nsize += setup_special_mode_ACE(pnntace, nmode);
|
||||
num_aces++;
|
||||
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
||||
nsize += setup_authusers_ACE(pnntace);
|
||||
nsize += setup_special_mode_ACE(pnntace, posix, nmode);
|
||||
num_aces++;
|
||||
if (modefromsid) {
|
||||
pnntace = (struct smb_ace *) (nacl_base + nsize);
|
||||
nsize += setup_authusers_ACE(pnntace);
|
||||
num_aces++;
|
||||
}
|
||||
goto set_size;
|
||||
}
|
||||
|
||||
@@ -1076,7 +1084,7 @@ static __u16 replace_sids_and_copy_aces(struct smb_acl *pdacl, struct smb_acl *p
|
||||
|
||||
static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
||||
struct smb_sid *pownersid, struct smb_sid *pgrpsid,
|
||||
__u64 *pnmode, bool mode_from_sid)
|
||||
__u64 *pnmode, bool mode_from_sid, bool posix)
|
||||
{
|
||||
int i;
|
||||
u16 size = 0;
|
||||
@@ -1094,11 +1102,11 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
||||
nsize = sizeof(struct smb_acl);
|
||||
|
||||
/* If pdacl is NULL, we don't have a src. Simply populate new ACL. */
|
||||
if (!pdacl) {
|
||||
if (!pdacl || posix) {
|
||||
populate_new_aces(nacl_base,
|
||||
pownersid, pgrpsid,
|
||||
pnmode, &num_aces, &nsize,
|
||||
mode_from_sid);
|
||||
mode_from_sid, posix);
|
||||
goto finalize_dacl;
|
||||
}
|
||||
|
||||
@@ -1115,7 +1123,7 @@ static int set_chmod_dacl(struct smb_acl *pdacl, struct smb_acl *pndacl,
|
||||
populate_new_aces(nacl_base,
|
||||
pownersid, pgrpsid,
|
||||
pnmode, &num_aces, &nsize,
|
||||
mode_from_sid);
|
||||
mode_from_sid, posix);
|
||||
|
||||
new_aces_set = true;
|
||||
}
|
||||
@@ -1144,7 +1152,7 @@ next_ace:
|
||||
populate_new_aces(nacl_base,
|
||||
pownersid, pgrpsid,
|
||||
pnmode, &num_aces, &nsize,
|
||||
mode_from_sid);
|
||||
mode_from_sid, posix);
|
||||
|
||||
new_aces_set = true;
|
||||
}
|
||||
@@ -1251,7 +1259,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb,
|
||||
/* Convert permission bits from mode to equivalent CIFS ACL */
|
||||
static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
|
||||
__u32 secdesclen, __u32 *pnsecdesclen, __u64 *pnmode, kuid_t uid, kgid_t gid,
|
||||
bool mode_from_sid, bool id_from_sid, int *aclflag)
|
||||
bool mode_from_sid, bool id_from_sid, bool posix, int *aclflag)
|
||||
{
|
||||
int rc = 0;
|
||||
__u32 dacloffset;
|
||||
@@ -1288,7 +1296,7 @@ static int build_sec_desc(struct smb_ntsd *pntsd, struct smb_ntsd *pnntsd,
|
||||
ndacl_ptr->num_aces = cpu_to_le32(0);
|
||||
|
||||
rc = set_chmod_dacl(dacl_ptr, ndacl_ptr, owner_sid_ptr, group_sid_ptr,
|
||||
pnmode, mode_from_sid);
|
||||
pnmode, mode_from_sid, posix);
|
||||
|
||||
sidsoffset = ndacloffset + le16_to_cpu(ndacl_ptr->size);
|
||||
/* copy the non-dacl portion of secdesc */
|
||||
@@ -1584,13 +1592,16 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
||||
struct smb_ntsd *pntsd = NULL; /* acl obtained from server */
|
||||
struct smb_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
struct tcon_link *tlink;
|
||||
struct smb_version_operations *ops;
|
||||
bool mode_from_sid, id_from_sid;
|
||||
const u32 info = 0;
|
||||
bool posix;
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink))
|
||||
return PTR_ERR(tlink);
|
||||
posix = tlink_tcon(tlink)->posix_extensions;
|
||||
|
||||
ops = tlink_tcon(tlink)->ses->server->ops;
|
||||
|
||||
@@ -1622,12 +1633,13 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
||||
id_from_sid = false;
|
||||
|
||||
/* Potentially, five new ACEs can be added to the ACL for U,G,O mapping */
|
||||
nsecdesclen = secdesclen;
|
||||
if (pnmode && *pnmode != NO_CHANGE_64) { /* chmod */
|
||||
if (mode_from_sid)
|
||||
nsecdesclen += 2 * sizeof(struct smb_ace);
|
||||
if (posix)
|
||||
nsecdesclen = 1 * sizeof(struct smb_ace);
|
||||
else if (mode_from_sid)
|
||||
nsecdesclen = secdesclen + (2 * sizeof(struct smb_ace));
|
||||
else /* cifsacl */
|
||||
nsecdesclen += 5 * sizeof(struct smb_ace);
|
||||
nsecdesclen = secdesclen + (5 * sizeof(struct smb_ace));
|
||||
} else { /* chown */
|
||||
/* When ownership changes, changes new owner sid length could be different */
|
||||
nsecdesclen = sizeof(struct smb_ntsd) + (sizeof(struct smb_sid) * 2);
|
||||
@@ -1657,7 +1669,7 @@ id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 *pnmode,
|
||||
}
|
||||
|
||||
rc = build_sec_desc(pntsd, pnntsd, secdesclen, &nsecdesclen, pnmode, uid, gid,
|
||||
mode_from_sid, id_from_sid, &aclflag);
|
||||
mode_from_sid, id_from_sid, posix, &aclflag);
|
||||
|
||||
cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
|
||||
|
||||
|
||||
@@ -546,6 +546,30 @@ static int cifs_show_devname(struct seq_file *m, struct dentry *root)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cifs_show_upcall_target(struct seq_file *s, struct cifs_sb_info *cifs_sb)
|
||||
{
|
||||
if (cifs_sb->ctx->upcall_target == UPTARGET_UNSPECIFIED) {
|
||||
seq_puts(s, ",upcall_target=app");
|
||||
return;
|
||||
}
|
||||
|
||||
seq_puts(s, ",upcall_target=");
|
||||
|
||||
switch (cifs_sb->ctx->upcall_target) {
|
||||
case UPTARGET_APP:
|
||||
seq_puts(s, "app");
|
||||
break;
|
||||
case UPTARGET_MOUNT:
|
||||
seq_puts(s, "mount");
|
||||
break;
|
||||
default:
|
||||
/* shouldn't ever happen */
|
||||
seq_puts(s, "unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* cifs_show_options() is for displaying mount options in /proc/mounts.
|
||||
* Not all settable options are displayed but most of the important
|
||||
@@ -562,6 +586,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
|
||||
seq_show_option(s, "vers", tcon->ses->server->vals->version_string);
|
||||
cifs_show_security(s, tcon->ses);
|
||||
cifs_show_cache_flavor(s, cifs_sb);
|
||||
cifs_show_upcall_target(s, cifs_sb);
|
||||
|
||||
if (tcon->no_lease)
|
||||
seq_puts(s, ",nolease");
|
||||
|
||||
@@ -153,6 +153,12 @@ enum securityEnum {
|
||||
Kerberos, /* Kerberos via SPNEGO */
|
||||
};
|
||||
|
||||
enum upcall_target_enum {
|
||||
UPTARGET_UNSPECIFIED, /* not specified, defaults to app */
|
||||
UPTARGET_MOUNT, /* upcall to the mount namespace */
|
||||
UPTARGET_APP, /* upcall to the application namespace which did the mount */
|
||||
};
|
||||
|
||||
enum cifs_reparse_type {
|
||||
CIFS_REPARSE_TYPE_NFS,
|
||||
CIFS_REPARSE_TYPE_WSL,
|
||||
@@ -1084,6 +1090,7 @@ struct cifs_ses {
|
||||
struct session_key auth_key;
|
||||
struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */
|
||||
enum securityEnum sectype; /* what security flavor was specified? */
|
||||
enum upcall_target_enum upcall_target; /* what upcall target was specified? */
|
||||
bool sign; /* is signing required? */
|
||||
bool domainAuto:1;
|
||||
bool expired_pwd; /* track if access denied or expired pwd so can know if need to update */
|
||||
@@ -2223,7 +2230,7 @@ static inline int cifs_get_num_sgs(const struct smb_rqst *rqst,
|
||||
struct kvec *iov = &rqst[i].rq_iov[j];
|
||||
|
||||
addr = (unsigned long)iov->iov_base + skip;
|
||||
if (unlikely(is_vmalloc_addr((void *)addr))) {
|
||||
if (is_vmalloc_or_module_addr((void *)addr)) {
|
||||
len = iov->iov_len - skip;
|
||||
nents += DIV_ROUND_UP(offset_in_page(addr) + len,
|
||||
PAGE_SIZE);
|
||||
@@ -2250,7 +2257,7 @@ static inline void cifs_sg_set_buf(struct sg_table *sgtable,
|
||||
unsigned int off = offset_in_page(addr);
|
||||
|
||||
addr &= PAGE_MASK;
|
||||
if (unlikely(is_vmalloc_addr((void *)addr))) {
|
||||
if (is_vmalloc_or_module_addr((void *)addr)) {
|
||||
do {
|
||||
unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
|
||||
|
||||
|
||||
@@ -244,7 +244,9 @@ extern int cifs_set_acl(struct mnt_idmap *idmap,
|
||||
extern int set_cifs_acl(struct smb_ntsd *pntsd, __u32 len, struct inode *ino,
|
||||
const char *path, int flag);
|
||||
extern unsigned int setup_authusers_ACE(struct smb_ace *pace);
|
||||
extern unsigned int setup_special_mode_ACE(struct smb_ace *pace, __u64 nmode);
|
||||
extern unsigned int setup_special_mode_ACE(struct smb_ace *pace,
|
||||
bool posix,
|
||||
__u64 nmode);
|
||||
extern unsigned int setup_special_user_owner_ACE(struct smb_ace *pace);
|
||||
|
||||
extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
|
||||
@@ -549,13 +551,6 @@ extern int generate_smb311signingkey(struct cifs_ses *ses,
|
||||
struct TCP_Server_Info *server);
|
||||
|
||||
#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
|
||||
extern int CIFSSMBCopy(unsigned int xid,
|
||||
struct cifs_tcon *source_tcon,
|
||||
const char *fromName,
|
||||
const __u16 target_tid,
|
||||
const char *toName, const int flags,
|
||||
const struct nls_table *nls_codepage,
|
||||
int remap_special_chars);
|
||||
extern ssize_t CIFSSMBQAllEAs(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const unsigned char *searchName,
|
||||
const unsigned char *ea_name, char *EAData,
|
||||
|
||||
@@ -2339,69 +2339,6 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
CIFSSMBCopy(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fromName, const __u16 target_tid, const char *toName,
|
||||
const int flags, const struct nls_table *nls_codepage, int remap)
|
||||
{
|
||||
int rc = 0;
|
||||
COPY_REQ *pSMB = NULL;
|
||||
COPY_RSP *pSMBr = NULL;
|
||||
int bytes_returned;
|
||||
int name_len, name_len2;
|
||||
__u16 count;
|
||||
|
||||
cifs_dbg(FYI, "In CIFSSMBCopy\n");
|
||||
copyRetry:
|
||||
rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
|
||||
(void **) &pSMBr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pSMB->BufferFormat = 0x04;
|
||||
pSMB->Tid2 = target_tid;
|
||||
|
||||
pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
|
||||
|
||||
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
|
||||
name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
|
||||
fromName, PATH_MAX, nls_codepage,
|
||||
remap);
|
||||
name_len++; /* trailing null */
|
||||
name_len *= 2;
|
||||
pSMB->OldFileName[name_len] = 0x04; /* pad */
|
||||
/* protocol requires ASCII signature byte on Unicode string */
|
||||
pSMB->OldFileName[name_len + 1] = 0x00;
|
||||
name_len2 =
|
||||
cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
|
||||
toName, PATH_MAX, nls_codepage, remap);
|
||||
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
|
||||
name_len2 *= 2; /* convert to bytes */
|
||||
} else {
|
||||
name_len = copy_path_name(pSMB->OldFileName, fromName);
|
||||
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
|
||||
name_len2 = copy_path_name(pSMB->OldFileName+name_len+1, toName);
|
||||
name_len2++; /* signature byte */
|
||||
}
|
||||
|
||||
count = 1 /* 1st signature byte */ + name_len + name_len2;
|
||||
inc_rfc1001_len(pSMB, count);
|
||||
pSMB->ByteCount = cpu_to_le16(count);
|
||||
|
||||
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
|
||||
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
|
||||
if (rc) {
|
||||
cifs_dbg(FYI, "Send error in copy = %d with %d files copied\n",
|
||||
rc, le16_to_cpu(pSMBr->CopyCount));
|
||||
}
|
||||
cifs_buf_release(pSMB);
|
||||
|
||||
if (rc == -EAGAIN)
|
||||
goto copyRetry;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
CIFSUnixCreateSymLink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
const char *fromName, const char *toName,
|
||||
@@ -5406,7 +5343,7 @@ SetTimesRetry:
|
||||
param_offset = offsetof(struct smb_com_transaction2_spi_req,
|
||||
InformationLevel) - 4;
|
||||
offset = param_offset + params;
|
||||
data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
|
||||
data_offset = (char *)pSMB + offsetof(typeof(*pSMB), hdr.Protocol) + offset;
|
||||
pSMB->ParameterOffset = cpu_to_le16(param_offset);
|
||||
pSMB->DataOffset = cpu_to_le16(offset);
|
||||
pSMB->SetupCount = 1;
|
||||
|
||||
@@ -2339,6 +2339,26 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
|
||||
|
||||
ses->sectype = ctx->sectype;
|
||||
ses->sign = ctx->sign;
|
||||
|
||||
/*
|
||||
*Explicitly marking upcall_target mount option for easier handling
|
||||
* by cifs_spnego.c and eventually cifs.upcall.c
|
||||
*/
|
||||
|
||||
switch (ctx->upcall_target) {
|
||||
case UPTARGET_UNSPECIFIED: /* default to app */
|
||||
case UPTARGET_APP:
|
||||
ses->upcall_target = UPTARGET_APP;
|
||||
break;
|
||||
case UPTARGET_MOUNT:
|
||||
ses->upcall_target = UPTARGET_MOUNT;
|
||||
break;
|
||||
default:
|
||||
// should never happen
|
||||
ses->upcall_target = UPTARGET_APP;
|
||||
break;
|
||||
}
|
||||
|
||||
ses->local_nls = load_nls(ctx->local_nls->charset);
|
||||
|
||||
/* add server as first channel */
|
||||
|
||||
@@ -173,8 +173,8 @@ static int dfscache_proc_show(struct seq_file *m, void *v)
|
||||
"cache entry: path=%s,type=%s,ttl=%d,etime=%ld,hdr_flags=0x%x,ref_flags=0x%x,interlink=%s,path_consumed=%d,expired=%s\n",
|
||||
ce->path, ce->srvtype == DFS_TYPE_ROOT ? "root" : "link",
|
||||
ce->ttl, ce->etime.tv_nsec, ce->hdr_flags, ce->ref_flags,
|
||||
DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
ce->path_consumed, cache_entry_expired(ce) ? "yes" : "no");
|
||||
str_yes_no(DFS_INTERLINK(ce->hdr_flags)),
|
||||
ce->path_consumed, str_yes_no(cache_entry_expired(ce)));
|
||||
|
||||
list_for_each_entry(t, &ce->tlist, list) {
|
||||
seq_printf(m, " %s%s\n",
|
||||
@@ -242,9 +242,9 @@ static inline void dump_ce(const struct cache_entry *ce)
|
||||
ce->srvtype == DFS_TYPE_ROOT ? "root" : "link", ce->ttl,
|
||||
ce->etime.tv_nsec,
|
||||
ce->hdr_flags, ce->ref_flags,
|
||||
DFS_INTERLINK(ce->hdr_flags) ? "yes" : "no",
|
||||
str_yes_no(DFS_INTERLINK(ce->hdr_flags)),
|
||||
ce->path_consumed,
|
||||
cache_entry_expired(ce) ? "yes" : "no");
|
||||
str_yes_no(cache_entry_expired(ce)));
|
||||
dump_tgts(ce);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,6 +67,12 @@ static const match_table_t cifs_secflavor_tokens = {
|
||||
{ Opt_sec_err, NULL }
|
||||
};
|
||||
|
||||
static const match_table_t cifs_upcall_target = {
|
||||
{ Opt_upcall_target_mount, "mount" },
|
||||
{ Opt_upcall_target_application, "app" },
|
||||
{ Opt_upcall_target_err, NULL }
|
||||
};
|
||||
|
||||
const struct fs_parameter_spec smb3_fs_parameters[] = {
|
||||
/* Mount options that take no arguments */
|
||||
fsparam_flag_no("user_xattr", Opt_user_xattr),
|
||||
@@ -178,6 +184,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
|
||||
fsparam_string("sec", Opt_sec),
|
||||
fsparam_string("cache", Opt_cache),
|
||||
fsparam_string("reparse", Opt_reparse),
|
||||
fsparam_string("upcall_target", Opt_upcalltarget),
|
||||
|
||||
/* Arguments that should be ignored */
|
||||
fsparam_flag("guest", Opt_ignore),
|
||||
@@ -248,6 +255,29 @@ cifs_parse_security_flavors(struct fs_context *fc, char *value, struct smb3_fs_c
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
cifs_parse_upcall_target(struct fs_context *fc, char *value, struct smb3_fs_context *ctx)
|
||||
{
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
|
||||
ctx->upcall_target = UPTARGET_UNSPECIFIED;
|
||||
|
||||
switch (match_token(value, cifs_upcall_target, args)) {
|
||||
case Opt_upcall_target_mount:
|
||||
ctx->upcall_target = UPTARGET_MOUNT;
|
||||
break;
|
||||
case Opt_upcall_target_application:
|
||||
ctx->upcall_target = UPTARGET_APP;
|
||||
break;
|
||||
|
||||
default:
|
||||
cifs_errorf(fc, "bad upcall target: %s\n", value);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const match_table_t cifs_cacheflavor_tokens = {
|
||||
{ Opt_cache_loose, "loose" },
|
||||
{ Opt_cache_strict, "strict" },
|
||||
@@ -1450,6 +1480,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
if (cifs_parse_security_flavors(fc, param->string, ctx) != 0)
|
||||
goto cifs_parse_mount_err;
|
||||
break;
|
||||
case Opt_upcalltarget:
|
||||
if (cifs_parse_upcall_target(fc, param->string, ctx) != 0)
|
||||
goto cifs_parse_mount_err;
|
||||
break;
|
||||
case Opt_cache:
|
||||
if (cifs_parse_cache_flavor(fc, param->string, ctx) != 0)
|
||||
goto cifs_parse_mount_err;
|
||||
@@ -1627,6 +1661,11 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
|
||||
}
|
||||
/* case Opt_ignore: - is ignored as expected ... */
|
||||
|
||||
if (ctx->multiuser && ctx->upcall_target == UPTARGET_MOUNT) {
|
||||
cifs_errorf(fc, "multiuser mount option not supported with upcalltarget set as 'mount'\n");
|
||||
goto cifs_parse_mount_err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
cifs_parse_mount_err:
|
||||
|
||||
@@ -61,6 +61,12 @@ enum cifs_sec_param {
|
||||
Opt_sec_err
|
||||
};
|
||||
|
||||
enum cifs_upcall_target_param {
|
||||
Opt_upcall_target_mount,
|
||||
Opt_upcall_target_application,
|
||||
Opt_upcall_target_err
|
||||
};
|
||||
|
||||
enum cifs_param {
|
||||
/* Mount options that take no arguments */
|
||||
Opt_user_xattr,
|
||||
@@ -114,6 +120,8 @@ enum cifs_param {
|
||||
Opt_multichannel,
|
||||
Opt_compress,
|
||||
Opt_witness,
|
||||
Opt_is_upcall_target_mount,
|
||||
Opt_is_upcall_target_application,
|
||||
|
||||
/* Mount options which take numeric value */
|
||||
Opt_backupuid,
|
||||
@@ -157,6 +165,7 @@ enum cifs_param {
|
||||
Opt_sec,
|
||||
Opt_cache,
|
||||
Opt_reparse,
|
||||
Opt_upcalltarget,
|
||||
|
||||
/* Mount options to be ignored */
|
||||
Opt_ignore,
|
||||
@@ -198,6 +207,7 @@ struct smb3_fs_context {
|
||||
umode_t file_mode;
|
||||
umode_t dir_mode;
|
||||
enum securityEnum sectype; /* sectype requested via mnt opts */
|
||||
enum upcall_target_enum upcall_target; /* where to upcall for mount */
|
||||
bool sign; /* was signing requested via mnt opts? */
|
||||
bool ignore_signature:1;
|
||||
bool retry:1;
|
||||
|
||||
@@ -598,6 +598,17 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
|
||||
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
||||
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
||||
fattr->cf_rdev = MKDEV(mjr, mnr);
|
||||
} else if (bytes_read == 16) {
|
||||
/*
|
||||
* Windows NFS server before Windows Server 2012
|
||||
* stores major and minor number in SFU-modified
|
||||
* style, just as 32-bit numbers. Recognize it.
|
||||
*/
|
||||
__u32 mjr; /* major */
|
||||
__u32 mnr; /* minor */
|
||||
mjr = le32_to_cpu(*(__le32 *)(pbuf+8));
|
||||
mnr = le32_to_cpu(*(__le32 *)(pbuf+12));
|
||||
fattr->cf_rdev = MKDEV(mjr, mnr);
|
||||
}
|
||||
} else if (memcmp("IntxCHR\0", pbuf, 8) == 0) {
|
||||
cifs_dbg(FYI, "Char device\n");
|
||||
@@ -610,6 +621,17 @@ cifs_sfu_type(struct cifs_fattr *fattr, const char *path,
|
||||
mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
|
||||
mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
|
||||
fattr->cf_rdev = MKDEV(mjr, mnr);
|
||||
} else if (bytes_read == 16) {
|
||||
/*
|
||||
* Windows NFS server before Windows Server 2012
|
||||
* stores major and minor number in SFU-modified
|
||||
* style, just as 32-bit numbers. Recognize it.
|
||||
*/
|
||||
__u32 mjr; /* major */
|
||||
__u32 mnr; /* minor */
|
||||
mjr = le32_to_cpu(*(__le32 *)(pbuf+8));
|
||||
mnr = le32_to_cpu(*(__le32 *)(pbuf+12));
|
||||
fattr->cf_rdev = MKDEV(mjr, mnr);
|
||||
}
|
||||
} else if (memcmp("LnxSOCK", pbuf, 8) == 0) {
|
||||
cifs_dbg(FYI, "Socket\n");
|
||||
@@ -3062,6 +3084,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
int rc = -EACCES;
|
||||
__u32 dosattr = 0;
|
||||
__u64 mode = NO_CHANGE_64;
|
||||
bool posix = cifs_sb_master_tcon(cifs_sb)->posix_extensions;
|
||||
|
||||
xid = get_xid();
|
||||
|
||||
@@ -3152,7 +3175,8 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
|
||||
mode = attrs->ia_mode;
|
||||
rc = 0;
|
||||
if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) ||
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID)) {
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID) ||
|
||||
posix) {
|
||||
rc = id_mode_to_cifs_acl(inode, full_path, &mode,
|
||||
INVALID_UID, INVALID_GID);
|
||||
if (rc) {
|
||||
|
||||
@@ -35,6 +35,9 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
|
||||
u16 len, plen;
|
||||
int rc = 0;
|
||||
|
||||
if (strlen(symname) > REPARSE_SYM_PATH_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
sym = kstrdup(symname, GFP_KERNEL);
|
||||
if (!sym)
|
||||
return -ENOMEM;
|
||||
@@ -64,7 +67,7 @@ int smb2_create_reparse_symlink(const unsigned int xid, struct inode *inode,
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
plen = 2 * UniStrnlen((wchar_t *)path, PATH_MAX);
|
||||
plen = 2 * UniStrnlen((wchar_t *)path, REPARSE_SYM_PATH_MAX);
|
||||
len = sizeof(*buf) + plen * 2;
|
||||
buf = kzalloc(len, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "fs_context.h"
|
||||
#include "cifsglob.h"
|
||||
|
||||
#define REPARSE_SYM_PATH_MAX 4060
|
||||
|
||||
/*
|
||||
* Used only by cifs.ko to ignore reparse points from files when client or
|
||||
* server doesn't support FSCTL_GET_REPARSE_POINT.
|
||||
|
||||
@@ -2606,7 +2606,7 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
|
||||
struct cifs_ses *ses = tcon->ses;
|
||||
struct TCP_Server_Info *server = ses->server;
|
||||
unsigned long len = smb_rqst_len(server, rqst);
|
||||
int i, num_padding;
|
||||
int num_padding;
|
||||
|
||||
shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base);
|
||||
if (shdr == NULL) {
|
||||
@@ -2615,44 +2615,13 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
|
||||
}
|
||||
|
||||
/* SMB headers in a compound are 8 byte aligned. */
|
||||
|
||||
/* No padding needed */
|
||||
if (!(len & 7))
|
||||
goto finished;
|
||||
|
||||
num_padding = 8 - (len & 7);
|
||||
if (!smb3_encryption_required(tcon)) {
|
||||
/*
|
||||
* If we do not have encryption then we can just add an extra
|
||||
* iov for the padding.
|
||||
*/
|
||||
if (!IS_ALIGNED(len, 8)) {
|
||||
num_padding = 8 - (len & 7);
|
||||
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
|
||||
rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
|
||||
rqst->rq_nvec++;
|
||||
len += num_padding;
|
||||
} else {
|
||||
/*
|
||||
* We can not add a small padding iov for the encryption case
|
||||
* because the encryption framework can not handle the padding
|
||||
* iovs.
|
||||
* We have to flatten this into a single buffer and add
|
||||
* the padding to it.
|
||||
*/
|
||||
for (i = 1; i < rqst->rq_nvec; i++) {
|
||||
memcpy(rqst->rq_iov[0].iov_base +
|
||||
rqst->rq_iov[0].iov_len,
|
||||
rqst->rq_iov[i].iov_base,
|
||||
rqst->rq_iov[i].iov_len);
|
||||
rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
|
||||
}
|
||||
memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
|
||||
0, num_padding);
|
||||
rqst->rq_iov[0].iov_len += num_padding;
|
||||
len += num_padding;
|
||||
rqst->rq_nvec = 1;
|
||||
}
|
||||
|
||||
finished:
|
||||
shdr->NextCommand = cpu_to_le32(len);
|
||||
}
|
||||
|
||||
@@ -4080,7 +4049,7 @@ map_oplock_to_lease(u8 oplock)
|
||||
if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
|
||||
return SMB2_LEASE_WRITE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE;
|
||||
else if (oplock == SMB2_OPLOCK_LEVEL_II)
|
||||
return SMB2_LEASE_READ_CACHING_LE;
|
||||
return SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE;
|
||||
else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
|
||||
return SMB2_LEASE_HANDLE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE |
|
||||
SMB2_LEASE_WRITE_CACHING_LE;
|
||||
|
||||
@@ -2683,7 +2683,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned int *len)
|
||||
ptr += sizeof(struct smb3_acl);
|
||||
|
||||
/* create one ACE to hold the mode embedded in reserved special SID */
|
||||
acelen = setup_special_mode_ACE((struct smb_ace *)ptr, (__u64)mode);
|
||||
acelen = setup_special_mode_ACE((struct smb_ace *)ptr, false, (__u64)mode);
|
||||
ptr += acelen;
|
||||
acl_size = acelen + sizeof(struct smb3_acl);
|
||||
ace_count = 1;
|
||||
@@ -3313,15 +3313,6 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server,
|
||||
return rc;
|
||||
|
||||
if (indatalen) {
|
||||
unsigned int len;
|
||||
|
||||
if (WARN_ON_ONCE(smb3_encryption_required(tcon) &&
|
||||
(check_add_overflow(total_len - 1,
|
||||
ALIGN(indatalen, 8), &len) ||
|
||||
len > MAX_CIFS_SMALL_BUFFER_SIZE))) {
|
||||
cifs_small_buf_release(req);
|
||||
return -EIO;
|
||||
}
|
||||
/*
|
||||
* indatalen is usually small at a couple of bytes max, so
|
||||
* just allocate through generic pool
|
||||
|
||||
@@ -37,8 +37,6 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses,
|
||||
struct smb_rqst *rqst);
|
||||
extern struct mid_q_entry *smb2_setup_async_request(
|
||||
struct TCP_Server_Info *server, struct smb_rqst *rqst);
|
||||
extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server,
|
||||
__u64 ses_id);
|
||||
extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server,
|
||||
__u64 ses_id, __u32 tid);
|
||||
extern int smb2_calc_signature(struct smb_rqst *rqst,
|
||||
|
||||
@@ -74,7 +74,7 @@ err:
|
||||
|
||||
|
||||
static
|
||||
int smb2_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
|
||||
int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
|
||||
{
|
||||
struct cifs_chan *chan;
|
||||
struct TCP_Server_Info *pserver;
|
||||
@@ -168,16 +168,41 @@ smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct cifs_ses *
|
||||
smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id)
|
||||
static int smb2_get_sign_key(struct TCP_Server_Info *server,
|
||||
__u64 ses_id, u8 *key)
|
||||
{
|
||||
struct cifs_ses *ses;
|
||||
int rc = -ENOENT;
|
||||
|
||||
if (SERVER_IS_CHAN(server))
|
||||
server = server->primary_server;
|
||||
|
||||
spin_lock(&cifs_tcp_ses_lock);
|
||||
ses = smb2_find_smb_ses_unlocked(server, ses_id);
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
|
||||
if (ses->Suid != ses_id)
|
||||
continue;
|
||||
|
||||
return ses;
|
||||
rc = 0;
|
||||
spin_lock(&ses->ses_lock);
|
||||
switch (ses->ses_status) {
|
||||
case SES_EXITING: /* SMB2_LOGOFF */
|
||||
case SES_GOOD:
|
||||
if (likely(ses->auth_key.response)) {
|
||||
memcpy(key, ses->auth_key.response,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
} else {
|
||||
rc = -EIO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
spin_unlock(&ses->ses_lock);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&cifs_tcp_ses_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct cifs_tcon *
|
||||
@@ -236,14 +261,16 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
unsigned char *sigptr = smb2_signature;
|
||||
struct kvec *iov = rqst->rq_iov;
|
||||
struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
|
||||
struct cifs_ses *ses;
|
||||
struct shash_desc *shash = NULL;
|
||||
struct smb_rqst drqst;
|
||||
__u64 sid = le64_to_cpu(shdr->SessionId);
|
||||
u8 key[SMB2_NTLMV2_SESSKEY_SIZE];
|
||||
|
||||
ses = smb2_find_smb_ses(server, le64_to_cpu(shdr->SessionId));
|
||||
if (unlikely(!ses)) {
|
||||
cifs_server_dbg(FYI, "%s: Could not find session\n", __func__);
|
||||
return -ENOENT;
|
||||
rc = smb2_get_sign_key(server, sid, key);
|
||||
if (unlikely(rc)) {
|
||||
cifs_server_dbg(FYI, "%s: [sesid=0x%llx] couldn't find signing key: %d\n",
|
||||
__func__, sid, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
|
||||
@@ -260,8 +287,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
shash = server->secmech.hmacsha256;
|
||||
}
|
||||
|
||||
rc = crypto_shash_setkey(shash->tfm, ses->auth_key.response,
|
||||
SMB2_NTLMV2_SESSKEY_SIZE);
|
||||
rc = crypto_shash_setkey(shash->tfm, key, sizeof(key));
|
||||
if (rc) {
|
||||
cifs_server_dbg(VFS,
|
||||
"%s: Could not update with response\n",
|
||||
@@ -303,8 +329,6 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
out:
|
||||
if (allocate_crypto)
|
||||
cifs_free_hash(&shash);
|
||||
if (ses)
|
||||
cifs_put_smb_ses(ses);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -570,7 +594,7 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
|
||||
struct smb_rqst drqst;
|
||||
u8 key[SMB3_SIGN_KEY_SIZE];
|
||||
|
||||
rc = smb2_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
|
||||
rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
|
||||
if (unlikely(rc)) {
|
||||
cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__);
|
||||
return rc;
|
||||
|
||||
@@ -418,19 +418,16 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct send_req_vars {
|
||||
struct smb2_transform_hdr tr_hdr;
|
||||
struct smb_rqst rqst[MAX_COMPOUND];
|
||||
struct kvec iov;
|
||||
};
|
||||
|
||||
static int
|
||||
smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
struct smb_rqst *rqst, int flags)
|
||||
{
|
||||
struct send_req_vars *vars;
|
||||
struct smb_rqst *cur_rqst;
|
||||
struct kvec *iov;
|
||||
struct smb2_transform_hdr tr_hdr;
|
||||
struct smb_rqst new_rqst[MAX_COMPOUND] = {};
|
||||
struct kvec iov = {
|
||||
.iov_base = &tr_hdr,
|
||||
.iov_len = sizeof(tr_hdr),
|
||||
};
|
||||
int rc;
|
||||
|
||||
if (flags & CIFS_COMPRESS_REQ)
|
||||
@@ -447,26 +444,15 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_rqst,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
vars = kzalloc(sizeof(*vars), GFP_NOFS);
|
||||
if (!vars)
|
||||
return -ENOMEM;
|
||||
cur_rqst = vars->rqst;
|
||||
iov = &vars->iov;
|
||||
|
||||
iov->iov_base = &vars->tr_hdr;
|
||||
iov->iov_len = sizeof(vars->tr_hdr);
|
||||
cur_rqst[0].rq_iov = iov;
|
||||
cur_rqst[0].rq_nvec = 1;
|
||||
new_rqst[0].rq_iov = &iov;
|
||||
new_rqst[0].rq_nvec = 1;
|
||||
|
||||
rc = server->ops->init_transform_rq(server, num_rqst + 1,
|
||||
&cur_rqst[0], rqst);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = __smb_send_rqst(server, num_rqst + 1, &cur_rqst[0]);
|
||||
smb3_free_compound_rqst(num_rqst, &cur_rqst[1]);
|
||||
out:
|
||||
kfree(vars);
|
||||
new_rqst, rqst);
|
||||
if (!rc) {
|
||||
rc = __smb_send_rqst(server, num_rqst + 1, new_rqst);
|
||||
smb3_free_compound_rqst(num_rqst, &new_rqst[1]);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user