Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.samba.org/sfrench/cifs-2.6
Browse files Browse the repository at this point in the history
Pull cifs fixes from Steve French:
 "Fixes for 4 cifs bugs, including a reconnect problem, a problem
  parsing responses to SMB2 open request, and setting nlink incorrectly
  to some servers which don't report it properly on the wire.  Also
  improves data integrity on reconnect with series from Pavel which adds
  durable handle support for SMB2."

* 'for-linus' of git://git.samba.org/sfrench/cifs-2.6:
  CIFS: Fix a deadlock when a file is reopened
  CIFS: Reopen the file if reconnect durable handle failed
  [CIFS] Fix minor endian error in durable handle patch series
  CIFS: Reconnect durable handles for SMB2
  CIFS: Make SMB2_open use cifs_open_parms struct
  CIFS: Introduce cifs_open_parms struct
  CIFS: Request durable open for SMB2 opens
  CIFS: Simplify SMB2 create context handling
  CIFS: Simplify SMB2_open code path
  CIFS: Respect create_options in smb2_open_file
  CIFS: Fix lease context buffer parsing
  [CIFS] use sensible file nlink values if unprovided
  Limit allocation of crypto mechanisms to dialect which requires
  • Loading branch information
Linus Torvalds committed Jul 13, 2013
2 parents 9903883 + 689c3db commit f1c4108
Show file tree
Hide file tree
Showing 15 changed files with 515 additions and 281 deletions.
195 changes: 85 additions & 110 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* fs/cifs/cifsencrypt.c
*
* Copyright (C) International Business Machines Corp., 2005,2006
* Copyright (C) International Business Machines Corp., 2005,2013
* Author(s): Steve French (sfrench@us.ibm.com)
*
* This library is free software; you can redistribute it and/or modify
Expand Down Expand Up @@ -31,6 +31,36 @@
#include <linux/random.h>
#include <linux/highmem.h>

static int
cifs_crypto_shash_md5_allocate(struct TCP_Server_Info *server)
{
int rc;
unsigned int size;

if (server->secmech.sdescmd5 != NULL)
return 0; /* already allocated */

server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
if (IS_ERR(server->secmech.md5)) {
cifs_dbg(VFS, "could not allocate crypto md5\n");
return PTR_ERR(server->secmech.md5);
}

size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.md5);
server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdescmd5) {
rc = -ENOMEM;
crypto_free_shash(server->secmech.md5);
server->secmech.md5 = NULL;
return rc;
}
server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
server->secmech.sdescmd5->shash.flags = 0x0;

return 0;
}

/*
* Calculate and return the CIFS signature based on the mac key and SMB PDU.
* The 16 byte signature must be allocated by the caller. Note we only use the
Expand All @@ -50,8 +80,11 @@ static int cifs_calc_signature(struct smb_rqst *rqst,
return -EINVAL;

if (!server->secmech.sdescmd5) {
cifs_dbg(VFS, "%s: Can't generate signature\n", __func__);
return -1;
rc = cifs_crypto_shash_md5_allocate(server);
if (rc) {
cifs_dbg(VFS, "%s: Can't alloc md5 crypto\n", __func__);
return -1;
}
}

rc = crypto_shash_init(&server->secmech.sdescmd5->shash);
Expand Down Expand Up @@ -556,6 +589,33 @@ CalcNTLMv2_response(const struct cifs_ses *ses, char *ntlmv2_hash)
return rc;
}

static int crypto_hmacmd5_alloc(struct TCP_Server_Info *server)
{
unsigned int size;

/* check if already allocated */
if (server->secmech.sdeschmacmd5)
return 0;

server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
if (IS_ERR(server->secmech.hmacmd5)) {
cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
return PTR_ERR(server->secmech.hmacmd5);
}

size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.hmacmd5);
server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdeschmacmd5) {
crypto_free_shash(server->secmech.hmacmd5);
server->secmech.hmacmd5 = NULL;
return -ENOMEM;
}
server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
server->secmech.sdeschmacmd5->shash.flags = 0x0;

return 0;
}

int
setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
Expand Down Expand Up @@ -606,6 +666,12 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)

