Skip to content
7 changes: 6 additions & 1 deletion drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1338,7 +1338,12 @@ EXPORT_SYMBOL_GPL(hid_snto32);

static u32 s32ton(__s32 value, unsigned n)
{
s32 a = value >> (n - 1);
s32 a;

if (!value || !n)
return 0;

a = value >> (n - 1);
if (a && a != -1)
return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
return value & ((1 << n) - 1);
Expand Down
12 changes: 6 additions & 6 deletions fs/cifs/cifsencrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ setup_ntlmv2_rsp(struct cifs_ses *ses, const struct nls_table *nls_cp)
unlock:
cifs_server_unlock(ses->server);
setup_ntlmv2_rsp_ret:
kfree(tiblob);
kfree_sensitive(tiblob);

return rc;
}
Expand Down Expand Up @@ -753,14 +753,14 @@ cifs_crypto_secmech_release(struct TCP_Server_Info *server)
server->secmech.ccmaesdecrypt = NULL;
}

kfree(server->secmech.sdesccmacaes);
kfree_sensitive(server->secmech.sdesccmacaes);
server->secmech.sdesccmacaes = NULL;
kfree(server->secmech.sdeschmacsha256);
kfree_sensitive(server->secmech.sdeschmacsha256);
server->secmech.sdeschmacsha256 = NULL;
kfree(server->secmech.sdeschmacmd5);
kfree_sensitive(server->secmech.sdeschmacmd5);
server->secmech.sdeschmacmd5 = NULL;
kfree(server->secmech.sdescmd5);
kfree_sensitive(server->secmech.sdescmd5);
server->secmech.sdescmd5 = NULL;
kfree(server->secmech.sdescsha512);
kfree_sensitive(server->secmech.sdescsha512);
server->secmech.sdescsha512 = NULL;
}
69 changes: 68 additions & 1 deletion fs/cifs/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <linux/in6.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/scatterlist.h>
#include <linux/mm.h>
#include <linux/mempool.h>
#include <linux/workqueue.h>
#include <linux/utsname.h>
Expand All @@ -21,7 +23,6 @@
#include "cifs_fs_sb.h"
#include "cifsacl.h"
#include <crypto/internal/hash.h>
#include <linux/scatterlist.h>
#include <uapi/linux/cifs/cifs_mount.h>
#include "../smbfs_common/smb2pdu.h"
#include "smb2pdu.h"
Expand Down Expand Up @@ -2117,4 +2118,70 @@ static inline size_t ntlmssp_workstation_name_size(const struct cifs_ses *ses)
return sizeof(ses->workstation_name);
}

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 */
4 changes: 2 additions & 2 deletions fs/cifs/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -606,8 +606,8 @@ int cifs_alloc_hash(const char *name, struct crypto_shash **shash,
struct sdesc **sdesc);
void cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc);

extern void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset);
void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset);
struct cifs_chan *
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);
Expand Down
6 changes: 3 additions & 3 deletions fs/cifs/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ cifs_abort_connection(struct TCP_Server_Info *server)
}
server->sequence_number = 0;
server->session_estab = false;
kfree(server->session_key.response);
kfree_sensitive(server->session_key.response);
server->session_key.response = NULL;
server->session_key.len = 0;
server->lstrp = jiffies;
Expand Down Expand Up @@ -1562,7 +1562,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)

cifs_crypto_secmech_release(server);

kfree(server->session_key.response);
kfree_sensitive(server->session_key.response);
server->session_key.response = NULL;
server->session_key.len = 0;
kfree(server->hostname);
Expand Down Expand Up @@ -4097,7 +4097,7 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
if (ses->auth_key.response) {
cifs_dbg(FYI, "Free previous auth_key.response = %p\n",
ses->auth_key.response);
kfree(ses->auth_key.response);
kfree_sensitive(ses->auth_key.response);
ses->auth_key.response = NULL;
ses->auth_key.len = 0;
}
Expand Down
12 changes: 10 additions & 2 deletions fs/cifs/fs_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,13 @@ do { \
cifs_sb->ctx->field = NULL; \
} while (0)

#define STEAL_STRING_SENSITIVE(cifs_sb, ctx, field) \
do { \
kfree_sensitive(ctx->field); \
ctx->field = cifs_sb->ctx->field; \
cifs_sb->ctx->field = NULL; \
} while (0)

