diff mbox series

SMB3 pass in mode bits in sd context on SMB3 create when "modefromsid" mounts

Message ID CAH2r5mtKatPDSLv2G+ifeo9JZj3-=QAe9eDOPmtOKPObZiu3jQ@mail.gmail.com
State New
Headers show
Series SMB3 pass in mode bits in sd context on SMB3 create when "modefromsid" mounts | expand

Commit Message

Steve French Dec. 6, 2019, 8:10 a.m. UTC
When using the special SID to store the mode bits in an ACE (See
http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx)
which is enabled with mount parm "modefromsid" we were not
passing in the mode via SMB3 create (although chmod was enabled).
SMB3 create allows a security descriptor context to be passed
in (which is more atomic and thus preferable to setting the mode
bits after create via a setinfo).

This patch enables setting the mode bits on create when using
modefromsid mount option.  In addition it fixes an endian
error in the definition of the Control field flags in the SMB3
security descriptor.
diff mbox series

Patch

From c31cc9b3b8b72be3904e82a745d56089daa643b3 Mon Sep 17 00:00:00 2001
From: Steve French <stfrench@microsoft.com>
Date: Fri, 6 Dec 2019 02:02:38 -0600
Subject: [PATCH] smb3: fix mode passed in on create for modetosid mount option

When using the special SID to store the mode bits in an ACE (See
http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx)
which is enabled with mount parm "modefromsid" we were not
passing in the mode via SMB3 create (although chmod was enabled).
SMB3 create allows a security descriptor context to be passed
in (which is more atomic and thus preferable to setting the mode
bits after create via a setinfo).

This patch enables setting the mode bits on create when using
modefromsid mount option.  In addition it fixes an endian
error in the definition of the Control field flags in the SMB3
security descriptor.

Signed-off-by: Steve French <stfrench@microsoft.com>
---
 fs/cifs/cifsacl.c   | 42 ++++++++++++++++----------
 fs/cifs/cifsacl.h   | 32 ++++++++++----------
 fs/cifs/cifsproto.h |  1 +
 fs/cifs/smb2pdu.c   | 72 +++++++++++++++++++++++++++++++++++++++++++--
 fs/cifs/smb2pdu.h   | 10 +++++++
 5 files changed, 123 insertions(+), 34 deletions(-)

diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 06ffe52bdcfa..89d0ded54b8d 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -802,6 +802,31 @@  static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl,
 	return;
 }
 
+/*
+ * Fill in the special SID based on the mode. See
+ * http://technet.microsoft.com/en-us/library/hh509017(v=ws.10).aspx
+ */
+unsigned int setup_special_mode_ACE(struct cifs_ace *pntace, __u64 nmode)
+{
+	int i;
+	unsigned int ace_size = 28;
+
+	pntace->type = ACCESS_ALLOWED;
+	pntace->flags = 0x0;
+	pntace->access_req = 0;
+	pntace->sid.num_subauth = 3;
+	pntace->sid.revision = 1;
+	for (i = 0; i < NUM_AUTHS; i++)
+		pntace->sid.authority[i] = sid_unix_NFS_mode.authority[i];
+
+	pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
+	pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
+	pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
+
+	/* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
+	pntace->size = cpu_to_le16(ace_size);
+	return ace_size;
+}
 
 static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
 			struct cifs_sid *pgrpsid, __u64 nmode, bool modefromsid)
@@ -815,23 +840,8 @@  static int set_chmod_dacl(struct cifs_acl *pndacl, struct cifs_sid *pownersid,
 	if (modefromsid) {
 		struct cifs_ace *pntace =
 			(struct cifs_ace *)((char *)pnndacl + size);
-		int i;
 
-		pntace->type = ACCESS_ALLOWED;
-		pntace->flags = 0x0;
-		pntace->access_req = 0;
-		pntace->sid.num_subauth = 3;
-		pntace->sid.revision = 1;
-		for (i = 0; i < NUM_AUTHS; i++)
-			pntace->sid.authority[i] =
-				sid_unix_NFS_mode.authority[i];
-		pntace->sid.sub_auth[0] = sid_unix_NFS_mode.sub_auth[0];
-		pntace->sid.sub_auth[1] = sid_unix_NFS_mode.sub_auth[1];
-		pntace->sid.sub_auth[2] = cpu_to_le32(nmode & 07777);
-
-		/* size = 1 + 1 + 2 + 4 + 1 + 1 + 6 + (psid->num_subauth*4) */
-		pntace->size = cpu_to_le16(28);
-		size += 28;
+		size += setup_special_mode_ACE(pntace, nmode);
 		num_aces++;
 	}
 
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index 439b99cefeb0..21d7dee98d01 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -147,22 +147,22 @@  struct smb3_sd {
 } __packed;
 
 /* Meaning of 'Control' field flags */
