diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/Kconfig | 8 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 2 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifs_spnego.c | 6 | ||||
-rw-r--r-- | fs/cifs/cifsacl.c | 47 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 26 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 22 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 9 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 17 | ||||
-rw-r--r-- | fs/cifs/connect.c | 86 | ||||
-rw-r--r-- | fs/cifs/dir.c | 18 | ||||
-rw-r--r-- | fs/cifs/file.c | 46 | ||||
-rw-r--r-- | fs/cifs/inode.c | 72 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 2 | ||||
-rw-r--r-- | fs/cifs/link.c | 2 | ||||
-rw-r--r-- | fs/cifs/misc.c | 2 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 12 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 1 |
19 files changed, 234 insertions, 153 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index 21ff76c22a17..2906ee276408 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig @@ -155,14 +155,14 @@ config CIFS_DFS_UPCALL points. If unsure, say N. config CIFS_NFSD_EXPORT - bool "Allow nfsd to export CIFS file system (EXPERIMENTAL)" - depends on CIFS && EXPERIMENTAL && BROKEN + bool "Allow nfsd to export CIFS file system" + depends on CIFS && BROKEN help Allows NFS server to export a CIFS mounted share (nfsd over cifs) config CIFS_SMB2 - bool "SMB2 network file system support (EXPERIMENTAL)" - depends on CIFS && EXPERIMENTAL && INET + bool "SMB2 network file system support" + depends on CIFS && INET select NLS select KEYS select FSCACHE diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index ce5cbd717bfc..210fce2df308 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -226,6 +226,8 @@ compose_mount_options_out: compose_mount_options_err: kfree(mountdata); mountdata = ERR_PTR(rc); + kfree(*devname); + *devname = NULL; goto compose_mount_options_out; } diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index c865bfdfe819..37e4a72a7d1c 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -55,10 +55,10 @@ struct cifs_sb_info { unsigned int wsize; unsigned long actimeo; /* attribute cache timeout (jiffies) */ atomic_t active; - uid_t mnt_uid; - gid_t mnt_gid; - uid_t mnt_backupuid; - gid_t mnt_backupgid; + kuid_t mnt_uid; + kgid_t mnt_gid; + kuid_t mnt_backupuid; + kgid_t mnt_backupgid; umode_t mnt_file_mode; umode_t mnt_dir_mode; unsigned int mnt_cifs_flags; diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 086f381d6489..10e774761299 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -149,10 +149,12 @@ cifs_get_spnego_key(struct cifs_ses *sesInfo) goto out; dp = description + strlen(description); - sprintf(dp, ";uid=0x%x", sesInfo->linux_uid); + sprintf(dp, ";uid=0x%x", + from_kuid_munged(&init_user_ns, sesInfo->linux_uid)); dp = description + strlen(description); - sprintf(dp, ";creduid=0x%x", sesInfo->cred_uid); + sprintf(dp, ";creduid=0x%x", + from_kuid_munged(&init_user_ns, sesInfo->cred_uid)); if (sesInfo->user_name) { dp = description + strlen(description); diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 5cbd00e74067..f1e3f25fe004 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -266,8 +266,8 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, struct key *sidkey; char *sidstr; const struct cred *saved_cred; - uid_t fuid = cifs_sb->mnt_uid; - gid_t fgid = cifs_sb->mnt_gid; + kuid_t fuid = cifs_sb->mnt_uid; + kgid_t fgid = cifs_sb->mnt_gid; /* * If we have too many subauthorities, then something is really wrong. @@ -297,6 +297,7 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, * probably a safe assumption but might be better to check based on * sidtype. */ + BUILD_BUG_ON(sizeof(uid_t) != sizeof(gid_t)); if (sidkey->datalen != sizeof(uid_t)) { rc = -EIO; cFYI(1, "%s: Downcall contained malformed key " @@ -305,10 +306,21 @@ sid_to_id(struct cifs_sb_info *cifs_sb, struct cifs_sid *psid, goto out_key_put; } - if (sidtype == SIDOWNER) - memcpy(&fuid, &sidkey->payload.value, sizeof(uid_t)); - else - memcpy(&fgid, &sidkey->payload.value, sizeof(gid_t)); + if (sidtype == SIDOWNER) { + kuid_t uid; + uid_t id; + memcpy(&id, &sidkey->payload.value, sizeof(uid_t)); + uid = make_kuid(&init_user_ns, id); + if (uid_valid(uid)) + fuid = uid; + } else { + kgid_t gid; + gid_t id; + memcpy(&id, &sidkey->payload.value, sizeof(gid_t)); + gid = make_kgid(&init_user_ns, id); + if (gid_valid(gid)) + fgid = gid; + } out_key_put: key_put(sidkey); @@ -346,7 +358,8 @@ init_cifs_idmap(void) if (!cred) return -ENOMEM; - keyring = keyring_alloc(".cifs_idmap", 0, 0, cred, + keyring = keyring_alloc(".cifs_idmap", + GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ, KEY_ALLOC_NOT_IN_QUOTA, NULL); @@ -774,7 +787,7 @@ static int parse_sec_desc(struct cifs_sb_info *cifs_sb, /* Convert permission bits from mode to equivalent CIFS ACL */ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, - __u32 secdesclen, __u64 nmode, uid_t uid, gid_t gid, int *aclflag) + __u32 secdesclen, __u64 nmode, kuid_t uid, kgid_t gid, int *aclflag) { int rc = 0; __u32 dacloffset; @@ -806,17 +819,19 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, *aclflag = CIFS_ACL_DACL; } else { memcpy(pnntsd, pntsd, secdesclen); - if (uid != NO_CHANGE_32) { /* chown */ + if (uid_valid(uid)) { /* chown */ + uid_t id; owner_sid_ptr = (struct cifs_sid *)((char *)pnntsd + le32_to_cpu(pnntsd->osidoffset)); nowner_sid_ptr = kmalloc(sizeof(struct cifs_sid), GFP_KERNEL); if (!nowner_sid_ptr) return -ENOMEM; - rc = id_to_sid(uid, SIDOWNER, nowner_sid_ptr); + id = from_kuid(&init_user_ns, uid); + rc = id_to_sid(id, SIDOWNER, nowner_sid_ptr); if (rc) { cFYI(1, "%s: Mapping error %d for owner id %d", - __func__, rc, uid); + __func__, rc, id); kfree(nowner_sid_ptr); return rc; } @@ -824,17 +839,19 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, kfree(nowner_sid_ptr); *aclflag = CIFS_ACL_OWNER; } - if (gid != NO_CHANGE_32) { /* chgrp */ + if (gid_valid(gid)) { /* chgrp */ + gid_t id; group_sid_ptr = (struct cifs_sid *)((char *)pnntsd + le32_to_cpu(pnntsd->gsidoffset)); ngroup_sid_ptr = kmalloc(sizeof(struct cifs_sid), GFP_KERNEL); if (!ngroup_sid_ptr) return -ENOMEM; - rc = id_to_sid(gid, SIDGROUP, ngroup_sid_ptr); + id = from_kgid(&init_user_ns, gid); + rc = id_to_sid(id, SIDGROUP, ngroup_sid_ptr); if (rc) { cFYI(1, "%s: Mapping error %d for group id %d", - __func__, rc, gid); + __func__, rc, id); kfree(ngroup_sid_ptr); return rc; } @@ -1002,7 +1019,7 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, /* Convert mode bits to an ACL so we can update the ACL on the server */ int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode, - uid_t uid, gid_t gid) + kuid_t uid, kgid_t gid) { int rc = 0; int aclflag = CIFS_ACL_DACL; /* default flag to set */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index de7f9168a118..3cf8a15af916 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -375,13 +375,15 @@ cifs_show_options(struct seq_file *s, struct dentry *root) (int)(srcaddr->sa_family)); } - seq_printf(s, ",uid=%u", cifs_sb->mnt_uid); + seq_printf(s, ",uid=%u", + from_kuid_munged(&init_user_ns, cifs_sb->mnt_uid)); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) seq_printf(s, ",forceuid"); else seq_printf(s, ",noforceuid"); - seq_printf(s, ",gid=%u", cifs_sb->mnt_gid); + seq_printf(s, ",gid=%u", + from_kgid_munged(&init_user_ns, cifs_sb->mnt_gid)); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) seq_printf(s, ",forcegid"); else @@ -436,9 +438,13 @@ cifs_show_options(struct seq_file *s, struct dentry *root) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) seq_printf(s, ",noperm"); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) - seq_printf(s, ",backupuid=%u", cifs_sb->mnt_backupuid); + seq_printf(s, ",backupuid=%u", + from_kuid_munged(&init_user_ns, + cifs_sb->mnt_backupuid)); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) - seq_printf(s, ",backupgid=%u", cifs_sb->mnt_backupgid); + seq_printf(s, ",backupgid=%u", + from_kgid_munged(&init_user_ns, + cifs_sb->mnt_backupgid)); seq_printf(s, ",rsize=%u", cifs_sb->rsize); seq_printf(s, ",wsize=%u", cifs_sb->wsize); @@ -558,6 +564,11 @@ cifs_get_root(struct smb_vol *vol, struct super_block *sb) dentry = ERR_PTR(-ENOENT); break; } + if (!S_ISDIR(dir->i_mode)) { + dput(dentry); + dentry = ERR_PTR(-ENOTDIR); + break; + } /* skip separators */ while (*s == sep) @@ -677,7 +688,7 @@ out_nls: static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(iocb->ki_filp); ssize_t written; int rc; @@ -701,7 +712,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence) */ if (whence != SEEK_SET && whence != SEEK_CUR) { int rc; - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); /* * We need to be sure that all dirty pages are written and the @@ -733,7 +744,7 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease) { /* note that this is called by vfs setlease with lock_flocks held to protect *lease from going away */ - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); struct cifsFileInfo *cfile = file->private_data; if (!(S_ISREG(inode->i_mode))) @@ -766,6 +777,7 @@ struct file_system_type cifs_fs_type = { .kill_sb = cifs_kill_sb, /* .fs_flags */ }; +MODULE_ALIAS_FS("cifs"); const struct inode_operations cifs_dir_inode_ops = { .create = cifs_create, .atomic_open = cifs_atomic_open, diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index e6899cea1c35..4f07f6fbe494 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -400,11 +400,11 @@ struct smb_vol { char *iocharset; /* local code page for mapping to and from Unicode */ char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ - uid_t cred_uid; - uid_t linux_uid; - gid_t linux_gid; - uid_t backupuid; - gid_t backupgid; + kuid_t cred_uid; + kuid_t linux_uid; + kgid_t linux_gid; + kuid_t backupuid; + kgid_t backupgid; umode_t file_mode; umode_t dir_mode; unsigned secFlg; @@ -703,8 +703,8 @@ struct cifs_ses { char *serverNOS; /* name of network operating system of server */ char *serverDomain; /* security realm of server */ __u64 Suid; /* remote smb uid */ - uid_t linux_uid; /* overriding owner of files on the mount */ - uid_t cred_uid; /* owner of credentials */ + kuid_t linux_uid; /* overriding owner of files on the mount */ + kuid_t cred_uid; /* owner of credentials */ unsigned int capabilities; char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for TCP names - will ipv6 and sctp addresses fit? */ @@ -838,7 +838,7 @@ struct cifs_tcon { */ struct tcon_link { struct rb_node tl_rbnode; - uid_t tl_uid; + kuid_t tl_uid; unsigned long tl_flags; #define TCON_LINK_MASTER 0 #define TCON_LINK_PENDING 1 @@ -931,7 +931,7 @@ struct cifsFileInfo { struct list_head tlist; /* pointer to next fid owned by tcon */ struct list_head flist; /* next fid (file instance) for this inode */ struct cifs_fid_locks *llist; /* brlocks held by this fid */ - unsigned int uid; /* allows finding which FileInfo structure */ + kuid_t uid; /* allows finding which FileInfo structure */ __u32 pid; /* process id who opened file */ struct cifs_fid fid; /* file id from remote */ /* BB add lock scope info here if needed */ ; @@ -1245,8 +1245,8 @@ struct cifs_fattr { u64 cf_eof; u64 cf_bytes; u64 cf_createtime; - uid_t cf_uid; - gid_t cf_gid; + kuid_t cf_uid; + kgid_t cf_gid; umode_t cf_mode; dev_t cf_rdev; unsigned int cf_nlink; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index b9d59a948a2c..e996ff6b26d1 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -277,7 +277,6 @@ #define CIFS_NO_HANDLE 0xFFFF #define NO_CHANGE_64 0xFFFFFFFFFFFFFFFFULL -#define NO_CHANGE_32 0xFFFFFFFFUL /* IPC$ in ASCII */ #define CIFS_IPC_RESOURCE "\x49\x50\x43\x24" diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1988c1baa224..f450f0683ddd 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -46,7 +46,8 @@ extern void _free_xid(unsigned int); ({ \ unsigned int __xid = _get_xid(); \ cFYI(1, "CIFS VFS: in %s as Xid: %u with uid: %d", \ - __func__, __xid, current_fsuid()); \ + __func__, __xid, \ + from_kuid(&init_user_ns, current_fsuid())); \ __xid; \ }) @@ -161,7 +162,7 @@ extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, const char *path, const __u16 *pfid); extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64, - uid_t, gid_t); + kuid_t, kgid_t); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, const char *, u32 *); extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, @@ -304,8 +305,8 @@ struct cifs_unix_set_info_args { __u64 atime; __u64 mtime; __u64 mode; - __u64 uid; - __u64 gid; + kuid_t uid; + kgid_t gid; dev_t device; }; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 76d0d2998850..8e2e799e7a24 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1909,9 +1909,12 @@ cifs_writev_requeue(struct cifs_writedata *wdata) } while (rc == -EAGAIN); for (i = 0; i < wdata->nr_pages; i++) { - if (rc != 0) - SetPageError(wdata->pages[i]); unlock_page(wdata->pages[i]); + if (rc != 0) { + SetPageError(wdata->pages[i]); + end_page_writeback(wdata->pages[i]); + page_cache_release(wdata->pages[i]); + } } mapping_set_error(inode->i_mapping, rc); @@ -5819,8 +5822,14 @@ static void cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, const struct cifs_unix_set_info_args *args) { + u64 uid = NO_CHANGE_64, gid = NO_CHANGE_64; u64 mode = args->mode; + if (uid_valid(args->uid)) + uid = from_kuid(&init_user_ns, args->uid); + if (gid_valid(args->gid)) + gid = from_kgid(&init_user_ns, args->gid); + /* * Samba server ignores set of file size to zero due to bugs in some * older clients, but we should be precise - we use SetFileSize to @@ -5833,8 +5842,8 @@ cifs_fill_unix_set_info(FILE_UNIX_BASIC_INFO *data_offset, data_offset->LastStatusChange = cpu_to_le64(args->ctime); data_offset->LastAccessTime = cpu_to_le64(args->atime); data_offset->LastModificationTime = cpu_to_le64(args->mtime); - data_offset->Uid = cpu_to_le64(args->uid); - data_offset->Gid = cpu_to_le64(args->gid); + data_offset->Uid = cpu_to_le64(uid); + data_offset->Gid = cpu_to_le64(gid); /* better to leave device as zero when it is */ data_offset->DevMajor = cpu_to_le64(MAJOR(args->device)); data_offset->DevMinor = cpu_to_le64(MINOR(args->device)); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 17c3643e5950..991c63c6bdd0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -97,7 +97,7 @@ enum { Opt_user, Opt_pass, Opt_ip, Opt_unc, Opt_domain, Opt_srcaddr, Opt_prefixpath, - Opt_iocharset, Opt_sockopt, + Opt_iocharset, Opt_netbiosname, Opt_servern, Opt_ver, Opt_vers, Opt_sec, Opt_cache, @@ -202,7 +202,6 @@ static const match_table_t cifs_mount_option_tokens = { { Opt_srcaddr, "srcaddr=%s" }, { Opt_prefixpath, "prefixpath=%s" }, { Opt_iocharset, "iocharset=%s" }, - { Opt_sockopt, "sockopt=%s" }, { Opt_netbiosname, "netbiosname=%s" }, { Opt_servern, "servern=%s" }, { Opt_ver, "ver=%s" }, @@ -987,6 +986,41 @@ static int get_option_ul(substring_t args[], unsigned long *option) return rc; } +static int get_option_uid(substring_t args[], kuid_t *result) +{ + unsigned long value; + kuid_t uid; + int rc; + + rc = get_option_ul(args, &value); + if (rc) + return rc; + + uid = make_kuid(current_user_ns(), value); + if (!uid_valid(uid)) + return -EINVAL; + + *result = uid; + return 0; +} + +static int get_option_gid(substring_t args[], kgid_t *result) +{ + unsigned long value; + kgid_t gid; + int rc; + + rc = get_option_ul(args, &value); + if (rc) + return rc; + + gid = make_kgid(current_user_ns(), value); + if (!gid_valid(gid)) + return -EINVAL; + + *result = gid; + return 0; +} static int cifs_parse_security_flavors(char *value, struct smb_vol *vol) @@ -996,7 +1030,7 @@ static int cifs_parse_security_flavors(char *value, switch (match_token(value, cifs_secflavor_tokens, args)) { case Opt_sec_krb5: - vol->secFlg |= CIFSSEC_MAY_KRB5; + vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MAY_SIGN; break; case Opt_sec_krb5i: vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN; @@ -1424,47 +1458,42 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, /* Numeric Values */ case Opt_backupuid: - if (get_option_ul(args, &option)) { + if (get_option_uid(args, &vol->backupuid)) { cERROR(1, "%s: Invalid backupuid value", __func__); goto cifs_parse_mount_err; } - vol->backupuid = option; vol->backupuid_specified = true; break; case Opt_backupgid: - if (get_option_ul(args, &option)) { + if (get_option_gid(args, &vol->backupgid)) { cERROR(1, "%s: Invalid backupgid value", __func__); goto cifs_parse_mount_err; } - vol->backupgid = option; vol->backupgid_specified = true; break; case Opt_uid: - if (get_option_ul(args, &option)) { + if (get_option_uid(args, &vol->linux_uid)) { cERROR(1, "%s: Invalid uid value", __func__); goto cifs_parse_mount_err; } - vol->linux_uid = option; uid_specified = true; break; case Opt_cruid: - if (get_option_ul(args, &option)) { + if (get_option_uid(args, &vol->cred_uid)) { cERROR(1, "%s: Invalid cruid value", __func__); goto cifs_parse_mount_err; } - vol->cred_uid = option; break; case Opt_gid: - if (get_option_ul(args, &option)) { + if (get_option_gid(args, &vol->linux_gid)) { cERROR(1, "%s: Invalid gid value", __func__); goto cifs_parse_mount_err; } - vol->linux_gid = option; gid_specified = true; break; case Opt_file_mode: @@ -1722,19 +1751,6 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, */ cFYI(1, "iocharset set to %s", string); break; - case Opt_sockopt: - string = match_strdup(args); - if (string == NULL) - goto out_nomem; - - if (strnicmp(string, "TCP_NODELAY", 11) == 0) { - printk(KERN_WARNING "CIFS: the " - "sockopt=TCP_NODELAY option has been " - "deprecated and will be removed " - "in 3.9\n"); - vol->sockopt_tcp_nodelay = 1; - } - break; case Opt_netbiosname: string = match_strdup(args); if (string == NULL) @@ -1917,7 +1933,7 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) } case AF_INET6: { struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; - struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs; + struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs; return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); } default: @@ -2241,7 +2257,7 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol) { switch (ses->server->secType) { case Kerberos: - if (vol->cred_uid != ses->cred_uid) + if (!uid_eq(vol->cred_uid, ses->cred_uid)) return 0; break; default: @@ -2713,7 +2729,7 @@ compare_mount_options(struct super_block *sb, struct cifs_mnt_data *mnt_data) if (new->rsize && new->rsize < old->rsize) return 0; - if (old->mnt_uid != new->mnt_uid || old->mnt_gid != new->mnt_gid) + if (!uid_eq(old->mnt_uid, new->mnt_uid) || !gid_eq(old->mnt_gid, new->mnt_gid)) return 0; if (old->mnt_file_mode != new->mnt_file_mode || @@ -3919,7 +3935,7 @@ cifs_set_vol_auth(struct smb_vol *vol, struct cifs_ses *ses) } static struct cifs_tcon * -cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) +cifs_construct_tcon(struct cifs_sb_info *cifs_sb, kuid_t fsuid) { int rc; struct cifs_tcon *master_tcon = cifs_sb_master_tcon(cifs_sb); @@ -3989,7 +4005,7 @@ cifs_sb_tcon_pending_wait(void *unused) /* find and return a tlink with given uid */ static struct tcon_link * -tlink_rb_search(struct rb_root *root, uid_t uid) +tlink_rb_search(struct rb_root *root, kuid_t uid) { struct rb_node *node = root->rb_node; struct tcon_link *tlink; @@ -3997,9 +4013,9 @@ tlink_rb_search(struct rb_root *root, uid_t uid) while (node) { tlink = rb_entry(node, struct tcon_link, tl_rbnode); - if (tlink->tl_uid > uid) + if (uid_gt(tlink->tl_uid, uid)) node = node->rb_left; - else if (tlink->tl_uid < uid) + else if (uid_lt(tlink->tl_uid, uid)) node = node->rb_right; else return tlink; @@ -4018,7 +4034,7 @@ tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) tlink = rb_entry(*new, struct tcon_link, tl_rbnode); parent = *new; - if (tlink->tl_uid > new_tlink->tl_uid) + if (uid_gt(tlink->tl_uid, new_tlink->tl_uid)) new = &((*new)->rb_left); else new = &((*new)->rb_right); @@ -4048,7 +4064,7 @@ struct tcon_link * cifs_sb_tlink(struct cifs_sb_info *cifs_sb) { int ret; - uid_t fsuid = current_fsuid(); + kuid_t fsuid = current_fsuid(); struct tcon_link *tlink, *newtlink; if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 8719bbe0dcc3..1cd016217448 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -342,14 +342,14 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid, *created |= FILE_CREATED; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { - args.uid = (__u64) current_fsuid(); + args.uid = current_fsuid(); if (inode->i_mode & S_ISGID) - args.gid = (__u64) inode->i_gid; + args.gid = inode->i_gid; else - args.gid = (__u64) current_fsgid(); + args.gid = current_fsgid(); } else { - args.uid = NO_CHANGE_64; - args.gid = NO_CHANGE_64; + args.uid = INVALID_UID; /* no change */ + args.gid = INVALID_GID; /* no change */ } CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid, current->tgid); @@ -588,11 +588,11 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode, .device = device_number, }; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { - args.uid = (__u64) current_fsuid(); - args.gid = (__u64) current_fsgid(); + args.uid = current_fsuid(); + args.gid = current_fsgid(); } else { - args.uid = NO_CHANGE_64; - args.gid = NO_CHANGE_64; + args.uid = INVALID_UID; /* no change */ + args.gid = INVALID_GID; /* no change */ } rc = CIFSSMBUnixSetPathInfo(xid, pTcon, full_path, &args, cifs_sb->local_nls, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8ea6ca50a665..8c0d85577314 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -43,6 +43,7 @@ #include "cifs_fs_sb.h" #include "fscache.h" + static inline int cifs_convert_flags(unsigned int flags) { if ((flags & O_ACCMODE) == O_RDONLY) @@ -72,10 +73,15 @@ static u32 cifs_posix_convert_flags(unsigned int flags) else if ((flags & O_ACCMODE) == O_RDWR) posix_flags = SMB_O_RDWR; - if (flags & O_CREAT) + if (flags & O_CREAT) { posix_flags |= SMB_O_CREAT; - if (flags & O_EXCL) - posix_flags |= SMB_O_EXCL; + if (flags & O_EXCL) + posix_flags |= SMB_O_EXCL; + } else if (flags & O_EXCL) + cFYI(1, "Application %s pid %d has incorrectly set O_EXCL flag" + "but not O_CREAT on file open. Ignoring O_EXCL", + current->comm, current->tgid); + if (flags & O_TRUNC) posix_flags |= SMB_O_TRUNC; /* be safe and imply O_SYNC for O_DSYNC */ @@ -515,8 +521,8 @@ int cifs_open(struct inode *inode, struct file *file) */ struct cifs_unix_set_info_args args = { .mode = inode->i_mode, - .uid = NO_CHANGE_64, - .gid = NO_CHANGE_64, + .uid = INVALID_UID, /* no change */ + .gid = INVALID_GID, /* no change */ .ctime = NO_CHANGE_64, .atime = NO_CHANGE_64, .mtime = NO_CHANGE_64, @@ -947,7 +953,7 @@ static int cifs_posix_lock_test(struct file *file, struct file_lock *flock) { int rc = 0; - struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(file_inode(file)); unsigned char saved_type = flock->fl_type; if ((flock->fl_flags & FL_POSIX) == 0) @@ -974,7 +980,7 @@ cifs_posix_lock_test(struct file *file, struct file_lock *flock) static int cifs_posix_lock_set(struct file *file, struct file_lock *flock) { - struct cifsInodeInfo *cinode = CIFS_I(file->f_path.dentry->d_inode); + struct cifsInodeInfo *cinode = CIFS_I(file_inode(file)); int rc = 1; if ((flock->fl_flags & FL_POSIX) == 0) @@ -1548,7 +1554,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock) cifs_sb = CIFS_SB(file->f_path.dentry->d_sb); netfid = cfile->fid.netfid; - cinode = CIFS_I(file->f_path.dentry->d_inode); + cinode = CIFS_I(file_inode(file)); if (cap_unix(tcon->ses) && (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability)) && @@ -1693,7 +1699,7 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, are always at the end of the list but since the first entry might have a close pending, we go through the whole list */ list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { - if (fsuid_only && open_file->uid != current_fsuid()) + if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) continue; if (OPEN_FMODE(open_file->f_flags) & FMODE_READ) { if (!open_file->invalidHandle) { @@ -1746,7 +1752,7 @@ refind_writable: list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (!any_available && open_file->pid != current->tgid) continue; - if (fsuid_only && open_file->uid != current_fsuid()) + if (fsuid_only && !uid_eq(open_file->uid, current_fsuid())) continue; if (OPEN_FMODE(open_file->f_flags) & FMODE_WRITE) { if (!open_file->invalidHandle) { @@ -2171,7 +2177,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end, struct cifs_tcon *tcon; struct TCP_Server_Info *server; struct cifsFileInfo *smbfile = file->private_data; - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); rc = filemap_write_and_wait_range(inode->i_mapping, start, end); @@ -2246,7 +2252,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync) */ int cifs_flush(struct file *file, fl_owner_t id) { - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); int rc = 0; if (file->f_mode & FMODE_WRITE) @@ -2480,7 +2486,7 @@ ssize_t cifs_user_writev(struct kiocb *iocb, const struct iovec *iov, ssize_t written; struct inode *inode; - inode = iocb->ki_filp->f_path.dentry->d_inode; + inode = file_inode(iocb->ki_filp); /* * BB - optimize the way when signing is disabled. We can drop this @@ -2543,7 +2549,7 @@ ssize_t cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(iocb->ki_filp); struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = (struct cifsFileInfo *) @@ -2915,7 +2921,7 @@ ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - struct inode *inode = iocb->ki_filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(iocb->ki_filp); struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = (struct cifsFileInfo *) @@ -3063,7 +3069,7 @@ static struct vm_operations_struct cifs_file_vm_ops = { int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma) { int rc, xid; - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); xid = get_xid(); @@ -3356,7 +3362,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, int rc; /* Is the page cached? */ - rc = cifs_readpage_from_fscache(file->f_path.dentry->d_inode, page); + rc = cifs_readpage_from_fscache(file_inode(file), page); if (rc == 0) goto read_complete; @@ -3371,8 +3377,8 @@ static int cifs_readpage_worker(struct file *file, struct page *page, else cFYI(1, "Bytes read %d", rc); - file->f_path.dentry->d_inode->i_atime = - current_fs_time(file->f_path.dentry->d_inode->i_sb); + file_inode(file)->i_atime = + current_fs_time(file_inode(file)->i_sb); if (PAGE_CACHE_SIZE > rc) memset(read_data + rc, 0, PAGE_CACHE_SIZE - rc); @@ -3381,7 +3387,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, SetPageUptodate(page); /* send this page to the cache */ - cifs_readpage_to_fscache(file->f_path.dentry->d_inode, page); + cifs_readpage_to_fscache(file_inode(file), page); rc = 0; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ed6208ff85a7..0079696305c9 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -244,15 +244,25 @@ cifs_unix_basic_to_fattr(struct cifs_fattr *fattr, FILE_UNIX_BASIC_INFO *info, break; } - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) - fattr->cf_uid = cifs_sb->mnt_uid; - else - fattr->cf_uid = le64_to_cpu(info->Uid); - - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) - fattr->cf_gid = cifs_sb->mnt_gid; - else - fattr->cf_gid = le64_to_cpu(info->Gid); + fattr->cf_uid = cifs_sb->mnt_uid; + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)) { + u64 id = le64_to_cpu(info->Uid); + if (id < ((uid_t)-1)) { + kuid_t uid = make_kuid(&init_user_ns, id); + if (uid_valid(uid)) + fattr->cf_uid = uid; + } + } + + fattr->cf_gid = cifs_sb->mnt_gid; + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID)) { + u64 id = le64_to_cpu(info->Gid); + if (id < ((gid_t)-1)) { + kgid_t gid = make_kgid(&init_user_ns, id); + if (gid_valid(gid)) + fattr->cf_gid = gid; + } + } fattr->cf_nlink = le64_to_cpu(info->Nlinks); } @@ -289,7 +299,7 @@ cifs_get_file_info_unix(struct file *filp) unsigned int xid; FILE_UNIX_BASIC_INFO find_data; struct cifs_fattr fattr; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(filp); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = filp->private_data; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); @@ -558,7 +568,7 @@ cifs_get_file_info(struct file *filp) unsigned int xid; FILE_ALL_INFO find_data; struct cifs_fattr fattr; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(filp); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsFileInfo *cfile = filp->private_data; struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); @@ -806,10 +816,9 @@ static bool inode_has_hashed_dentries(struct inode *inode) { struct dentry *dentry; - struct hlist_node *p; spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) { + hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { if (!d_unhashed(dentry) || IS_ROOT(dentry)) { spin_unlock(&inode->i_lock); return true; @@ -986,6 +995,15 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, return PTR_ERR(tlink); tcon = tlink_tcon(tlink); + /* + * We cannot rename the file if the server doesn't support + * CAP_INFOLEVEL_PASSTHRU + */ + if (!(tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)) { + rc = -EBUSY; + goto out; + } + rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN, DELETE|FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR, &netfid, &oplock, NULL, cifs_sb->local_nls, @@ -1014,7 +1032,7 @@ cifs_rename_pending_delete(const char *full_path, struct dentry *dentry, current->tgid); /* although we would like to mark the file hidden if that fails we will still try to rename it */ - if (rc != 0) + if (!rc) cifsInode->cifsAttrs = dosattr; else dosattr = origattr; /* since not able to change them */ @@ -1245,14 +1263,14 @@ cifs_mkdir_qinfo(struct inode *parent, struct dentry *dentry, umode_t mode, .device = 0, }; if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { - args.uid = (__u64)current_fsuid(); + args.uid = current_fsuid(); if (parent->i_mode & S_ISGID) - args.gid = (__u64)parent->i_gid; + args.gid = parent->i_gid; else - args.gid = (__u64)current_fsgid(); + args.gid = current_fsgid(); } else { - args.uid = NO_CHANGE_64; - args.gid = NO_CHANGE_64; + args.uid = INVALID_UID; /* no change */ + args.gid = INVALID_GID; /* no change */ } CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, cifs_sb->local_nls, @@ -1678,7 +1696,7 @@ cifs_invalidate_mapping(struct inode *inode) int cifs_revalidate_file_attr(struct file *filp) { int rc = 0; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(filp); struct cifsFileInfo *cfile = (struct cifsFileInfo *) filp->private_data; if (!cifs_inode_needs_reval(inode)) @@ -1735,7 +1753,7 @@ out: int cifs_revalidate_file(struct file *filp) { int rc; - struct inode *inode = filp->f_path.dentry->d_inode; + struct inode *inode = file_inode(filp); rc = cifs_revalidate_file_attr(filp); if (rc) @@ -2013,12 +2031,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) if (attrs->ia_valid & ATTR_UID) args->uid = attrs->ia_uid; else - args->uid = NO_CHANGE_64; + args->uid = INVALID_UID; /* no change */ if (attrs->ia_valid & ATTR_GID) args->gid = attrs->ia_gid; else - args->gid = NO_CHANGE_64; + args->gid = INVALID_GID; /* no change */ if (attrs->ia_valid & ATTR_ATIME) args->atime = cifs_UnixTimeToNT(attrs->ia_atime); @@ -2086,8 +2104,8 @@ static int cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) { unsigned int xid; - uid_t uid = NO_CHANGE_32; - gid_t gid = NO_CHANGE_32; + kuid_t uid = INVALID_UID; + kgid_t gid = INVALID_GID; struct inode *inode = direntry->d_inode; struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsInodeInfo *cifsInode = CIFS_I(inode); @@ -2146,7 +2164,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) #ifdef CONFIG_CIFS_ACL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { - if (uid != NO_CHANGE_32 || gid != NO_CHANGE_32) { + if (uid_valid(uid) || gid_valid(gid)) { rc = id_mode_to_cifs_acl(inode, full_path, NO_CHANGE_64, uid, gid); if (rc) { @@ -2170,7 +2188,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) #ifdef CONFIG_CIFS_ACL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { rc = id_mode_to_cifs_acl(inode, full_path, mode, - NO_CHANGE_32, NO_CHANGE_32); + INVALID_UID, INVALID_GID); if (rc) { cFYI(1, "%s: Setting ACL failed with error: %d", __func__, rc); diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index fd5009d56f9f..6c9f1214cf0b 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c @@ -30,7 +30,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) { - struct inode *inode = filep->f_dentry->d_inode; + struct inode *inode = file_inode(filep); int rc = -ENOTTY; /* strange error - but the precedent */ unsigned int xid; struct cifs_sb_info *cifs_sb; diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 51dc2fb6e854..9f6c4c45d21e 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -76,7 +76,7 @@ symlink_hash(unsigned int link_len, const char *link_str, u8 *md5_hash) } rc = crypto_shash_update(&sdescmd5->shash, link_str, link_len); if (rc) { - cERROR(1, "%s: Could not update iwth link_str", __func__); + cERROR(1, "%s: Could not update with link_str", __func__); goto symlink_hash_err; } rc = crypto_shash_final(&sdescmd5->shash, md5_hash); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 3a00c0d0cead..1b15bf839f37 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -569,7 +569,7 @@ bool backup_cred(struct cifs_sb_info *cifs_sb) { if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPUID) { - if (cifs_sb->mnt_backupuid == current_fsuid()) + if (uid_eq(cifs_sb->mnt_backupuid, current_fsuid())) return true; } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_BACKUPGID) { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index cdd6ff48246b..df40cc5fd13a 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -82,12 +82,10 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, cFYI(1, "%s: for %s", __func__, name->name); - if (parent->d_op && parent->d_op->d_hash) - parent->d_op->d_hash(parent, parent->d_inode, name); - else - name->hash = full_name_hash(name->name, name->len); + dentry = d_hash_and_lookup(parent, name); + if (unlikely(IS_ERR(dentry))) + return; - dentry = d_lookup(parent, name); if (dentry) { int err; @@ -505,7 +503,7 @@ static int cifs_entry_is_dot(struct cifs_dirent *de, bool is_unicode) whether we can use the cached search results from the previous search */ static int is_dir_changed(struct file *file) { - struct inode *inode = file->f_path.dentry->d_inode; + struct inode *inode = file_inode(file); struct cifsInodeInfo *cifsInfo = CIFS_I(inode); if (cifsInfo->time == 0) @@ -778,7 +776,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) switch ((int) file->f_pos) { case 0: if (filldir(direntry, ".", 1, file->f_pos, - file->f_path.dentry->d_inode->i_ino, DT_DIR) < 0) { + file_inode(file)->i_ino, DT_DIR) < 0) { cERROR(1, "Filldir for current dir failed"); rc = -ENOMEM; break; diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index c9c7aa7ed966..bceffe7b8f8d 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -744,4 +744,5 @@ struct smb_version_values smb30_values = { .cap_unix = 0, .cap_nt_find = SMB2_NT_FIND, .cap_large_files = SMB2_LARGE_FILES, + .oplock_read = SMB2_OPLOCK_LEVEL_II, }; |