Skip to content

Commit 7c0ec89

Browse files
committed
Merge tag '5.13-rc4-smb3' of git://git.samba.org/sfrench/cifs-2.6
Pull cifs fixes from Steve French: "Three SMB3 fixes. Two for stable, and the other fixes a problem pointed out with a recently added ioctl" * tag '5.13-rc4-smb3' of git://git.samba.org/sfrench/cifs-2.6: cifs: change format of CIFS_FULL_KEY_DUMP ioctl cifs: fix string declarations and assignments in tracepoints cifs: set server->cipher_type to AES-128-CCM for SMB3.0
2 parents 5ff2756 + 1bb5681 commit 7c0ec89

File tree

5 files changed

+150
-57
lines changed

5 files changed

+150
-57
lines changed

fs/cifs/cifs_ioctl.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,28 @@ struct smb3_key_debug_info {
7272
} __packed;
7373

7474
/*
75-
* Dump full key (32 byte encrypt/decrypt keys instead of 16 bytes)
76-
* is needed if GCM256 (stronger encryption) negotiated
75+
* Dump variable-sized keys
7776
*/
7877
struct smb3_full_key_debug_info {
79-
__u64 Suid;
78+
/* INPUT: size of userspace buffer */
79+
__u32 in_size;
80+
81+
/*
82+
* INPUT: 0 for current user, otherwise session to dump
83+
* OUTPUT: session id that was dumped
84+
*/
85+
__u64 session_id;
8086
__u16 cipher_type;
81-
__u8 auth_key[16]; /* SMB2_NTLMV2_SESSKEY_SIZE */
82-
__u8 smb3encryptionkey[32]; /* SMB3_ENC_DEC_KEY_SIZE */
83-
__u8 smb3decryptionkey[32]; /* SMB3_ENC_DEC_KEY_SIZE */
87+
__u8 session_key_length;
88+
__u8 server_in_key_length;
89+
__u8 server_out_key_length;
90+
__u8 data[];
91+
/*
92+
* return this struct with the keys appended at the end:
93+
* __u8 session_key[session_key_length];
94+
* __u8 server_in_key[server_in_key_length];
95+
* __u8 server_out_key[server_out_key_length];
96+
*/
8497
} __packed;
8598

