Skip to content

Commit fa4022c

Browse files
committed
Merge tag 'v6.9-rc3-SMB3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6
Pull smb client fixes from Steve French: - fix for oops in cifs_get_fattr of deleted files - fix for the remote open counter going negative in some directory lease cases - fix for mkfifo to instantiate dentry to avoid possible crash - important fix to allow handling key rotation for mount and remount (ie cases that are becoming more common when password that was used for the mount will expire soon but will be replaced by new password) * tag 'v6.9-rc3-SMB3-client-fixes' of git://git.samba.org/sfrench/cifs-2.6: smb3: fix broken reconnect when password changing on the server by allowing password rotation smb: client: instantiate when creating SFU files smb3: fix Open files on server counter going negative smb: client: fix NULL ptr deref in cifs_mark_open_handles_for_deleted_file()
2 parents 8f2c057 + 35f8342 commit fa4022c

File tree

9 files changed

+103
-42
lines changed

9 files changed

+103
-42
lines changed

fs/smb/client/cached_dir.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,8 @@ smb2_close_cached_fid(struct kref *ref)
433433
if (cfid->is_open) {
434434
rc = SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
435435
cfid->fid.volatile_fid);
436-
if (rc != -EBUSY && rc != -EAGAIN)
437-
atomic_dec(&cfid->tcon->num_remote_opens);
436+
if (rc) /* should we retry on -EBUSY or -EAGAIN? */
437+
cifs_dbg(VFS, "close cached dir rc %d\n", rc);
438438
}
439439

440440
free_cached_dir(cfid);

fs/smb/client/cifsglob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ struct cifs_ses {
10771077
and after mount option parsing we fill it */
10781078
char *domainName;
10791079
char *password;
1080+
char *password2; /* When key rotation used, new password may be set before it expires */
10801081
char workstation_name[CIFS_MAX_WORKSTATION_LEN];
10811082
struct session_key auth_key;
10821083
struct ntlmssp_auth *ntlmssp; /* ciphertext, flags, server challenge */

fs/smb/client/connect.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
21832183
}
21842184