static int smb3_reconfigure(struct fs_context *fc)
{
struct smb3_fs_context *ctx = smb3_fc2context(fc);
Expand All @@ -809,7 +816,7 @@ static int smb3_reconfigure(struct fs_context *fc)
STEAL_STRING(cifs_sb, ctx, UNC);
STEAL_STRING(cifs_sb, ctx, source);
STEAL_STRING(cifs_sb, ctx, username);
STEAL_STRING(cifs_sb, ctx, password);
STEAL_STRING_SENSITIVE(cifs_sb, ctx, password);
STEAL_STRING(cifs_sb, ctx, domainname);
STEAL_STRING(cifs_sb, ctx, nodename);
STEAL_STRING(cifs_sb, ctx, iocharset);
Expand Down Expand Up @@ -1150,7 +1157,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
}
break;
case Opt_pass:
kfree(ctx->password);
kfree_sensitive(ctx->password);
ctx->password = NULL;
if (strlen(param->string) == 0)
break;
Expand Down Expand Up @@ -1458,6 +1465,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc,
return 0;

cifs_parse_mount_err:
kfree_sensitive(ctx->password);
return -EINVAL;
}

Expand Down
6 changes: 3 additions & 3 deletions fs/cifs/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1118,7 +1118,7 @@ cifs_alloc_hash(const char *name,
void
cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
{
kfree(*sdesc);
kfree_sensitive(*sdesc);
*sdesc = NULL;
if (*shash)
crypto_free_shash(*shash);
Expand All @@ -1132,8 +1132,8 @@ cifs_free_hash(struct crypto_shash **shash, struct sdesc **sdesc)
* @len: Where to store the length for this page:
* @offset: Where to store the offset for this page
*/
void rqst_page_get_length(struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset)
void rqst_page_get_length(const struct smb_rqst *rqst, unsigned int page,
unsigned int *len, unsigned int *offset)
{
*len = rqst->rq_pagesz;
*offset = (page == 0) ? rqst->rq_offset : 0;
Expand Down
24 changes: 15 additions & 9 deletions fs/cifs/sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -1211,6 +1211,12 @@ sess_alloc_buffer(struct sess_data *sess_data, int wct)
static void
sess_free_buffer(struct sess_data *sess_data)
{
int i;

/* zero the session data before freeing, as it might contain sensitive info (keys, etc) */
for (i = 0; i < 3; i++)
if (sess_data->iov[i].iov_base)
memzero_explicit(sess_data->iov[i].iov_base, sess_data->iov[i].iov_len);

free_rsp_buf(sess_data->buf0_type, sess_data->iov[0].iov_base);
sess_data->buf0_type = CIFS_NO_BUFFER;
Expand Down Expand Up @@ -1372,7 +1378,7 @@ sess_auth_ntlmv2(struct sess_data *sess_data)
sess_data->result = rc;
sess_data->func = NULL;
sess_free_buffer(sess_data);
kfree(ses->auth_key.response);
kfree_sensitive(ses->auth_key.response);
ses->auth_key.response = NULL;
}

Expand Down Expand Up @@ -1511,7 +1517,7 @@ sess_auth_kerberos(struct sess_data *sess_data)
sess_data->result = rc;
sess_data->func = NULL;
sess_free_buffer(sess_data);
kfree(ses->auth_key.response);
kfree_sensitive(ses->auth_key.response);
ses->auth_key.response = NULL;
}

Expand Down Expand Up @@ -1646,7 +1652,7 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);

out_free_ntlmsspblob:
kfree(ntlmsspblob);
kfree_sensitive(ntlmsspblob);
out:
sess_free_buffer(sess_data);

Expand All @@ -1656,9 +1662,9 @@ sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
}

/* Else error. Cleanup */
kfree(ses->auth_key.response);
kfree_sensitive(ses->auth_key.response);
ses->auth_key.response = NULL;
kfree(ses->ntlmssp);
kfree_sensitive(ses->ntlmssp);
ses->ntlmssp = NULL;

sess_data->func = NULL;
Expand Down Expand Up @@ -1757,17 +1763,17 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
}

out_free_ntlmsspblob:
kfree(ntlmsspblob);
kfree_sensitive(ntlmsspblob);
out:
sess_free_buffer(sess_data);

if (!rc)
rc = sess_establish_session(sess_data);

/* Cleanup */
kfree(ses->auth_key.response);
kfree_sensitive(ses->auth_key.response);
ses->auth_key.response = NULL;
kfree(ses->ntlmssp);
kfree_sensitive(ses->ntlmssp);
ses->ntlmssp = NULL;

sess_data->func = NULL;
Expand Down Expand Up @@ -1843,7 +1849,7 @@ int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
rc = sess_data->result;

out:
kfree(sess_data);
kfree_sensitive(sess_data);
return rc;
}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
Loading
Loading