[linux-cifs-client] [PATCH 08/15] cifs: have find_readable/writable_file filter by fsuid
Jeff Layton
jlayton at samba.org
Tue Mar 30 13:51:10 MDT 2010
From: Jeff Layton <jlayton at redhat.com>
When we implement multisession mounts, we'll need to filter filehandles
by fsuid. Add a flag for multisession mounts and code to filter by
fsuid when it's set.
Signed-off-by: Jeff Layton <jlayton at redhat.com>
---
fs/cifs/cifs_fs_sb.h | 3 ++-
fs/cifs/cifsacl.c | 4 ++--
fs/cifs/cifsproto.h | 4 ++--
fs/cifs/dir.c | 1 +
fs/cifs/file.c | 31 ++++++++++++++++++++++++-------
fs/cifs/inode.c | 6 +++---
6 files changed, 34 insertions(+), 15 deletions(-)
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
index 7f5bc7c..037dbab 100644
--- a/fs/cifs/cifs_fs_sb.h
+++ b/fs/cifs/cifs_fs_sb.h
@@ -33,6 +33,7 @@
#define CIFS_MOUNT_DYNPERM 0x1000 /* allow in-memory only mode setting */
#define CIFS_MOUNT_NOPOSIXBRL 0x2000 /* mandatory not posix byte range lock */
#define CIFS_MOUNT_NOSSYNC 0x4000 /* don't do slow SMBflush on every sync*/
+#define CIFS_MOUNT_MULTISES 0x8000 /* multisession mount */
struct cifs_sb_info {
struct cifsTconInfo *tcon; /* primary mount */
@@ -43,7 +44,7 @@ struct cifs_sb_info {
gid_t mnt_gid;
mode_t mnt_file_mode;
mode_t mnt_dir_mode;
- int mnt_cifs_flags;
+ unsigned int mnt_cifs_flags;
int prepathlen;
char *prepath; /* relative path under the share to mount to */
#ifdef CONFIG_CIFS_DFS_UPCALL
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 99e32e4..5e4ea43 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -602,7 +602,7 @@ static struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
struct cifsFileInfo *open_file = NULL;
if (inode)
- open_file = find_readable_file(CIFS_I(inode));
+ open_file = find_readable_file(CIFS_I(inode), true);
if (!open_file)
return get_cifs_acl_by_path(cifs_sb, path, pacllen);
@@ -660,7 +660,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));
- open_file = find_readable_file(CIFS_I(inode));
+ open_file = find_readable_file(CIFS_I(inode), true);
if (!open_file)
return set_cifs_acl_by_path(cifs_sb, path, pnntsd, acllen);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index bf18970..4b048f1 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -66,9 +66,9 @@ extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern bool is_valid_oplock_break(struct smb_hdr *smb,
struct TCP_Server_Info *);
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
-extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *);
+extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
#endif
extern unsigned int smbCalcSize(struct smb_hdr *ptr);
extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr);
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 1ade8e1..dbc6b97 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -148,6 +148,7 @@ cifs_new_fileinfo(struct inode *newinode, __u16 fileHandle,
pCifsFile->netfid = fileHandle;
pCifsFile->pid = current->tgid;
+ pCifsFile->uid = current_fsuid();
pCifsFile->pInode = igrab(newinode);
pCifsFile->mnt = mnt;
pCifsFile->pfile = file;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 6377cb8..8285d14 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1163,9 +1163,15 @@ static ssize_t cifs_write(struct file *file, const char *write_data,
}
#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 cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
+
+ /* only filter by fsuid on multisession mounts */
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES))
+ fsuid_only = false;
read_lock(&GlobalSMBSeslock);
/* we could simply get the first_list_entry since write-only entries
@@ -1174,6 +1180,8 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
if (open_file->closePend)
continue;
+ if (fsuid_only && open_file->uid != current_fsuid())
+ continue;
if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_RDONLY))) {
if (!open_file->invalidHandle) {
@@ -1193,9 +1201,11 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode)
}
#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 cifs_sb_info *cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb);
bool any_available = false;
int rc;
@@ -1209,13 +1219,19 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode)
return NULL;
}
+ /* only filter by fsuid on multisession mounts */
+ if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTISES))
+ fsuid_only = false;
+
read_lock(&GlobalSMBSeslock);
refind_writable:
list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {
- if (open_file->closePend ||
- (!any_available && open_file->pid != current->tgid))
+ if (open_file->closePend)
+ continue;
+ if (!any_available && open_file->pid != current->tgid)
+ continue;
+ if (fsuid_only && open_file->uid != current_fsuid())
continue;
-
if (open_file->pfile &&
((open_file->pfile->f_flags & O_RDWR) ||
(open_file->pfile->f_flags & O_WRONLY))) {
@@ -1310,7 +1326,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to)
if (mapping->host->i_size - offset < (loff_t)to)
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) {
bytes_written = cifs_write(open_file->pfile, write_data,
to-from, &offset);
@@ -1493,7 +1509,8 @@ retry:
* CIFSSMBWrite2. We can't rely on the last handle
* we used to still be valid
*/
- open_file = find_writable_file(CIFS_I(mapping->host));
+ open_file = find_writable_file(CIFS_I(mapping->host),
+ false);
if (!open_file) {
cERROR(1, ("No writable handles for inode"));
rc = -EBADF;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8c912e1..e09bf9f 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -852,7 +852,7 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, int xid,
/*
* If the file is already open for write, just use that fileid
*/
- open_file = find_writable_file(cifsInode);
+ open_file = find_writable_file(cifsInode, true);
if (open_file) {
netfid = open_file->netfid;
netpid = open_file->pid;
@@ -1668,7 +1668,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
* writebehind data than the SMB timeout for the SetPathInfo
* request would allow
*/
- open_file = find_writable_file(cifsInode);
+ open_file = find_writable_file(cifsInode, true);
if (open_file) {
__u16 nfid = open_file->netfid;
__u32 npid = open_file->pid;
@@ -1828,7 +1828,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
args->ctime = NO_CHANGE_64;
args->device = 0;
- open_file = find_writable_file(cifsInode);
+ open_file = find_writable_file(cifsInode, true);
if (open_file) {
u16 nfid = open_file->netfid;
u32 npid = open_file->pid;
--
1.6.6.1
More information about the linux-cifs-client
mailing list