21852185
++delim;
2186+
/* BB consider adding support for password2 (Key Rotation) for multiuser in future */
21862187
ctx->password = kstrndup(delim, len, GFP_KERNEL);
21872188
if (!ctx->password) {
21882189
cifs_dbg(FYI, "Unable to allocate %zd bytes for password\n",
@@ -2206,6 +2207,7 @@ cifs_set_cifscreds(struct smb3_fs_context *ctx, struct cifs_ses *ses)
22062207
kfree(ctx->username);
22072208
ctx->username = NULL;
22082209
kfree_sensitive(ctx->password);
2210+
/* no need to free ctx->password2 since not allocated in this path */
22092211
ctx->password = NULL;
22102212
goto out_key_put;
22112213
}
@@ -2317,6 +2319,12 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb3_fs_context *ctx)
23172319
if (!ses->password)
23182320
goto get_ses_fail;
23192321
}
2322+
/* ctx->password freed at unmount */
2323+
if (ctx->password2) {
2324+
ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
2325+
if (!ses->password2)
2326+
goto get_ses_fail;
2327+
}
23202328
if (ctx->domainname) {
23212329
ses->domainName = kstrdup(ctx->domainname, GFP_KERNEL);
23222330
if (!ses->domainName)

fs/smb/client/fs_context.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = {
162162
fsparam_string("username", Opt_user),
163163
fsparam_string("pass", Opt_pass),
164164
fsparam_string("password", Opt_pass),
165+
fsparam_string("password2", Opt_pass2),
165166
fsparam_string("ip", Opt_ip),
166167
fsparam_string("addr", Opt_ip),
167168
fsparam_string("domain", Opt_domain),
@@ -345,6 +346,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
345346
new_ctx->nodename = NULL;
346347
new_ctx->username = NULL;
347348
new_ctx->password = NULL;
349+
new_ctx->password2 = NULL;
348350
new_ctx->server_hostname = NULL;
349351
new_ctx->domainname = NULL;
350352
new_ctx->UNC = NULL;
@@ -357,6 +359,7 @@ smb3_fs_context_dup(struct smb3_fs_context *new_ctx, struct smb3_fs_context *ctx
357359
DUP_CTX_STR(prepath);
358360
DUP_CTX_STR(username);
359361
DUP_CTX_STR(password);
362+
DUP_CTX_STR(password2);
360363
DUP_CTX_STR(server_hostname);
361364
DUP_CTX_STR(UNC);
362365
DUP_CTX_STR(source);
@@ -905,6 +908,8 @@ static int smb3_reconfigure(struct fs_context *fc)
905908
else {
906909
kfree_sensitive(ses->password);
907910
ses->password = kstrdup(ctx->password, GFP_KERNEL);
911+
kfree_sensitive(ses->password2);
912+
ses->password2 = kstrdup(ctx->password2, GFP_KERNEL);
908913
}
909914
STEAL_STRING(cifs_sb, ctx, domainname);
910915
STEAL_STRING(cifs_sb, ctx, nodename);
@@ -1305,6 +1310,18 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
13051310
goto cifs_parse_mount_err;
13061311
}
13071312
break;
1313+
case Opt_pass2:
1314+
kfree_sensitive(ctx->password2);
1315+
ctx->password2 = NULL;
1316+
if (strlen(param->string) == 0)
1317+
break;
1318+
1319+
ctx->password2 = kstrdup(param->string, GFP_KERNEL);
1320+
if (ctx->password2 == NULL) {
1321+
cifs_errorf(fc, "OOM when copying password2 string\n");
1322+
goto cifs_parse_mount_err;
1323+
}
1324+
break;
13081325
case Opt_ip:
13091326
if (strlen(param->string) == 0) {
13101327
ctx->got_ip = false;
@@ -1608,6 +1625,8 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
16081625
cifs_parse_mount_err:
16091626
kfree_sensitive(ctx->password);
16101627
ctx->password = NULL;
1628+
kfree_sensitive(ctx->password2);
1629+
ctx->password2 = NULL;
16111630
return -EINVAL;
16121631
}
16131632

@@ -1713,6 +1732,8 @@ smb3_cleanup_fs_context_contents(struct smb3_fs_context *ctx)
17131732
ctx->username = NULL;
17141733
kfree_sensitive(ctx->password);
17151734
ctx->password = NULL;
1735+
kfree_sensitive(ctx->password2);
1736+
ctx->password2 = NULL;
17161737
kfree(ctx->server_hostname);
17171738
ctx->server_hostname = NULL;
17181739
kfree(ctx->UNC);

fs/smb/client/fs_context.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ enum cifs_param {
145145
Opt_source,
146146
Opt_user,
147147
Opt_pass,
148+
Opt_pass2,
148149
Opt_ip,
149150
Opt_domain,
150151
Opt_srcaddr,
@@ -177,6 +178,7 @@ struct smb3_fs_context {
177178

178179
char *username;
179180
char *password;
181+
char *password2;
180182
char *domainname;
181183
char *source;
182184
char *server_hostname;

fs/smb/client/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1105,7 +1105,8 @@ static int cifs_get_fattr(struct cifs_open_info_data *data,
11051105
} else {
11061106
cifs_open_info_to_fattr(fattr, data, sb);
11071107
}
1108-
if (!rc && fattr->cf_flags & CIFS_FATTR_DELETE_PENDING)
1108+
if (!rc && *inode &&
1109+
(fattr->cf_flags & CIFS_FATTR_DELETE_PENDING))
11091110
cifs_mark_open_handles_for_deleted_file(*inode, full_path);
11101111
break;
11111112
case -EREMOTE:

fs/smb/client/misc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
9898
kfree(buf_to_free->serverDomain);
9999
kfree(buf_to_free->serverNOS);
100100
kfree_sensitive(buf_to_free->password);
101+
kfree_sensitive(buf_to_free->password2);
101102
kfree(buf_to_free->user_name);
102103
kfree(buf_to_free->domainName);
103104
kfree_sensitive(buf_to_free->auth_key.response);

fs/smb/client/smb2ops.c

Lines changed: 55 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4964,68 +4964,84 @@ static int smb2_next_header(struct TCP_Server_Info *server, char *buf,
49644964
return 0;
49654965
}
49664966

4967-
int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
4968-
struct dentry *dentry, struct cifs_tcon *tcon,
4969-
const char *full_path, umode_t mode, dev_t dev)
4967+
static int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
4968+
struct dentry *dentry, struct cifs_tcon *tcon,
4969+
const char *full_path, umode_t mode, dev_t dev)
49704970
{
4971-
struct cifs_open_info_data buf = {};
49724971
struct TCP_Server_Info *server = tcon->ses->server;
49734972
struct cifs_open_parms oparms;
49744973
struct cifs_io_parms io_parms = {};
49754974
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
49764975
struct cifs_fid fid;
49774976
unsigned int bytes_written;
4978-
struct win_dev *pdev;
4977+
struct win_dev pdev = {};
49794978
struct kvec iov[2];
49804979
__u32 oplock = server->oplocks ? REQ_OPLOCK : 0;
49814980
int rc;
49824981

4983-
if (!S_ISCHR(mode) && !S_ISBLK(mode) && !S_ISFIFO(mode))
4982+
switch (mode & S_IFMT) {
4983+
case S_IFCHR:
4984+
strscpy(pdev.type, "IntxCHR");
4985+
pdev.major = cpu_to_le64(MAJOR(dev));
4986+
pdev.minor = cpu_to_le64(MINOR(dev));
4987+
break;
4988+
case S_IFBLK:
4989+
strscpy(pdev.type, "IntxBLK");
4990+
pdev.major = cpu_to_le64(MAJOR(dev));
4991+
pdev.minor = cpu_to_le64(MINOR(dev));
4992+
break;
4993+
case S_IFIFO:
4994+
strscpy(pdev.type, "LnxFIFO");
4995+
break;
4996+
default:
49844997
return -EPERM;
4998+
}
49854999

4986-
oparms = (struct cifs_open_parms) {
4987-
.tcon = tcon,
4988-
.cifs_sb = cifs_sb,
4989-
.desired_access = GENERIC_WRITE,
4990-
.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
4991-
CREATE_OPTION_SPECIAL),
4992-
.disposition = FILE_CREATE,
4993-
.path = full_path,
4994-
.fid = &fid,
4995-
};
5000+
oparms = CIFS_OPARMS(cifs_sb, tcon, full_path, GENERIC_WRITE,
5001+
FILE_CREATE, CREATE_NOT_DIR |
5002+
CREATE_OPTION_SPECIAL, ACL_NO_MODE);
5003+
oparms.fid = &fid;
49965004

4997-
rc = server->ops->open(xid, &oparms, &oplock, &buf);
5005+
rc = server->ops->open(xid, &oparms, &oplock, NULL);
49985006
if (rc)
49995007
return rc;
50005008

5001-
/*
5002-
* BB Do not bother to decode buf since no local inode yet to put
5003-
* timestamps in, but we can reuse it safely.
5004-
*/
5005-
pdev = (struct win_dev *)&buf.fi;
50065009
io_parms.pid = current->tgid;
50075010
io_parms.tcon = tcon;
5008-
io_parms.length = sizeof(*pdev);
5009-
iov[1].iov_base = pdev;
5010-
iov[1].iov_len = sizeof(*pdev);
5011-
if (S_ISCHR(mode)) {
5012-
memcpy(pdev->type, "IntxCHR", 8);
5013-
pdev->major = cpu_to_le64(MAJOR(dev));
5014-
pdev->minor = cpu_to_le64(MINOR(dev));
5015-
} else if (S_ISBLK(mode)) {
5016-
memcpy(pdev->type, "IntxBLK", 8);
5017-
pdev->major = cpu_to_le64(MAJOR(dev));
5018-
pdev->minor = cpu_to_le64(MINOR(dev));
5019-
} else if (S_ISFIFO(mode)) {
5020-
memcpy(pdev->type, "LnxFIFO", 8);
5021-
}
5011+
io_parms.length = sizeof(pdev);
5012+
iov[1].iov_base = &pdev;
5013+
iov[1].iov_len = sizeof(pdev);
50225014

50235015
rc = server->ops->sync_write(xid, &fid, &io_parms,
50245016
&bytes_written, iov, 1);
50255017
server->ops->close(xid, tcon, &fid);
5026-
d_drop(dentry);
5027-
/* FIXME: add code here to set EAs */
5028-
cifs_free_open_info(&buf);
5018+
return rc;
5019+
}
5020+
5021+
int cifs_sfu_make_node(unsigned int xid, struct inode *inode,
5022+
struct dentry *dentry, struct cifs_tcon *tcon,
5023+
const char *full_path, umode_t mode, dev_t dev)
5024+
{
5025+
struct inode *new = NULL;
5026+
int rc;
5027+
5028+
rc = __cifs_sfu_make_node(xid, inode, dentry, tcon,
5029+
full_path, mode, dev);
5030+
if (rc)
5031+
return rc;
5032+
5033+
if (tcon->posix_extensions) {
5034+
rc = smb311_posix_get_inode_info(&new, full_path, NULL,
5035+
inode->i_sb, xid);
5036+
} else if (tcon->unix_ext) {
5037+
rc = cifs_get_inode_info_unix(&new, full_path,
5038+
inode->i_sb, xid);
5039+
} else {
5040+
rc = cifs_get_inode_info(&new, full_path, NULL,
5041+
inode->i_sb, xid, NULL);
5042+
}
5043+
if (!rc)
5044+
d_instantiate(dentry, new);
50295045
return rc;
50305046
}
50315047

fs/smb/client/smb2pdu.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,17 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
367367
}
368368

369369
rc = cifs_setup_session(0, ses, server, nls_codepage);
370+
if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
371+
/*
372+
* Try alternate password for next reconnect (key rotation
373+
* could be enabled on the server e.g.) if an alternate
374+
* password is available and the current password is expired,
375+
* but do not swap on non pwd related errors like host down
376+
*/
377+
if (ses->password2)
378+
swap(ses->password2, ses->password);
379+
}
380+
370381
if ((rc == -EACCES) && !tcon->retry) {
371382
mutex_unlock(&ses->session_mutex);
372383
rc = -EHOSTDOWN;

0 commit comments

Comments
 (0)