Skip to content

Commit 1d22968

Browse files
committed
Merge tag 'v7.0-rc-part2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - Fix three potential double free vulnerabilities - Fix data corruption due to racy lease checks - Enforce SMB1 signing verification checks - Fix invalid mount option parsing - Remove unneeded tracepoint - Various minor error code corrections - Minor cleanup * tag 'v7.0-rc-part2-smb3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb: client: terminate session upon failed client required signing cifs: some missing initializations on replay cifs: remove unnecessary tracing after put tcon cifs: update internal module version number smb: client: fix data corruption due to racy lease checks smb/client: move NT_STATUS_MORE_ENTRIES smb/client: rename to NT_ERROR_INVALID_DATATYPE smb/client: rename to NT_STATUS_SOME_NOT_MAPPED smb/client: map NT_STATUS_PRIVILEGE_NOT_HELD smb/client: map NT_STATUS_MORE_PROCESSING_REQUIRED smb/client: map NT_STATUS_BUFFER_OVERFLOW smb/client: map NT_STATUS_NOTIFY_ENUM_DIR cifs: SMB1 split: Remove duplicate include of cifs_debug.h smb: client: fix regression with mount options parsing
2 parents e81dd54 + dc96f01 commit 1d22968

14 files changed

Lines changed: 136 additions & 73 deletions

File tree

fs/smb/client/cifsfs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,6 @@ extern const struct export_operations cifs_export_ops;
147147
#endif /* CONFIG_CIFS_NFSD_EXPORT */
148148

149149
/* when changing internal version - update following two lines at same time */
150-
#define SMB3_PRODUCT_BUILD 58
151-
#define CIFS_VERSION "2.58"
150+
#define SMB3_PRODUCT_BUILD 59
151+
#define CIFS_VERSION "2.59"
152152
#endif /* _CIFSFS_H */

fs/smb/client/cifsglob.h

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -515,8 +515,10 @@ struct smb_version_operations {
515515
/* check for STATUS_NETWORK_SESSION_EXPIRED */
516516
bool (*is_session_expired)(char *);
517517
/* send oplock break response */
518-
int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid, __u64 volatile_fid,
519-
__u16 net_fid, struct cifsInodeInfo *cifs_inode);
518+
int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid,
519+
__u64 volatile_fid, __u16 net_fid,
520+
struct cifsInodeInfo *cifs_inode,
521+
unsigned int oplock);
520522
/* query remote filesystem */
521523
int (*queryfs)(const unsigned int, struct cifs_tcon *,
522524
const char *, struct cifs_sb_info *, struct kstatfs *);
@@ -1531,10 +1533,6 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry,
15311533
#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)
15321534
#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG)
15331535

1534-
#define CIFS_CACHE_READ(cinode) ((cinode->oplock & CIFS_CACHE_READ_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE))
1535-
#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
1536-
#define CIFS_CACHE_WRITE(cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE))
1537-
15381536
/*
15391537
* One of these for each file inode
15401538
*/
@@ -2312,4 +2310,30 @@ static inline void cifs_requeue_server_reconn(struct TCP_Server_Info *server)
23122310
queue_delayed_work(cifsiod_wq, &server->reconnect, delay * HZ);
23132311
}
23142312

2313+
static inline bool __cifs_cache_state_check(struct cifsInodeInfo *cinode,
2314+
unsigned int oplock_flags,
2315+
unsigned int sb_flags)
2316+
{
2317+
struct cifs_sb_info *cifs_sb = CIFS_SB(cinode->netfs.inode.i_sb);
2318+
unsigned int oplock = READ_ONCE(cinode->oplock);
2319+
unsigned int sflags = cifs_sb->mnt_cifs_flags;
2320+
2321+
return (oplock & oplock_flags) || (sflags & sb_flags);
2322+
}
2323+
2324+
#define CIFS_CACHE_READ(cinode) \
2325+
__cifs_cache_state_check(cinode, CIFS_CACHE_READ_FLG, \
2326+
CIFS_MOUNT_RO_CACHE)
2327+
#define CIFS_CACHE_HANDLE(cinode) \
2328+
__cifs_cache_state_check(cinode, CIFS_CACHE_HANDLE_FLG, 0)
2329+
#define CIFS_CACHE_WRITE(cinode) \
2330+
__cifs_cache_state_check(cinode, CIFS_CACHE_WRITE_FLG, \
2331+
CIFS_MOUNT_RW_CACHE)
2332+
2333+
static inline void cifs_reset_oplock(struct cifsInodeInfo *cinode)
2334+
{
2335+
scoped_guard(spinlock, &cinode->open_file_lock)
2336+
WRITE_ONCE(cinode->oplock, 0);
2337+
}
2338+
23152339
#endif /* _CIFS_GLOB_H */

