first set of cifs fixes for 4.13, bug fixes and improved POSIX character mapping
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQGcBAABAgAGBQJZYBCAAAoJEIosvXAHck9R2tMMAKSzD0O4cQn+TVEDpw9ZkwSc g7xKjG57q/wc0ZuOk75FR9CPiWBgyno/3W7hsTfm/PhyqPHw2dOaCkgcUbahNamH RlxY3TzU8yAUucxDdFcxL47whdj1NJwDynyjtHshEL3eKx2bd5STG8cw4UQrSLOU CrG0XlqthPrgNEJavYP6bvrdfiuYeAnYykDdHwJiFLGVGgBhzqRVgjrTJkFClIlf qQEal4+H2Hz5rM89I0xQLZINh4UflPtX8lIngohyHnpT5sFxal4k2BnibjFzG8Vg r/zc5ePjEBvkIlpF5pAS2P6LO9295qOAltK5Wiq+7DYVS/KUDguQDMaXCTWb/zI6 rAi7TFCNlDOOmySj0vsU2AqubI9ZZ2iCeA4eaPRrSVda3ZAG2hNYm+M1P91trS6d fqNJTsaPMYF4Je3lC7fe4PQIzBcq+H9gQk4gC0mAgyJ1rQmjSlm+yBop4ZdzepIA g+q7HgOA8QL/+a7D/1AfPTp9dcT5z0V5vz60+KKWXQ== =XSvA -----END PGP SIGNATURE----- Merge tag 'cifs-bug-fixes-for-4.13' of git://git.samba.org/sfrench/cifs-2.6 Pull cifs fixes from Steve French: "First set of CIFS/SMB3 fixes for the merge window. Also improves POSIX character mapping for SMB3" * tag 'cifs-bug-fixes-for-4.13' of git://git.samba.org/sfrench/cifs-2.6: CIFS: fix circular locking dependency cifs: set oparms.create_options rather than or'ing in CREATE_OPEN_BACKUP_INTENT cifs: Do not modify mid entry after submitting I/O in cifs_call_async CIFS: add SFM mapping for 0x01-0x1F cifs: hide unused functions cifs: Use smb 2 - 3 and cifsacl mount options getacl functions cifs: prototype declaration and definition for smb 2 - 3 and cifsacl mount options CIFS: add CONFIG_CIFS_DEBUG_KEYS to dump encryption keys cifs: set mapping error when page writeback fails in writepage or launder_pages SMB3: Enable encryption for SMB3.1.1
This commit is contained in:
commit
3ea4fcc5fe
8 changed files with 219 additions and 25 deletions
|
@ -146,6 +146,15 @@ config CIFS_DEBUG2
|
|||
option can be turned off unless you are debugging
|
||||
cifs problems. If unsure, say N.
|
||||
|
||||
config CIFS_DEBUG_DUMP_KEYS
|
||||
bool "Dump encryption keys for offline decryption (Unsafe)"
|
||||
depends on CIFS_DEBUG && CIFS_SMB2
|
||||
help
|
||||
Enabling this will dump the encryption and decryption keys
|
||||
used to communicate on an encrypted share connection on the
|
||||
console. This allows Wireshark to decrypt and dissect
|
||||
encrypted network captures. Enable this carefully.
|
||||
|
||||
config CIFS_DFS_UPCALL
|
||||
bool "DFS feature support"
|
||||
depends on CIFS && KEYS
|
||||
|
|
|
@ -79,6 +79,10 @@ convert_sfu_char(const __u16 src_char, char *target)
|
|||
static bool
|
||||
convert_sfm_char(const __u16 src_char, char *target)
|
||||
{
|
||||
if (src_char >= 0xF001 && src_char <= 0xF01F) {
|
||||
*target = src_char - 0xF000;
|
||||
return true;
|
||||
}
|
||||
switch (src_char) {
|
||||
case SFM_COLON:
|
||||
*target = ':';
|
||||
|
@ -417,6 +421,10 @@ static __le16 convert_to_sfm_char(char src_char, bool end_of_string)
|
|||
{
|
||||
__le16 dest_char;
|
||||
|
||||
if (src_char >= 0x01 && src_char <= 0x1F) {
|
||||
dest_char = cpu_to_le16(src_char + 0xF000);
|
||||
return dest_char;
|
||||
}
|
||||
switch (src_char) {
|
||||
case ':':
|
||||
dest_char = cpu_to_le16(SFM_COLON);
|
||||
|
|
|
@ -2234,14 +2234,16 @@ cifs_writepage_locked(struct page *page, struct writeback_control *wbc)
|
|||
set_page_writeback(page);
|
||||
retry_write:
|
||||
rc = cifs_partialpagewrite(page, 0, PAGE_SIZE);
|
||||
if (rc == -EAGAIN && wbc->sync_mode == WB_SYNC_ALL)
|
||||
goto retry_write;
|
||||
else if (rc == -EAGAIN)
|
||||
if (rc == -EAGAIN) {
|
||||
if (wbc->sync_mode == WB_SYNC_ALL)
|
||||
goto retry_write;
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
else if (rc != 0)
|
||||
} else if (rc != 0) {
|
||||
SetPageError(page);
|
||||
else
|
||||
mapping_set_error(page->mapping, rc);
|
||||
} else {
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
end_page_writeback(page);
|
||||
put_page(page);
|
||||
free_xid(xid);
|
||||
|
@ -2810,12 +2812,12 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
|
|||
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
||||
ssize_t rc;
|
||||
|
||||
inode_lock(inode);
|
||||
/*
|
||||
* We need to hold the sem to be sure nobody modifies lock list
|
||||
* with a brlock that prevents writing.
|
||||
*/
|
||||
down_read(&cinode->lock_sem);
|
||||
inode_lock(inode);
|
||||
|
||||
rc = generic_write_checks(iocb, from);
|
||||
if (rc <= 0)
|
||||
|
@ -2828,11 +2830,11 @@ cifs_writev(struct kiocb *iocb, struct iov_iter *from)
|
|||
else
|
||||
rc = -EACCES;
|
||||
out:
|
||||
up_read(&cinode->lock_sem);
|
||||
inode_unlock(inode);
|
||||
|
||||
if (rc > 0)
|
||||
rc = generic_write_sync(iocb, rc);
|
||||
up_read(&cinode->lock_sem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -1288,6 +1288,108 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
return rc;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
static struct cifs_ntsd *
|
||||
get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
||||
const struct cifs_fid *cifsfid, u32 *pacllen)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
unsigned int xid;
|
||||
int rc = -EOPNOTSUPP;
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
|
||||
if (IS_ERR(tlink))
|
||||
return ERR_CAST(tlink);
|
||||
|
||||
xid = get_xid();
|
||||
cifs_dbg(FYI, "trying to get acl\n");
|
||||
|
||||
rc = SMB2_query_acl(xid, tlink_tcon(tlink), cifsfid->persistent_fid,
|
||||
cifsfid->volatile_fid, (void **)&pntsd, pacllen);
|
||||
free_xid(xid);
|
||||
|
||||
cifs_put_tlink(tlink);
|
||||
|
||||
cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
return pntsd;
|
||||
|
||||
}
|
||||
|
||||
static struct cifs_ntsd *
|
||||
get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
|
||||
const char *path, u32 *pacllen)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
||||
unsigned int xid;
|
||||
int rc;
|
||||
struct cifs_tcon *tcon;
|
||||
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
||||
struct cifs_fid fid;
|
||||
struct cifs_open_parms oparms;
|
||||
__le16 *utf16_path;
|
||||
|
||||
cifs_dbg(FYI, "get smb3 acl for path %s\n", path);
|
||||
if (IS_ERR(tlink))
|
||||
return ERR_CAST(tlink);
|
||||
|
||||
tcon = tlink_tcon(tlink);
|
||||
xid = get_xid();
|
||||
|
||||
if (backup_cred(cifs_sb))
|
||||
oparms.create_options = CREATE_OPEN_BACKUP_INTENT;
|
||||
else
|
||||
oparms.create_options = 0;
|
||||
|
||||
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
||||
if (!utf16_path)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
oparms.tcon = tcon;
|
||||
oparms.desired_access = READ_CONTROL;
|
||||
oparms.disposition = FILE_OPEN;
|
||||
oparms.fid = &fid;
|
||||
oparms.reconnect = false;
|
||||
|
||||
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
|
||||
kfree(utf16_path);
|
||||
if (!rc) {
|
||||
rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
|
||||
fid.volatile_fid, (void **)&pntsd, pacllen);
|
||||
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
||||
}
|
||||
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid(xid);
|
||||
|
||||
cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
return pntsd;
|
||||
}
|
||||
|
||||
/* Retrieve an ACL from the server */
|
||||
static struct cifs_ntsd *
|
||||
get_smb2_acl(struct cifs_sb_info *cifs_sb,
|
||||
struct inode *inode, const char *path,
|
||||
u32 *pacllen)
|
||||
{
|
||||
struct cifs_ntsd *pntsd = NULL;
|
||||
struct cifsFileInfo *open_file = NULL;
|
||||
|
||||
if (inode)
|
||||
open_file = find_readable_file(CIFS_I(inode), true);
|
||||
if (!open_file)
|
||||
return get_smb2_acl_by_path(cifs_sb, path, pacllen);
|
||||
|
||||
pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
|
||||
cifsFileInfo_put(open_file);
|
||||
return pntsd;
|
||||
}
|
||||
#endif
|
||||
|
||||
static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||
loff_t offset, loff_t len, bool keep_size)
|
||||
{
|
||||
|
@ -2393,6 +2495,11 @@ struct smb_version_operations smb20_operations = {
|
|||
.dir_needs_close = smb2_dir_needs_close,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
/* .set_acl = set_smb3_acl, */
|
||||
#endif /* CIFS_ACL */
|
||||
};
|
||||
|
||||
struct smb_version_operations smb21_operations = {
|
||||
|
@ -2477,6 +2584,11 @@ struct smb_version_operations smb21_operations = {
|
|||
.enum_snapshots = smb3_enum_snapshots,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
/* .set_acl = set_smb3_acl, */
|
||||
#endif /* CIFS_ACL */
|
||||
};
|
||||
|
||||
struct smb_version_operations smb30_operations = {
|
||||
|
@ -2571,6 +2683,11 @@ struct smb_version_operations smb30_operations = {
|
|||
.receive_transform = smb3_receive_transform,
|
||||
.get_dfs_refer = smb2_get_dfs_refer,
|
||||
.select_sectype = smb2_select_sectype,
|
||||
#ifdef CONFIG_CIFS_ACL
|
||||
.get_acl = get_smb2_acl,
|
||||
.get_acl_by_fid = get_smb2_acl_by_fid,
|
||||
/* .set_acl = set_smb3_acl, */
|
||||
#endif /* CIFS_ACL */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CIFS_SMB311
|
||||
|
@ -2753,7 +2870,7 @@ struct smb_version_values smb302_values = {
|
|||
struct smb_version_values smb311_values = {
|
||||
.version_string = SMB311_VERSION_STRING,
|
||||
.protocol_id = SMB311_PROT_ID,
|
||||
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
|
||||
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION,
|
||||
.large_lock_type = 0,
|
||||
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
|
||||
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
|
||||
|
|
|
@ -2081,8 +2081,9 @@ validate_and_copy_buf(unsigned int offset, unsigned int buffer_length,
|
|||
|
||||
static int
|
||||
query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, u8 info_class,
|
||||
size_t output_len, size_t min_len, void *data)
|
||||
u64 persistent_fid, u64 volatile_fid, u8 info_class, u8 info_type,
|
||||
u32 additional_info, size_t output_len, size_t min_len, void **data,
|
||||
u32 *dlen)
|
||||
{
|
||||
struct smb2_query_info_req *req;
|
||||
struct smb2_query_info_rsp *rsp = NULL;
|
||||
|
@ -2108,10 +2109,11 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
if (encryption_required(tcon))
|
||||
flags |= CIFS_TRANSFORM_REQ;
|
||||
|
||||
req->InfoType = SMB2_O_INFO_FILE;
|
||||
req->InfoType = info_type;
|
||||
req->FileInfoClass = info_class;
|
||||
req->PersistentFileId = persistent_fid;
|
||||
req->VolatileFileId = volatile_fid;
|
||||
req->AdditionalInformation = cpu_to_le32(additional_info);
|
||||
/* 4 for rfc1002 length field and 1 for Buffer */
|
||||
req->InputBufferOffset =
|
||||
cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
|
||||
|
@ -2130,24 +2132,51 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
goto qinf_exit;
|
||||
}
|
||||
|
||||
if (dlen) {
|
||||
*dlen = le32_to_cpu(rsp->OutputBufferLength);
|
||||
if (!*data) {
|
||||
*data = kmalloc(*dlen, GFP_KERNEL);
|
||||
if (!*data) {
|
||||
cifs_dbg(VFS,
|
||||
"Error %d allocating memory for acl\n",
|
||||
rc);
|
||||
*dlen = 0;
|
||||
goto qinf_exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
|
||||
le32_to_cpu(rsp->OutputBufferLength),
|
||||
&rsp->hdr, min_len, data);
|
||||
&rsp->hdr, min_len, *data);
|
||||
|
||||
qinf_exit:
|
||||
free_rsp_buf(resp_buftype, rsp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
struct smb2_file_all_info *data)
|
||||
int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid, struct smb2_file_all_info *data)
|
||||
{
|
||||
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
FILE_ALL_INFORMATION,
|
||||
FILE_ALL_INFORMATION, SMB2_O_INFO_FILE, 0,
|
||||
sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
|
||||
sizeof(struct smb2_file_all_info), data);
|
||||
sizeof(struct smb2_file_all_info), (void **)&data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int
|
||||
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
void **data, u32 *plen)
|
||||
{
|
||||
__u32 additional_info = OWNER_SECINFO | GROUP_SECINFO | DACL_SECINFO;
|
||||
*plen = 0;
|
||||
|
||||
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
0, SMB2_O_INFO_SECURITY, additional_info,
|
||||
SMB2_MAX_BUFFER_SIZE,
|
||||
sizeof(struct smb2_file_all_info), data, plen);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -2155,9 +2184,10 @@ SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
|
||||
{
|
||||
return query_info(xid, tcon, persistent_fid, volatile_fid,
|
||||
FILE_INTERNAL_INFORMATION,
|
||||
FILE_INTERNAL_INFORMATION, SMB2_O_INFO_FILE, 0,
|
||||
sizeof(struct smb2_file_internal_info),
|
||||
sizeof(struct smb2_file_internal_info), uniqueid);
|
||||
sizeof(struct smb2_file_internal_info),
|
||||
(void **)&uniqueid, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -135,6 +135,9 @@ extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
|
|||
extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
struct smb2_file_all_info *data);
|
||||
extern int SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_file_id, u64 volatile_file_id,
|
||||
void **data, unsigned int *plen);
|
||||
extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
|
||||
u64 persistent_fid, u64 volatile_fid,
|
||||
__le64 *uniqueid);
|
||||
|
|
|
@ -335,9 +335,31 @@ generate_smb3signingkey(struct cifs_ses *ses,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
return generate_key(ses, ptriplet->decryption.label,
|
||||
ptriplet->decryption.context,
|
||||
ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
|
||||
rc = generate_key(ses, ptriplet->decryption.label,
|
||||
ptriplet->decryption.context,
|
||||
ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
|
||||
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
#ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
|
||||
cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__);
|
||||
/*
|
||||
* The session id is opaque in terms of endianness, so we can't
|
||||
* print it as a long long. we dump it as we got it on the wire
|
||||
*/
|
||||
cifs_dbg(VFS, "Session Id %*ph\n", (int)sizeof(ses->Suid),
|
||||
&ses->Suid);
|
||||
cifs_dbg(VFS, "Session Key %*ph\n",
|
||||
SMB2_NTLMV2_SESSKEY_SIZE, ses->auth_key.response);
|
||||
cifs_dbg(VFS, "Signing Key %*ph\n",
|
||||
SMB3_SIGN_KEY_SIZE, ses->smb3signingkey);
|
||||
cifs_dbg(VFS, "ServerIn Key %*ph\n",
|
||||
SMB3_SIGN_KEY_SIZE, ses->smb3encryptionkey);
|
||||
cifs_dbg(VFS, "ServerOut Key %*ph\n",
|
||||
SMB3_SIGN_KEY_SIZE, ses->smb3decryptionkey);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -536,11 +536,14 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst,
|
|||
list_add_tail(&mid->qhead, &server->pending_mid_q);
|
||||
spin_unlock(&GlobalMid_Lock);
|
||||
|
||||
|
||||
/*
|
||||
* Need to store the time in mid before calling I/O. For call_async,
|
||||
* I/O response may come back and free the mid entry on another thread.
|
||||
*/
|
||||
cifs_save_when_sent(mid);
|
||||
cifs_in_send_inc(server);
|
||||
rc = smb_send_rqst(server, rqst, flags);
|
||||
cifs_in_send_dec(server);
|
||||
cifs_save_when_sent(mid);
|
||||
|
||||
if (rc < 0) {
|
||||
server->sequence_number -= 2;
|
||||
|
|
Loading…
Reference in a new issue