-#define ACL_CONTROL_SR	0x0001	/* Self relative */
-#define ACL_CONTROL_RM	0x0002	/* Resource manager control bits */
-#define ACL_CONTROL_PS	0x0004	/* SACL protected from inherits */
-#define ACL_CONTROL_PD	0x0008	/* DACL protected from inherits */
-#define ACL_CONTROL_SI	0x0010	/* SACL Auto-Inherited */
-#define ACL_CONTROL_DI	0x0020	/* DACL Auto-Inherited */
-#define ACL_CONTROL_SC	0x0040	/* SACL computed through inheritance */
-#define ACL_CONTROL_DC	0x0080	/* DACL computed through inheritence */
-#define ACL_CONTROL_SS	0x0100	/* Create server ACL */
-#define ACL_CONTROL_DT	0x0200	/* DACL provided by trusteed source */
-#define ACL_CONTROL_SD	0x0400	/* SACL defaulted */
-#define ACL_CONTROL_SP	0x0800	/* SACL is present on object */
-#define ACL_CONTROL_DD	0x1000	/* DACL defaulted */
-#define ACL_CONTROL_DP	0x2000	/* DACL is present on object */
-#define ACL_CONTROL_GD	0x4000	/* Group was defaulted */
-#define ACL_CONTROL_OD	0x8000	/* User was defaulted */
+#define ACL_CONTROL_SR	0x8000	/* Self relative */
+#define ACL_CONTROL_RM	0x4000	/* Resource manager control bits */
+#define ACL_CONTROL_PS	0x2000	/* SACL protected from inherits */
+#define ACL_CONTROL_PD	0x1000	/* DACL protected from inherits */
+#define ACL_CONTROL_SI	0x0800	/* SACL Auto-Inherited */
+#define ACL_CONTROL_DI	0x0400	/* DACL Auto-Inherited */
+#define ACL_CONTROL_SC	0x0200	/* SACL computed through inheritance */
+#define ACL_CONTROL_DC	0x0100	/* DACL computed through inheritence */
+#define ACL_CONTROL_SS	0x0080	/* Create server ACL */
+#define ACL_CONTROL_DT	0x0040	/* DACL provided by trusted source */
+#define ACL_CONTROL_SD	0x0020	/* SACL defaulted */
+#define ACL_CONTROL_SP	0x0010	/* SACL is present on object */
+#define ACL_CONTROL_DD	0x0008	/* DACL defaulted */
+#define ACL_CONTROL_DP	0x0004	/* DACL is present on object */
+#define ACL_CONTROL_GD	0x0002	/* Group was defaulted */
+#define ACL_CONTROL_OD	0x0001	/* User was defaulted */
 
 /* Meaning of AclRevision flags */
 #define ACL_REVISION	0x02 /* See section 2.4.4.1 of MS-DTYP */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 1ed695336f62..9c229408a251 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -213,6 +213,7 @@  extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
 						const struct cifs_fid *, u32 *);
 extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
 				const char *, int);
+extern unsigned int setup_special_mode_ACE(struct cifs_ace *pace, __u64 nmode);
 
 extern void dequeue_mid(struct mid_q_entry *mid, bool malformed);
 extern int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 187a5ce68806..dc75a4925ab5 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2191,6 +2191,73 @@  add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewarp)
 	return 0;
 }
 
