fs/smb/client/smb2inode.c

Source file repositories/reference/linux-study-clean/fs/smb/client/smb2inode.c

File Facts

System
Linux kernel
Corpus path
fs/smb/client/smb2inode.c
Extension
.c
Size
45861 bytes
Lines
1565
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct wsl_query_ea {
	__le32	next;
	__u8	name_len;
	__u8	name[SMB2_WSL_XATTR_NAME_LEN + 1];
} __packed;

#define NEXT_OFF cpu_to_le32(sizeof(struct wsl_query_ea))

static const struct wsl_query_ea wsl_query_eas[] = {
	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_UID, },
	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_GID, },
	{ .next = NEXT_OFF, .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_MODE, },
	{ .next = 0,        .name_len = SMB2_WSL_XATTR_NAME_LEN, .name = SMB2_WSL_XATTR_DEV, },
};

static int check_wsl_eas(struct kvec *rsp_iov)
{
	struct smb2_file_full_ea_info *ea;
	struct smb2_query_info_rsp *rsp = rsp_iov->iov_base;
	unsigned long addr;
	u32 outlen, next;
	u16 vlen;
	u8 nlen;
	u8 *ea_end, *iov_end;

	outlen = le32_to_cpu(rsp->OutputBufferLength);
	if (outlen < SMB2_WSL_MIN_QUERY_EA_RESP_SIZE ||
	    outlen > SMB2_WSL_MAX_QUERY_EA_RESP_SIZE)
		return -EINVAL;

	ea = (void *)((u8 *)rsp_iov->iov_base +
		      le16_to_cpu(rsp->OutputBufferOffset));
	ea_end = (u8 *)ea + outlen;
	iov_end = (u8 *)rsp_iov->iov_base + rsp_iov->iov_len;
	if (ea_end > iov_end)
		return -EINVAL;

	for (;;) {
		if ((u8 *)ea > ea_end - sizeof(*ea))
			return -EINVAL;

		nlen = ea->ea_name_length;
		vlen = le16_to_cpu(ea->ea_value_length);
		if (nlen != SMB2_WSL_XATTR_NAME_LEN ||
		    (u8 *)ea->ea_data + nlen + 1 + vlen > ea_end)
			return -EINVAL;

		switch (vlen) {
		case 4:
			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) &&
			    strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) &&
			    strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen))
				return -EINVAL;
			break;
		case 8:
			if (strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
				return -EINVAL;
			break;
		case 0:
			if (!strncmp(ea->ea_data, SMB2_WSL_XATTR_UID, nlen) ||
			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_GID, nlen) ||
			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_MODE, nlen) ||
			    !strncmp(ea->ea_data, SMB2_WSL_XATTR_DEV, nlen))
				break;
			fallthrough;
		default:
			return -EINVAL;
		}

		next = le32_to_cpu(ea->next_entry_offset);
		if (!next)
			break;
		if (!IS_ALIGNED(next, 4) ||
		    check_add_overflow((unsigned long)ea, next, &addr))
			return -EINVAL;
		ea = (void *)addr;
	}
	return 0;
}

/*
 * If @cfile is NULL, then need to account for trailing CLOSE request in the
 * compound chain.
 */
static void set_next_compound(struct cifs_tcon *tcon,
			      struct cifsFileInfo *cfile,
			      int i, int num_cmds,
			      struct smb_rqst *rqst, int *num_rqst)
{
	int k = !cfile ? 1 : 0;

Annotation

Implementation Notes