Skip to content

Commit

Permalink
Merge tag '6.1-rc-smb3-client-fixes-part2' of git://git.samba.org/sfr…
Browse files Browse the repository at this point in the history
…ench/cifs-2.6

Pull more cifs updates from Steve French:

 - fix a regression in guest mounts to old servers

 - improvements to directory leasing (caching directory entries safely
   beyond the root directory)

 - symlink improvement (reducing roundtrips needed to process symlinks)

 - an lseek fix (to problem where some dir entries could be skipped)

 - improved ioctl for returning more detailed information on directory
   change notifications

 - clarify multichannel interface query warning

 - cleanup fix (for better aligning buffers using ALIGN and round_up)

 - a compounding fix

 - fix some uninitialized variable bugs found by Coverity and the kernel
   test robot

* tag '6.1-rc-smb3-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6:
  smb3: improve SMB3 change notification support
  cifs: lease key is uninitialized in two additional functions when smb1
  cifs: lease key is uninitialized in smb1 paths
  smb3: must initialize two ACL struct fields to zero
  cifs: fix double-fault crash during ntlmssp
  cifs: fix static checker warning
  cifs: use ALIGN() and round_up() macros
  cifs: find and use the dentry for cached non-root directories also
  cifs: enable caching of directories for which a lease is held
  cifs: prevent copying past input buffer boundaries
  cifs: fix uninitialised var in smb2_compound_op()
  cifs: improve symlink handling for smb2+
  smb3: clarify multichannel warning
  cifs: fix regression in very old smb1 mounts
  cifs: fix skipping to incorrect offset in emit_cached_dirents
  • Loading branch information
torvalds committed Oct 16, 2022
2 parents 8049387 + e3e9463 commit b08cd74
Show file tree
Hide file tree
Showing 23 changed files with 922 additions and 726 deletions.
469 changes: 284 additions & 185 deletions fs/cifs/cached_dir.c

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions fs/cifs/cached_dir.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,32 @@ struct cached_dirents {
};

struct cached_fid {
struct list_head entry;
struct cached_fids *cfids;
const char *path;
bool is_valid:1; /* Do we have a useable root fid */
bool file_all_info_is_valid:1;
bool has_lease:1;
bool is_open:1;
bool on_list:1;
bool file_all_info_is_valid:1;
unsigned long time; /* jiffies of when lease was taken */
struct kref refcount;
struct cifs_fid fid;
struct mutex fid_mutex;
spinlock_t fid_lock;
struct cifs_tcon *tcon;
struct dentry *dentry;
struct work_struct lease_break;
struct smb2_file_all_info file_all_info;
struct cached_dirents dirents;
};

#define MAX_CACHED_FIDS 16
struct cached_fids {
struct mutex cfid_list_mutex;
struct cached_fid *cfid;
/* Must be held when:
* - accessing the cfids->entries list
*/
spinlock_t cfid_list_lock;
int num_entries;
struct list_head entries;
};

extern struct cached_fids *init_cached_dirs(void);
Expand All @@ -61,8 +69,6 @@ extern int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
struct dentry *dentry,
struct cached_fid **cfid);
extern void close_cached_dir(struct cached_fid *cfid);
extern void close_cached_dir_lease(struct cached_fid *cfid);
extern void close_cached_dir_lease_locked(struct cached_fid *cfid);
extern void close_all_cached_dirs(struct cifs_sb_info *cifs_sb);
extern void invalidate_all_cached_dirs(struct cifs_tcon *tcon);
extern int cached_dir_lease_break(struct cifs_tcon *tcon, __u8 lease_key[16]);
Expand Down
8 changes: 8 additions & 0 deletions fs/cifs/cifs_ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ struct smb3_notify {
bool watch_tree;
} __packed;

struct smb3_notify_info {
__u32 completion_filter;
bool watch_tree;
__u32 data_len; /* size of notify data below */
__u8 notify_data[];
} __packed;