+/* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */
+static struct crt_sd_ctxt *
+create_sd_buf(umode_t mode, unsigned int *len)
+{
+	struct crt_sd_ctxt *buf;
+	struct cifs_ace *pace;
+	int sdlen = 0;
+
+	*len = roundup(sizeof(struct crt_sd_ctxt) + sizeof(struct cifs_ace), 8);
+	buf = kzalloc(*len, GFP_KERNEL);
+	if (buf == NULL)
+		return buf;
+
+	sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) +
+		 sizeof(struct cifs_ace);
+
+	buf->ccontext.DataOffset = cpu_to_le16(offsetof
+					(struct crt_sd_ctxt, sd));
+	buf->ccontext.DataLength = cpu_to_le32(sdlen);
+	buf->ccontext.NameOffset = cpu_to_le16(offsetof
+				(struct crt_sd_ctxt, Name));
+	buf->ccontext.NameLength = cpu_to_le16(4);
+	/* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */
+	buf->Name[0] = 'S';
+	buf->Name[1] = 'e';
+	buf->Name[2] = 'c';
+	buf->Name[3] = 'D';
+	buf->sd.Revision = 1;  /* Must be one see MS-DTYP 2.4.6 */
+	/*
+	 * ACL is "self relative" ie ACL is stored in contiguous block of memory
+	 * and "DP" ie the DACL is present
+	 */
+	buf->sd.Control = cpu_to_le16(ACL_CONTROL_SR | ACL_CONTROL_DP);
+
+	/* offset owner, group and Sbz1 and SACL are all zero */
+	buf->sd.OffsetDacl = cpu_to_le32(sizeof(struct smb3_sd));
+	buf->acl.AclRevision = ACL_REVISION; /* See 2.4.4.1 of MS-DTYP */
+
+	/* create one ACE to hold the mode embedded in reserved special SID */
+	pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf);
+	buf->acl.AclSize =
+		cpu_to_le16(sizeof(struct cifs_acl) +
+			    setup_special_mode_ACE(pace, (__u64)mode));
+	buf->acl.AceCount = cpu_to_le16(1);
+	return buf;
+}
+
+static int
+add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
+{
+	struct smb2_create_req *req = iov[0].iov_base;
+	unsigned int num = *num_iovec;
+	unsigned int len = 0;
+
+	iov[num].iov_base = create_sd_buf(mode, &len);
+	if (iov[num].iov_base == NULL)
+		return -ENOMEM;
+	iov[num].iov_len = len;
+	if (!req->CreateContextsOffset)
+		req->CreateContextsOffset = cpu_to_le32(
+				sizeof(struct smb2_create_req) +
+				iov[num - 1].iov_len);
+	le32_add_cpu(&req->CreateContextsLength, len);
+	*num_iovec = num + 1;
+	return 0;
+}
+
 static struct crt_query_id_ctxt *
 create_query_id_buf(void)
 {
@@ -2563,7 +2630,7 @@  SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
 			return rc;
 	}
 
-	if ((oparms->disposition == FILE_CREATE) &&
+	if ((oparms->disposition != FILE_OPEN) &&
 	    (oparms->mode != ACL_NO_MODE)) {
 		if (n_iov > 2) {
 			struct create_context *ccontext =
@@ -2572,7 +2639,8 @@  SMB2_open_init(struct cifs_tcon *tcon, struct smb_rqst *rqst, __u8 *oplock,
 				cpu_to_le32(iov[n_iov-1].iov_len);
 		}
 
-		/* rc = add_sd_context(iov, &n_iov, oparms->mode); */
+		cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode);
+		rc = add_sd_context(iov, &n_iov, oparms->mode);
 		if (rc)
 			return rc;
 	}
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index fa2533da316d..7b1c379fdf7a 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -25,6 +25,7 @@ 
 #define _SMB2PDU_H
 
 #include <net/sock.h>
+#include <cifsacl.h>
 
 /*
  * Note that, due to trying to use names similar to the protocol specifications,
@@ -855,6 +856,15 @@  struct crt_query_id_ctxt {
 	__u8	Name[8];
 } __packed;
 
+struct crt_sd_ctxt {
+	struct create_context ccontext;
+	__u8	Name[8];
+	struct smb3_sd sd;
+	struct smb3_acl acl;
+	/* Followed by at least 4 ACEs */
+} __packed;
+
+
 #define COPY_CHUNK_RES_KEY_SIZE	24
 struct resume_key_req {
 	char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
-- 
2.23.0