Commit 349e13ad authored by Aurelien Aptel's avatar Aurelien Aptel Committed by Steve French
Browse files

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: default avatarAurelien Aptel <aaptel@suse.com>
Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
parent 2e8af978
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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+ */
+95 −0
Original line number Diff line number Diff line
@@ -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)
{
+44 −0
Original line number Diff line number Diff line
@@ -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 */
+2 −0
Original line number Diff line number Diff line
@@ -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 */