fs/smb/client/file.c

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -731,14 +731,14 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
731731
oplock = fid->pending_open->oplock;
732732
list_del(&fid->pending_open->olist);
733733

734-
fid->purge_cache = false;
735-
server->ops->set_fid(cfile, fid, oplock);
736-
737734
list_add(&cfile->tlist, &tcon->openFileList);
738735
atomic_inc(&tcon->num_local_opens);
739736

740737
/* if readable file instance put first in list*/
741738
spin_lock(&cinode->open_file_lock);
739+
fid->purge_cache = false;
740+
server->ops->set_fid(cfile, fid, oplock);
741+
742742
if (file->f_mode & FMODE_READ)
743743
list_add(&cfile->flist, &cinode->openFileList);
744744
else
@@ -1410,7 +1410,8 @@ cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
14101410
oplock = 0;
14111411
}
14121412

1413-
server->ops->set_fid(cfile, &cfile->fid, oplock);
1413+
scoped_guard(spinlock, &cinode->open_file_lock)
1414+
server->ops->set_fid(cfile, &cfile->fid, oplock);
14141415
if (oparms.reconnect)
14151416
cifs_relock_file(cfile);
14161417

@@ -1437,11 +1438,11 @@ smb2_can_defer_close(struct inode *inode, struct cifs_deferred_close *dclose)
14371438
{
14381439
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
14391440
struct cifsInodeInfo *cinode = CIFS_I(inode);
1441+
unsigned int oplock = READ_ONCE(cinode->oplock);
14401442

1441-
return (cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose &&
1442-
(cinode->oplock == CIFS_CACHE_RHW_FLG ||
1443-
cinode->oplock == CIFS_CACHE_RH_FLG) &&
1444-
!test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags));
1443+
return cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose &&
1444+
(oplock == CIFS_CACHE_RHW_FLG || oplock == CIFS_CACHE_RH_FLG) &&
1445+
!test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags);
14451446

14461447
}
14471448

@@ -2371,7 +2372,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
23712372
cifs_zap_mapping(inode);
23722373
cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n",
23732374
inode);
2374-
CIFS_I(inode)->oplock = 0;
2375+
cifs_reset_oplock(CIFS_I(inode));
23752376
}
23762377

23772378
rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
@@ -2930,7 +2931,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from)
29302931
cifs_zap_mapping(inode);
29312932
cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n",
29322933
inode);
2933-
cinode->oplock = 0;
2934+
cifs_reset_oplock(cinode);
29342935
}
29352936
out:
29362937
cifs_put_writer(cinode);
@@ -2966,7 +2967,7 @@ ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
29662967
cifs_dbg(FYI,
29672968
"Set no oplock for inode=%p after a write operation\n",
29682969
inode);
2969-
cinode->oplock = 0;
2970+
cifs_reset_oplock(cinode);
29702971
}
29712972
return written;
29722973
}
@@ -3154,9 +3155,11 @@ void cifs_oplock_break(struct work_struct *work)
31543155
struct super_block *sb = inode->i_sb;
31553156
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
31563157
struct cifsInodeInfo *cinode = CIFS_I(inode);
3158+
bool cache_read, cache_write, cache_handle;
31573159
struct cifs_tcon *tcon;
31583160
struct TCP_Server_Info *server;
31593161
struct tcon_link *tlink;
3162+
unsigned int oplock;
31603163
int rc = 0;
31613164
bool purge_cache = false, oplock_break_cancelled;
31623165
__u64 persistent_fid, volatile_fid;
@@ -3177,29 +3180,40 @@ void cifs_oplock_break(struct work_struct *work)
31773180
tcon = tlink_tcon(tlink);
31783181
server = tcon->ses->server;
31793182

3180-
server->ops->downgrade_oplock(server, cinode, cfile->oplock_level,
3181-
cfile->oplock_epoch, &purge_cache);
3183+
scoped_guard(spinlock, &cinode->open_file_lock) {
3184+
unsigned int sbflags = cifs_sb->mnt_cifs_flags;
3185+
3186+
server->ops->downgrade_oplock(server, cinode, cfile->oplock_level,
3187+
cfile->oplock_epoch, &purge_cache);
3188+
oplock = READ_ONCE(cinode->oplock);
3189+
cache_read = (oplock & CIFS_CACHE_READ_FLG) ||
3190+
(sbflags & CIFS_MOUNT_RO_CACHE);
3191+
cache_write = (oplock & CIFS_CACHE_WRITE_FLG) ||
3192+
(sbflags & CIFS_MOUNT_RW_CACHE);
3193+
cache_handle = oplock & CIFS_CACHE_HANDLE_FLG;
3194+
}
31823195

