13 cifs/smb3 client fixes

-----BEGIN PGP SIGNATURE-----
 
 iQGzBAABCgAdFiEE6fsu8pdIjtWE/DpLiiy9cAdyT1EFAmObnuoACgkQiiy9cAdy
 T1GD2Av8CsAWbrFNa5blTrtbZcEN5bkllLN2HC2BbCHFiFHcRWLCctEjfq7SlvZR
 5JKgUL00mT4qAwGsjmfvHlqM1MFCwx27EoVMRZwYrEOnJKvHbX4VF/G74XSJHIdI
 0zPtBblJq0l8AautwBwrI3OxO1u2WYR7P/mCi9/AxXxgGRgZDXIprjEX+A2w+FwG
 oi9w2BJo2LX/3STEPRjgblIrIqU1iu9tSvEoMsjeFn+yCk5IqeII0P+TPcLcNRFd
 kdQcTkjcj1yAZqhnXr7xpnimIwliXTxC4eCytJTDVMSJ9B08f4mOpM8JLfi4VyNr
 hT9Y3C97+7FfYthP7d31ubMt6WonoujW8s4bSQ6hNoQDLhfoNClWEzv5HNyYxQDZ
 2dGzY+zwpbAnwZ/b8I/6xT46Xl+RutJ9TsLtN1q45RtdoNvomcby4PLccOgH2vGy
 hIe3kBozV0yD/CsOA5bIMFR4rNXXmq9oHyMDUrv6xKcoAQAD65PiY3GredrT+BI0
 6CaVK/v5
 =Ufyp
 -----END PGP SIGNATURE-----

Merge tag '6.2-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6

Pull cifs client updates from Steve French:

 - SMB3.1.1 POSIX Extensions fixes

 - remove use of generic_writepages() and ->cifs_writepage(), in favor
   of ->cifs_writepages() and ->migrate_folio()

 - memory management fixes

 - mount parm parsing fixes

 - minor cleanup fixes

* tag '6.2-rc-smb3-client-fixes-part1' of git://git.samba.org/sfrench/cifs-2.6:
  cifs: Remove duplicated include in cifsglob.h
  cifs: fix oops during encryption
  cifs: print warning when conflicting soft vs. hard mount options specified
  cifs: fix missing display of three mount options
  cifs: fix various whitespace errors in headers
  cifs: minor cleanup of some headers
  cifs: skip alloc when request has no pages
  cifs: remove ->writepage
  cifs: stop using generic_writepages
  cifs: wire up >migrate_folio
  cifs: Parse owner/group for stat in smb311 posix extensions
  cifs: Add "extbuf" and "extbuflen" args to smb2_compound_op()
  Fix path in cifs/usage.rst
This commit is contained in:
Linus Torvalds 2022-12-15 14:53:14 -08:00
commit 851f657a86
14 changed files with 300 additions and 168 deletions

View File

@ -858,7 +858,7 @@ CIFS kernel module parameters
These module parameters can be specified or modified either during the time of These module parameters can be specified or modified either during the time of
module loading or during the runtime by using the interface:: module loading or during the runtime by using the interface::
/proc/module/cifs/parameters/<param> /sys/module/cifs/parameters/<param>
i.e.:: i.e.::

View File

@ -108,7 +108,7 @@ struct smb3_notify_info {
#define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify) #define CIFS_IOC_NOTIFY _IOW(CIFS_IOCTL_MAGIC, 9, struct smb3_notify)
#define CIFS_DUMP_FULL_KEY _IOWR(CIFS_IOCTL_MAGIC, 10, struct smb3_full_key_debug_info) #define CIFS_DUMP_FULL_KEY _IOWR(CIFS_IOCTL_MAGIC, 10, struct smb3_full_key_debug_info)
#define CIFS_IOC_NOTIFY_INFO _IOWR(CIFS_IOCTL_MAGIC, 11, struct smb3_notify_info) #define CIFS_IOC_NOTIFY_INFO _IOWR(CIFS_IOCTL_MAGIC, 11, struct smb3_notify_info)
#define CIFS_IOC_SHUTDOWN _IOR ('X', 125, __u32) #define CIFS_IOC_SHUTDOWN _IOR('X', 125, __u32)
/* /*
* Flags for going down operation * Flags for going down operation

View File

@ -678,9 +678,15 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_printf(s, ",echo_interval=%lu", seq_printf(s, ",echo_interval=%lu",
tcon->ses->server->echo_interval / HZ); tcon->ses->server->echo_interval / HZ);
/* Only display max_credits if it was overridden on mount */ /* Only display the following if overridden on mount */
if (tcon->ses->server->max_credits != SMB2_MAX_CREDITS_AVAILABLE) if (tcon->ses->server->max_credits != SMB2_MAX_CREDITS_AVAILABLE)
seq_printf(s, ",max_credits=%u", tcon->ses->server->max_credits); seq_printf(s, ",max_credits=%u", tcon->ses->server->max_credits);
if (tcon->ses->server->tcp_nodelay)
seq_puts(s, ",tcpnodelay");
if (tcon->ses->server->noautotune)
seq_puts(s, ",noautotune");
if (tcon->ses->server->noblocksnd)
seq_puts(s, ",noblocksend");
if (tcon->snapshot_time) if (tcon->snapshot_time)
seq_printf(s, ",snapshot=%llu", tcon->snapshot_time); seq_printf(s, ",snapshot=%llu", tcon->snapshot_time);

View File

@ -105,8 +105,8 @@ extern int cifs_lock(struct file *, int, struct file_lock *);
extern int cifs_fsync(struct file *, loff_t, loff_t, int); extern int cifs_fsync(struct file *, loff_t, loff_t, int);
extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int); extern int cifs_strict_fsync(struct file *, loff_t, loff_t, int);
extern int cifs_flush(struct file *, fl_owner_t id); extern int cifs_flush(struct file *, fl_owner_t id);
extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern int cifs_file_mmap(struct file *file, struct vm_area_struct *vma);
extern int cifs_file_strict_mmap(struct file * , struct vm_area_struct *); extern int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma);
extern const struct file_operations cifs_dir_ops; extern const struct file_operations cifs_dir_ops;
extern int cifs_dir_open(struct inode *inode, struct file *file); extern int cifs_dir_open(struct inode *inode, struct file *file);
extern int cifs_readdir(struct file *file, struct dir_context *ctx); extern int cifs_readdir(struct file *file, struct dir_context *ctx);