memcpy(ses->auth_key.response + baselen, tiblob, tilen);

rc = crypto_hmacmd5_alloc(ses->server);
if (rc) {
cifs_dbg(VFS, "could not crypto alloc hmacmd5 rc %d\n", rc);
goto setup_ntlmv2_rsp_ret;
}

/* calculate ntlmv2_hash */
rc = calc_ntlmv2_hash(ses, ntlmv2_hash, nls_cp);
if (rc) {
Expand Down Expand Up @@ -705,123 +771,32 @@ calc_seckey(struct cifs_ses *ses)
void
cifs_crypto_shash_release(struct TCP_Server_Info *server)
{
if (server->secmech.cmacaes)
if (server->secmech.cmacaes) {
crypto_free_shash(server->secmech.cmacaes);
server->secmech.cmacaes = NULL;
}

if (server->secmech.hmacsha256)
if (server->secmech.hmacsha256) {
crypto_free_shash(server->secmech.hmacsha256);
server->secmech.hmacsha256 = NULL;
}

if (server->secmech.md5)
if (server->secmech.md5) {
crypto_free_shash(server->secmech.md5);
server->secmech.md5 = NULL;
}

if (server->secmech.hmacmd5)
if (server->secmech.hmacmd5) {
crypto_free_shash(server->secmech.hmacmd5);
server->secmech.hmacmd5 = NULL;
}

kfree(server->secmech.sdesccmacaes);

server->secmech.sdesccmacaes = NULL;
kfree(server->secmech.sdeschmacsha256);

server->secmech.sdeschmacsha256 = NULL;
kfree(server->secmech.sdeschmacmd5);

server->secmech.sdeschmacmd5 = NULL;
kfree(server->secmech.sdescmd5);
}

int
cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
{
int rc;
unsigned int size;

server->secmech.hmacmd5 = crypto_alloc_shash("hmac(md5)", 0, 0);
if (IS_ERR(server->secmech.hmacmd5)) {
cifs_dbg(VFS, "could not allocate crypto hmacmd5\n");
return PTR_ERR(server->secmech.hmacmd5);
}

server->secmech.md5 = crypto_alloc_shash("md5", 0, 0);
if (IS_ERR(server->secmech.md5)) {
cifs_dbg(VFS, "could not allocate crypto md5\n");
rc = PTR_ERR(server->secmech.md5);
goto crypto_allocate_md5_fail;
}

server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
if (IS_ERR(server->secmech.hmacsha256)) {
cifs_dbg(VFS, "could not allocate crypto hmacsha256\n");
rc = PTR_ERR(server->secmech.hmacsha256);
goto crypto_allocate_hmacsha256_fail;
}

server->secmech.cmacaes = crypto_alloc_shash("cmac(aes)", 0, 0);
if (IS_ERR(server->secmech.cmacaes)) {
cifs_dbg(VFS, "could not allocate crypto cmac-aes");
rc = PTR_ERR(server->secmech.cmacaes);
goto crypto_allocate_cmacaes_fail;
}

size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.hmacmd5);
server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdeschmacmd5) {
rc = -ENOMEM;
goto crypto_allocate_hmacmd5_sdesc_fail;
}
server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
server->secmech.sdeschmacmd5->shash.flags = 0x0;

size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.md5);
server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdescmd5) {
rc = -ENOMEM;
goto crypto_allocate_md5_sdesc_fail;
}
server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
server->secmech.sdescmd5->shash.flags = 0x0;

size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.hmacsha256);
server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdeschmacsha256) {
rc = -ENOMEM;
goto crypto_allocate_hmacsha256_sdesc_fail;
}
server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
server->secmech.sdeschmacsha256->shash.flags = 0x0;

size = sizeof(struct shash_desc) +
crypto_shash_descsize(server->secmech.cmacaes);
server->secmech.sdesccmacaes = kmalloc(size, GFP_KERNEL);
if (!server->secmech.sdesccmacaes) {
cifs_dbg(VFS, "%s: Can't alloc cmacaes\n", __func__);
rc = -ENOMEM;
goto crypto_allocate_cmacaes_sdesc_fail;
}
server->secmech.sdesccmacaes->shash.tfm = server->secmech.cmacaes;
server->secmech.sdesccmacaes->shash.flags = 0x0;