3183-
if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) &&
3184-
cifs_has_mand_locks(cinode)) {
3196+
if (!cache_write && cache_read && cifs_has_mand_locks(cinode)) {
31853197
cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n",
31863198
inode);
3187-
cinode->oplock = 0;
3199+
cifs_reset_oplock(cinode);
3200+
oplock = 0;
3201+
cache_read = cache_write = cache_handle = false;
31883202
}
31893203

31903204
if (S_ISREG(inode->i_mode)) {
3191-
if (CIFS_CACHE_READ(cinode))
3205+
if (cache_read)
31923206
break_lease(inode, O_RDONLY);
31933207
else
31943208
break_lease(inode, O_WRONLY);
31953209
rc = filemap_fdatawrite(inode->i_mapping);
3196-
if (!CIFS_CACHE_READ(cinode) || purge_cache) {
3210+
if (!cache_read || purge_cache) {
31973211
rc = filemap_fdatawait(inode->i_mapping);
31983212
mapping_set_error(inode->i_mapping, rc);
31993213
cifs_zap_mapping(inode);
32003214
}
32013215
cifs_dbg(FYI, "Oplock flush inode %p rc %d\n", inode, rc);
3202-
if (CIFS_CACHE_WRITE(cinode))
3216+
if (cache_write)
32033217
goto oplock_break_ack;
32043218
}
32053219

@@ -3214,7 +3228,7 @@ void cifs_oplock_break(struct work_struct *work)
32143228
* So, new open will not use cached handle.
32153229
*/
32163230

3217-
if (!CIFS_CACHE_HANDLE(cinode) && !list_empty(&cinode->deferred_closes))
3231+
if (!cache_handle && !list_empty(&cinode->deferred_closes))
32183232
cifs_close_deferred_file(cinode);
32193233

32203234
persistent_fid = cfile->fid.persistent_fid;
@@ -3232,7 +3246,8 @@ void cifs_oplock_break(struct work_struct *work)
32323246
if (!oplock_break_cancelled && !list_empty(&cinode->openFileList)) {
32333247
spin_unlock(&cinode->open_file_lock);
32343248
rc = server->ops->oplock_response(tcon, persistent_fid,
3235-
volatile_fid, net_fid, cinode);
3249+
volatile_fid, net_fid,
3250+
cinode, oplock);
32363251
cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
32373252
} else
32383253
spin_unlock(&cinode->open_file_lock);

fs/smb/client/fs_context.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -825,9 +825,7 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
825825
if (ret < 0)
826826
break;
827827
}
828-
ret = smb3_handle_conflicting_options(fc);
829-
830-
return ret;
828+
return ret ?: smb3_handle_conflicting_options(fc);
831829
}
832830

833831
/*

fs/smb/client/nterr.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
const struct nt_err_code_struct nt_errs[] = {
1515
{"NT_STATUS_OK", NT_STATUS_OK},
1616
{"NT_STATUS_PENDING", NT_STATUS_PENDING},
17+
{"NT_STATUS_NOTIFY_ENUM_DIR", NT_STATUS_NOTIFY_ENUM_DIR},
1718
{"NT_STATUS_MEDIA_CHANGED", NT_STATUS_MEDIA_CHANGED},
1819
{"NT_STATUS_END_OF_MEDIA", NT_STATUS_END_OF_MEDIA},
1920
{"NT_STATUS_MEDIA_CHECK", NT_STATUS_MEDIA_CHECK},
@@ -694,7 +695,7 @@ const struct nt_err_code_struct nt_errs[] = {
694695
{"NT_STATUS_NETWORK_SESSION_EXPIRED", NT_STATUS_NETWORK_SESSION_EXPIRED},
695696
{"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES},
696697
{"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES},
697-
{"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED},
698+
{"NT_STATUS_SOME_NOT_MAPPED", NT_STATUS_SOME_NOT_MAPPED},
698699
{"NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB},
699700
{"NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP",
700701
NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP},

fs/smb/client/nterr.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ struct nt_err_code_struct {
2222

2323
extern const struct nt_err_code_struct nt_errs[];
2424

25-
/* Win32 Status codes. */
26-
#define NT_STATUS_MORE_ENTRIES 0x0105
25+
/* Win32 Error Codes. */
2726
#define NT_ERROR_INVALID_PARAMETER 0x0057
2827
#define NT_ERROR_INSUFFICIENT_BUFFER 0x007a
29-
#define NT_STATUS_1804 0x070c
30-
#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c
28+
#define NT_ERROR_INVALID_DATATYPE 0x070c
3129

3230
/*
33-
* Win32 Error codes extracted using a loop in smbclient then printing a netmon
31+
* NTSTATUS Values extracted using a loop in smbclient then printing a netmon
3432
* sniff to a file.
3533
*/
3634

