From patchwork Tue May 15 23:59:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ronnie Sahlberg X-Patchwork-Id: 10402349 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 2687A601E9 for ; Tue, 15 May 2018 23:59:40 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 17831286FF for ; Tue, 15 May 2018 23:59:40 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 08F8628702; Tue, 15 May 2018 23:59:40 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 880B8286FF for ; Tue, 15 May 2018 23:59:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751333AbeEOX7j (ORCPT ); Tue, 15 May 2018 19:59:39 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:44350 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751400AbeEOX7i (ORCPT ); Tue, 15 May 2018 19:59:38 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CB986BB408; Tue, 15 May 2018 23:59:37 +0000 (UTC) Received: from test1190.test.redhat.com (vpn2-54-54.bne.redhat.com [10.64.54.54]) by smtp.corp.redhat.com (Postfix) with ESMTP id E8BBA1134CA5; Tue, 15 May 2018 23:59:35 +0000 (UTC) From: Ronnie Sahlberg To: linux-cifs Cc: Steve French Subject: [PATCH] cifs: check for size before setting/adding an EA Date: Wed, 16 May 2018 09:59:27 +1000 Message-Id: <20180515235927.29024-1-lsahlber@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 15 May 2018 23:59:37 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Tue, 15 May 2018 23:59:37 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'lsahlber@redhat.com' RCPT:'' Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP RHBZ: 1247871 Before we set/add the xattr to the SMB2 Extended Attributes we read the existing EAs for the file and check if there is enough space to store the new attribute. (Assuming it is a new attribute and not just changing an existing attribute.) We have a maximum amount of bufferspace we can use when reading the full set of all EAs. from the server. This limit is currently set at 64kb. We need to ensure that if we add a new EA that it will fit in the remaining space of that buffer. If not and we cause the total size of all EAs to exceed that maximum we will no longer be able to access the EAs at all. Even getfattr will then fail with an error due to the response being too big. Reported-by: Xiaoli Feng Signed-off-by: Ronnie Sahlberg --- fs/cifs/smb2ops.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- fs/cifs/smb2pdu.c | 5 +++-- fs/cifs/smb2proto.h | 3 ++- 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index ceaa358723f0..4f254153fed2 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -615,7 +615,7 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, rc = SMB2_query_eas(xid, tcon, fid.persistent_fid, fid.volatile_fid, - ea_buf_size, smb2_data); + ea_buf_size, smb2_data, NULL); if (rc != -E2BIG) break; @@ -648,6 +648,30 @@ smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon, } +static struct smb2_file_full_ea_info * +smb2_get_full_ea(const unsigned int xid, struct cifs_tcon *tcon, + struct cifs_fid *fid, u32 *data_len) +{ + struct smb2_file_full_ea_info *smb2_data; + int rc; + + smb2_data = kzalloc(SMB2_MAX_EA_BUF, GFP_KERNEL); + if (smb2_data == NULL) + return NULL; + + rc = SMB2_query_eas(xid, tcon, fid->persistent_fid, fid->volatile_fid, + SMB2_MAX_EA_BUF, smb2_data, data_len); + + if (rc) { + kfree(smb2_data); + return NULL; + } + + return smb2_data; +} + + + static int smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, const char *path, const char *ea_name, const void *ea_value, @@ -662,6 +686,8 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, struct smb2_file_full_ea_info *ea; int ea_name_len = strlen(ea_name); int len; + struct smb2_file_full_ea_info *smb2_data; + __u32 data_len; if (ea_name_len > 255) return -EINVAL; @@ -671,7 +697,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, return -ENOMEM; oparms.tcon = tcon; - oparms.desired_access = FILE_WRITE_EA; + oparms.desired_access = FILE_READ_EA | FILE_WRITE_EA; oparms.disposition = FILE_OPEN; oparms.create_options = 0; oparms.fid = &fid; @@ -684,7 +710,21 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, return rc; } + smb2_data = smb2_get_full_ea(xid, tcon, &fid, &data_len); + if (smb2_data == NULL) { + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + return -ENOMEM; + } + kfree(smb2_data); + data_len = (data_len + 3) & ~3; + len = sizeof(ea) + ea_name_len + ea_value_len + 1; + + if (data_len + len > SMB2_MAX_EA_BUF) { + SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); + return -ENOSPC; + } + ea = kzalloc(len, GFP_KERNEL); if (ea == NULL) { SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid); diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 35350057fc23..bd8327e24270 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -2355,14 +2355,15 @@ 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, - int ea_buf_size, struct smb2_file_full_ea_info *data) + int ea_buf_size, struct smb2_file_full_ea_info *data, + u32 *data_len) { return query_info(xid, tcon, persistent_fid, volatile_fid, FILE_FULL_EA_INFORMATION, SMB2_O_INFO_FILE, 0, ea_buf_size, sizeof(struct smb2_file_full_ea_info), (void **)&data, - NULL); + data_len); } int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon, diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 4b0db6af7fe7..524ef587bd1c 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h @@ -138,7 +138,8 @@ extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, 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); + struct smb2_file_full_ea_info *data, + u32 *data_len); 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);