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

Commit 351a7934 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6

Pull CIFS fixes from Steve French:
 "Three cifs fixes, the most important fixing the problem with passing
  bogus pointers with writev (CVE-2014-0069).

  Two additional cifs fixes are still in review (including the fix for
  an append problem which Al also discovered)"

* 'for-linus' of git://git.samba.org/sfrench/cifs-2.6:
  CIFS: Fix too big maxBuf size for SMB3 mounts
  cifs: ensure that uncached writes handle unmapped areas correctly
  [CIFS] Fix cifsacl mounts over smb2 to not call cifs
parents 7026f192 2365c4ea
Loading
Loading
Loading
Loading
+24 −9
Original line number Diff line number Diff line
@@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd,
	return rc;
}

static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
		__u16 fid, u32 *pacllen)
struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
		const struct cifs_fid *cifsfid, u32 *pacllen)
{
	struct cifs_ntsd *pntsd = NULL;
	unsigned int xid;
@@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb,
		return ERR_CAST(tlink);

	xid = get_xid();
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen);
	rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd,
				pacllen);
	free_xid(xid);

	cifs_put_tlink(tlink);
@@ -946,7 +947,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
	if (!open_file)
		return get_cifs_acl_by_path(cifs_sb, path, pacllen);

	pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
	pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen);
	cifsFileInfo_put(open_file);
	return pntsd;
}
@@ -1006,19 +1007,31 @@ out:
/* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */
int
cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
		  struct inode *inode, const char *path, const __u16 *pfid)
		  struct inode *inode, const char *path,
		  const struct cifs_fid *pfid)
{
	struct cifs_ntsd *pntsd = NULL;
	u32 acllen = 0;
	int rc = 0;
	struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
	struct cifs_tcon *tcon;

	cifs_dbg(NOISY, "converting ACL to mode for %s\n", path);

	if (pfid)
		pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen);
	else
		pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen);
	if (IS_ERR(tlink))
		return PTR_ERR(tlink);
	tcon = tlink_tcon(tlink);

	if (pfid && (tcon->ses->server->ops->get_acl_by_fid))
		pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid,
							  &acllen);
	else if (tcon->ses->server->ops->get_acl)
		pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
							&acllen);
	else {
		cifs_put_tlink(tlink);
		return -EOPNOTSUPP;
	}
	/* if we can retrieve the ACL, now parse Access Control Entries, ACEs */
	if (IS_ERR(pntsd)) {
		rc = PTR_ERR(pntsd);
@@ -1030,6 +1043,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr,
			cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc);
	}

	cifs_put_tlink(tlink);

	return rc;
}

+2 −0
Original line number Diff line number Diff line
@@ -398,6 +398,8 @@ struct smb_version_operations {
			const struct nls_table *, int);
	struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *,
			const char *, u32 *);
	struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *,
			const struct cifs_fid *, u32 *);
	int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
			int);
};
+4 −2
Original line number Diff line number Diff line
@@ -151,7 +151,7 @@ extern struct inode *cifs_iget(struct super_block *sb,

extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
			       FILE_ALL_INFO *data, struct super_block *sb,
			       int xid, const __u16 *fid);
			       int xid, const struct cifs_fid *fid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
			const unsigned char *search_path,
			struct super_block *sb, unsigned int xid);
@@ -162,11 +162,13 @@ extern int cifs_rename_pending_delete(const char *full_path,
				      const unsigned int xid);
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);
			      const char *path, const struct cifs_fid *pfid);
extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64,
					kuid_t, kgid_t);
extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *,
					const char *, u32 *);
extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *,
						const struct cifs_fid *, u32 *);
extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *,
				const char *, int);

+1 −1
Original line number Diff line number Diff line
@@ -378,7 +378,7 @@ cifs_create_get_file_info:
					      xid);
	else {
		rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
					 xid, &fid->netfid);
					 xid, fid);
		if (newinode) {
			if (server->ops->set_lease_key)
				server->ops->set_lease_key(newinode, fid);
+35 −4
Original line number Diff line number Diff line
@@ -244,7 +244,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
					      xid);
	else
		rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
					 xid, &fid->netfid);
					 xid, fid);

out:
	kfree(buf);
@@ -2389,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
		 unsigned long nr_segs, loff_t *poffset)
{
	unsigned long nr_pages, i;
	size_t copied, len, cur_len;
	size_t bytes, copied, len, cur_len;
	ssize_t total_written = 0;
	loff_t offset;
	struct iov_iter it;
@@ -2444,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,

		save_len = cur_len;
		for (i = 0; i < nr_pages; i++) {
			copied = min_t(const size_t, cur_len, PAGE_SIZE);
			bytes = min_t(const size_t, cur_len, PAGE_SIZE);
			copied = iov_iter_copy_from_user(wdata->pages[i], &it,
							 0, copied);
							 0, bytes);
			cur_len -= copied;
			iov_iter_advance(&it, copied);
			/*
			 * If we didn't copy as much as we expected, then that
			 * may mean we trod into an unmapped area. Stop copying
			 * at that point. On the next pass through the big
			 * loop, we'll likely end up getting a zero-length
			 * write and bailing out of it.
			 */
			if (copied < bytes)
				break;
		}
		cur_len = save_len - cur_len;

		/*
		 * If we have no data to send, then that probably means that
		 * the copy above failed altogether. That's most likely because
		 * the address in the iovec was bogus. Set the rc to -EFAULT,
		 * free anything we allocated and bail out.
		 */
		if (!cur_len) {
			for (i = 0; i < nr_pages; i++)
				put_page(wdata->pages[i]);
			kfree(wdata);
			rc = -EFAULT;
			break;
		}

		/*
		 * i + 1 now represents the number of pages we actually used in
		 * the copy phase above. Bring nr_pages down to that, and free
		 * any pages that we didn't use.
		 */
		for ( ; nr_pages > i + 1; nr_pages--)
			put_page(wdata->pages[nr_pages - 1]);

		wdata->sync_mode = WB_SYNC_ALL;
		wdata->nr_pages = nr_pages;
		wdata->offset = (__u64)offset;
Loading