@@ -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);
@@ -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,
@@ -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);
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 <xifeng@redhat.com> Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/smb2ops.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- fs/cifs/smb2pdu.c | 5 +++-- fs/cifs/smb2proto.h | 3 ++- 3 files changed, 47 insertions(+), 5 deletions(-)