smb3: allow decryption keys to be dumped by admin for debugging
authorSteve French <stfrench@microsoft.com>
Thu, 19 Sep 2019 09:00:55 +0000 (04:00 -0500)
committerSteve French <stfrench@microsoft.com>
Sat, 21 Sep 2019 11:02:26 +0000 (06:02 -0500)
In order to debug certain problems it is important to be able
to decrypt network traces (e.g. wireshark) but to do this we
need to be able to dump out the encryption/decryption keys.
Dumping them to an ioctl is safer than dumping then to dmesg,
(and better than showing all keys in a pseudofile).

Restrict this to root (CAP_SYS_ADMIN), and only for a mount
that this admin has access to.

Sample smbinfo output:
SMB3.0 encryption
Session Id:   0x82d2ec52
Session Key:  a5 6d 81 d0 e c1 ca e1 d8 13 aa 20 e8 f2 cc 71
Server Encryption Key:  1a c3 be ba 3d fc dc 3c e bc 93 9e 50 9e 19 c1
Server Decryption Key:  e0 d4 d9 43 1b a2 1b e3 d8 76 77 49 56 f7 20 88

Reviewed-by: Aurelien Aptel <aaptel@suse.com>
Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/cifs/cifs_ioctl.h
fs/cifs/ioctl.c

index 6c3bd07..0f0dc1c 100644 (file)
@@ -57,9 +57,18 @@ struct smb_query_info {
        /* char buffer[]; */
 } __packed;
 
+struct smb3_key_debug_info {
+       __u64   Suid;
+       __u16   cipher_type;
+       __u8    auth_key[16]; /* SMB2_NTLMV2_SESSKEY_SIZE */
+       __u8    smb3encryptionkey[SMB3_SIGN_KEY_SIZE];
+       __u8    smb3decryptionkey[SMB3_SIGN_KEY_SIZE];
+} __packed;
+
 #define CIFS_IOCTL_MAGIC       0xCF
 #define CIFS_IOC_COPYCHUNK_FILE        _IOW(CIFS_IOCTL_MAGIC, 3, int)
 #define CIFS_IOC_SET_INTEGRITY  _IO(CIFS_IOCTL_MAGIC, 4)
 #define CIFS_IOC_GET_MNT_INFO _IOR(CIFS_IOCTL_MAGIC, 5, struct smb_mnt_fs_info)
 #define CIFS_ENUMERATE_SNAPSHOTS _IOR(CIFS_IOCTL_MAGIC, 6, struct smb_snapshot_array)
 #define CIFS_QUERY_INFO _IOWR(CIFS_IOCTL_MAGIC, 7, struct smb_query_info)
+#define CIFS_DUMP_KEY _IOWR(CIFS_IOCTL_MAGIC, 8, struct smb3_key_debug_info)
index 76ddd98..1a01e10 100644 (file)
@@ -164,6 +164,7 @@ static long smb_mnt_get_fsinfo(unsigned int xid, struct cifs_tcon *tcon,
 long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
 {
        struct inode *inode = file_inode(filep);
+       struct smb3_key_debug_info pkey_inf;
        int rc = -ENOTTY; /* strange error - but the precedent */
        unsigned int xid;
        struct cifsFileInfo *pSMBFile = filep->private_data;
@@ -270,6 +271,34 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        else
                                rc = -EOPNOTSUPP;
                        break;
+               case CIFS_DUMP_KEY:
+                       if (pSMBFile == NULL)
+                               break;
+                       if (!capable(CAP_SYS_ADMIN)) {
+                               rc = -EACCES;
+                               break;
+                       }
+
+                       tcon = tlink_tcon(pSMBFile->tlink);
+                       if (!smb3_encryption_required(tcon)) {
+                               rc = -EOPNOTSUPP;
+                               break;
+                       }
+                       pkey_inf.cipher_type =
+                               le16_to_cpu(tcon->ses->server->cipher_type);
+                       pkey_inf.Suid = tcon->ses->Suid;
+                       memcpy(pkey_inf.auth_key, tcon->ses->auth_key.response,
+                                       16 /* SMB2_NTLMV2_SESSKEY_SIZE */);
+                       memcpy(pkey_inf.smb3decryptionkey,
+                             tcon->ses->smb3decryptionkey, SMB3_SIGN_KEY_SIZE);
+                       memcpy(pkey_inf.smb3encryptionkey,
+                             tcon->ses->smb3encryptionkey, SMB3_SIGN_KEY_SIZE);
+                       if (copy_to_user((void __user *)arg, &pkey_inf,
+                                       sizeof(struct smb3_key_debug_info)))
+                               rc = -EFAULT;
+                       else
+                               rc = 0;
+                       break;
                default:
                        cifs_dbg(FYI, "unsupported ioctl\n");
                        break;