Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6508d904 authored by Jeff Layton's avatar Jeff Layton Committed by Steve French
Browse files

cifs: have find_readable/writable_file filter by fsuid



When we implement multiuser mounts, we'll need to filter filehandles
by fsuid. Add a flag for multiuser mounts and code to filter by
fsuid when it's set.

Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 13cfb733
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@
#define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_NOSSYNC      0x4000 /* don't do slow SMBflush on every sync*/
#define CIFS_MOUNT_FSCACHE	0x8000 /* local caching enabled */
#define CIFS_MOUNT_FSCACHE	0x8000 /* local caching enabled */
#define CIFS_MOUNT_MF_SYMLINKS	0x10000 /* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MF_SYMLINKS	0x10000 /* Minshall+French Symlinks enabled */
#define CIFS_MOUNT_MULTIUSER	0x20000 /* multiuser mount */


struct cifs_sb_info {
struct cifs_sb_info {
	struct cifsTconInfo *ptcon;	/* primary mount */
	struct cifsTconInfo *ptcon;	/* primary mount */
@@ -48,7 +49,7 @@ struct cifs_sb_info {
	gid_t	mnt_gid;
	gid_t	mnt_gid;
	mode_t	mnt_file_mode;
	mode_t	mnt_file_mode;
	mode_t	mnt_dir_mode;
	mode_t	mnt_dir_mode;
	int     mnt_cifs_flags;
	unsigned int mnt_cifs_flags;
	int	prepathlen;
	int	prepathlen;
	char   *prepath; /* relative path under the share to mount to */
	char   *prepath; /* relative path under the share to mount to */
#ifdef CONFIG_CIFS_DFS_UPCALL
#ifdef CONFIG_CIFS_DFS_UPCALL
+2 −2
Original line number Original line Diff line number Diff line
@@ -615,7 +615,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
	struct cifsFileInfo *open_file = NULL;
	struct cifsFileInfo *open_file = NULL;


	if (inode)
	if (inode)
		open_file = find_readable_file(CIFS_I(inode));
		open_file = find_readable_file(CIFS_I(inode), true);
	if (!open_file)
	if (!open_file)
		return get_cifs_acl_by_path(cifs_sb, path, pacllen);
		return get_cifs_acl_by_path(cifs_sb, path, pacllen);


@@ -685,7 +685,7 @@ static int set_cifs_acl(struct cifs_ntsd *pnntsd, __u32 acllen,


	cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);
	cFYI(DBG2, "set ACL for %s from mode 0x%x", path, inode->i_mode);


	open_file = find_readable_file(CIFS_I(inode));
	open_file = find_readable_file(CIFS_I(inode), true);
	if (!open_file)
	if (!open_file)
		return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
		return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);


+2 −2
Original line number Original line Diff line number Diff line
@@ -78,9 +78,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern bool is_valid_oplock_break(struct smb_hdr *smb,
extern bool is_valid_oplock_break(struct smb_hdr *smb,
				  struct TCP_Server_Info *);
				  struct TCP_Server_Info *);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
#ifdef CONFIG_CIFS_EXPERIMENTAL
#ifdef CONFIG_CIFS_EXPERIMENTAL
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
#endif
#endif
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
+1 −0
Original line number Original line Diff line number Diff line
@@ -144,6 +144,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle, struct file *file,


	pCifsFile->netfid = fileHandle;
	pCifsFile->netfid = fileHandle;
	pCifsFile->pid = current->tgid;
	pCifsFile->pid = current->tgid;
	pCifsFile->uid = current_fsuid();
	pCifsFile->pInode = igrab(newinode);
	pCifsFile->pInode = igrab(newinode);
	pCifsFile->mnt = mnt;
	pCifsFile->mnt = mnt;
	pCifsFile->pfile = file;
	pCifsFile->pfile = file;
+25 −8
Original line number Original line Diff line number Diff line
@@ -1168,9 +1168,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
}
}