3735
#define NT_STATUS_OK 0x0000
3836
#define NT_STATUS_PENDING 0x0103
39-
#define NT_STATUS_SOME_UNMAPPED 0x0107
37+
#define NT_STATUS_MORE_ENTRIES 0x0105
38+
#define NT_STATUS_SOME_NOT_MAPPED 0x0107
39+
#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c
4040
#define NT_STATUS_BUFFER_OVERFLOW 0x80000005
4141
#define NT_STATUS_NO_MORE_ENTRIES 0x8000001a
4242
#define NT_STATUS_MEDIA_CHANGED 0x8000001c

fs/smb/client/smb1maperror.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ static const struct {
112112
__u32 ntstatus;
113113
} ntstatus_to_dos_map[] = {
114114
{
115+
ERRSRV, ERR_NOTIFY_ENUM_DIR, NT_STATUS_NOTIFY_ENUM_DIR}, {
116+
ERRDOS, ERRmoredata, NT_STATUS_BUFFER_OVERFLOW}, {
117+
ERRDOS, ERRmoredata, NT_STATUS_MORE_PROCESSING_REQUIRED}, {
118+
ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, {
115119
ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {
116120
ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, {
117121
ERRDOS, ERRbadpipe, NT_STATUS_INVALID_INFO_CLASS}, {

fs/smb/client/smb1ops.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,7 @@ cifs_downgrade_oplock(struct TCP_Server_Info *server,
395395
struct cifsInodeInfo *cinode, __u32 oplock,
396396
__u16 epoch, bool *purge_cache)
397397
{
398+
lockdep_assert_held(&cinode->open_file_lock);
398399
cifs_set_oplock_level(cinode, oplock);
399400
}
400401

@@ -894,6 +895,9 @@ static void
894895
cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
895896
{
896897
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
898+
899+
lockdep_assert_held(&cinode->open_file_lock);
900+
897901
cfile->fid.netfid = fid->netfid;
898902
cifs_set_oplock_level(cinode, oplock);
899903
cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
@@ -1139,12 +1143,16 @@ cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
11391143
return CIFSFindClose(xid, tcon, fid->netfid);
11401144
}
11411145

1142-
static int
1143-
cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
1144-
__u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode)
1146+
static int cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid,
1147+
__u64 volatile_fid, __u16 net_fid,
1148+
struct cifsInodeInfo *cinode, unsigned int oplock)
11451149
{
1150+
unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags;
1151+
__u8 op;
1152+
1153+
op = !!((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE));
11461154
return CIFSSMBLock(0, tcon, net_fid, current->tgid, 0, 0, 0, 0,
1147-
LOCKING_ANDX_OPLOCK_RELEASE, false, CIFS_CACHE_READ(cinode) ? 1 : 0);
1155+
LOCKING_ANDX_OPLOCK_RELEASE, false, op);
11481156
}
11491157

11501158
static int

fs/smb/client/smb1transport.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
#include "cifs_debug.h"
3030
#include "smbdirect.h"
3131
#include "compress.h"
32-
#include "cifs_debug.h"
3332

3433
/* Max number of iovectors we can use off the stack when sending requests. */
3534
#define CIFS_MAX_IOV_SIZE 8
@@ -170,12 +169,18 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
170169

171170
iov[0].iov_base = mid->resp_buf;
172171
iov[0].iov_len = len;
173-
/* FIXME: add code to kill session */
172+
174173
rc = cifs_verify_signature(&rqst, server,
175174
mid->sequence_number);
176-
if (rc)
175+
if (rc) {
177176
cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n",
178177
rc);
178+
179+
if (!(server->sec_mode & SECMODE_SIGN_REQUIRED)) {
180+
cifs_reconnect(server, true);
181+
return rc;
182+
}
183+
}
179184
}
180185

181186
/* BB special case reconnect tid and uid here? */

fs/smb/client/smb2misc.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -484,16 +484,16 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
484484
return to;
485485
}
486486

487-
__le32
488-
smb2_get_lease_state(struct cifsInodeInfo *cinode)
487+
__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int oplock)
489488
{
489+
unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags;
490490
__le32 lease = 0;
491491

492-
if (CIFS_CACHE_WRITE(cinode))
492+
if ((oplock & CIFS_CACHE_WRITE_FLG) || (sbflags & CIFS_MOUNT_RW_CACHE))
493493
lease |= SMB2_LEASE_WRITE_CACHING_LE;
494-
if (CIFS_CACHE_HANDLE(cinode))
494+
if (oplock & CIFS_CACHE_HANDLE_FLG)
495495
lease |= SMB2_LEASE_HANDLE_CACHING_LE;
496-
if (CIFS_CACHE_READ(cinode))
496+
if ((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE))
497497
lease |= SMB2_LEASE_READ_CACHING_LE;
498498
return lease;
499499
}

0 commit comments

Comments
 (0)