return 0;

crypto_allocate_cmacaes_sdesc_fail:
kfree(server->secmech.sdeschmacsha256);

crypto_allocate_hmacsha256_sdesc_fail:
kfree(server->secmech.sdescmd5);

crypto_allocate_md5_sdesc_fail:
kfree(server->secmech.sdeschmacmd5);

crypto_allocate_hmacmd5_sdesc_fail:
crypto_free_shash(server->secmech.cmacaes);

crypto_allocate_cmacaes_fail:
crypto_free_shash(server->secmech.hmacsha256);

crypto_allocate_hmacsha256_fail:
crypto_free_shash(server->secmech.md5);

crypto_allocate_md5_fail:
crypto_free_shash(server->secmech.hmacmd5);

return rc;
server->secmech.sdescmd5 = NULL;
}
17 changes: 14 additions & 3 deletions fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ struct cifs_writedata;
struct cifs_io_parms;
struct cifs_search_info;
struct cifsInodeInfo;
struct cifs_open_parms;

struct smb_version_operations {
int (*send_cancel)(struct TCP_Server_Info *, void *,
Expand Down Expand Up @@ -307,9 +308,8 @@ struct smb_version_operations {
const char *, const char *,
struct cifs_sb_info *);
/* open a file for non-posix mounts */
int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
struct cifs_sb_info *);
int (*open)(const unsigned int, struct cifs_open_parms *,
__u32 *, FILE_ALL_INFO *);
/* set fid protocol-specific info */
void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
/* close a file */
Expand Down Expand Up @@ -912,6 +912,17 @@ struct cifs_search_info {
bool smallBuf:1; /* so we know which buf_release function to call */
};

struct cifs_open_parms {
struct cifs_tcon *tcon;
struct cifs_sb_info *cifs_sb;
int disposition;
int desired_access;
int create_options;
const char *path;
struct cifs_fid *fid;
bool reconnect:1;
};

struct cifs_fid {
__u16 netfid;
#ifdef CONFIG_CIFS_SMB2
Expand Down
1 change: 0 additions & 1 deletion fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,6 @@ extern int SMBNTencrypt(unsigned char *, unsigned char *, unsigned char *,
const struct nls_table *);
extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
extern int cifs_crypto_shash_allocate(struct TCP_Server_Info *);
extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
extern int calc_seckey(struct cifs_ses *);
extern void generate_smb3signingkey(struct TCP_Server_Info *);
Expand Down
6 changes: 0 additions & 6 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2108,12 +2108,6 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
goto out_err;
}

rc = cifs_crypto_shash_allocate(tcp_ses);
if (rc) {
cifs_dbg(VFS, "could not setup hash structures rc %d\n", rc);
goto out_err;
}

tcp_ses->ops = volume_info->ops;
tcp_ses->vals = volume_info->vals;
cifs_set_net_ns(tcp_ses, get_net(current->nsproxy->net_ns));
Expand Down
14 changes: 11 additions & 3 deletions fs/cifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
struct inode *newinode = NULL;
int disposition;
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;

*oplock = 0;
if (tcon->ses->server->oplocks)
Expand Down Expand Up @@ -319,9 +320,16 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
if (backup_cred(cifs_sb))
create_options |= CREATE_OPEN_BACKUP_INTENT;

rc = server->ops->open(xid, tcon, full_path, disposition,
desired_access, create_options, fid, oplock,
buf, cifs_sb);
oparms.tcon = tcon;
oparms.cifs_sb = cifs_sb;
oparms.desired_access = desired_access;
oparms.create_options = create_options;
oparms.disposition = disposition;
oparms.path = full_path;
oparms.fid = fid;
oparms.reconnect = false;

rc = server->ops->open(xid, &oparms, oplock, buf);
if (rc) {
cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
goto out;
Expand Down
Loading

0 comments on commit f1c4108

Please sign in to comment.