View File

@ -13,6 +13,8 @@
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/inet.h> #include <linux/inet.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/mm.h>
#include <linux/mempool.h> #include <linux/mempool.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/utsname.h> #include <linux/utsname.h>
@ -21,7 +23,6 @@
#include "cifs_fs_sb.h" #include "cifs_fs_sb.h"
#include "cifsacl.h" #include "cifsacl.h"
#include <crypto/internal/hash.h> #include <crypto/internal/hash.h>
#include <linux/scatterlist.h>
#include <uapi/linux/cifs/cifs_mount.h> #include <uapi/linux/cifs/cifs_mount.h>
#include "../smbfs_common/smb2pdu.h" #include "../smbfs_common/smb2pdu.h"
#include "smb2pdu.h" #include "smb2pdu.h"
@ -785,6 +786,7 @@ static inline unsigned int
in_flight(struct TCP_Server_Info *server) in_flight(struct TCP_Server_Info *server)
{ {
unsigned int num; unsigned int num;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
num = server->in_flight; num = server->in_flight;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
@ -795,6 +797,7 @@ static inline bool
has_credits(struct TCP_Server_Info *server, int *credits, int num_credits) has_credits(struct TCP_Server_Info *server, int *credits, int num_credits)
{ {
int num; int num;
spin_lock(&server->req_lock); spin_lock(&server->req_lock);
num = *credits; num = *credits;
spin_unlock(&server->req_lock); spin_unlock(&server->req_lock);
@ -1025,7 +1028,7 @@ struct cifs_ses {
struct TCP_Server_Info *server; /* pointer to server info */ struct TCP_Server_Info *server; /* pointer to server info */
int ses_count; /* reference counter */ int ses_count; /* reference counter */
enum ses_status_enum ses_status; /* updates protected by cifs_tcp_ses_lock */ enum ses_status_enum ses_status; /* updates protected by cifs_tcp_ses_lock */
unsigned overrideSecFlg; /* if non-zero override global sec flags */ unsigned int overrideSecFlg; /* if non-zero override global sec flags */
char *serverOS; /* name of operating system underlying server */ char *serverOS; /* name of operating system underlying server */
char *serverNOS; /* name of network operating system of server */ char *serverNOS; /* name of network operating system of server */
char *serverDomain; /* security realm of server */ char *serverDomain; /* security realm of server */
@ -1381,7 +1384,7 @@ struct cifsFileInfo {
__u32 pid; /* process id who opened file */ __u32 pid; /* process id who opened file */
struct cifs_fid fid; /* file id from remote */ struct cifs_fid fid; /* file id from remote */
struct list_head rlist; /* reconnect list */ struct list_head rlist; /* reconnect list */
/* BB add lock scope info here if needed */ ; /* BB add lock scope info here if needed */
/* lock scope id (0 if none) */ /* lock scope id (0 if none) */
struct dentry *dentry; struct dentry *dentry;
struct tcon_link *tlink; struct tcon_link *tlink;
@ -1769,6 +1772,7 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param,
int number_of_items) int number_of_items)
{ {
int i; int i;
if ((number_of_items == 0) || (param == NULL)) if ((number_of_items == 0) || (param == NULL))
return; return;
for (i = 0; i < number_of_items; i++) { for (i = 0; i < number_of_items; i++) {
@ -2137,4 +2141,70 @@ static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const
dst->FileNameLength = src->FileNameLength; dst->FileNameLength = src->FileNameLength;
} }
static inline unsigned int cifs_get_num_sgs(const struct smb_rqst *rqst,
int num_rqst,
const u8 *sig)
{
unsigned int len, skip;
unsigned int nents = 0;
unsigned long addr;
int i, j;
/* Assumes the first rqst has a transform header as the first iov.
* I.e.
* rqst[0].rq_iov[0] is transform header
* rqst[0].rq_iov[1+] data to be encrypted/decrypted
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
*/
for (i = 0; i < num_rqst; i++) {
/*
* The first rqst has a transform header where the
* first 20 bytes are not part of the encrypted blob.
*/
for (j = 0; j < rqst[i].rq_nvec; j++) {
struct kvec *iov = &rqst[i].rq_iov[j];
skip = (i == 0) && (j == 0) ? 20 : 0;
addr = (unsigned long)iov->iov_base + skip;
if (unlikely(is_vmalloc_addr((void *)addr))) {
len = iov->iov_len - skip;
nents += DIV_ROUND_UP(offset_in_page(addr) + len,
PAGE_SIZE);
} else {
nents++;
}
}
nents += rqst[i].rq_npages;
}
nents += DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_SIZE);
return nents;
}
/* We can not use the normal sg_set_buf() as we will sometimes pass a
* stack object as buf.
*/
static inline struct scatterlist *cifs_sg_set_buf(struct scatterlist *sg,
const void *buf,
unsigned int buflen)
{
unsigned long addr = (unsigned long)buf;
unsigned int off = offset_in_page(addr);
addr &= PAGE_MASK;
if (unlikely(is_vmalloc_addr((void *)addr))) {
do {
unsigned int len = min_t(unsigned int, buflen, PAGE_SIZE - off);
sg_set_page(sg++, vmalloc_to_page((void *)addr), len, off);
off = 0;
addr += PAGE_SIZE;
buflen -= len;
} while (buflen);
} else {
sg_set_page(sg++, virt_to_page(addr), buflen, off);
}
return sg;
}
#endif /* _CIFS_GLOB_H */ #endif /* _CIFS_GLOB_H */

View File

@ -1429,7 +1429,7 @@ typedef struct smb_com_transaction_change_notify_req {
__u8 WatchTree; /* 1 = Monitor subdirectories */ __u8 WatchTree; /* 1 = Monitor subdirectories */
__u8 Reserved2; __u8 Reserved2;
__le16 ByteCount; __le16 ByteCount;
/* __u8 Pad[3];*/ /* __u8 Pad[3];*/
/* __u8 Data[1];*/ /* __u8 Data[1];*/
} __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ;
@ -1752,8 +1752,7 @@ struct smb_com_transaction2_sfi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2; struct trans2_resp t2;
__u16 ByteCount; __u16 ByteCount;
__u16 Reserved2; /* parameter word reserved - __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
present for infolevels > 100 */
} __attribute__((packed)); } __attribute__((packed));
struct smb_t2_qfi_req { struct smb_t2_qfi_req {
@ -1768,8 +1767,7 @@ struct smb_t2_qfi_rsp {
struct smb_hdr hdr; /* wct = 10 + SetupCount */ struct smb_hdr hdr; /* wct = 10 + SetupCount */
struct trans2_resp t2; struct trans2_resp t2;
__u16 ByteCount; __u16 ByteCount;
__u16 Reserved2; /* parameter word reserved - __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */
present for infolevels > 100 */
} __attribute__((packed)); } __attribute__((packed));
/* /*
@ -2146,13 +2144,11 @@ typedef struct {
#define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based #define CIFS_UNIX_POSIX_PATH_OPS_CAP 0x00000020 /* Allow new POSIX path based
calls including posix open calls including posix open
and posix unlink */ and posix unlink */
#define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up #define CIFS_UNIX_LARGE_READ_CAP 0x00000040 /* support reads >128K (up to 0xFFFF00 */
to 0xFFFF00 */
#define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080 #define CIFS_UNIX_LARGE_WRITE_CAP 0x00000080
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */ #define CIFS_UNIX_TRANSPORT_ENCRYPTION_CAP 0x00000100 /* can do SPNEGO crypt */
#define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */ #define CIFS_UNIX_TRANSPORT_ENCRYPTION_MANDATORY_CAP 0x00000200 /* must do */
#define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and #define CIFS_UNIX_PROXY_CAP 0x00000400 /* Proxy cap: 0xACE ioctl and QFS PROXY call */
QFS PROXY call */
#ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_POSIX
/* presumably don't need the 0x20 POSIX_PATH_OPS_CAP since we never send /* presumably don't need the 0x20 POSIX_PATH_OPS_CAP since we never send
LockingX instead of posix locking call on unix sess (and we do not expect LockingX instead of posix locking call on unix sess (and we do not expect
@ -2368,8 +2364,7 @@ typedef struct {
struct file_allocation_info { struct file_allocation_info {
__le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */
} __attribute__((packed)); /* size used on disk, for level 0x103 for set, } __packed; /* size used on disk, for level 0x103 for set, 0x105 for query */
0x105 for query */
struct file_end_of_file_info { struct file_end_of_file_info {
__le64 FileSize; /* offset to end of file */ __le64 FileSize; /* offset to end of file */
@ -2409,8 +2404,7 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
__le16 access_entry_count; /* access ACL - count of entries */ __le16 access_entry_count; /* access ACL - count of entries */
__le16 default_entry_count; /* default ACL - count of entries */ __le16 default_entry_count; /* default ACL - count of entries */
struct cifs_posix_ace ace_array[]; struct cifs_posix_ace ace_array[];
/* followed by /* followed by struct cifs_posix_ace default_ace_array[] */
struct cifs_posix_ace default_ace_arraay[] */
} __attribute__((packed)); /* level 0x204 */ } __attribute__((packed)); /* level 0x204 */
/* types of access control entries already defined in posix_acl.h */ /* types of access control entries already defined in posix_acl.h */
@ -2429,17 +2423,17 @@ struct cifs_posix_acl { /* access conrol list (ACL) */
/* end of POSIX ACL definitions */ /* end of POSIX ACL definitions */
/* POSIX Open Flags */ /* POSIX Open Flags */
#define SMB_O_RDONLY 0x1 #define SMB_O_RDONLY 0x1
#define SMB_O_WRONLY 0x2 #define SMB_O_WRONLY 0x2
#define SMB_O_RDWR 0x4 #define SMB_O_RDWR 0x4
#define SMB_O_CREAT 0x10 #define SMB_O_CREAT 0x10
#define SMB_O_EXCL 0x20 #define SMB_O_EXCL 0x20
#define SMB_O_TRUNC 0x40 #define SMB_O_TRUNC 0x40
#define SMB_O_APPEND 0x80 #define SMB_O_APPEND 0x80
#define SMB_O_SYNC 0x100 #define SMB_O_SYNC 0x100
#define SMB_O_DIRECTORY 0x200 #define SMB_O_DIRECTORY 0x200
#define SMB_O_NOFOLLOW 0x400 #define SMB_O_NOFOLLOW 0x400
#define SMB_O_DIRECT 0x800 #define SMB_O_DIRECT 0x800
typedef struct { typedef struct {
__le32 OpenFlags; /* same as NT CreateX */ __le32 OpenFlags; /* same as NT CreateX */
@ -2716,15 +2710,13 @@ typedef struct file_xattr_info {
__u32 xattr_value_len; __u32 xattr_value_len;
char xattr_name[]; char xattr_name[];
/* followed by xattr_value[xattr_value_len], no pad */ /* followed by xattr_value[xattr_value_len], no pad */
} __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute info } __packed FILE_XATTR_INFO; /* extended attribute info level 0x205 */
level 0x205 */
/* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */ /* flags for lsattr and chflags commands removed arein uapi/linux/fs.h */
typedef struct file_chattr_info { typedef struct file_chattr_info {
__le64 mask; /* list of all possible attribute bits */ __le64 mask; /* list of all possible attribute bits */
__le64 mode; /* list of actual attribute bits on this inode */ __le64 mode; /* list of actual attribute bits on this inode */
} __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes } __packed FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */
(chattr, chflags) level 0x206 */ #endif /* POSIX */
#endif /* POSIX */
#endif /* _CIFSPDU_H */ #endif /* _CIFSPDU_H */

View File

@ -124,7 +124,7 @@ extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *,
struct kvec * /* resp vec */); struct kvec * /* resp vec */);
extern int SendReceiveBlockingLock(const unsigned int xid, extern int SendReceiveBlockingLock(const unsigned int xid,
struct cifs_tcon *ptcon, struct cifs_tcon *ptcon,
struct smb_hdr *in_buf , struct smb_hdr *in_buf,
struct smb_hdr *out_buf, struct smb_hdr *out_buf,
int *bytes_returned); int *bytes_returned);
void void
@ -604,8 +604,8 @@ int setup_aio_ctx_iter(struct cifs_aio_ctx *ctx, struct iov_iter *iter, int rw);
int cifs_alloc_hash(const char *name, struct shash_desc **sdesc); int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
void cifs_free_hash(struct shash_desc **sdesc); void cifs_free_hash(struct shash_desc **sdesc);
extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset); unsigned int *len, unsigned int *offset);
struct cifs_chan * struct cifs_chan *
cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server); cifs_ses_find_chan(struct cifs_ses *ses, struct TCP_Server_Info *server);
int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses); int cifs_try_adding_channels(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses);