#define CIFS_IOCTL_MAGIC 0xCF
#define CIFS_IOC_COPYCHUNK_FILE _IOW(CIFS_IOCTL_MAGIC, 3, int)
#define CIFS_IOC_SET_INTEGRITY _IO(CIFS_IOCTL_MAGIC, 4)
Expand All @@ -100,6 +107,7 @@ struct smb3_notify {
#define CIFS_DUMP_KEY _IOWR(CIFS_IOCTL_MAGIC, 8, struct smb3_key_debug_info)
#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_IOC_NOTIFY_INFO _IOWR(CIFS_IOCTL_MAGIC, 11, struct smb3_notify_info)
#define CIFS_IOC_SHUTDOWN _IOR ('X', 125, __u32)

/*
Expand Down
9 changes: 7 additions & 2 deletions fs/cifs/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ cifs_alloc_inode(struct super_block *sb)
cifs_inode->epoch = 0;
spin_lock_init(&cifs_inode->open_file_lock);
generate_random_uuid(cifs_inode->lease_key);
cifs_inode->symlink_target = NULL;

/*
* Can not set i_flags here - they get immediately overwritten to zero
Expand All @@ -412,7 +413,11 @@ cifs_alloc_inode(struct super_block *sb)
static void
cifs_free_inode(struct inode *inode)
{
kmem_cache_free(cifs_inode_cachep, CIFS_I(inode));
struct cifsInodeInfo *cinode = CIFS_I(inode);

if (S_ISLNK(inode->i_mode))
kfree(cinode->symlink_target);
kmem_cache_free(cifs_inode_cachep, cinode);
}

static void
Expand Down Expand Up @@ -1139,7 +1144,7 @@ const struct inode_operations cifs_file_inode_ops = {
};

const struct inode_operations cifs_symlink_inode_ops = {
.get_link = cifs_get_link,
.get_link = simple_get_link,
.permission = cifs_permission,
.listxattr = cifs_listxattr,
};
Expand Down
48 changes: 37 additions & 11 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,19 @@ struct cifs_cred {
struct cifs_ace *aces;
};

struct cifs_open_info_data {
char *symlink_target;
union {
struct smb2_file_all_info fi;
struct smb311_posix_qinfo posix_fi;
};
};

static inline void cifs_free_open_info(struct cifs_open_info_data *data)
{
kfree(data->symlink_target);
}

/*
*****************************************************************
* Except the CIFS PDUs themselves all the
Expand Down Expand Up @@ -307,20 +320,20 @@ struct smb_version_operations {
int (*is_path_accessible)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *);
/* query path data from the server */
int (*query_path_info)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *,
FILE_ALL_INFO *, bool *, bool *);
int (*query_path_info)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path,
struct cifs_open_info_data *data, bool *adjust_tz, bool *reparse);
/* query file data from the server */
int (*query_file_info)(const unsigned int, struct cifs_tcon *,
struct cifs_fid *, FILE_ALL_INFO *);
int (*query_file_info)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile, struct cifs_open_info_data *data);
/* query reparse tag from srv to determine which type of special file */
int (*query_reparse_tag)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *path,
__u32 *reparse_tag);
/* get server index number */
int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const char *,
u64 *uniqueid, FILE_ALL_INFO *);
int (*get_srv_inum)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifs_sb_info *cifs_sb, const char *full_path, u64 *uniqueid,
struct cifs_open_info_data *data);
/* set size by path */
int (*set_path_size)(const unsigned int, struct cifs_tcon *,
const char *, __u64, struct cifs_sb_info *, bool);
Expand Down Expand Up @@ -369,8 +382,8 @@ struct smb_version_operations {
struct cifs_sb_info *, const char *,
char **, bool);
/* open a file for non-posix mounts */
int (*open)(const unsigned int, struct cifs_open_parms *,
__u32 *, FILE_ALL_INFO *);
int (*open)(const unsigned int xid, struct cifs_open_parms *oparms, __u32 *oplock,
void *buf);
/* set fid protocol-specific info */
void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
/* close a file */
Expand Down Expand Up @@ -441,7 +454,7 @@ struct smb_version_operations {
int (*enum_snapshots)(const unsigned int xid, struct cifs_tcon *tcon,
struct cifsFileInfo *src_file, void __user *);
int (*notify)(const unsigned int xid, struct file *pfile,
void __user *pbuf);
void __user *pbuf, bool return_changes);
int (*query_mf_symlink)(unsigned int, struct cifs_tcon *,
struct cifs_sb_info *, const unsigned char *,
char *, unsigned int *);
Expand Down Expand Up @@ -1123,6 +1136,7 @@ struct cifs_fattr {
struct timespec64 cf_mtime;
struct timespec64 cf_ctime;
u32 cf_cifstag;
char *cf_symlink_target;
};

/*
Expand Down Expand Up @@ -1385,6 +1399,7 @@ struct cifsFileInfo {
struct work_struct put; /* work for the final part of _put */
struct delayed_work deferred;
bool deferred_close_scheduled; /* Flag to indicate close is scheduled */
char *symlink_target;
};