#ifdef CONFIG_CIFS_EXPERIMENTAL
#ifdef CONFIG_CIFS_EXPERIMENTAL
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode,
					bool fsuid_only)
{
{
	struct cifsFileInfo *open_file = NULL;
	struct cifsFileInfo *open_file = NULL;
	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);

	/* only filter by fsuid on multiuser mounts */
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
		fsuid_only = false;


	read_lock(&GlobalSMBSeslock);
	read_lock(&GlobalSMBSeslock);
	/* we could simply get the first_list_entry since write-only entries
	/* we could simply get the first_list_entry since write-only entries
@@ -1179,6 +1185,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
		if (open_file->closePend)
		if (open_file->closePend)
			continue;
			continue;
		if (fsuid_only && open_file->uid != current_fsuid())
			continue;
		if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
		if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
		    (open_file->pfile->f_flags & O_RDONLY))) {
		    (open_file->pfile->f_flags & O_RDONLY))) {
			if (!open_file->invalidHandle) {
			if (!open_file->invalidHandle) {
@@ -1198,9 +1206,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
}
}
#endif
#endif


struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode,
					bool fsuid_only)
{
{
	struct cifsFileInfo *open_file;
	struct cifsFileInfo *open_file;
	struct cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
	bool any_available = false;
	bool any_available = false;
	int rc;
	int rc;


@@ -1214,13 +1224,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
		return NULL;
		return NULL;
	}
	}


	/* only filter by fsuid on multiuser mounts */
	if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
		fsuid_only = false;

	read_lock(&GlobalSMBSeslock);
	read_lock(&GlobalSMBSeslock);
refind_writable:
refind_writable:
	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
		if (open_file->closePend ||
		if (open_file->closePend)
		    (!any_available && open_file->pid != current->tgid))
			continue;
		if (!any_available && open_file->pid != current->tgid)
			continue;
		if (fsuid_only && open_file->uid != current_fsuid())
			continue;
			continue;

		if (open_file->pfile &&
		if (open_file->pfile &&
		    ((open_file->pfile->f_flags & O_RDWR) ||
		    ((open_file->pfile->f_flags & O_RDWR) ||
		     (open_file->pfile->f_flags & O_WRONLY))) {
		     (open_file->pfile->f_flags & O_WRONLY))) {
@@ -1315,7 +1331,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
	if (mapping->host->i_size - offset < (loff_t)to)
	if (mapping->host->i_size - offset < (loff_t)to)
		to = (unsigned)(mapping->host->i_size - offset);
		to = (unsigned)(mapping->host->i_size - offset);


	open_file = find_writable_file(CIFS_I(mapping->host));
	open_file = find_writable_file(CIFS_I(mapping->host), false);
	if (open_file) {
	if (open_file) {
		bytes_written = cifs_write(open_file->pfile, write_data,
		bytes_written = cifs_write(open_file->pfile, write_data,
					   to-from, &offset);
					   to-from, &offset);
@@ -1388,7 +1404,7 @@ static int cifs_writepages(struct address_space *mapping,
	 * but it'll at least handle the return. Maybe it should be
	 * but it'll at least handle the return. Maybe it should be
	 * a BUG() instead?
	 * a BUG() instead?
	 */
	 */
	open_file = find_writable_file(CIFS_I(mapping->host));
	open_file = find_writable_file(CIFS_I(mapping->host), false);
	if (!open_file) {
	if (!open_file) {
		kfree(iov);
		kfree(iov);
		return generic_writepages(mapping, wbc);
		return generic_writepages(mapping, wbc);
@@ -1505,7 +1521,8 @@ static int cifs_writepages(struct address_space *mapping,
				break;
				break;
		}
		}
		if (n_iov) {
		if (n_iov) {
			open_file = find_writable_file(CIFS_I(mapping->host));
			open_file = find_writable_file(CIFS_I(mapping->host),
							false);
			if (!open_file) {
			if (!open_file) {
				cERROR(1, "No writable handles for inode");
				cERROR(1, "No writable handles for inode");
				rc = -EBADF;
				rc = -EBADF;
Loading