View File

@ -2646,6 +2646,21 @@ wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages,
return rc; return rc;
} }
static int
cifs_writepage_locked(struct page *page, struct writeback_control *wbc);
static int cifs_write_one_page(struct page *page, struct writeback_control *wbc,
void *data)
{
struct address_space *mapping = data;
int ret;
ret = cifs_writepage_locked(page, wbc);
unlock_page(page);
mapping_set_error(mapping, ret);
return ret;
}
static int cifs_writepages(struct address_space *mapping, static int cifs_writepages(struct address_space *mapping,
struct writeback_control *wbc) struct writeback_control *wbc)
{ {
@ -2662,10 +2677,11 @@ static int cifs_writepages(struct address_space *mapping,
/* /*
* If wsize is smaller than the page cache size, default to writing * If wsize is smaller than the page cache size, default to writing
* one page at a time via cifs_writepage * one page at a time.
*/ */
if (cifs_sb->ctx->wsize < PAGE_SIZE) if (cifs_sb->ctx->wsize < PAGE_SIZE)
return generic_writepages(mapping, wbc); return write_cache_pages(mapping, wbc, cifs_write_one_page,
mapping);
xid = get_xid(); xid = get_xid();
if (wbc->range_cyclic) { if (wbc->range_cyclic) {
@ -2852,13 +2868,6 @@ retry_write:
return rc; return rc;
} }
static int cifs_writepage(struct page *page, struct writeback_control *wbc)
{
int rc = cifs_writepage_locked(page, wbc);
unlock_page(page);
return rc;
}
static int cifs_write_end(struct file *file, struct address_space *mapping, static int cifs_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied, loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata) struct page *page, void *fsdata)
@ -5231,7 +5240,6 @@ static bool cifs_dirty_folio(struct address_space *mapping, struct folio *folio)
const struct address_space_operations cifs_addr_ops = { const struct address_space_operations cifs_addr_ops = {
.read_folio = cifs_read_folio, .read_folio = cifs_read_folio,
.readahead = cifs_readahead, .readahead = cifs_readahead,
.writepage = cifs_writepage,
.writepages = cifs_writepages, .writepages = cifs_writepages,
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
@ -5240,10 +5248,10 @@ const struct address_space_operations cifs_addr_ops = {
.direct_IO = cifs_direct_io, .direct_IO = cifs_direct_io,
.invalidate_folio = cifs_invalidate_folio, .invalidate_folio = cifs_invalidate_folio,
.launder_folio = cifs_launder_folio, .launder_folio = cifs_launder_folio,
.migrate_folio = filemap_migrate_folio,
/* /*
* TODO: investigate and if useful we could add an cifs_migratePage * TODO: investigate and if useful we could add an is_dirty_writeback
* helper (under an CONFIG_MIGRATION) in the future, and also * helper if needed
* investigate and add an is_dirty_writeback helper if needed
*/ */
.swap_activate = cifs_swap_activate, .swap_activate = cifs_swap_activate,
.swap_deactivate = cifs_swap_deactivate, .swap_deactivate = cifs_swap_deactivate,
@ -5256,7 +5264,6 @@ const struct address_space_operations cifs_addr_ops = {
*/ */
const struct address_space_operations cifs_addr_ops_smallbuf = { const struct address_space_operations cifs_addr_ops_smallbuf = {
.read_folio = cifs_read_folio, .read_folio = cifs_read_folio,
.writepage = cifs_writepage,
.writepages = cifs_writepages, .writepages = cifs_writepages,
.write_begin = cifs_write_begin, .write_begin = cifs_write_begin,
.write_end = cifs_write_end, .write_end = cifs_write_end,
@ -5264,4 +5271,5 @@ const struct address_space_operations cifs_addr_ops_smallbuf = {
.release_folio = cifs_release_folio, .release_folio = cifs_release_folio,
.invalidate_folio = cifs_invalidate_folio, .invalidate_folio = cifs_invalidate_folio,
.launder_folio = cifs_launder_folio, .launder_folio = cifs_launder_folio,
.migrate_folio = filemap_migrate_folio,
}; };

View File

@ -884,16 +884,21 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
ctx->nodfs = 1; ctx->nodfs = 1;
break; break;
case Opt_hard: case Opt_hard:
if (result.negated) if (result.negated) {
if (ctx->retry == 1)
cifs_dbg(VFS, "conflicting hard vs. soft mount options\n");
ctx->retry = 0; ctx->retry = 0;
else } else
ctx->retry = 1; ctx->retry = 1;
break; break;
case Opt_soft: case Opt_soft:
if (result.negated) if (result.negated)
ctx->retry = 1; ctx->retry = 1;
else else {
if (ctx->retry == 1)
cifs_dbg(VFS, "conflicting hard vs soft mount options\n");
ctx->retry = 0; ctx->retry = 0;
}
break; break;
case Opt_mapposix: case Opt_mapposix:
if (result.negated) if (result.negated)

View File

@ -632,6 +632,8 @@ static int cifs_sfu_mode(struct cifs_fattr *fattr, const unsigned char *path,
/* Fill a cifs_fattr struct with info from POSIX info struct */ /* Fill a cifs_fattr struct with info from POSIX info struct */
static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data, static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_open_info_data *data,
struct cifs_sid *owner,
struct cifs_sid *group,
struct super_block *sb, bool adjust_tz, bool symlink) struct super_block *sb, bool adjust_tz, bool symlink)
{ {
struct smb311_posix_qinfo *info = &data->posix_fi; struct smb311_posix_qinfo *info = &data->posix_fi;
@ -680,8 +682,8 @@ static void smb311_posix_info_to_fattr(struct cifs_fattr *fattr, struct cifs_ope
} }
/* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */ /* else if reparse point ... TODO: add support for FIFO and blk dev; special file types */
fattr->cf_uid = cifs_sb->ctx->linux_uid; /* TODO: map uid and gid from SID */ sid_to_id(cifs_sb, owner, fattr, SIDOWNER);
fattr->cf_gid = cifs_sb->ctx->linux_gid; sid_to_id(cifs_sb, group, fattr, SIDGROUP);
cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n", cifs_dbg(FYI, "POSIX query info: mode 0x%x uniqueid 0x%llx nlink %d\n",
fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink); fattr->cf_mode, fattr->cf_uniqueid, fattr->cf_nlink);
@ -1175,6 +1177,7 @@ smb311_posix_get_inode_info(struct inode **inode,
struct cifs_fattr fattr = {0}; struct cifs_fattr fattr = {0};
bool symlink = false; bool symlink = false;
struct cifs_open_info_data data = {}; struct cifs_open_info_data data = {};
struct cifs_sid owner, group;
int rc = 0; int rc = 0;
int tmprc = 0; int tmprc = 0;
@ -1192,7 +1195,8 @@ smb311_posix_get_inode_info(struct inode **inode,
goto out; goto out;
} }
rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data, &adjust_tz, rc = smb311_posix_query_path_info(xid, tcon, cifs_sb, full_path, &data,
&owner, &group, &adjust_tz,
&symlink); &symlink);
/* /*
@ -1201,7 +1205,8 @@ smb311_posix_get_inode_info(struct inode **inode,
switch (rc) { switch (rc) {
case 0: case 0:
smb311_posix_info_to_fattr(&fattr, &data, sb, adjust_tz, symlink); smb311_posix_info_to_fattr(&fattr, &data, &owner, &group,
sb, adjust_tz, symlink);
break; break;
case -EREMOTE: case -EREMOTE:
/* DFS link, no metadata available on this server */ /* DFS link, no metadata available on this server */

View File

@ -1136,8 +1136,8 @@ cifs_free_hash(struct shash_desc **sdesc)
* @len: Where to store the length for this page: * @len: Where to store the length for this page:
* @offset: Where to store the offset for this page * @offset: Where to store the offset for this page
*/ */
void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page, void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset) unsigned int *len, unsigned int *offset)
{ {
*len = rqst->rq_pagesz; *len = rqst->rq_pagesz;
*offset = (page == 0) ? rqst->rq_offset : 0; *offset = (page == 0) ? rqst->rq_offset : 0;

View File

@ -59,6 +59,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, struct cifs_sb_info *cifs_sb, const char *full_path,
__u32 desired_access, __u32 create_disposition, __u32 create_options, __u32 desired_access, __u32 create_disposition, __u32 create_options,
umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile, umode_t mode, void *ptr, int command, struct cifsFileInfo *cfile,
__u8 **extbuf, size_t *extbuflen,
struct kvec *err_iov, int *err_buftype) struct kvec *err_iov, int *err_buftype)
{ {
struct cop_vars *vars = NULL; struct cop_vars *vars = NULL;
@ -430,6 +431,21 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
&rsp_iov[1], sizeof(idata->posix_fi) /* add SIDs */, &rsp_iov[1], sizeof(idata->posix_fi) /* add SIDs */,
(char *)&idata->posix_fi); (char *)&idata->posix_fi);
} }
if (rc == 0) {
unsigned int length = le32_to_cpu(qi_rsp->OutputBufferLength);
if (length > sizeof(idata->posix_fi)) {
char *base = (char *)rsp_iov[1].iov_base +
le16_to_cpu(qi_rsp->OutputBufferOffset) +
sizeof(idata->posix_fi);
*extbuflen = length - sizeof(idata->posix_fi);
*extbuf = kmemdup(base, *extbuflen, GFP_KERNEL);
if (!*extbuf)
rc = -ENOMEM;
} else {
rc = -EINVAL;
}
}
if (rqst[1].rq_iov) if (rqst[1].rq_iov)
SMB2_query_info_free(&rqst[1]); SMB2_query_info_free(&rqst[1]);
if (rqst[2].rq_iov) if (rqst[2].rq_iov)
@ -539,7 +555,7 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
cifs_get_readable_path(tcon, full_path, &cfile); cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile, create_options, ACL_NO_MODE, data, SMB2_OP_QUERY_INFO, cfile,
err_iov, err_buftype); NULL, NULL, err_iov, err_buftype);
if (rc == -EOPNOTSUPP) { if (rc == -EOPNOTSUPP) {
if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER && if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE && ((struct smb2_hdr *)err_iov[0].iov_base)->Command == SMB2_CREATE &&
@ -555,7 +571,7 @@ int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
cifs_get_readable_path(tcon, full_path, &cfile); cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
FILE_OPEN, create_options, ACL_NO_MODE, data, FILE_OPEN, create_options, ACL_NO_MODE, data,
SMB2_OP_QUERY_INFO, cfile, NULL, NULL); SMB2_OP_QUERY_INFO, cfile, NULL, NULL, NULL, NULL);
} }
out: out:
@ -568,13 +584,20 @@ out:
int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, struct cifs_sb_info *cifs_sb, const char *full_path,
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse) struct cifs_open_info_data *data,
struct cifs_sid *owner,
struct cifs_sid *group,
bool *adjust_tz, bool *reparse)
{ {
int rc; int rc;
__u32 create_options = 0; __u32 create_options = 0;
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
struct kvec err_iov[3] = {}; struct kvec err_iov[3] = {};
int err_buftype[3] = {}; int err_buftype[3] = {};
__u8 *sidsbuf = NULL;
__u8 *sidsbuf_end = NULL;
size_t sidsbuflen = 0;
size_t owner_len, group_len;
*adjust_tz = false; *adjust_tz = false;
*reparse = false; *reparse = false;
@ -589,7 +612,7 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
cifs_get_readable_path(tcon, full_path, &cfile); cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, FILE_OPEN,
create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile, create_options, ACL_NO_MODE, data, SMB2_OP_POSIX_QUERY_INFO, cfile,
err_iov, err_buftype); &sidsbuf, &sidsbuflen, err_iov, err_buftype);
if (rc == -EOPNOTSUPP) { if (rc == -EOPNOTSUPP) {
/* BB TODO: When support for special files added to Samba re-verify this path */ /* BB TODO: When support for special files added to Samba re-verify this path */
if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER && if (err_iov[0].iov_base && err_buftype[0] != CIFS_NO_BUFFER &&
@ -606,10 +629,31 @@ int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
cifs_get_readable_path(tcon, full_path, &cfile); cifs_get_readable_path(tcon, full_path, &cfile);
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, FILE_READ_ATTRIBUTES,
FILE_OPEN, create_options, ACL_NO_MODE, data, FILE_OPEN, create_options, ACL_NO_MODE, data,
SMB2_OP_POSIX_QUERY_INFO, cfile, NULL, NULL); SMB2_OP_POSIX_QUERY_INFO, cfile,
&sidsbuf, &sidsbuflen, NULL, NULL);
}
if (rc == 0) {
sidsbuf_end = sidsbuf + sidsbuflen;
owner_len = posix_info_sid_size(sidsbuf, sidsbuf_end);
if (owner_len == -1) {
rc = -EINVAL;
goto out;
}
memcpy(owner, sidsbuf, owner_len);
group_len = posix_info_sid_size(
sidsbuf + owner_len, sidsbuf_end);
if (group_len == -1) {
rc = -EINVAL;
goto out;
}
memcpy(group, sidsbuf + owner_len, group_len);
} }
out: out:
kfree(sidsbuf);
free_rsp_buf(err_buftype[0], err_iov[0].iov_base); free_rsp_buf(err_buftype[0], err_iov[0].iov_base);
free_rsp_buf(err_buftype[1], err_iov[1].iov_base); free_rsp_buf(err_buftype[1], err_iov[1].iov_base);
free_rsp_buf(err_buftype[2], err_iov[2].iov_base); free_rsp_buf(err_buftype[2], err_iov[2].iov_base);
@ -624,7 +668,7 @@ smb2_mkdir(const unsigned int xid, struct inode *parent_inode, umode_t mode,
return smb2_compound_op(xid, tcon, cifs_sb, name, return smb2_compound_op(xid, tcon, cifs_sb, name,
FILE_WRITE_ATTRIBUTES, FILE_CREATE, FILE_WRITE_ATTRIBUTES, FILE_CREATE,
CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR, CREATE_NOT_FILE, mode, NULL, SMB2_OP_MKDIR,
NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL);
} }
void void
@ -646,7 +690,7 @@ smb2_mkdir_setinfo(struct inode *inode, const char *name,
tmprc = smb2_compound_op(xid, tcon, cifs_sb, name, tmprc = smb2_compound_op(xid, tcon, cifs_sb, name,
FILE_WRITE_ATTRIBUTES, FILE_CREATE, FILE_WRITE_ATTRIBUTES, FILE_CREATE,
CREATE_NOT_FILE, ACL_NO_MODE, CREATE_NOT_FILE, ACL_NO_MODE,
&data, SMB2_OP_SET_INFO, cfile, NULL, NULL); &data, SMB2_OP_SET_INFO, cfile, NULL, NULL, NULL, NULL);
if (tmprc == 0) if (tmprc == 0)
cifs_i->cifsAttrs = dosattrs; cifs_i->cifsAttrs = dosattrs;
} }
@ -658,7 +702,7 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
drop_cached_dir_by_name(xid, tcon, name, cifs_sb); drop_cached_dir_by_name(xid, tcon, name, cifs_sb);
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
CREATE_NOT_FILE, ACL_NO_MODE, CREATE_NOT_FILE, ACL_NO_MODE,
NULL, SMB2_OP_RMDIR, NULL, NULL, NULL); NULL, SMB2_OP_RMDIR, NULL, NULL, NULL, NULL, NULL);
} }
int int
@ -667,7 +711,7 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
{ {
return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN, return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT, CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL); ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL, NULL, NULL);
} }
static int static int
@ -686,7 +730,7 @@ smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
} }
rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access, rc = smb2_compound_op(xid, tcon, cifs_sb, from_name, access,
FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name, FILE_OPEN, 0, ACL_NO_MODE, smb2_to_name,
command, cfile, NULL, NULL); command, cfile, NULL, NULL, NULL, NULL);
smb2_rename_path: smb2_rename_path:
kfree(smb2_to_name); kfree(smb2_to_name);
return rc; return rc;
@ -727,7 +771,7 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile); cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
return smb2_compound_op(xid, tcon, cifs_sb, full_path, return smb2_compound_op(xid, tcon, cifs_sb, full_path,
FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE, FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
&eof, SMB2_OP_SET_EOF, cfile, NULL, NULL); &eof, SMB2_OP_SET_EOF, cfile, NULL, NULL, NULL, NULL);
} }
int int
@ -754,7 +798,7 @@ smb2_set_file_info(struct inode *inode, const char *full_path,
rc = smb2_compound_op(xid, tcon, cifs_sb, full_path, rc = smb2_compound_op(xid, tcon, cifs_sb, full_path,
FILE_WRITE_ATTRIBUTES, FILE_OPEN, FILE_WRITE_ATTRIBUTES, FILE_OPEN,
0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile, 0, ACL_NO_MODE, buf, SMB2_OP_SET_INFO, cfile,
NULL, NULL); NULL, NULL, NULL, NULL);
cifs_put_tlink(tlink); cifs_put_tlink(tlink);
return rc; return rc;
} }