8699
struct smb3_notify {

fs/cifs/cifspdu.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@
148148
#define SMB3_SIGN_KEY_SIZE (16)
149149

150150
/*
151-
* Size of the smb3 encryption/decryption keys
151+
* Size of the smb3 encryption/decryption key storage.
152+
* This size is big enough to store any cipher key types.
152153
*/
153154
#define SMB3_ENC_DEC_KEY_SIZE (32)
154155

fs/cifs/ioctl.c

Lines changed: 105 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "cifsfs.h"
3434
#include "cifs_ioctl.h"
3535
#include "smb2proto.h"
36+
#include "smb2glob.h"
3637
#include <linux/btrfs.h>
3738

3839
static long cifs_ioctl_query_info(unsigned int xid, struct file *filep,
@@ -214,48 +215,112 @@ static int cifs_shutdown(struct super_block *sb, unsigned long arg)
214215
return 0;
215216
}
216217

217-
static int cifs_dump_full_key(struct cifs_tcon *tcon, unsigned long arg)
218+
static int cifs_dump_full_key(struct cifs_tcon *tcon, struct smb3_full_key_debug_info __user *in)
218219
{
219-
struct smb3_full_key_debug_info pfull_key_inf;
220-
__u64 suid;
221-
struct list_head *tmp;
220+
struct smb3_full_key_debug_info out;
222221
struct cifs_ses *ses;
222+
int rc = 0;
223223
bool found = false;
224+
u8 __user *end;
224225

225-
if (!smb3_encryption_required(tcon))
226-
return -EOPNOTSUPP;
226+
if (!smb3_encryption_required(tcon)) {
227+
rc = -EOPNOTSUPP;
228+
goto out;
229+
}
230+
231+
/* copy user input into our output buffer */
232+
if (copy_from_user(&out, in, sizeof(out))) {
233+
rc = -EINVAL;
234+
goto out;
235+
}
236+
237+
if (!out.session_id) {
238+
/* if ses id is 0, use current user session */
239+
ses = tcon->ses;
240+
} else {
241+
/* otherwise if a session id is given, look for it in all our sessions */
242+
struct cifs_ses *ses_it = NULL;
243+
struct TCP_Server_Info *server_it = NULL;
227244

228-
ses = tcon->ses; /* default to user id for current user */
229-
if (get_user(suid, (__u64 __user *)arg))
230-
suid = 0;
231-
if (suid) {
232-
/* search to see if there is a session with a matching SMB UID */
233245
spin_lock(&cifs_tcp_ses_lock);
234-
list_for_each(tmp, &tcon->ses->server->smb_ses_list) {
235-
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
236-
if (ses->Suid == suid) {
237-
found = true;
238-
break;
246+
list_for_each_entry(server_it, &cifs_tcp_ses_list, tcp_ses_list) {
247+
list_for_each_entry(ses_it, &server_it->smb_ses_list, smb_ses_list) {
248+
if (ses_it->Suid == out.session_id) {
249+
ses = ses_it;
250+
/*
251+
* since we are using the session outside the crit
252+
* section, we need to make sure it won't be released
253+
* so increment its refcount
254+
*/
255+
ses->ses_count++;
256+
found = true;
257+
goto search_end;
258+
}
239259
}
240260
}
261+
search_end:
241262
spin_unlock(&cifs_tcp_ses_lock);
242-
if (found == false)
243-
return -EINVAL;
244-
} /* else uses default user's SMB UID (ie current user) */
245-
246-
pfull_key_inf.cipher_type = le16_to_cpu(ses->server->cipher_type);
247-
pfull_key_inf.Suid = ses->Suid;
248-
memcpy(pfull_key_inf.auth_key, ses->auth_key.response,
249-
16 /* SMB2_NTLMV2_SESSKEY_SIZE */);
250-
memcpy(pfull_key_inf.smb3decryptionkey, ses->smb3decryptionkey,
251-
32 /* SMB3_ENC_DEC_KEY_SIZE */);
252-
memcpy(pfull_key_inf.smb3encryptionkey,
253-
ses->smb3encryptionkey, 32 /* SMB3_ENC_DEC_KEY_SIZE */);
254-
if (copy_to_user((void __user *)arg, &pfull_key_inf,
255-
sizeof(struct smb3_full_key_debug_info)))
256-
return -EFAULT;
263+
if (!found) {
264+
rc = -ENOENT;
265+
goto out;
266+
}
267+
}
257268

258-
return 0;
269+
switch (ses->server->cipher_type) {
270+
case SMB2_ENCRYPTION_AES128_CCM:
271+
case SMB2_ENCRYPTION_AES128_GCM:
272+
out.session_key_length = CIFS_SESS_KEY_SIZE;
273+
out.server_in_key_length = out.server_out_key_length = SMB3_GCM128_CRYPTKEY_SIZE;
274+
break;
275+
case SMB2_ENCRYPTION_AES256_CCM:
276+
case SMB2_ENCRYPTION_AES256_GCM:
277+
out.session_key_length = CIFS_SESS_KEY_SIZE;
278+
out.server_in_key_length = out.server_out_key_length = SMB3_GCM256_CRYPTKEY_SIZE;
279+
break;
280+
default:
281+
rc = -EOPNOTSUPP;
282+
goto out;
283+
}
284+
285+
/* check if user buffer is big enough to store all the keys */
286+
if (out.in_size < sizeof(out) + out.session_key_length + out.server_in_key_length
287+
+ out.server_out_key_length) {
288+
rc = -ENOBUFS;
289+
goto out;
290+
}
291+
292+
out.session_id = ses->Suid;
293+
out.cipher_type = le16_to_cpu(ses->server->cipher_type);
294+
295+
/* overwrite user input with our output */
296+
if (copy_to_user(in, &out, sizeof(out))) {
297+
rc = -EINVAL;
298+
goto out;
299+
}
300+
301+
/* append all the keys at the end of the user buffer */
302+
end = in->data;
303+
if (copy_to_user(end, ses->auth_key.response, out.session_key_length)) {
304+
rc = -EINVAL;
305+
goto out;
306+
}
307+
end += out.session_key_length;
308+
309+
if (copy_to_user(end, ses->smb3encryptionkey, out.server_in_key_length)) {
310+
rc = -EINVAL;
311+
goto out;
312+
}
313+
end += out.server_in_key_length;
314+
315+
if (copy_to_user(end, ses->smb3decryptionkey, out.server_out_key_length)) {
316+
rc = -EINVAL;
317+
goto out;
318+
}
319+
320+
out:
321+
if (found)
322+
cifs_put_smb_ses(ses);
323+
return rc;
259324
}
260325

261326
long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
@@ -371,6 +436,10 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
371436
rc = -EOPNOTSUPP;
372437
break;
373438
case CIFS_DUMP_KEY:
439+
/*
440+
* Dump encryption keys. This is an old ioctl that only
441+
* handles AES-128-{CCM,GCM}.
442+
*/
374443
if (pSMBFile == NULL)
375444
break;
376445
if (!capable(CAP_SYS_ADMIN)) {
@@ -398,20 +467,18 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
398467
else
399468
rc = 0;
400469
break;
401-
/*
402-
* Dump full key (32 bytes instead of 16 bytes) is
403-
* needed if GCM256 (stronger encryption) negotiated
404-
*/
405470
case CIFS_DUMP_FULL_KEY:
471+
/*
472+
* Dump encryption keys (handles any key sizes)
473+
*/
406474
if (pSMBFile == NULL)
407475
break;
408476
if (!capable(CAP_SYS_ADMIN)) {
409477
rc = -EACCES;
410478
break;
411479
}
412480
tcon = tlink_tcon(pSMBFile->tlink);
413-
rc = cifs_dump_full_key(tcon, arg);
414-
481+
rc = cifs_dump_full_key(tcon, (void __user *)arg);
415482
break;
416483
case CIFS_IOC_NOTIFY:
417484
if (!S_ISDIR(inode->i_mode)) {

fs/cifs/smb2pdu.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,13 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
958958
/* Internal types */
959959
server->capabilities |= SMB2_NT_FIND | SMB2_LARGE_FILES;
960960

961+
/*
962+
* SMB3.0 supports only 1 cipher and doesn't have a encryption neg context
963+
* Set the cipher type manually.
964+
*/
965+
if (server->dialect == SMB30_PROT_ID && (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION))
966+
server->cipher_type = SMB2_ENCRYPTION_AES128_CCM;
967+
961968
security_blob = smb2_get_data_area_len(&blob_offset, &blob_length,
962969
(struct smb2_sync_hdr *)rsp);
963970
/*

fs/cifs/trace.h

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212

1313
#include <linux/tracepoint.h>
1414

15+
/*
16+
* Please use this 3-part article as a reference for writing new tracepoints:
17+
* https://lwn.net/Articles/379903/
18+
*/
19+
1520
/* For logging errors in read or write */
1621
DECLARE_EVENT_CLASS(smb3_rw_err_class,
1722
TP_PROTO(unsigned int xid,
@@ -529,16 +534,16 @@ DECLARE_EVENT_CLASS(smb3_exit_err_class,
529534
TP_ARGS(xid, func_name, rc),
530535
TP_STRUCT__entry(
531536
__field(unsigned int, xid)
532-
__field(const char *, func_name)
537+
__string(func_name, func_name)
533538
__field(int, rc)
534539
),
535540
TP_fast_assign(
536541
__entry->xid = xid;
537-
__entry->func_name = func_name;
542+
__assign_str(func_name, func_name);
538543
__entry->rc = rc;
539544
),
540545
TP_printk("\t%s: xid=%u rc=%d",
541-
__entry->func_name, __entry->xid, __entry->rc)
546+
__get_str(func_name), __entry->xid, __entry->rc)
542547
)
543548

544549
#define DEFINE_SMB3_EXIT_ERR_EVENT(name) \
@@ -583,14 +588,14 @@ DECLARE_EVENT_CLASS(smb3_enter_exit_class,
583588
TP_ARGS(xid, func_name),
584589
TP_STRUCT__entry(
585590
__field(unsigned int, xid)
586-
__field(const char *, func_name)
591+
__string(func_name, func_name)
587592
),
588593
TP_fast_assign(
589594
__entry->xid = xid;
590-
__entry->func_name = func_name;
595+
__assign_str(func_name, func_name);
591596
),
592597
TP_printk("\t%s: xid=%u",
593-
__entry->func_name, __entry->xid)
598+
__get_str(func_name), __entry->xid)
594599
)
595600

596601
#define DEFINE_SMB3_ENTER_EXIT_EVENT(name) \
@@ -857,16 +862,16 @@ DECLARE_EVENT_CLASS(smb3_reconnect_class,
857862
TP_STRUCT__entry(
858863
__field(__u64, currmid)
859864
__field(__u64, conn_id)
860-
__field(char *, hostname)
865+
__string(hostname, hostname)
861866
),
862867
TP_fast_assign(
863868
__entry->currmid = currmid;
864869
__entry->conn_id = conn_id;
865-
__entry->hostname = hostname;
870+
__assign_str(hostname, hostname);
866871
),
867872
TP_printk("conn_id=0x%llx server=%s current_mid=%llu",
868873
__entry->conn_id,
869-
__entry->hostname,
874+
__get_str(hostname),
870875
__entry->currmid)
871876
)
872877

@@ -891,23 +896,23 @@ DECLARE_EVENT_CLASS(smb3_credit_class,
891896
TP_STRUCT__entry(
892897
__field(__u64, currmid)
893898
__field(__u64, conn_id)
894-
__field(char *, hostname)
899+
__string(hostname, hostname)
895900
__field(int, credits)
896901
__field(int, credits_to_add)
897902
__field(int, in_flight)
898903
),
899904
TP_fast_assign(
900905
__entry->currmid = currmid;
901906
__entry->conn_id = conn_id;
902-
__entry->hostname = hostname;
907+
__assign_str(hostname, hostname);
903908
__entry->credits = credits;
904909
__entry->credits_to_add = credits_to_add;
905910
__entry->in_flight = in_flight;
906911
),
907912
TP_printk("conn_id=0x%llx server=%s current_mid=%llu "
908913
"credits=%d credit_change=%d in_flight=%d",
909914
__entry->conn_id,
910-
__entry->hostname,
915+
__get_str(hostname),
911916
__entry->currmid,
912917
__entry->credits,
913918
__entry->credits_to_add,

0 commit comments

Comments
 (0)