struct cifs_io_parms {
Expand Down Expand Up @@ -1543,6 +1558,7 @@ struct cifsInodeInfo {
struct list_head deferred_closes; /* list of deferred closes */
spinlock_t deferred_lock; /* protection on deferred list */
bool lease_granted; /* Flag to indicate whether lease or oplock is granted. */
char *symlink_target;
};

static inline struct cifsInodeInfo *
Expand Down Expand Up @@ -2111,4 +2127,14 @@ static inline size_t ntlmssp_workstation_name_size(const struct cifs_ses *ses)
return sizeof(ses->workstation_name);
}

static inline void move_cifs_info_to_smb2(struct smb2_file_all_info *dst, const FILE_ALL_INFO *src)
{
memcpy(dst, src, (size_t)((u8 *)&src->AccessFlags - (u8 *)src));
dst->AccessFlags = src->AccessFlags;
dst->CurrentByteOffset = src->CurrentByteOffset;
dst->Mode = src->Mode;
dst->AlignmentRequirement = src->AlignmentRequirement;
dst->FileNameLength = src->FileNameLength;
}

#endif /* _CIFS_GLOB_H */
13 changes: 6 additions & 7 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,10 +182,9 @@ extern int cifs_unlock_range(struct cifsFileInfo *cfile,
extern int cifs_push_mandatory_locks(struct cifsFileInfo *cfile);

extern void cifs_down_write(struct rw_semaphore *sem);
extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
struct file *file,
struct tcon_link *tlink,
__u32 oplock);
struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
struct tcon_link *tlink, __u32 oplock,
const char *symlink_target);
extern int cifs_posix_open(const char *full_path, struct inode **inode,
struct super_block *sb, int mode,
unsigned int f_flags, __u32 *oplock, __u16 *netfid,
Expand All @@ -200,9 +199,9 @@ extern int cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
extern struct inode *cifs_iget(struct super_block *sb,
struct cifs_fattr *fattr);

extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
FILE_ALL_INFO *data, struct super_block *sb,
int xid, const struct cifs_fid *fid);
int cifs_get_inode_info(struct inode **inode, const char *full_path,
struct cifs_open_info_data *data, struct super_block *sb, int xid,
const struct cifs_fid *fid);
extern int smb311_posix_get_inode_info(struct inode **pinode, const char *search_path,
struct super_block *sb, unsigned int xid);
extern int cifs_get_inode_info_unix(struct inode **pinode,
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifssmb.c
Original file line number Diff line number Diff line change
Expand Up @@ -2305,7 +2305,7 @@ int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *pTcon,
remap);
}
rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str);
count = sizeof(struct set_file_rename) + (2 * len_of_str);
byte_count += count;
pSMB->DataCount = cpu_to_le16(count);
pSMB->TotalDataCount = pSMB->DataCount;
Expand Down
22 changes: 14 additions & 8 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2832,9 +2832,12 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
* sessinit is sent but no second negprot
*/
struct rfc1002_session_packet *ses_init_buf;
unsigned int req_noscope_len;
struct smb_hdr *smb_buf;

ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
GFP_KERNEL);

if (ses_init_buf) {
ses_init_buf->trailer.session_req.called_len = 32;

Expand Down Expand Up @@ -2870,8 +2873,12 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
ses_init_buf->trailer.session_req.scope2 = 0;
smb_buf = (struct smb_hdr *)ses_init_buf;

/* sizeof RFC1002_SESSION_REQUEST with no scope */
smb_buf->smb_buf_length = cpu_to_be32(0x81000044);
/* sizeof RFC1002_SESSION_REQUEST with no scopes */
req_noscope_len = sizeof(struct rfc1002_session_packet) - 2;

/* == cpu_to_be32(0x81000044) */
smb_buf->smb_buf_length =
cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | req_noscope_len);
rc = smb_send(server, smb_buf, 0x44);
kfree(ses_init_buf);
/*
Expand Down Expand Up @@ -3922,12 +3929,11 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
pSMB->AndXCommand = 0xFF;
pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO);
bcc_ptr = &pSMB->Password[0];
if (tcon->pipe || (ses->server->sec_mode & SECMODE_USER)) {
pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
*bcc_ptr = 0; /* password is null byte */
bcc_ptr++; /* skip password */
/* already aligned so no need to do it below */
}

pSMB->PasswordLength = cpu_to_le16(1); /* minimum */
*bcc_ptr = 0; /* password is null byte */
bcc_ptr++; /* skip password */
/* already aligned so no need to do it below */

if (ses->server->sign)
smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
Expand Down
Loading

0 comments on commit b08cd74

Please sign in to comment.