cifs: add smb2 POSIX info level

* add new info level and structs for SMB2 posix extension
* add functions to parse and validate it

Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
Aurelien Aptel 2020-02-08 15:50:57 +01:00 committed by Steve French
parent 2e8af978d9
commit 349e13ad30
4 changed files with 142 additions and 0 deletions

View File

@ -1691,6 +1691,7 @@ struct smb_t2_rsp {
#define SMB_FIND_FILE_ID_FULL_DIR_INFO 0x105
#define SMB_FIND_FILE_ID_BOTH_DIR_INFO 0x106
#define SMB_FIND_FILE_UNIX 0x202
#define SMB_FIND_FILE_POSIX_INFO 0x064
typedef struct smb_com_transaction2_qpi_req {
struct smb_hdr hdr; /* wct = 14+ */

View File

@ -4302,6 +4302,101 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
return rc;
}
static int posix_info_sid_size(const void *beg, const void *end)
{
size_t subauth;
int total;
if (beg + 1 > end)
return -1;
subauth = *(u8 *)(beg+1);
if (subauth < 1 || subauth > 15)
return -1;
total = 1 + 1 + 6 + 4*subauth;
if (beg + total > end)
return -1;
return total;
}
int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out)
{
int total_len = 0;
int sid_len;
int name_len;
const void *owner_sid;
const void *group_sid;
const void *name;
/* if no end bound given, assume payload to be correct */
if (!end) {
const struct smb2_posix_info *p = beg;
end = beg + le32_to_cpu(p->NextEntryOffset);
/* last element will have a 0 offset, pick a sensible bound */
if (end == beg)
end += 0xFFFF;
}
/* check base buf */
if (beg + sizeof(struct smb2_posix_info) > end)
return -1;
total_len = sizeof(struct smb2_posix_info);
/* check owner sid */
owner_sid = beg + total_len;
sid_len = posix_info_sid_size(owner_sid, end);
if (sid_len < 0)
return -1;
total_len += sid_len;
/* check group sid */
group_sid = beg + total_len;
sid_len = posix_info_sid_size(group_sid, end);
if (sid_len < 0)
return -1;
total_len += sid_len;
/* check name len */
if (beg + total_len + 4 > end)
return -1;
name_len = le32_to_cpu(*(__le32 *)(beg + total_len));
if (name_len < 1 || name_len > 0xFFFF)
return -1;
total_len += 4;
/* check name */
name = beg + total_len;
if (name + name_len > end)
return -1;
total_len += name_len;
if (out) {
out->base = beg;
out->size = total_len;
out->name_len = name_len;
out->name = name;
memcpy(&out->owner, owner_sid,
posix_info_sid_size(owner_sid, end));
memcpy(&out->group, group_sid,
posix_info_sid_size(group_sid, end));
}
return total_len;
}
static int posix_info_extra_size(const void *beg, const void *end)
{
int len = posix_info_parse(beg, end, NULL);
if (len < 0)
return -1;
return len - sizeof(struct smb2_posix_info);
}
static unsigned int
num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
{

View File

@ -1613,5 +1613,49 @@ struct create_posix_rsp {
* var sized group SID
*/
} __packed;
/*
* SMB2-only POSIX info level
*
* See posix_info_sid_size(), posix_info_extra_size() and
* posix_info_parse() to help with the handling of this struct.
*/
struct smb2_posix_info {
__le32 NextEntryOffset;
__u32 Ignored;
__le64 CreationTime;
__le64 LastAccessTime;
__le64 LastWriteTime;
__le64 ChangeTime;
__le64 EndOfFile;
__le64 AllocationSize;
__le32 DosAttributes;
__le64 Inode;
__le32 DeviceId;
__le32 Zero;
/* beginning of POSIX Create Context Response */
__le32 HardLinks;
__le32 ReparseTag;
__le32 Mode;
/*
* var sized owner SID
* var sized group SID
* le32 filenamelength
* u8 filename[]
*/
} __packed;
/*
* Parsed version of the above struct. Allows direct access to the
* variable length fields
*/
struct smb2_posix_info_parsed {
const struct smb2_posix_info *base;
size_t size;
struct cifs_sid owner;
struct cifs_sid group;
int name_len;
const u8 *name;
};
#endif /* _SMB2PDU_H */

View File

@ -272,4 +272,6 @@ extern int smb2_query_info_compound(const unsigned int xid,
u32 class, u32 type, u32 output_len,
struct kvec *rsp, int *buftype,
struct cifs_sb_info *cifs_sb);
int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out);
#endif /* _SMB2PROTO_H */