View File

@ -4204,69 +4204,82 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8); memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
} }
/* We can not use the normal sg_set_buf() as we will sometimes pass a static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb_rqst *rqst,
* stack object as buf. int num_rqst, const u8 *sig, u8 **iv,
*/ struct aead_request **req, struct scatterlist **sgl,
static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int *num_sgs)
unsigned int buflen)
{ {
void *addr; unsigned int req_size = sizeof(**req) + crypto_aead_reqsize(tfm);
/* unsigned int iv_size = crypto_aead_ivsize(tfm);
* VMAP_STACK (at least) puts stack into the vmalloc address space unsigned int len;
*/ u8 *p;
if (is_vmalloc_addr(buf))
addr = vmalloc_to_page(buf);
else
addr = virt_to_page(buf);
sg_set_page(sg, addr, buflen, offset_in_page(buf));
}
/* Assumes the first rqst has a transform header as the first iov. *num_sgs = cifs_get_num_sgs(rqst, num_rqst, sig);
* I.e.
* rqst[0].rq_iov[0] is transform header
* rqst[0].rq_iov[1+] data to be encrypted/decrypted
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
*/
static struct scatterlist *
init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
{
unsigned int sg_len;
struct scatterlist *sg;
unsigned int i;
unsigned int j;
unsigned int idx = 0;
int skip;
sg_len = 1; len = iv_size;
for (i = 0; i < num_rqst; i++) len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1);
sg_len += rqst[i].rq_nvec + rqst[i].rq_npages; len = ALIGN(len, crypto_tfm_ctx_alignment());
len += req_size;
len = ALIGN(len, __alignof__(struct scatterlist));
len += *num_sgs * sizeof(**sgl);
sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL); p = kmalloc(len, GFP_ATOMIC);
if (!sg) if (!p)
return NULL; return NULL;
sg_init_table(sg, sg_len); *iv = (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1);
*req = (struct aead_request *)PTR_ALIGN(*iv + iv_size,
crypto_tfm_ctx_alignment());
*sgl = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size,
__alignof__(struct scatterlist));
return p;
}
static void *smb2_get_aead_req(struct crypto_aead *tfm, const struct smb_rqst *rqst,
int num_rqst, const u8 *sig, u8 **iv,
struct aead_request **req, struct scatterlist **sgl)
{
unsigned int off, len, skip;
struct scatterlist *sg;
unsigned int num_sgs;
unsigned long addr;
int i, j;
void *p;
p = smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, sgl, &num_sgs);
if (!p)
return NULL;
sg_init_table(*sgl, num_sgs);
sg = *sgl;
/* Assumes the first rqst has a transform header as the first iov.
* I.e.
* rqst[0].rq_iov[0] is transform header
* rqst[0].rq_iov[1+] data to be encrypted/decrypted
* rqst[1+].rq_iov[0+] data to be encrypted/decrypted
*/
for (i = 0; i < num_rqst; i++) { for (i = 0; i < num_rqst; i++) {
/*
* The first rqst has a transform header where the
* first 20 bytes are not part of the encrypted blob.
*/
for (j = 0; j < rqst[i].rq_nvec; j++) { for (j = 0; j < rqst[i].rq_nvec; j++) {
/* struct kvec *iov = &rqst[i].rq_iov[j];
* The first rqst has a transform header where the
* first 20 bytes are not part of the encrypted blob
*/
skip = (i == 0) && (j == 0) ? 20 : 0; skip = (i == 0) && (j == 0) ? 20 : 0;
smb2_sg_set_buf(&sg[idx++], addr = (unsigned long)iov->iov_base + skip;
rqst[i].rq_iov[j].iov_base + skip, len = iov->iov_len - skip;
rqst[i].rq_iov[j].iov_len - skip); sg = cifs_sg_set_buf(sg, (void *)addr, len);
} }
for (j = 0; j < rqst[i].rq_npages; j++) { for (j = 0; j < rqst[i].rq_npages; j++) {
unsigned int len, offset; rqst_page_get_length(&rqst[i], j, &len, &off);
sg_set_page(sg++, rqst[i].rq_pages[j], len, off);
rqst_page_get_length(&rqst[i], j, &len, &offset);
sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, offset);
} }
} }
smb2_sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE); cifs_sg_set_buf(sg, sig, SMB2_SIGNATURE_SIZE);
return sg;
return p;
} }
static int static int
@ -4314,11 +4327,11 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
u8 sign[SMB2_SIGNATURE_SIZE] = {}; u8 sign[SMB2_SIGNATURE_SIZE] = {};
u8 key[SMB3_ENC_DEC_KEY_SIZE]; u8 key[SMB3_ENC_DEC_KEY_SIZE];
struct aead_request *req; struct aead_request *req;
char *iv; u8 *iv;
unsigned int iv_len;
DECLARE_CRYPTO_WAIT(wait); DECLARE_CRYPTO_WAIT(wait);
struct crypto_aead *tfm; struct crypto_aead *tfm;
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize); unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
void *creq;
rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key); rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
if (rc) { if (rc) {
@ -4352,32 +4365,15 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
return rc; return rc;
} }
req = aead_request_alloc(tfm, GFP_KERNEL); creq = smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg);
if (!req) { if (unlikely(!creq))
cifs_server_dbg(VFS, "%s: Failed to alloc aead request\n", __func__);
return -ENOMEM; return -ENOMEM;
}
if (!enc) { if (!enc) {
memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
crypt_len += SMB2_SIGNATURE_SIZE; crypt_len += SMB2_SIGNATURE_SIZE;
} }
sg = init_sg(num_rqst, rqst, sign);
if (!sg) {
cifs_server_dbg(VFS, "%s: Failed to init sg\n", __func__);
rc = -ENOMEM;
goto free_req;
}
iv_len = crypto_aead_ivsize(tfm);
iv = kzalloc(iv_len, GFP_KERNEL);
if (!iv) {
cifs_server_dbg(VFS, "%s: Failed to alloc iv\n", __func__);
rc = -ENOMEM;
goto free_sg;
}
if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) || if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM)) (server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
@ -4386,6 +4382,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
} }
aead_request_set_tfm(req, tfm);
aead_request_set_crypt(req, sg, sg, crypt_len, iv); aead_request_set_crypt(req, sg, sg, crypt_len, iv);
aead_request_set_ad(req, assoc_data_len); aead_request_set_ad(req, assoc_data_len);
@ -4398,11 +4395,7 @@ crypt_message(struct TCP_Server_Info *server, int num_rqst,
if (!rc && enc) if (!rc && enc)
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
kfree_sensitive(iv); kfree_sensitive(creq);
free_sg:
kfree_sensitive(sg);
free_req:
kfree_sensitive(req);
return rc; return rc;
} }
@ -4445,21 +4438,27 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
int rc = -ENOMEM; int rc = -ENOMEM;
for (i = 1; i < num_rqst; i++) { for (i = 1; i < num_rqst; i++) {
npages = old_rq[i - 1].rq_npages; struct smb_rqst *old = &old_rq[i - 1];
struct smb_rqst *new = &new_rq[i];
orig_len += smb_rqst_len(server, old);
new->rq_iov = old->rq_iov;
new->rq_nvec = old->rq_nvec;
npages = old->rq_npages;
if (!npages)
continue;
pages = kmalloc_array(npages, sizeof(struct page *), pages = kmalloc_array(npages, sizeof(struct page *),
GFP_KERNEL); GFP_KERNEL);
if (!pages) if (!pages)
goto err_free; goto err_free;
new_rq[i].rq_pages = pages; new->rq_pages = pages;
new_rq[i].rq_npages = npages; new->rq_npages = npages;
new_rq[i].rq_offset = old_rq[i - 1].rq_offset; new->rq_offset = old->rq_offset;
new_rq[i].rq_pagesz = old_rq[i - 1].rq_pagesz; new->rq_pagesz = old->rq_pagesz;
new_rq[i].rq_tailsz = old_rq[i - 1].rq_tailsz; new->rq_tailsz = old->rq_tailsz;
new_rq[i].rq_iov = old_rq[i - 1].rq_iov;
new_rq[i].rq_nvec = old_rq[i - 1].rq_nvec;
orig_len += smb_rqst_len(server, &old_rq[i - 1]);
for (j = 0; j < npages; j++) { for (j = 0; j < npages; j++) {
pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM); pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
@ -4472,14 +4471,14 @@ smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
char *dst, *src; char *dst, *src;
unsigned int offset, len; unsigned int offset, len;
rqst_page_get_length(&new_rq[i], j, &len, &offset); rqst_page_get_length(new, j, &len, &offset);
dst = (char *) kmap(new_rq[i].rq_pages[j]) + offset; dst = kmap_local_page(new->rq_pages[j]) + offset;
src = (char *) kmap(old_rq[i - 1].rq_pages[j]) + offset; src = kmap_local_page(old->rq_pages[j]) + offset;
memcpy(dst, src, len); memcpy(dst, src, len);
kunmap(new_rq[i].rq_pages[j]); kunmap(new->rq_pages[j]);
kunmap(old_rq[i - 1].rq_pages[j]); kunmap(old->rq_pages[j]);
} }
} }

View File

@ -277,7 +277,10 @@ extern int smb2_query_info_compound(const unsigned int xid,
/* query path info from the server using SMB311 POSIX extensions*/ /* query path info from the server using SMB311 POSIX extensions*/
int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon, int smb311_posix_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, struct cifs_sb_info *cifs_sb, const char *full_path,
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse); struct cifs_open_info_data *data,
struct cifs_sid *owner,
struct cifs_sid *group,
bool *adjust_tz, bool *reparse);
int posix_info_parse(const void *beg, const void *end, int posix_info_parse(const void *beg, const void *end,
struct smb2_posix_info_parsed *out); struct smb2_posix_info_parsed *out);
int posix_info_sid_size(const void *beg, const void *end); int posix_info_sid_size(const void *beg, const void *end);