All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] cifs: handle large EA requests more gracefully in smb2+
@ 2017-09-27 23:39 Ronnie Sahlberg
  0 siblings, 0 replies; 4+ messages in thread
From: Ronnie Sahlberg @ 2017-09-27 23:39 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French

Update reading the EA using increasingly larger buffer sizes
until the response will fit in the buffer, or we exceed the
(arbitrary) maximum set to 64kb.

Without this change, a user is able to add more and more EAs using
setfattr until the point where the total space of all EAs exceed 2kb
at which point the user can no longer list the EAs at all
and getfattr will abort with an error.


The same issue still exists for EAs in SMB1.

Signed-off-by: Ronnie Sahlberg <lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Reported-by: Xiaoli Feng <xifeng-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>

---
 fs/cifs/smb2maperror.c |  2 +-
 fs/cifs/smb2ops.c      | 31 +++++++++++++++++++++++++------
 fs/cifs/smb2pdu.c      |  6 +++---
 fs/cifs/smb2pdu.h      |  3 ++-
 fs/cifs/smb2proto.h    |  1 +
 5 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index 7ca9808a0daa..62c88dfed57b 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
 	{STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
 	{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
 	{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
-	{STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
+	{STATUS_BUFFER_OVERFLOW, -E2BIG, "STATUS_BUFFER_OVERFLOW"},
 	{STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
 	{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
 	{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0dafdbae1f8c..bdb963d0ba32 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -522,6 +522,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 	struct cifs_open_parms oparms;
 	struct cifs_fid fid;
 	struct smb2_file_full_ea_info *smb2_data;
+	int ea_buf_size = SMB2_MIN_EA_BUF;
 
 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
 	if (!utf16_path)
@@ -541,14 +542,32 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 	}
 
-	smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL);
-	if (smb2_data == NULL) {
-		SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
-		return -ENOMEM;
+	while (1) {
+		smb2_data = kzalloc(ea_buf_size, GFP_KERNEL);
+		if (smb2_data == NULL) {
+			SMB2_close(xid, tcon, fid.persistent_fid,
+				   fid.volatile_fid);
+			return -ENOMEM;
+		}
+
+		rc = SMB2_query_eas(xid, tcon, fid.persistent_fid,
+				    fid.volatile_fid,
+				    ea_buf_size, smb2_data);
+
+		if (rc != -E2BIG)
+			break;
+
+		kfree(smb2_data);
+		ea_buf_size <<= 1;
+
+		if (ea_buf_size > SMB2_MAX_EA_BUF) {
+			cifs_dbg(VFS, "EA size is too large\n");
+			SMB2_close(xid, tcon, fid.persistent_fid,
+				   fid.volatile_fid);
+			return -ENOMEM;
+		}
 	}
 
-	rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid,
-			    smb2_data);
 	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
 
 	if (!rc)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6f0e6343c15e..ba3865b338d8 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2233,12 +2233,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
 }
 
 int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
-	u64 persistent_fid, u64 volatile_fid,
-	struct smb2_file_full_ea_info *data)
+		   u64 persistent_fid, u64 volatile_fid,
+		   int ea_buf_size, struct smb2_file_full_ea_info *data)
 {
 	return query_info(xid, tcon, persistent_fid, volatile_fid,
 			  FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
-			  SMB2_MAX_EA_BUF,
+			  ea_buf_size,
 			  sizeof(struct smb2_file_full_ea_info),
 			  (void **)&data,
 			  NULL);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 6c9653a130c8..4c155b95b558 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -1178,7 +1178,8 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
 	char   FileName[0];     /* Name to be assigned to new link */
 } __packed; /* level 11 Set */
 
-#define SMB2_MAX_EA_BUF 2048
+#define SMB2_MIN_EA_BUF  2048
+#define SMB2_MAX_EA_BUF 65536
 
 struct smb2_file_full_ea_info { /* encoding of response for level 15 */
 	__le32 next_entry_offset;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 003217099ef3..e9ab5227e7a8 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -134,6 +134,7 @@ extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
 		      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 			  u64 persistent_file_id, u64 volatile_file_id,
+			  int ea_buf_size,
 			  struct smb2_file_full_ea_info *data);
 extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 			   u64 persistent_file_id, u64 volatile_file_id,
-- 
2.13.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH] cifs: handle large EA requests more gracefully in smb2+
       [not found]     ` <20170927063221.GA11315-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
@ 2017-09-27  6:39       ` ronnie sahlberg
  0 siblings, 0 replies; 4+ messages in thread
From: ronnie sahlberg @ 2017-09-27  6:39 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Ronnie Sahlberg, linux-cifs, Steve French

My mistake.  I misremembered the limit for XFS.

Unless there are other issues in the reviews that will require a
re-spin, maybe Steve
can tweak the commit message.

regards
Ronnie Sahlberg

On Wed, Sep 27, 2017 at 4:32 PM, Christoph Hellwig <hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> wrote:
> On Wed, Sep 27, 2017 at 04:20:01PM +1000, Ronnie Sahlberg wrote:
>> The maximum is currently set to 64kb almost arbitrarily. 64kb is
>> the maximum size of all xattrs under XFS so at least for
>> samba + XFS (or EXT4) servers we will not be able to write so many
>> EAs that we no longer can list them any more.
>
> This description looks confusing.
>
> For XFS the limits is 64kb for each individual xattr, not for all attrs.
>
> But your patch seems to be about the listxattr path anyway if I read
> it correctly.  There the VFS exposes a limit of XATTR_LIST_MAX,
> which also happens to be 64kb for the buffer size that contains all
> the xattr _names_.  Note that XFS could support almost arbitrary large
> amounts of xatttrs names (and on IRIX does), but on Linux we limit it
> to this limit of the VFS listxattr interface.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-cifs" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] cifs: handle large EA requests more gracefully in smb2+
       [not found] ` <20170927062001.979-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
@ 2017-09-27  6:32   ` Christoph Hellwig
       [not found]     ` <20170927063221.GA11315-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Christoph Hellwig @ 2017-09-27  6:32 UTC (permalink / raw)
  To: Ronnie Sahlberg; +Cc: linux-cifs, Steve French

On Wed, Sep 27, 2017 at 04:20:01PM +1000, Ronnie Sahlberg wrote:
> The maximum is currently set to 64kb almost arbitrarily. 64kb is
> the maximum size of all xattrs under XFS so at least for
> samba + XFS (or EXT4) servers we will not be able to write so many
> EAs that we no longer can list them any more.

This description looks confusing.

For XFS the limits is 64kb for each individual xattr, not for all attrs.

But your patch seems to be about the listxattr path anyway if I read
it correctly.  There the VFS exposes a limit of XATTR_LIST_MAX,
which also happens to be 64kb for the buffer size that contains all
the xattr _names_.  Note that XFS could support almost arbitrary large
amounts of xatttrs names (and on IRIX does), but on Linux we limit it
to this limit of the VFS listxattr interface.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH] cifs: handle large EA requests more gracefully in smb2+
@ 2017-09-27  6:20 Ronnie Sahlberg
       [not found] ` <20170927062001.979-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
  0 siblings, 1 reply; 4+ messages in thread
From: Ronnie Sahlberg @ 2017-09-27  6:20 UTC (permalink / raw)
  To: linux-cifs; +Cc: Steve French

Update update reading the EA using increasingly larger buffer sizes
until the response will fit in the buffer, or we exceed the
(arbitrary) maximum set to 64kb.

Without this change, a user is able to add more and more EAs using
setfattr until the point where the total space of all EAs exceed 2kb
at which point the user can no longer list the EAs at all
and getfattr will abort with an error.

The maximum is currently set to 64kb almost arbitrarily. 64kb is
the maximum size of all xattrs under XFS so at least for
samba + XFS (or EXT4) servers we will not be able to write so many
EAs that we no longer can list them any more.

The same issue still exists for EAs in SMB1.

Signed-off-by: Ronnie Sahlberg <lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
---
 fs/cifs/smb2maperror.c |  2 +-
 fs/cifs/smb2ops.c      | 31 +++++++++++++++++++++++++------
 fs/cifs/smb2pdu.c      |  6 +++---
 fs/cifs/smb2pdu.h      |  3 ++-
 fs/cifs/smb2proto.h    |  1 +
 5 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index 7ca9808a0daa..62c88dfed57b 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
 	{STATUS_DATATYPE_MISALIGNMENT, -EIO, "STATUS_DATATYPE_MISALIGNMENT"},
 	{STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
 	{STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
-	{STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
+	{STATUS_BUFFER_OVERFLOW, -E2BIG, "STATUS_BUFFER_OVERFLOW"},
 	{STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
 	{STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
 	{STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 0dafdbae1f8c..bdb963d0ba32 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -522,6 +522,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 	struct cifs_open_parms oparms;
 	struct cifs_fid fid;
 	struct smb2_file_full_ea_info *smb2_data;
+	int ea_buf_size = SMB2_MIN_EA_BUF;
 
 	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
 	if (!utf16_path)
@@ -541,14 +542,32 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 		return rc;
 	}
 
-	smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL);
-	if (smb2_data == NULL) {
-		SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
-		return -ENOMEM;
+	while (1) {
+		smb2_data = kzalloc(ea_buf_size, GFP_KERNEL);
+		if (smb2_data == NULL) {
+			SMB2_close(xid, tcon, fid.persistent_fid,
+				   fid.volatile_fid);
+			return -ENOMEM;
+		}
+
+		rc = SMB2_query_eas(xid, tcon, fid.persistent_fid,
+				    fid.volatile_fid,
+				    ea_buf_size, smb2_data);
+
+		if (rc != -E2BIG)
+			break;
+
+		kfree(smb2_data);
+		ea_buf_size <<= 1;
+
+		if (ea_buf_size > SMB2_MAX_EA_BUF) {
+			cifs_dbg(VFS, "EA size is too large\n");
+			SMB2_close(xid, tcon, fid.persistent_fid,
+				   fid.volatile_fid);
+			return -ENOMEM;
+		}
 	}
 
-	rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid,
-			    smb2_data);
 	SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
 
 	if (!rc)
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6f0e6343c15e..ba3865b338d8 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -2233,12 +2233,12 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon,
 }
 
 int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
-	u64 persistent_fid, u64 volatile_fid,
-	struct smb2_file_full_ea_info *data)
+		   u64 persistent_fid, u64 volatile_fid,
+		   int ea_buf_size, struct smb2_file_full_ea_info *data)
 {
 	return query_info(xid, tcon, persistent_fid, volatile_fid,
 			  FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0,
-			  SMB2_MAX_EA_BUF,
+			  ea_buf_size,
 			  sizeof(struct smb2_file_full_ea_info),
 			  (void **)&data,
 			  NULL);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 6c9653a130c8..4c155b95b558 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -1178,7 +1178,8 @@ struct smb2_file_link_info { /* encoding of request for level 11 */
 	char   FileName[0];     /* Name to be assigned to new link */
 } __packed; /* level 11 Set */
 
-#define SMB2_MAX_EA_BUF 2048
+#define SMB2_MIN_EA_BUF  2048
+#define SMB2_MAX_EA_BUF 65536
 
 struct smb2_file_full_ea_info { /* encoding of response for level 15 */
 	__le32 next_entry_offset;
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h
index 003217099ef3..e9ab5227e7a8 100644
--- a/fs/cifs/smb2proto.h
+++ b/fs/cifs/smb2proto.h
@@ -134,6 +134,7 @@ extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
 		      u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
 			  u64 persistent_file_id, u64 volatile_file_id,
+			  int ea_buf_size,
 			  struct smb2_file_full_ea_info *data);
 extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 			   u64 persistent_file_id, u64 volatile_file_id,
-- 
2.13.3

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2017-09-27 23:39 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-27 23:39 [PATCH] cifs: handle large EA requests more gracefully in smb2+ Ronnie Sahlberg
  -- strict thread matches above, loose matches on Subject: below --
2017-09-27  6:20 Ronnie Sahlberg
     [not found] ` <20170927062001.979-1-lsahlber-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-09-27  6:32   ` Christoph Hellwig
     [not found]     ` <20170927063221.GA11315-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2017-09-27  6:39       ` ronnie sahlberg

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.