2019-05-09 03:36:25 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2011-02-25 02:07:19 +08:00
|
|
|
/*
|
|
|
|
* SMB2 version specific operations
|
|
|
|
*
|
|
|
|
* Copyright (c) 2012, Jeff Layton <jlayton@redhat.com>
|
|
|
|
*/
|
|
|
|
|
2012-09-19 07:20:28 +08:00
|
|
|
#include <linux/pagemap.h>
|
2012-09-19 07:20:34 +08:00
|
|
|
#include <linux/vfs.h>
|
2014-07-20 10:44:58 +08:00
|
|
|
#include <linux/falloc.h>
|
2016-11-04 07:47:37 +08:00
|
|
|
#include <linux/scatterlist.h>
|
2017-03-30 18:34:14 +08:00
|
|
|
#include <linux/uuid.h>
|
2019-09-20 12:29:39 +08:00
|
|
|
#include <linux/sort.h>
|
2016-11-04 07:47:37 +08:00
|
|
|
#include <crypto/aead.h>
|
2020-05-23 15:30:11 +08:00
|
|
|
#include <linux/fiemap.h>
|
2022-01-11 08:00:02 +08:00
|
|
|
#include <uapi/linux/magic.h>
|
2020-01-17 09:45:02 +08:00
|
|
|
#include "cifsfs.h"
|
2011-02-25 02:07:19 +08:00
|
|
|
#include "cifsglob.h"
|
2011-12-27 02:53:34 +08:00
|
|
|
#include "smb2pdu.h"
|
|
|
|
#include "smb2proto.h"
|
2012-05-23 20:18:00 +08:00
|
|
|
#include "cifsproto.h"
|
|
|
|
#include "cifs_debug.h"
|
2013-08-14 23:25:21 +08:00
|
|
|
#include "cifs_unicode.h"
|
2012-09-19 07:20:33 +08:00
|
|
|
#include "smb2status.h"
|
2012-09-19 07:20:34 +08:00
|
|
|
#include "smb2glob.h"
|
2016-10-01 10:14:26 +08:00
|
|
|
#include "cifs_ioctl.h"
|
2017-11-23 08:38:39 +08:00
|
|
|
#include "smbdirect.h"
|
2022-02-23 09:14:16 +08:00
|
|
|
#include "fscache.h"
|
2020-12-10 13:07:12 +08:00
|
|
|
#include "fs_context.h"
|
2012-05-23 20:18:00 +08:00
|
|
|
|
2019-01-19 09:25:36 +08:00
|
|
|
/* Change credits for different ops and return the total number of credits */
|
2012-05-23 20:18:00 +08:00
|
|
|
static int
|
|
|
|
change_conf(struct TCP_Server_Info *server)
|
|
|
|
{
|
|
|
|
server->credits += server->echo_credits + server->oplock_credits;
|
|
|
|
server->oplock_credits = server->echo_credits = 0;
|
|
|
|
switch (server->credits) {
|
|
|
|
case 0:
|
2019-01-19 09:25:36 +08:00
|
|
|
return 0;
|
2012-05-23 20:18:00 +08:00
|
|
|
case 1:
|
|
|
|
server->echoes = false;
|
|
|
|
server->oplocks = false;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
server->echoes = true;
|
|
|
|
server->oplocks = false;
|
|
|
|
server->echo_credits = 1;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
server->echoes = true;
|
2015-09-22 22:29:38 +08:00
|
|
|
if (enable_oplocks) {
|
|
|
|
server->oplocks = true;
|
|
|
|
server->oplock_credits = 1;
|
|
|
|
} else
|
|
|
|
server->oplocks = false;
|
|
|
|
|
2012-05-23 20:18:00 +08:00
|
|
|
server->echo_credits = 1;
|
|
|
|
}
|
|
|
|
server->credits -= server->echo_credits + server->oplock_credits;
|
2019-01-19 09:25:36 +08:00
|
|
|
return server->credits + server->echo_credits + server->oplock_credits;
|
2012-05-23 20:18:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2019-01-17 03:12:41 +08:00
|
|
|
smb2_add_credits(struct TCP_Server_Info *server,
|
|
|
|
const struct cifs_credits *credits, const int optype)
|
2012-05-23 20:18:00 +08:00
|
|
|
{
|
2019-01-19 09:25:36 +08:00
|
|
|
int *val, rc = -1;
|
2021-02-04 15:20:46 +08:00
|
|
|
int scredits, in_flight;
|
2019-01-17 03:12:41 +08:00
|
|
|
unsigned int add = credits->value;
|
|
|
|
unsigned int instance = credits->instance;
|
|
|
|
bool reconnect_detected = false;
|
2021-02-04 15:20:46 +08:00
|
|
|
bool reconnect_with_invalid_credits = false;
|
2019-01-19 09:25:36 +08:00
|
|
|
|
2012-05-23 20:18:00 +08:00
|
|
|
spin_lock(&server->req_lock);
|
|
|
|
val = server->ops->get_credits_field(server, optype);
|
2018-09-01 14:10:17 +08:00
|
|
|
|
|
|
|
/* eg found case where write overlapping reconnect messed up credits */
|
|
|
|
if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0))
|
2021-02-04 15:20:46 +08:00
|
|
|
reconnect_with_invalid_credits = true;
|
|
|
|
|
2019-01-17 03:12:41 +08:00
|
|
|
if ((instance == 0) || (instance == server->reconnect_instance))
|
|
|
|
*val += add;
|
|
|
|
else
|
|
|
|
reconnect_detected = true;
|
2018-09-01 14:10:17 +08:00
|
|
|
|
2016-09-23 13:44:16 +08:00
|
|
|
if (*val > 65000) {
|
|
|
|
*val = 65000; /* Don't get near 64K credits, avoid srv bugs */
|
2020-04-15 13:42:53 +08:00
|
|
|
pr_warn_once("server overflowed SMB3 credits\n");
|
2016-09-23 13:44:16 +08:00
|
|
|
}
|
2012-05-23 20:18:00 +08:00
|
|
|
server->in_flight--;
|
2021-02-04 14:49:52 +08:00
|
|
|
if (server->in_flight == 0 &&
|
|
|
|
((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
|
|
|
|
((optype & CIFS_OP_MASK) != CIFS_SESS_OP))
|
2012-05-23 20:18:00 +08:00
|
|
|
rc = change_conf(server);
|
2012-09-19 07:20:33 +08:00
|
|
|
/*
|
|
|
|
* Sometimes server returns 0 credits on oplock break ack - we need to
|
|
|
|
* rebalance credits in this case.
|
|
|
|
*/
|
|
|
|
else if (server->in_flight > 0 && server->oplock_credits == 0 &&
|
|
|
|
server->oplocks) {
|
|
|
|
if (server->credits > 1) {
|
|
|
|
server->credits--;
|
|
|
|
server->oplock_credits++;
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 15:20:46 +08:00
|
|
|
scredits = *val;
|
|
|
|
in_flight = server->in_flight;
|
2012-05-23 20:18:00 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
|
|
|
wake_up(&server->request_q);
|
2019-01-19 09:25:36 +08:00
|
|
|
|
2020-11-13 00:56:49 +08:00
|
|
|
if (reconnect_detected) {
|
2021-02-04 15:20:46 +08:00
|
|
|
trace_smb3_reconnect_detected(server->CurrentMid,
|
|
|
|
server->conn_id, server->hostname, scredits, add, in_flight);
|
|
|
|
|
2019-01-17 03:12:41 +08:00
|
|
|
cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n",
|
|
|
|
add, instance);
|
2020-11-13 00:56:49 +08:00
|
|
|
}
|
2019-01-17 03:12:41 +08:00
|
|
|
|
2021-02-04 15:20:46 +08:00
|
|
|
if (reconnect_with_invalid_credits) {
|
|
|
|
trace_smb3_reconnect_with_invalid_credits(server->CurrentMid,
|
|
|
|
server->conn_id, server->hostname, scredits, add, in_flight);
|
|
|
|
cifs_dbg(FYI, "Negotiate operation when server credits is non-zero. Optype: %d, server credits: %d, credits added: %d\n",
|
|
|
|
optype, scredits, add);
|
|
|
|
}
|
|
|
|
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
2019-01-26 02:56:41 +08:00
|
|
|
if (server->tcpStatus == CifsNeedReconnect
|
2021-07-20 01:05:53 +08:00
|
|
|
|| server->tcpStatus == CifsExiting) {
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2019-01-19 09:25:36 +08:00
|
|
|
return;
|
2021-07-20 01:05:53 +08:00
|
|
|
}
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2019-01-19 09:25:36 +08:00
|
|
|
|
|
|
|
switch (rc) {
|
|
|
|
case -1:
|
|
|
|
/* change_conf hasn't been executed */
|
|
|
|
break;
|
|
|
|
case 0:
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "Possible client or server bug - zero credits\n");
|
2019-01-19 09:25:36 +08:00
|
|
|
break;
|
|
|
|
case 1:
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "disabling echoes and oplocks\n");
|
2019-01-19 09:25:36 +08:00
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
cifs_dbg(FYI, "disabling oplocks\n");
|
|
|
|
break;
|
|
|
|
default:
|
2021-02-04 15:20:46 +08:00
|
|
|
/* change_conf rebalanced credits for different types */
|
|
|
|
break;
|
2019-01-19 09:25:36 +08:00
|
|
|
}
|
2021-02-04 15:20:46 +08:00
|
|
|
|
|
|
|
trace_smb3_add_credits(server->CurrentMid,
|
|
|
|
server->conn_id, server->hostname, scredits, add, in_flight);
|
|
|
|
cifs_dbg(FYI, "%s: added %u credits total=%d\n", __func__, add, scredits);
|
2012-05-23 20:18:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
smb2_set_credits(struct TCP_Server_Info *server, const int val)
|
|
|
|
{
|
2021-02-04 15:20:46 +08:00
|
|
|
int scredits, in_flight;
|
|
|
|
|
2012-05-23 20:18:00 +08:00
|
|
|
spin_lock(&server->req_lock);
|
|
|
|
server->credits = val;
|
2018-09-19 15:38:17 +08:00
|
|
|
if (val == 1)
|
|
|
|
server->reconnect_instance++;
|
2021-02-04 15:20:46 +08:00
|
|
|
scredits = server->credits;
|
|
|
|
in_flight = server->in_flight;
|
2012-05-23 20:18:00 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
2020-11-13 00:56:49 +08:00
|
|
|
|
|
|
|
trace_smb3_set_credits(server->CurrentMid,
|
2021-02-04 15:20:46 +08:00
|
|
|
server->conn_id, server->hostname, scredits, val, in_flight);
|
2020-11-13 00:56:49 +08:00
|
|
|
cifs_dbg(FYI, "%s: set %u credits\n", __func__, val);
|
|
|
|
|
2018-09-23 00:25:04 +08:00
|
|
|
/* don't log while holding the lock */
|
|
|
|
if (val == 1)
|
|
|
|
cifs_dbg(FYI, "set credits to 1 due to smb2 reconnect\n");
|
2012-05-23 20:18:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int *
|
|
|
|
smb2_get_credits_field(struct TCP_Server_Info *server, const int optype)
|
|
|
|
{
|
|
|
|
switch (optype) {
|
|
|
|
case CIFS_ECHO_OP:
|
|
|
|
return &server->echo_credits;
|
|
|
|
case CIFS_OBREAK_OP:
|
|
|
|
return &server->oplock_credits;
|
|
|
|
default:
|
|
|
|
return &server->credits;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
smb2_get_credits(struct mid_q_entry *mid)
|
|
|
|
{
|
2019-11-22 03:35:13 +08:00
|
|
|
return mid->credits_received;
|
2012-05-23 20:18:00 +08:00
|
|
|
}
|
2011-12-27 02:53:34 +08:00
|
|
|
|
2014-06-05 23:03:27 +08:00
|
|
|
static int
|
|
|
|
smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size,
|
2019-01-17 03:12:41 +08:00
|
|
|
unsigned int *num, struct cifs_credits *credits)
|
2014-06-05 23:03:27 +08:00
|
|
|
{
|
|
|
|
int rc = 0;
|
2021-02-04 15:20:46 +08:00
|
|
|
unsigned int scredits, in_flight;
|
2014-06-05 23:03:27 +08:00
|
|
|
|
|
|
|
spin_lock(&server->req_lock);
|
|
|
|
while (1) {
|
|
|
|
if (server->credits <= 0) {
|
|
|
|
spin_unlock(&server->req_lock);
|
|
|
|
cifs_num_waiters_inc(server);
|
|
|
|
rc = wait_event_killable(server->request_q,
|
2019-03-08 10:58:20 +08:00
|
|
|
has_credits(server, &server->credits, 1));
|
2014-06-05 23:03:27 +08:00
|
|
|
cifs_num_waiters_dec(server);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
spin_lock(&server->req_lock);
|
|
|
|
} else {
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
2014-06-05 23:03:27 +08:00
|
|
|
if (server->tcpStatus == CifsExiting) {
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2014-06-05 23:03:27 +08:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2014-06-05 23:03:27 +08:00
|
|
|
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_lock(&server->req_lock);
|
2014-06-05 23:03:27 +08:00
|
|
|
scredits = server->credits;
|
|
|
|
/* can deadlock with reopen */
|
2019-01-18 00:21:24 +08:00
|
|
|
if (scredits <= 8) {
|
2014-06-05 23:03:27 +08:00
|
|
|
*num = SMB2_MAX_BUFFER_SIZE;
|
2019-01-17 03:12:41 +08:00
|
|
|
credits->value = 0;
|
|
|
|
credits->instance = 0;
|
2014-06-05 23:03:27 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-01-18 00:21:24 +08:00
|
|
|
/* leave some credits for reopen and other ops */
|
|
|
|
scredits -= 8;
|
2014-06-05 23:03:27 +08:00
|
|
|
*num = min_t(unsigned int, size,
|
|
|
|
scredits * SMB2_MAX_BUFFER_SIZE);
|
|
|
|
|
2019-01-17 03:12:41 +08:00
|
|
|
credits->value =
|
|
|
|
DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE);
|
|
|
|
credits->instance = server->reconnect_instance;
|
|
|
|
server->credits -= credits->value;
|
2014-06-05 23:03:27 +08:00
|
|
|
server->in_flight++;
|
2019-09-10 11:57:11 +08:00
|
|
|
if (server->in_flight > server->max_in_flight)
|
|
|
|
server->max_in_flight = server->in_flight;
|
2014-06-05 23:03:27 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-02-04 15:20:46 +08:00
|
|
|
scredits = server->credits;
|
|
|
|
in_flight = server->in_flight;
|
2014-06-05 23:03:27 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
2020-11-13 00:56:49 +08:00
|
|
|
|
|
|
|
trace_smb3_add_credits(server->CurrentMid,
|
2021-02-04 15:20:46 +08:00
|
|
|
server->conn_id, server->hostname, scredits, -(credits->value), in_flight);
|
2020-11-13 00:56:49 +08:00
|
|
|
cifs_dbg(FYI, "%s: removed %u credits total=%d\n",
|
|
|
|
__func__, credits->value, scredits);
|
|
|
|
|
2014-06-05 23:03:27 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-01-24 10:15:52 +08:00
|
|
|
static int
|
|
|
|
smb2_adjust_credits(struct TCP_Server_Info *server,
|
|
|
|
struct cifs_credits *credits,
|
|
|
|
const unsigned int payload_size)
|
|
|
|
{
|
|
|
|
int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE);
|
2021-02-04 15:20:46 +08:00
|
|
|
int scredits, in_flight;
|
2019-01-24 10:15:52 +08:00
|
|
|
|
|
|
|
if (!credits->value || credits->value == new_val)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (credits->value < new_val) {
|
2020-11-13 00:56:49 +08:00
|
|
|
trace_smb3_too_many_credits(server->CurrentMid,
|
2021-02-04 15:20:46 +08:00
|
|
|
server->conn_id, server->hostname, 0, credits->value - new_val, 0);
|
2020-11-13 00:56:49 +08:00
|
|
|
cifs_server_dbg(VFS, "request has less credits (%d) than required (%d)",
|
|
|
|
credits->value, new_val);
|
|
|
|
|
2019-01-24 10:15:52 +08:00
|
|
|
return -ENOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock(&server->req_lock);
|
|
|
|
|
|
|
|
if (server->reconnect_instance != credits->instance) {
|
2021-02-04 15:20:46 +08:00
|
|
|
scredits = server->credits;
|
|
|
|
in_flight = server->in_flight;
|
2019-01-24 10:15:52 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
2021-02-04 15:20:46 +08:00
|
|
|
|
2020-11-13 00:56:49 +08:00
|
|
|
trace_smb3_reconnect_detected(server->CurrentMid,
|
2021-02-04 15:20:46 +08:00
|
|
|
server->conn_id, server->hostname, scredits,
|
|
|
|
credits->value - new_val, in_flight);
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "trying to return %d credits to old session\n",
|
2019-01-24 10:15:52 +08:00
|
|
|
credits->value - new_val);
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
|
|
|
|
|
|
|
server->credits += credits->value - new_val;
|
2020-11-13 00:56:49 +08:00
|
|
|
scredits = server->credits;
|
2021-02-04 15:20:46 +08:00
|
|
|
in_flight = server->in_flight;
|
2019-01-24 10:15:52 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
|
|
|
wake_up(&server->request_q);
|
2020-11-13 00:56:49 +08:00
|
|
|
|
|
|
|
trace_smb3_add_credits(server->CurrentMid,
|
2021-02-04 15:20:46 +08:00
|
|
|
server->conn_id, server->hostname, scredits,
|
|
|
|
credits->value - new_val, in_flight);
|
2020-11-13 00:56:49 +08:00
|
|
|
cifs_dbg(FYI, "%s: adjust added %u credits total=%d\n",
|
|
|
|
__func__, credits->value - new_val, scredits);
|
|
|
|
|
2021-02-04 15:20:46 +08:00
|
|
|
credits->value = new_val;
|
|
|
|
|
2019-01-24 10:15:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-12-27 02:53:34 +08:00
|
|
|
static __u64
|
|
|
|
smb2_get_next_mid(struct TCP_Server_Info *server)
|
|
|
|
{
|
|
|
|
__u64 mid;
|
|
|
|
/* for SMB2 we need the current value */
|
|
|
|
spin_lock(&GlobalMid_Lock);
|
|
|
|
mid = server->CurrentMid++;
|
|
|
|
spin_unlock(&GlobalMid_Lock);
|
|
|
|
return mid;
|
|
|
|
}
|
2011-02-25 02:07:19 +08:00
|
|
|
|
2019-03-05 06:02:50 +08:00
|
|
|
static void
|
|
|
|
smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val)
|
|
|
|
{
|
|
|
|
spin_lock(&GlobalMid_Lock);
|
|
|
|
if (server->CurrentMid >= val)
|
|
|
|
server->CurrentMid -= val;
|
|
|
|
spin_unlock(&GlobalMid_Lock);
|
|
|
|
}
|
|
|
|
|
2011-06-08 19:51:07 +08:00
|
|
|
static struct mid_q_entry *
|
2020-10-29 13:03:10 +08:00
|
|
|
__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue)
|
2011-06-08 19:51:07 +08:00
|
|
|
{
|
|
|
|
struct mid_q_entry *mid;
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2016-10-25 06:33:04 +08:00
|
|
|
__u64 wire_mid = le64_to_cpu(shdr->MessageId);
|
2011-06-08 19:51:07 +08:00
|
|
|
|
2016-10-25 06:33:04 +08:00
|
|
|
if (shdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "Encrypted frame parsing not supported yet\n");
|
2015-12-19 03:05:30 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-06-08 19:51:07 +08:00
|
|
|
spin_lock(&GlobalMid_Lock);
|
|
|
|
list_for_each_entry(mid, &server->pending_mid_q, qhead) {
|
2014-12-10 01:37:00 +08:00
|
|
|
if ((mid->mid == wire_mid) &&
|
2011-06-08 19:51:07 +08:00
|
|
|
(mid->mid_state == MID_REQUEST_SUBMITTED) &&
|
2016-10-25 06:33:04 +08:00
|
|
|
(mid->command == shdr->Command)) {
|
2018-06-25 20:05:25 +08:00
|
|
|
kref_get(&mid->refcount);
|
2020-10-29 13:03:10 +08:00
|
|
|
if (dequeue) {
|
|
|
|
list_del_init(&mid->qhead);
|
|
|
|
mid->mid_flags |= MID_DELETED;
|
|
|
|
}
|
2011-06-08 19:51:07 +08:00
|
|
|
spin_unlock(&GlobalMid_Lock);
|
|
|
|
return mid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spin_unlock(&GlobalMid_Lock);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-10-29 13:03:10 +08:00
|
|
|
static struct mid_q_entry *
|
|
|
|
smb2_find_mid(struct TCP_Server_Info *server, char *buf)
|
|
|
|
{
|
|
|
|
return __smb2_find_mid(server, buf, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct mid_q_entry *
|
|
|
|
smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf)
|
|
|
|
{
|
|
|
|
return __smb2_find_mid(server, buf, true);
|
|
|
|
}
|
|
|
|
|
2011-06-08 19:51:07 +08:00
|
|
|
static void
|
2018-04-23 04:45:53 +08:00
|
|
|
smb2_dump_detail(void *buf, struct TCP_Server_Info *server)
|
2011-06-08 19:51:07 +08:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_CIFS_DEBUG2
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2011-06-08 19:51:07 +08:00
|
|
|
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n",
|
2016-10-25 06:33:04 +08:00
|
|
|
shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId,
|
2021-11-05 07:39:01 +08:00
|
|
|
shdr->Id.SyncId.ProcessId);
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "smb buf %p len %u\n", buf,
|
2018-05-07 04:58:51 +08:00
|
|
|
server->ops->calc_smb_size(buf, server));
|
2011-06-08 19:51:07 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2011-12-27 20:12:43 +08:00
|
|
|
static bool
|
|
|
|
smb2_need_neg(struct TCP_Server_Info *server)
|
|
|
|
{
|
|
|
|
return server->max_read == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2021-07-19 21:54:16 +08:00
|
|
|
smb2_negotiate(const unsigned int xid,
|
|
|
|
struct cifs_ses *ses,
|
|
|
|
struct TCP_Server_Info *server)
|
2011-12-27 20:12:43 +08:00
|
|
|
{
|
|
|
|
int rc;
|
2019-05-09 03:36:25 +08:00
|
|
|
|
2021-06-26 02:54:32 +08:00
|
|
|
spin_lock(&GlobalMid_Lock);
|
2021-07-19 21:54:16 +08:00
|
|
|
server->CurrentMid = 0;
|
2021-06-26 02:54:32 +08:00
|
|
|
spin_unlock(&GlobalMid_Lock);
|
2021-07-19 21:54:16 +08:00
|
|
|
rc = SMB2_negotiate(xid, ses, server);
|
2011-12-27 20:12:43 +08:00
|
|
|
/* BB we probably don't need to retry with modern servers */
|
|
|
|
if (rc == -EAGAIN)
|
|
|
|
rc = -EHOSTDOWN;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:28 +08:00
|
|
|
static unsigned int
|
2020-12-10 13:07:12 +08:00
|
|
|
smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
2012-09-19 07:20:28 +08:00
|
|
|
{
|
|
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
|
|
unsigned int wsize;
|
|
|
|
|
|
|
|
/* start with specified wsize, or default */
|
2020-12-10 13:07:12 +08:00
|
|
|
wsize = ctx->wsize ? ctx->wsize : CIFS_DEFAULT_IOSIZE;
|
2012-09-19 07:20:28 +08:00
|
|
|
wsize = min_t(unsigned int, wsize, server->max_write);
|
2014-06-05 23:03:27 +08:00
|
|
|
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
|
|
|
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
2012-09-19 07:20:28 +08:00
|
|
|
|
|
|
|
return wsize;
|
|
|
|
}
|
|
|
|
|
2018-09-26 04:33:47 +08:00
|
|
|
static unsigned int
|
2020-12-10 13:07:12 +08:00
|
|
|
smb3_negotiate_wsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
2018-09-26 04:33:47 +08:00
|
|
|
{
|
|
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
|
|
unsigned int wsize;
|
|
|
|
|
|
|
|
/* start with specified wsize, or default */
|
2020-12-10 13:07:12 +08:00
|
|
|
wsize = ctx->wsize ? ctx->wsize : SMB3_DEFAULT_IOSIZE;
|
2018-09-26 04:33:47 +08:00
|
|
|
wsize = min_t(unsigned int, wsize, server->max_write);
|
|
|
|
#ifdef CONFIG_CIFS_SMB_DIRECT
|
|
|
|
if (server->rdma) {
|
|
|
|
if (server->sign)
|
2020-03-27 10:42:24 +08:00
|
|
|
/*
|
|
|
|
* Account for SMB2 data transfer packet header and
|
|
|
|
* possible encryption header
|
|
|
|
*/
|
2018-09-26 04:33:47 +08:00
|
|
|
wsize = min_t(unsigned int,
|
2020-03-27 10:42:24 +08:00
|
|
|
wsize,
|
|
|
|
server->smbd_conn->max_fragmented_send_size -
|
|
|
|
SMB2_READWRITE_PDU_HEADER_SIZE -
|
|
|
|
sizeof(struct smb2_transform_hdr));
|
2018-09-26 04:33:47 +08:00
|
|
|
else
|
|
|
|
wsize = min_t(unsigned int,
|
|
|
|
wsize, server->smbd_conn->max_readwrite_size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
|
|
|
wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE);
|
|
|
|
|
|
|
|
return wsize;
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:28 +08:00
|
|
|
static unsigned int
|
2020-12-10 13:07:12 +08:00
|
|
|
smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
2012-09-19 07:20:28 +08:00
|
|
|
{
|
|
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
|
|
unsigned int rsize;
|
|
|
|
|
|
|
|
/* start with specified rsize, or default */
|
2020-12-10 13:07:12 +08:00
|
|
|
rsize = ctx->rsize ? ctx->rsize : CIFS_DEFAULT_IOSIZE;
|
2012-09-19 07:20:28 +08:00
|
|
|
rsize = min_t(unsigned int, rsize, server->max_read);
|
2014-06-25 15:28:57 +08:00
|
|
|
|
|
|
|
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
|
|
|
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
2012-09-19 07:20:28 +08:00
|
|
|
|
|
|
|
return rsize;
|
|
|
|
}
|
|
|
|
|
2018-09-26 04:33:47 +08:00
|
|
|
static unsigned int
|
2020-12-10 13:07:12 +08:00
|
|
|
smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
|
2018-09-26 04:33:47 +08:00
|
|
|
{
|
|
|
|
struct TCP_Server_Info *server = tcon->ses->server;
|
|
|
|
unsigned int rsize;
|
|
|
|
|
|
|
|
/* start with specified rsize, or default */
|
2020-12-10 13:07:12 +08:00
|
|
|
rsize = ctx->rsize ? ctx->rsize : SMB3_DEFAULT_IOSIZE;
|
2018-09-26 04:33:47 +08:00
|
|
|
rsize = min_t(unsigned int, rsize, server->max_read);
|
|
|
|
#ifdef CONFIG_CIFS_SMB_DIRECT
|
|
|
|
if (server->rdma) {
|
|
|
|
if (server->sign)
|
2020-03-27 10:42:24 +08:00
|
|
|
/*
|
|
|
|
* Account for SMB2 data transfer packet header and
|
|
|
|
* possible encryption header
|
|
|
|
*/
|
2018-09-26 04:33:47 +08:00
|
|
|
rsize = min_t(unsigned int,
|
2020-03-27 10:42:24 +08:00
|
|
|
rsize,
|
|
|
|
server->smbd_conn->max_fragmented_recv_size -
|
|
|
|
SMB2_READWRITE_PDU_HEADER_SIZE -
|
|
|
|
sizeof(struct smb2_transform_hdr));
|
2018-09-26 04:33:47 +08:00
|
|
|
else
|
|
|
|
rsize = min_t(unsigned int,
|
|
|
|
rsize, server->smbd_conn->max_readwrite_size);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!(server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
|
|
|
|
rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE);
|
|
|
|
|
|
|
|
return rsize;
|
|
|
|
}
|
2018-06-14 23:04:51 +08:00
|
|
|
|
|
|
|
static int
|
|
|
|
parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
|
|
|
|
size_t buf_len,
|
|
|
|
struct cifs_server_iface **iface_list,
|
|
|
|
size_t *iface_count)
|
|
|
|
{
|
|
|
|
struct network_interface_info_ioctl_rsp *p;
|
|
|
|
struct sockaddr_in *addr4;
|
|
|
|
struct sockaddr_in6 *addr6;
|
|
|
|
struct iface_info_ipv4 *p4;
|
|
|
|
struct iface_info_ipv6 *p6;
|
|
|
|
struct cifs_server_iface *info;
|
|
|
|
ssize_t bytes_left;
|
|
|
|
size_t next = 0;
|
|
|
|
int nb_iface = 0;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
*iface_list = NULL;
|
|
|
|
*iface_count = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fist pass: count and sanity check
|
|
|
|
*/
|
|
|
|
|
|
|
|
bytes_left = buf_len;
|
|
|
|
p = buf;
|
|
|
|
while (bytes_left >= sizeof(*p)) {
|
|
|
|
nb_iface++;
|
|
|
|
next = le32_to_cpu(p->Next);
|
|
|
|
if (!next) {
|
|
|
|
bytes_left -= sizeof(*p);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
|
|
|
|
bytes_left -= next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nb_iface) {
|
|
|
|
cifs_dbg(VFS, "%s: malformed interface info\n", __func__);
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2020-12-09 11:13:31 +08:00
|
|
|
/* Azure rounds the buffer size up 8, to a 16 byte boundary */
|
|
|
|
if ((bytes_left > 8) || p->Next)
|
2018-06-14 23:04:51 +08:00
|
|
|
cifs_dbg(VFS, "%s: incomplete interface info\n", __func__);
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Second pass: extract info to internal structure
|
|
|
|
*/
|
|
|
|
|
|
|
|
*iface_list = kcalloc(nb_iface, sizeof(**iface_list), GFP_KERNEL);
|
|
|
|
if (!*iface_list) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
info = *iface_list;
|
|
|
|
bytes_left = buf_len;
|
|
|
|
p = buf;
|
|
|
|
while (bytes_left >= sizeof(*p)) {
|
|
|
|
info->speed = le64_to_cpu(p->LinkSpeed);
|
2021-07-12 18:34:02 +08:00
|
|
|
info->rdma_capable = le32_to_cpu(p->Capability & RDMA_CAPABLE) ? 1 : 0;
|
|
|
|
info->rss_capable = le32_to_cpu(p->Capability & RSS_CAPABLE) ? 1 : 0;
|
2018-06-14 23:04:51 +08:00
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: adding iface %zu\n", __func__, *iface_count);
|
|
|
|
cifs_dbg(FYI, "%s: speed %zu bps\n", __func__, info->speed);
|
|
|
|
cifs_dbg(FYI, "%s: capabilities 0x%08x\n", __func__,
|
|
|
|
le32_to_cpu(p->Capability));
|
|
|
|
|
|
|
|
switch (p->Family) {
|
|
|
|
/*
|
|
|
|
* The kernel and wire socket structures have the same
|
|
|
|
* layout and use network byte order but make the
|
|
|
|
* conversion explicit in case either one changes.
|
|
|
|
*/
|
|
|
|
case INTERNETWORK:
|
|
|
|
addr4 = (struct sockaddr_in *)&info->sockaddr;
|
|
|
|
p4 = (struct iface_info_ipv4 *)p->Buffer;
|
|
|
|
addr4->sin_family = AF_INET;
|
|
|
|
memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
|
|
|
|
|
|
|
|
/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
|
|
|
|
addr4->sin_port = cpu_to_be16(CIFS_PORT);
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
|
|
|
|
&addr4->sin_addr);
|
|
|
|
break;
|
|
|
|
case INTERNETWORKV6:
|
|
|
|
addr6 = (struct sockaddr_in6 *)&info->sockaddr;
|
|
|
|
p6 = (struct iface_info_ipv6 *)p->Buffer;
|
|
|
|
addr6->sin6_family = AF_INET6;
|
|
|
|
memcpy(&addr6->sin6_addr, &p6->IPv6Address, 16);
|
|
|
|
|
|
|
|
/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
|
|
|
|
addr6->sin6_flowinfo = 0;
|
|
|
|
addr6->sin6_scope_id = 0;
|
|
|
|
addr6->sin6_port = cpu_to_be16(CIFS_PORT);
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
|
|
|
|
&addr6->sin6_addr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cifs_dbg(VFS,
|
|
|
|
"%s: skipping unsupported socket family\n",
|
|
|
|
__func__);
|
|
|
|
goto next_iface;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*iface_count)++;
|
|
|
|
info++;
|
|
|
|
next_iface:
|
|
|
|
next = le32_to_cpu(p->Next);
|
|
|
|
if (!next)
|
|
|
|
break;
|
|
|
|
p = (struct network_interface_info_ioctl_rsp *)((u8 *)p+next);
|
|
|
|
bytes_left -= next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!*iface_count) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
if (rc) {
|
|
|
|
kfree(*iface_list);
|
|
|
|
*iface_count = 0;
|
|
|
|
*iface_list = NULL;
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-09-20 12:29:39 +08:00
|
|
|
static int compare_iface(const void *ia, const void *ib)
|
|
|
|
{
|
|
|
|
const struct cifs_server_iface *a = (struct cifs_server_iface *)ia;
|
|
|
|
const struct cifs_server_iface *b = (struct cifs_server_iface *)ib;
|
|
|
|
|
|
|
|
return a->speed == b->speed ? 0 : (a->speed > b->speed ? -1 : 1);
|
|
|
|
}
|
2018-06-14 23:04:51 +08:00
|
|
|
|
2013-10-14 14:21:53 +08:00
|
|
|
static int
|
|
|
|
SMB3_request_interfaces(const unsigned int xid, struct cifs_tcon *tcon)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned int ret_data_len = 0;
|
2018-06-14 23:04:51 +08:00
|
|
|
struct network_interface_info_ioctl_rsp *out_buf = NULL;
|
|
|
|
struct cifs_server_iface *iface_list;
|
|
|
|
size_t iface_count;
|
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2013-10-14 14:21:53 +08:00
|
|
|
|
|
|
|
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
|
|
|
|
FSCTL_QUERY_NETWORK_INTERFACE_INFO, true /* is_fsctl */,
|
|
|
|
NULL /* no data input */, 0 /* no data input */,
|
2019-03-29 11:32:49 +08:00
|
|
|
CIFSMaxBufSize, (char **)&out_buf, &ret_data_len);
|
2018-06-29 11:53:39 +08:00
|
|
|
if (rc == -EOPNOTSUPP) {
|
|
|
|
cifs_dbg(FYI,
|
|
|
|
"server does not support query network interfaces\n");
|
|
|
|
goto out;
|
|
|
|
} else if (rc != 0) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_tcon_dbg(VFS, "error %d on ioctl to get interface list\n", rc);
|
2018-06-14 23:04:51 +08:00
|
|
|
goto out;
|
2014-10-17 04:13:14 +08:00
|
|
|
}
|
2018-06-14 23:04:51 +08:00
|
|
|
|
|
|
|
rc = parse_server_interfaces(out_buf, ret_data_len,
|
|
|
|
&iface_list, &iface_count);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
2019-09-20 12:29:39 +08:00
|
|
|
/* sort interfaces from fastest to slowest */
|
|
|
|
sort(iface_list, iface_count, sizeof(*iface_list), compare_iface, NULL);
|
|
|
|
|
2018-06-14 23:04:51 +08:00
|
|
|
spin_lock(&ses->iface_lock);
|
|
|
|
kfree(ses->iface_list);
|
|
|
|
ses->iface_list = iface_list;
|
|
|
|
ses->iface_count = iface_count;
|
|
|
|
ses->iface_last_update = jiffies;
|
|
|
|
spin_unlock(&ses->iface_lock);
|
|
|
|
|
|
|
|
out:
|
2016-09-29 17:20:23 +08:00
|
|
|
kfree(out_buf);
|
2013-10-14 14:21:53 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-07-31 06:48:22 +08:00
|
|
|
static void
|
|
|
|
smb2_close_cached_fid(struct kref *ref)
|
2018-06-14 04:48:35 +08:00
|
|
|
{
|
2018-07-31 06:48:22 +08:00
|
|
|
struct cached_fid *cfid = container_of(ref, struct cached_fid,
|
|
|
|
refcount);
|
|
|
|
|
2018-06-14 04:48:35 +08:00
|
|
|
if (cfid->is_valid) {
|
|
|
|
cifs_dbg(FYI, "clear cached root file handle\n");
|
|
|
|
SMB2_close(0, cfid->tcon, cfid->fid->persistent_fid,
|
|
|
|
cfid->fid->volatile_fid);
|
2021-09-10 05:46:45 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We only check validity above to send SMB2_close,
|
|
|
|
* but we still need to invalidate these entries
|
|
|
|
* when this function is called
|
|
|
|
*/
|
|
|
|
cfid->is_valid = false;
|
|
|
|
cfid->file_all_info_is_valid = false;
|
|
|
|
cfid->has_lease = false;
|
|
|
|
if (cfid->dentry) {
|
|
|
|
dput(cfid->dentry);
|
|
|
|
cfid->dentry = NULL;
|
2018-06-14 04:48:35 +08:00
|
|
|
}
|
2018-07-31 06:48:22 +08:00
|
|
|
}
|
|
|
|
|
2021-03-09 07:07:29 +08:00
|
|
|
void close_cached_dir(struct cached_fid *cfid)
|
2018-07-31 06:48:22 +08:00
|
|
|
{
|
|
|
|
mutex_lock(&cfid->fid_mutex);
|
|
|
|
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
2018-06-14 04:48:35 +08:00
|
|
|
mutex_unlock(&cfid->fid_mutex);
|
|
|
|
}
|
|
|
|
|
2021-03-09 07:07:29 +08:00
|
|
|
void close_cached_dir_lease_locked(struct cached_fid *cfid)
|
2019-12-11 03:44:52 +08:00
|
|
|
{
|
|
|
|
if (cfid->has_lease) {
|
|
|
|
cfid->has_lease = false;
|
|
|
|
kref_put(&cfid->refcount, smb2_close_cached_fid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-09 07:07:29 +08:00
|
|
|
void close_cached_dir_lease(struct cached_fid *cfid)
|
2019-12-11 03:44:52 +08:00
|
|
|
{
|
|
|
|
mutex_lock(&cfid->fid_mutex);
|
2021-03-09 07:07:29 +08:00
|
|
|
close_cached_dir_lease_locked(cfid);
|
2019-12-11 03:44:52 +08:00
|
|
|
mutex_unlock(&cfid->fid_mutex);
|
|
|
|
}
|
|
|
|
|
2018-07-31 06:48:22 +08:00
|
|
|
void
|
|
|
|
smb2_cached_lease_break(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct cached_fid *cfid = container_of(work,
|
|
|
|
struct cached_fid, lease_break);
|
|
|
|
|
2021-03-09 07:07:29 +08:00
|
|
|
close_cached_dir_lease(cfid);
|
2018-07-31 06:48:22 +08:00
|
|
|
}
|
|
|
|
|
2018-04-26 11:19:09 +08:00
|
|
|
/*
|
2021-03-09 07:07:29 +08:00
|
|
|
* Open the and cache a directory handle.
|
|
|
|
* Only supported for the root handle.
|
2018-04-26 11:19:09 +08:00
|
|
|
*/
|
2021-03-09 07:07:29 +08:00
|
|
|
int open_cached_dir(unsigned int xid, struct cifs_tcon *tcon,
|
2021-03-09 07:07:28 +08:00
|
|
|
const char *path,
|
2020-10-05 10:37:52 +08:00
|
|
|
struct cifs_sb_info *cifs_sb,
|
|
|
|
struct cached_fid **cfid)
|
2018-04-26 11:19:09 +08:00
|
|
|
{
|
2019-03-12 11:58:31 +08:00
|
|
|
struct cifs_ses *ses = tcon->ses;
|
|
|
|
struct TCP_Server_Info *server = ses->server;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct smb2_create_rsp *o_rsp = NULL;
|
|
|
|
struct smb2_query_info_rsp *qi_rsp = NULL;
|
|
|
|
int resp_buftype[2];
|
|
|
|
struct smb_rqst rqst[2];
|
|
|
|
struct kvec rsp_iov[2];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct kvec qi_iov[1];
|
|
|
|
int rc, flags = 0;
|
|
|
|
__le16 utf16_path = 0; /* Null - since an open of top of share */
|
2018-06-14 04:48:35 +08:00
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_II;
|
2020-10-05 10:37:52 +08:00
|
|
|
struct cifs_fid *pfid;
|
2021-03-09 07:07:31 +08:00
|
|
|
struct dentry *dentry;
|
2018-04-26 11:19:09 +08:00
|
|
|
|
2021-03-09 07:07:27 +08:00
|
|
|
if (tcon->nohandlecache)
|
|
|
|
return -ENOTSUPP;
|
|
|
|
|
2021-03-09 07:07:30 +08:00
|
|
|
if (cifs_sb->root == NULL)
|
|
|
|
return -ENOENT;
|
|
|
|
|
2021-03-09 07:07:28 +08:00
|
|
|
if (strlen(path))
|
2021-03-09 07:07:30 +08:00
|
|
|
return -ENOENT;
|
2021-03-09 07:07:28 +08:00
|
|
|
|
2021-03-09 07:07:31 +08:00
|
|
|
dentry = cifs_sb->root;
|
|
|
|
|
2018-06-14 04:48:35 +08:00
|
|
|
mutex_lock(&tcon->crfid.fid_mutex);
|
|
|
|
if (tcon->crfid.is_valid) {
|
2018-04-26 11:19:09 +08:00
|
|
|
cifs_dbg(FYI, "found a cached root file handle\n");
|
2020-10-05 10:37:52 +08:00
|
|
|
*cfid = &tcon->crfid;
|
2018-07-31 06:48:22 +08:00
|
|
|
kref_get(&tcon->crfid.refcount);
|
2018-06-14 04:48:35 +08:00
|
|
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
2018-04-26 11:19:09 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-13 06:52:54 +08:00
|
|
|
/*
|
|
|
|
* We do not hold the lock for the open because in case
|
|
|
|
* SMB2_open needs to reconnect, it will end up calling
|
|
|
|
* cifs_mark_open_files_invalid() which takes the lock again
|
|
|
|
* thus causing a deadlock
|
|
|
|
*/
|
|
|
|
|
|
|
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
|
|
|
|
2019-03-12 11:58:31 +08:00
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
2020-04-21 10:44:24 +08:00
|
|
|
if (!server->ops->new_lease_key)
|
|
|
|
return -EIO;
|
|
|
|
|
2020-10-05 10:37:52 +08:00
|
|
|
pfid = tcon->crfid.fid;
|
2020-04-21 10:44:24 +08:00
|
|
|
server->ops->new_lease_key(pfid);
|
|
|
|
|
2019-03-12 11:58:31 +08:00
|
|
|
memset(rqst, 0, sizeof(rqst));
|
|
|
|
resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
|
|
|
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
|
|
|
|
|
|
|
/* Open */
|
|
|
|
memset(&open_iov, 0, sizeof(open_iov));
|
|
|
|
rqst[0].rq_iov = open_iov;
|
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2019-03-12 11:58:31 +08:00
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
|
|
|
oparms.fid = pfid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, &utf16_path);
|
2019-03-12 11:58:31 +08:00
|
|
|
if (rc)
|
2019-09-13 06:52:54 +08:00
|
|
|
goto oshr_free;
|
2019-03-12 11:58:31 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
|
|
|
|
|
|
|
memset(&qi_iov, 0, sizeof(qi_iov));
|
|
|
|
rqst[1].rq_iov = qi_iov;
|
|
|
|
rqst[1].rq_nvec = 1;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[1], COMPOUND_FID,
|
2019-03-12 11:58:31 +08:00
|
|
|
COMPOUND_FID, FILE_ALL_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0,
|
|
|
|
sizeof(struct smb2_file_all_info) +
|
|
|
|
PATH_MAX * 2, 0, NULL);
|
|
|
|
if (rc)
|
2019-09-13 06:52:54 +08:00
|
|
|
goto oshr_free;
|
2019-03-12 11:58:31 +08:00
|
|
|
|
|
|
|
smb2_set_related(&rqst[1]);
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, 2, rqst,
|
2019-03-12 11:58:31 +08:00
|
|
|
resp_buftype, rsp_iov);
|
2019-07-17 18:46:28 +08:00
|
|
|
mutex_lock(&tcon->crfid.fid_mutex);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we need to check again as the cached root might have
|
|
|
|
* been successfully re-opened from a concurrent process
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (tcon->crfid.is_valid) {
|
|
|
|
/* work was already done */
|
|
|
|
|
|
|
|
/* stash fids for close() later */
|
|
|
|
struct cifs_fid fid = {
|
|
|
|
.persistent_fid = pfid->persistent_fid,
|
|
|
|
.volatile_fid = pfid->volatile_fid,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
2021-04-15 23:24:09 +08:00
|
|
|
* caller expects this func to set the fid in crfid to valid
|
|
|
|
* cached root, so increment the refcount.
|
2019-07-17 18:46:28 +08:00
|
|
|
*/
|
|
|
|
kref_get(&tcon->crfid.refcount);
|
|
|
|
|
|
|
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
|
|
|
|
|
|
|
if (rc == 0) {
|
|
|
|
/* close extra handle outside of crit sec */
|
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
|
|
}
|
2020-06-13 20:27:09 +08:00
|
|
|
rc = 0;
|
2019-07-17 18:46:28 +08:00
|
|
|
goto oshr_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cached root is still invalid, continue normaly */
|
|
|
|
|
2019-09-11 13:07:36 +08:00
|
|
|
if (rc) {
|
|
|
|
if (rc == -EREMCHG) {
|
|
|
|
tcon->need_reconnect = true;
|
2020-04-15 13:42:53 +08:00
|
|
|
pr_warn_once("server share %s deleted\n",
|
|
|
|
tcon->treeName);
|
2019-09-11 13:07:36 +08:00
|
|
|
}
|
2019-03-12 11:58:31 +08:00
|
|
|
goto oshr_exit;
|
2019-09-11 13:07:36 +08:00
|
|
|
}
|
2019-03-12 11:58:31 +08:00
|
|
|
|
2019-09-22 13:55:46 +08:00
|
|
|
atomic_inc(&tcon->num_remote_opens);
|
|
|
|
|
2019-03-12 11:58:31 +08:00
|
|
|
o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
|
2022-03-22 00:08:25 +08:00
|
|
|
oparms.fid->persistent_fid = o_rsp->PersistentFileId;
|
|
|
|
oparms.fid->volatile_fid = o_rsp->VolatileFileId;
|
2019-03-12 11:58:31 +08:00
|
|
|
#ifdef CONFIG_CIFS_DEBUG2
|
2021-11-05 07:39:01 +08:00
|
|
|
oparms.fid->mid = le64_to_cpu(o_rsp->hdr.MessageId);
|
2019-03-12 11:58:31 +08:00
|
|
|
#endif /* CIFS_DEBUG2 */
|
|
|
|
|
|
|
|
tcon->crfid.tcon = tcon;
|
|
|
|
tcon->crfid.is_valid = true;
|
2021-03-09 07:07:31 +08:00
|
|
|
tcon->crfid.dentry = dentry;
|
|
|
|
dget(dentry);
|
2019-03-12 11:58:31 +08:00
|
|
|
kref_init(&tcon->crfid.refcount);
|
|
|
|
|
2019-07-19 06:22:18 +08:00
|
|
|
/* BB TBD check to see if oplock level check can be removed below */
|
2019-03-28 09:20:02 +08:00
|
|
|
if (o_rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) {
|
2021-04-15 23:24:09 +08:00
|
|
|
/*
|
|
|
|
* See commit 2f94a3125b87. Increment the refcount when we
|
|
|
|
* get a lease for root, release it if lease break occurs
|
|
|
|
*/
|
2019-03-28 09:20:02 +08:00
|
|
|
kref_get(&tcon->crfid.refcount);
|
2019-12-11 03:44:52 +08:00
|
|
|
tcon->crfid.has_lease = true;
|
2019-07-19 06:22:18 +08:00
|
|
|
smb2_parse_contexts(server, o_rsp,
|
|
|
|
&oparms.fid->epoch,
|
2020-03-03 00:53:22 +08:00
|
|
|
oparms.fid->lease_key, &oplock,
|
|
|
|
NULL, NULL);
|
2019-03-28 09:20:02 +08:00
|
|
|
} else
|
|
|
|
goto oshr_exit;
|
2019-03-12 11:58:31 +08:00
|
|
|
|
|
|
|
qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
|
|
|
if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
|
|
|
|
goto oshr_exit;
|
2019-04-01 07:53:44 +08:00
|
|
|
if (!smb2_validate_and_copy_iov(
|
2019-03-12 11:58:31 +08:00
|
|
|
le16_to_cpu(qi_rsp->OutputBufferOffset),
|
|
|
|
sizeof(struct smb2_file_all_info),
|
|
|
|
&rsp_iov[1], sizeof(struct smb2_file_all_info),
|
2019-04-01 07:53:44 +08:00
|
|
|
(char *)&tcon->crfid.file_all_info))
|
2019-12-25 11:30:20 +08:00
|
|
|
tcon->crfid.file_all_info_is_valid = true;
|
2021-03-09 07:07:33 +08:00
|
|
|
tcon->crfid.time = jiffies;
|
|
|
|
|
2019-03-12 11:58:31 +08:00
|
|
|
|
2019-07-17 18:46:28 +08:00
|
|
|
oshr_exit:
|
2018-06-14 04:48:35 +08:00
|
|
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
2019-07-17 18:46:28 +08:00
|
|
|
oshr_free:
|
2019-03-12 11:58:31 +08:00
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
SMB2_query_info_free(&rqst[1]);
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
2020-10-05 10:37:52 +08:00
|
|
|
if (rc == 0)
|
|
|
|
*cfid = &tcon->crfid;
|
2018-04-26 11:19:09 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-03-09 07:07:32 +08:00
|
|
|
int open_cached_dir_by_dentry(struct cifs_tcon *tcon,
|
|
|
|
struct dentry *dentry,
|
|
|
|
struct cached_fid **cfid)
|
|
|
|
{
|
|
|
|
mutex_lock(&tcon->crfid.fid_mutex);
|
|
|
|
if (tcon->crfid.dentry == dentry) {
|
|
|
|
cifs_dbg(FYI, "found a cached root file handle by dentry\n");
|
|
|
|
*cfid = &tcon->crfid;
|
|
|
|
kref_get(&tcon->crfid.refcount);
|
|
|
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mutex_unlock(&tcon->crfid.fid_mutex);
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2013-10-10 09:55:53 +08:00
|
|
|
static void
|
2020-02-04 03:46:43 +08:00
|
|
|
smb3_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2013-10-10 09:55:53 +08:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le16 srch_path = 0; /* Null - open root of share */
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
2020-10-05 10:37:52 +08:00
|
|
|
struct cached_fid *cfid = NULL;
|
2013-10-10 09:55:53 +08:00
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2013-10-10 09:55:53 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2021-03-09 07:07:29 +08:00
|
|
|
rc = open_cached_dir(xid, tcon, "", cifs_sb, &cfid);
|
2021-03-09 07:07:27 +08:00
|
|
|
if (rc == 0)
|
|
|
|
memcpy(&fid, cfid->fid, sizeof(struct cifs_fid));
|
|
|
|
else
|
2018-06-08 11:21:18 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
|
2020-03-03 00:53:22 +08:00
|
|
|
NULL, NULL);
|
2013-10-10 09:55:53 +08:00
|
|
|
if (rc)
|
|
|
|
return;
|
|
|
|
|
2013-10-14 14:21:53 +08:00
|
|
|
SMB3_request_interfaces(xid, tcon);
|
|
|
|
|
2013-10-10 09:55:53 +08:00
|
|
|
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
FS_ATTRIBUTE_INFORMATION);
|
|
|
|
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
FS_DEVICE_INFORMATION);
|
2018-06-25 12:18:52 +08:00
|
|
|
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
FS_VOLUME_INFORMATION);
|
2013-10-10 09:55:53 +08:00
|
|
|
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
FS_SECTOR_SIZE_INFORMATION); /* SMB3 specific */
|
2021-03-09 07:07:27 +08:00
|
|
|
if (cfid == NULL)
|
2018-04-26 11:19:09 +08:00
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
2018-07-31 06:48:22 +08:00
|
|
|
else
|
2021-03-09 07:07:29 +08:00
|
|
|
close_cached_dir(cfid);
|
2013-10-10 09:55:53 +08:00
|
|
|
}
|
|
|
|
|
2013-10-09 15:07:00 +08:00
|
|
|
static void
|
2020-02-04 03:46:43 +08:00
|
|
|
smb2_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2013-10-09 15:07:00 +08:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le16 srch_path = 0; /* Null - open root of share */
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2013-10-09 15:07:00 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-03-03 00:53:22 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
|
|
|
|
NULL, NULL);
|
2013-10-09 15:07:00 +08:00
|
|
|
if (rc)
|
|
|
|
return;
|
|
|
|
|
2013-10-10 02:36:35 +08:00
|
|
|
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
FS_ATTRIBUTE_INFORMATION);
|
|
|
|
SMB2_QFS_attr(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
FS_DEVICE_INFORMATION);
|
2013-10-09 15:07:00 +08:00
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
|
|
}
|
|
|
|
|
2011-12-27 02:58:46 +08:00
|
|
|
static int
|
|
|
|
smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le16 *utf16_path;
|
2012-09-19 07:20:33 +08:00
|
|
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
2013-07-09 22:20:30 +08:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
2011-12-27 02:58:46 +08:00
|
|
|
|
2018-06-14 04:48:35 +08:00
|
|
|
if ((*full_path == 0) && tcon->crfid.is_valid)
|
2018-04-26 11:19:09 +08:00
|
|
|
return 0;
|
|
|
|
|
2011-12-27 02:58:46 +08:00
|
|
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
|
|
|
if (!utf16_path)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2013-07-09 22:20:30 +08:00
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2013-07-09 22:20:30 +08:00
|
|
|
oparms.fid = &fid;
|
2013-07-09 22:40:58 +08:00
|
|
|
oparms.reconnect = false;
|
2013-07-09 22:20:30 +08:00
|
|
|
|
2020-03-03 00:53:22 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
|
|
|
|
NULL);
|
2011-12-27 02:58:46 +08:00
|
|
|
if (rc) {
|
|
|
|
kfree(utf16_path);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-07-09 22:20:30 +08:00
|
|
|
rc = SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
2011-12-27 02:58:46 +08:00
|
|
|
kfree(utf16_path);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2011-12-29 21:06:33 +08:00
|
|
|
static int
|
|
|
|
smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
|
|
|
u64 *uniqueid, FILE_ALL_INFO *data)
|
|
|
|
{
|
|
|
|
*uniqueid = le64_to_cpu(data->IndexNumber);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:27 +08:00
|
|
|
static int
|
|
|
|
smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_fid *fid, FILE_ALL_INFO *data)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct smb2_file_all_info *smb2_data;
|
|
|
|
|
2014-08-22 17:32:11 +08:00
|
|
|
smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + PATH_MAX * 2,
|
2012-09-19 07:20:27 +08:00
|
|
|
GFP_KERNEL);
|
|
|
|
if (smb2_data == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid,
|
|
|
|
smb2_data);
|
|
|
|
if (!rc)
|
|
|
|
move_smb2_info_to_cifs(data, smb2_data);
|
|
|
|
kfree(smb2_data);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-09-05 17:24:15 +08:00
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
2017-08-24 09:24:55 +08:00
|
|
|
static ssize_t
|
|
|
|
move_smb2_ea_to_cifs(char *dst, size_t dst_size,
|
|
|
|
struct smb2_file_full_ea_info *src, size_t src_size,
|
|
|
|
const unsigned char *ea_name)
|
|
|
|
{
|
|
|
|
int rc = 0;
|
|
|
|
unsigned int ea_name_len = ea_name ? strlen(ea_name) : 0;
|
|
|
|
char *name, *value;
|
2018-10-25 13:43:36 +08:00
|
|
|
size_t buf_size = dst_size;
|
2017-08-24 09:24:55 +08:00
|
|
|
size_t name_len, value_len, user_name_len;
|
|
|
|
|
|
|
|
while (src_size > 0) {
|
|
|
|
name = &src->ea_data[0];
|
|
|
|
name_len = (size_t)src->ea_name_length;
|
|
|
|
value = &src->ea_data[src->ea_name_length + 1];
|
|
|
|
value_len = (size_t)le16_to_cpu(src->ea_value_length);
|
|
|
|
|
2019-05-09 03:36:25 +08:00
|
|
|
if (name_len == 0)
|
2017-08-24 09:24:55 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
if (src_size < 8 + name_len + 1 + value_len) {
|
|
|
|
cifs_dbg(FYI, "EA entry goes beyond length of list\n");
|
|
|
|
rc = -EIO;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ea_name) {
|
|
|
|
if (ea_name_len == name_len &&
|
|
|
|
memcmp(ea_name, name, name_len) == 0) {
|
|
|
|
rc = value_len;
|
|
|
|
if (dst_size == 0)
|
|
|
|
goto out;
|
|
|
|
if (dst_size < value_len) {
|
|
|
|
rc = -ERANGE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
memcpy(dst, value, value_len);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* 'user.' plus a terminating null */
|
|
|
|
user_name_len = 5 + 1 + name_len;
|
|
|
|
|
2018-10-25 13:43:36 +08:00
|
|
|
if (buf_size == 0) {
|
|
|
|
/* skip copy - calc size only */
|
|
|
|
rc += user_name_len;
|
|
|
|
} else if (dst_size >= user_name_len) {
|
2017-08-24 09:24:55 +08:00
|
|
|
dst_size -= user_name_len;
|
|
|
|
memcpy(dst, "user.", 5);
|
|
|
|
dst += 5;
|
|
|
|
memcpy(dst, src->ea_data, name_len);
|
|
|
|
dst += name_len;
|
|
|
|
*dst = 0;
|
|
|
|
++dst;
|
2018-10-25 13:43:36 +08:00
|
|
|
rc += user_name_len;
|
2017-08-24 09:24:55 +08:00
|
|
|
} else {
|
|
|
|
/* stop before overrun buffer */
|
|
|
|
rc = -ERANGE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!src->next_entry_offset)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (src_size < le32_to_cpu(src->next_entry_offset)) {
|
|
|
|
/* stop before overrun buffer */
|
|
|
|
rc = -ERANGE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
src_size -= le32_to_cpu(src->next_entry_offset);
|
|
|
|
src = (void *)((char *)src +
|
|
|
|
le32_to_cpu(src->next_entry_offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* didn't find the named attribute */
|
|
|
|
if (ea_name)
|
|
|
|
rc = -ENODATA;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return (ssize_t)rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t
|
|
|
|
smb2_query_eas(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const unsigned char *path, const unsigned char *ea_name,
|
|
|
|
char *ea_data, size_t buf_size,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
|
|
|
int rc;
|
2018-11-27 07:52:04 +08:00
|
|
|
struct kvec rsp_iov = {NULL, 0};
|
|
|
|
int buftype = CIFS_NO_BUFFER;
|
|
|
|
struct smb2_query_info_rsp *rsp;
|
|
|
|
struct smb2_file_full_ea_info *info = NULL;
|
2017-08-24 09:24:55 +08:00
|
|
|
|
2022-03-22 14:29:02 +08:00
|
|
|
rc = smb2_query_info_compound(xid, tcon, path,
|
2018-11-27 07:52:04 +08:00
|
|
|
FILE_READ_EA,
|
|
|
|
FILE_FULL_EA_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE,
|
2019-01-29 10:46:17 +08:00
|
|
|
CIFSMaxBufSize -
|
|
|
|
MAX_SMB2_CREATE_RESPONSE_SIZE -
|
|
|
|
MAX_SMB2_CLOSE_RESPONSE_SIZE,
|
2018-11-27 07:52:04 +08:00
|
|
|
&rsp_iov, &buftype, cifs_sb);
|
2017-08-24 09:24:55 +08:00
|
|
|
if (rc) {
|
2018-11-27 07:52:04 +08:00
|
|
|
/*
|
|
|
|
* If ea_name is NULL (listxattr) and there are no EAs,
|
|
|
|
* return 0 as it's not an error. Otherwise, the specified
|
|
|
|
* ea_name was not found.
|
|
|
|
*/
|
|
|
|
if (!ea_name && rc == -ENODATA)
|
|
|
|
rc = 0;
|
|
|
|
goto qeas_exit;
|
2017-08-24 09:24:55 +08:00
|
|
|
}
|
|
|
|
|
2018-11-27 07:52:04 +08:00
|
|
|
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
|
|
|
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
|
|
|
le32_to_cpu(rsp->OutputBufferLength),
|
|
|
|
&rsp_iov,
|
|
|
|
sizeof(struct smb2_file_full_ea_info));
|
|
|
|
if (rc)
|
|
|
|
goto qeas_exit;
|
2017-08-24 09:24:55 +08:00
|
|
|
|
2018-11-27 07:52:04 +08:00
|
|
|
info = (struct smb2_file_full_ea_info *)(
|
|
|
|
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
|
|
|
rc = move_smb2_ea_to_cifs(ea_data, buf_size, info,
|
|
|
|
le32_to_cpu(rsp->OutputBufferLength), ea_name);
|
2017-08-24 09:24:55 +08:00
|
|
|
|
2018-11-27 07:52:04 +08:00
|
|
|
qeas_exit:
|
|
|
|
free_rsp_buf(buftype, rsp_iov.iov_base);
|
2017-08-24 09:24:55 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-08-24 09:24:56 +08:00
|
|
|
|
|
|
|
static int
|
|
|
|
smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *path, const char *ea_name, const void *ea_value,
|
|
|
|
const __u16 ea_value_len, const struct nls_table *nls_codepage,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
2018-11-06 20:52:43 +08:00
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2020-06-01 01:38:22 +08:00
|
|
|
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
2018-11-06 20:52:43 +08:00
|
|
|
__le16 *utf16_path = NULL;
|
2017-08-24 09:24:56 +08:00
|
|
|
int ea_name_len = strlen(ea_name);
|
2021-03-08 23:00:50 +08:00
|
|
|
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
2017-08-24 09:24:56 +08:00
|
|
|
int len;
|
2018-11-06 20:52:43 +08:00
|
|
|
struct smb_rqst rqst[3];
|
|
|
|
int resp_buftype[3];
|
|
|
|
struct kvec rsp_iov[3];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
|
|
|
unsigned int size[1];
|
|
|
|
void *data[1];
|
|
|
|
struct smb2_file_full_ea_info *ea = NULL;
|
|
|
|
struct kvec close_iov[1];
|
2020-02-13 10:14:47 +08:00
|
|
|
struct smb2_query_info_rsp *rsp;
|
|
|
|
int rc, used_len = 0;
|
2018-11-06 20:52:43 +08:00
|
|
|
|
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
2017-08-24 09:24:56 +08:00
|
|
|
|
|
|
|
if (ea_name_len > 255)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
|
|
|
if (!utf16_path)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2018-11-06 20:52:43 +08:00
|
|
|
memset(rqst, 0, sizeof(rqst));
|
|
|
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
|
|
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
|
|
|
|
2019-02-07 13:48:44 +08:00
|
|
|
if (ses->server->ops->query_all_EAs) {
|
|
|
|
if (!ea_value) {
|
|
|
|
rc = ses->server->ops->query_all_EAs(xid, tcon, path,
|
|
|
|
ea_name, NULL, 0,
|
|
|
|
cifs_sb);
|
|
|
|
if (rc == -ENODATA)
|
|
|
|
goto sea_exit;
|
2020-02-13 10:14:47 +08:00
|
|
|
} else {
|
|
|
|
/* If we are adding a attribute we should first check
|
|
|
|
* if there will be enough space available to store
|
|
|
|
* the new EA. If not we should not add it since we
|
|
|
|
* would not be able to even read the EAs back.
|
|
|
|
*/
|
2022-03-22 14:29:02 +08:00
|
|
|
rc = smb2_query_info_compound(xid, tcon, path,
|
2020-02-13 10:14:47 +08:00
|
|
|
FILE_READ_EA,
|
|
|
|
FILE_FULL_EA_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE,
|
|
|
|
CIFSMaxBufSize -
|
|
|
|
MAX_SMB2_CREATE_RESPONSE_SIZE -
|
|
|
|
MAX_SMB2_CLOSE_RESPONSE_SIZE,
|
|
|
|
&rsp_iov[1], &resp_buftype[1], cifs_sb);
|
|
|
|
if (rc == 0) {
|
|
|
|
rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
|
|
|
used_len = le32_to_cpu(rsp->OutputBufferLength);
|
|
|
|
}
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
|
|
resp_buftype[1] = CIFS_NO_BUFFER;
|
|
|
|
memset(&rsp_iov[1], 0, sizeof(rsp_iov[1]));
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
/* Use a fudge factor of 256 bytes in case we collide
|
|
|
|
* with a different set_EAs command.
|
|
|
|
*/
|
|
|
|
if(CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE -
|
|
|
|
MAX_SMB2_CLOSE_RESPONSE_SIZE - 256 <
|
|
|
|
used_len + ea_name_len + ea_value_len + 1) {
|
|
|
|
rc = -ENOSPC;
|
|
|
|
goto sea_exit;
|
|
|
|
}
|
2019-02-07 13:48:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-06 20:52:43 +08:00
|
|
|
/* Open */
|
|
|
|
memset(&open_iov, 0, sizeof(open_iov));
|
|
|
|
rqst[0].rq_iov = open_iov;
|
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
|
|
|
|
|
|
|
memset(&oparms, 0, sizeof(oparms));
|
2017-08-24 09:24:56 +08:00
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_WRITE_EA;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2017-08-24 09:24:56 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, utf16_path);
|
2018-11-06 20:52:43 +08:00
|
|
|
if (rc)
|
|
|
|
goto sea_exit;
|
2018-12-31 11:43:40 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
2018-11-06 20:52:43 +08:00
|
|
|
|
|
|
|
|
|
|
|
/* Set Info */
|
|
|
|
memset(&si_iov, 0, sizeof(si_iov));
|
|
|
|
rqst[1].rq_iov = si_iov;
|
|
|
|
rqst[1].rq_nvec = 1;
|
2017-08-24 09:24:56 +08:00
|
|
|
|
2020-10-11 02:25:54 +08:00
|
|
|
len = sizeof(*ea) + ea_name_len + ea_value_len + 1;
|
2017-08-24 09:24:56 +08:00
|
|
|
ea = kzalloc(len, GFP_KERNEL);
|
|
|
|
if (ea == NULL) {
|
2018-11-06 20:52:43 +08:00
|
|
|
rc = -ENOMEM;
|
|
|
|
goto sea_exit;
|
2017-08-24 09:24:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ea->ea_name_length = ea_name_len;
|
|
|
|
ea->ea_value_length = cpu_to_le16(ea_value_len);
|
|
|
|
memcpy(ea->ea_data, ea_name, ea_name_len + 1);
|
|
|
|
memcpy(ea->ea_data + ea_name_len + 1, ea_value, ea_value_len);
|
|
|
|
|
2018-11-06 20:52:43 +08:00
|
|
|
size[0] = len;
|
|
|
|
data[0] = ea;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_set_info_init(tcon, server,
|
|
|
|
&rqst[1], COMPOUND_FID,
|
2018-11-06 20:52:43 +08:00
|
|
|
COMPOUND_FID, current->tgid,
|
|
|
|
FILE_FULL_EA_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
2018-12-31 11:43:40 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[1]);
|
2018-11-06 20:52:43 +08:00
|
|
|
smb2_set_related(&rqst[1]);
|
2018-07-05 01:16:16 +08:00
|
|
|
|
2017-08-24 09:24:56 +08:00
|
|
|
|
2018-11-06 20:52:43 +08:00
|
|
|
/* Close */
|
|
|
|
memset(&close_iov, 0, sizeof(close_iov));
|
|
|
|
rqst[2].rq_iov = close_iov;
|
|
|
|
rqst[2].rq_nvec = 1;
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
2018-11-06 20:52:43 +08:00
|
|
|
smb2_set_related(&rqst[2]);
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, 3, rqst,
|
2018-11-06 20:52:43 +08:00
|
|
|
resp_buftype, rsp_iov);
|
2019-09-22 13:55:46 +08:00
|
|
|
/* no need to bump num_remote_opens because handle immediately closed */
|
2018-11-06 20:52:43 +08:00
|
|
|
|
|
|
|
sea_exit:
|
|
|
|
kfree(ea);
|
|
|
|
kfree(utf16_path);
|
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
SMB2_set_info_free(&rqst[1]);
|
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
2017-08-24 09:24:56 +08:00
|
|
|
return rc;
|
|
|
|
}
|
2017-09-05 17:24:15 +08:00
|
|
|
#endif
|
2017-08-24 09:24:56 +08:00
|
|
|
|
2012-07-12 22:30:44 +08:00
|
|
|
static bool
|
|
|
|
smb2_can_echo(struct TCP_Server_Info *server)
|
|
|
|
{
|
|
|
|
return server->echoes;
|
|
|
|
}
|
|
|
|
|
2012-05-28 19:19:39 +08:00
|
|
|
static void
|
|
|
|
smb2_clear_stats(struct cifs_tcon *tcon)
|
|
|
|
{
|
|
|
|
int i;
|
2019-05-09 03:36:25 +08:00
|
|
|
|
2012-05-28 19:19:39 +08:00
|
|
|
for (i = 0; i < NUMBER_OF_SMB2_COMMANDS; i++) {
|
|
|
|
atomic_set(&tcon->stats.smb2_stats.smb2_com_sent[i], 0);
|
|
|
|
atomic_set(&tcon->stats.smb2_stats.smb2_com_failed[i], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-20 03:15:30 +08:00
|
|
|
static void
|
|
|
|
smb2_dump_share_caps(struct seq_file *m, struct cifs_tcon *tcon)
|
|
|
|
{
|
|
|
|
seq_puts(m, "\n\tShare Capabilities:");
|
|
|
|
if (tcon->capabilities & SMB2_SHARE_CAP_DFS)
|
|
|
|
seq_puts(m, " DFS,");
|
|
|
|
if (tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
|
|
|
|
seq_puts(m, " CONTINUOUS AVAILABILITY,");
|
|
|
|
if (tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT)
|
|
|
|
seq_puts(m, " SCALEOUT,");
|
|
|
|
if (tcon->capabilities & SMB2_SHARE_CAP_CLUSTER)
|
|
|
|
seq_puts(m, " CLUSTER,");
|
|
|
|
if (tcon->capabilities & SMB2_SHARE_CAP_ASYMMETRIC)
|
|
|
|
seq_puts(m, " ASYMMETRIC,");
|
|
|
|
if (tcon->capabilities == 0)
|
|
|
|
seq_puts(m, " None");
|
2013-10-10 09:55:53 +08:00
|
|
|
if (tcon->ss_flags & SSINFO_FLAGS_ALIGNED_DEVICE)
|
|
|
|
seq_puts(m, " Aligned,");
|
|
|
|
if (tcon->ss_flags & SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE)
|
|
|
|
seq_puts(m, " Partition Aligned,");
|
|
|
|
if (tcon->ss_flags & SSINFO_FLAGS_NO_SEEK_PENALTY)
|
|
|
|
seq_puts(m, " SSD,");
|
|
|
|
if (tcon->ss_flags & SSINFO_FLAGS_TRIM_ENABLED)
|
|
|
|
seq_puts(m, " TRIM-support,");
|
|
|
|
|
2013-06-20 03:15:30 +08:00
|
|
|
seq_printf(m, "\tShare Flags: 0x%x", tcon->share_flags);
|
2018-05-20 14:27:03 +08:00
|
|
|
seq_printf(m, "\n\ttid: 0x%x", tcon->tid);
|
2013-10-10 09:55:53 +08:00
|
|
|
if (tcon->perf_sector_size)
|
|
|
|
seq_printf(m, "\tOptimal sector size: 0x%x",
|
|
|
|
tcon->perf_sector_size);
|
2018-05-20 14:27:03 +08:00
|
|
|
seq_printf(m, "\tMaximal Access: 0x%x", tcon->maximal_access);
|
2013-06-20 03:15:30 +08:00
|
|
|
}
|
|
|
|
|
2012-05-28 19:19:39 +08:00
|
|
|
static void
|
|
|
|
smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
|
|
|
|
{
|
|
|
|
atomic_t *sent = tcon->stats.smb2_stats.smb2_com_sent;
|
|
|
|
atomic_t *failed = tcon->stats.smb2_stats.smb2_com_failed;
|
2018-07-28 04:14:04 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Can't display SMB2_NEGOTIATE, SESSION_SETUP, LOGOFF, CANCEL and ECHO
|
|
|
|
* totals (requests sent) since those SMBs are per-session not per tcon
|
|
|
|
*/
|
2018-07-31 14:46:47 +08:00
|
|
|
seq_printf(m, "\nBytes read: %llu Bytes written: %llu",
|
|
|
|
(long long)(tcon->bytes_read),
|
|
|
|
(long long)(tcon->bytes_written));
|
2018-10-20 06:14:32 +08:00
|
|
|
seq_printf(m, "\nOpen files: %d total (local), %d open on server",
|
|
|
|
atomic_read(&tcon->num_local_opens),
|
|
|
|
atomic_read(&tcon->num_remote_opens));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nTreeConnects: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_TREE_CONNECT_HE]),
|
|
|
|
atomic_read(&failed[SMB2_TREE_CONNECT_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nTreeDisconnects: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_TREE_DISCONNECT_HE]),
|
|
|
|
atomic_read(&failed[SMB2_TREE_DISCONNECT_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nCreates: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_CREATE_HE]),
|
|
|
|
atomic_read(&failed[SMB2_CREATE_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nCloses: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_CLOSE_HE]),
|
|
|
|
atomic_read(&failed[SMB2_CLOSE_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nFlushes: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_FLUSH_HE]),
|
|
|
|
atomic_read(&failed[SMB2_FLUSH_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nReads: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_READ_HE]),
|
|
|
|
atomic_read(&failed[SMB2_READ_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nWrites: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_WRITE_HE]),
|
|
|
|
atomic_read(&failed[SMB2_WRITE_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nLocks: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_LOCK_HE]),
|
|
|
|
atomic_read(&failed[SMB2_LOCK_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nIOCTLs: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_IOCTL_HE]),
|
|
|
|
atomic_read(&failed[SMB2_IOCTL_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nQueryDirectories: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_QUERY_DIRECTORY_HE]),
|
|
|
|
atomic_read(&failed[SMB2_QUERY_DIRECTORY_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nChangeNotifies: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_CHANGE_NOTIFY_HE]),
|
|
|
|
atomic_read(&failed[SMB2_CHANGE_NOTIFY_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nQueryInfos: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_QUERY_INFO_HE]),
|
|
|
|
atomic_read(&failed[SMB2_QUERY_INFO_HE]));
|
2018-07-28 04:14:04 +08:00
|
|
|
seq_printf(m, "\nSetInfos: %d total %d failed",
|
2012-05-28 19:19:39 +08:00
|
|
|
atomic_read(&sent[SMB2_SET_INFO_HE]),
|
|
|
|
atomic_read(&failed[SMB2_SET_INFO_HE]));
|
|
|
|
seq_printf(m, "\nOplockBreaks: %d sent %d failed",
|
|
|
|
atomic_read(&sent[SMB2_OPLOCK_BREAK_HE]),
|
|
|
|
atomic_read(&failed[SMB2_OPLOCK_BREAK_HE]));
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:26 +08:00
|
|
|
static void
|
|
|
|
smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
|
|
|
|
{
|
2015-03-18 06:25:59 +08:00
|
|
|
struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry));
|
2013-09-05 20:11:28 +08:00
|
|
|
struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
|
|
|
|
|
2012-09-19 07:20:26 +08:00
|
|
|
cfile->fid.persistent_fid = fid->persistent_fid;
|
|
|
|
cfile->fid.volatile_fid = fid->volatile_fid;
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 18:19:06 +08:00
|
|
|
cfile->fid.access = fid->access;
|
2018-10-31 08:50:31 +08:00
|
|
|
#ifdef CONFIG_CIFS_DEBUG2
|
|
|
|
cfile->fid.mid = fid->mid;
|
|
|
|
#endif /* CIFS_DEBUG2 */
|
2013-09-06 01:30:16 +08:00
|
|
|
server->ops->set_oplock_level(cinode, oplock, fid->epoch,
|
|
|
|
&fid->purge_cache);
|
2013-09-05 17:01:06 +08:00
|
|
|
cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
|
2016-09-22 13:38:50 +08:00
|
|
|
memcpy(cfile->fid.create_guid, fid->create_guid, 16);
|
2012-09-19 07:20:26 +08:00
|
|
|
}
|
|
|
|
|
2012-09-25 15:00:07 +08:00
|
|
|
static void
|
2012-09-19 07:20:26 +08:00
|
|
|
smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_fid *fid)
|
|
|
|
{
|
2012-09-25 15:00:07 +08:00
|
|
|
SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
|
2012-09-19 07:20:26 +08:00
|
|
|
}
|
|
|
|
|
2019-12-03 11:46:54 +08:00
|
|
|
static void
|
|
|
|
smb2_close_getattr(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile)
|
|
|
|
{
|
|
|
|
struct smb2_file_network_open_info file_inf;
|
|
|
|
struct inode *inode;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = __SMB2_close(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, &file_inf);
|
|
|
|
if (rc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
inode = d_inode(cfile->dentry);
|
|
|
|
|
|
|
|
spin_lock(&inode->i_lock);
|
|
|
|
CIFS_I(inode)->time = jiffies;
|
|
|
|
|
|
|
|
/* Creation time should not need to be updated on close */
|
|
|
|
if (file_inf.LastWriteTime)
|
|
|
|
inode->i_mtime = cifs_NTtimeToUnix(file_inf.LastWriteTime);
|
|
|
|
if (file_inf.ChangeTime)
|
|
|
|
inode->i_ctime = cifs_NTtimeToUnix(file_inf.ChangeTime);
|
|
|
|
if (file_inf.LastAccessTime)
|
|
|
|
inode->i_atime = cifs_NTtimeToUnix(file_inf.LastAccessTime);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* i_blocks is not related to (i_size / i_blksize),
|
|
|
|
* but instead 512 byte (2**9) size is required for
|
|
|
|
* calculating num blocks.
|
|
|
|
*/
|
|
|
|
if (le64_to_cpu(file_inf.AllocationSize) > 4096)
|
|
|
|
inode->i_blocks =
|
|
|
|
(512 - 1 + le64_to_cpu(file_inf.AllocationSize)) >> 9;
|
|
|
|
|
|
|
|
/* End of file and Attributes should not have to be updated on close */
|
|
|
|
spin_unlock(&inode->i_lock);
|
|
|
|
}
|
|
|
|
|
2013-11-14 14:05:36 +08:00
|
|
|
static int
|
|
|
|
SMB2_request_res_key(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
u64 persistent_fid, u64 volatile_fid,
|
|
|
|
struct copychunk_ioctl *pcchunk)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned int ret_data_len;
|
|
|
|
struct resume_key_req *res_key;
|
|
|
|
|
|
|
|
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
|
|
|
|
FSCTL_SRV_REQUEST_RESUME_KEY, true /* is_fsctl */,
|
2019-03-29 11:32:49 +08:00
|
|
|
NULL, 0 /* no input */, CIFSMaxBufSize,
|
2013-11-14 14:05:36 +08:00
|
|
|
(char **)&res_key, &ret_data_len);
|
|
|
|
|
2021-04-20 12:22:37 +08:00
|
|
|
if (rc == -EOPNOTSUPP) {
|
|
|
|
pr_warn_once("Server share %s does not support copy range\n", tcon->treeName);
|
|
|
|
goto req_res_key_exit;
|
|
|
|
} else if (rc) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_tcon_dbg(VFS, "refcpy ioctl error %d getting resume key\n", rc);
|
2013-11-14 14:05:36 +08:00
|
|
|
goto req_res_key_exit;
|
|
|
|
}
|
|
|
|
if (ret_data_len < sizeof(struct resume_key_req)) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_tcon_dbg(VFS, "Invalid refcopy resume key length\n");
|
2013-11-14 14:05:36 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto req_res_key_exit;
|
|
|
|
}
|
|
|
|
memcpy(pcchunk->SourceKey, res_key->ResumeKey, COPY_CHUNK_RES_KEY_SIZE);
|
|
|
|
|
|
|
|
req_res_key_exit:
|
|
|
|
kfree(res_key);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-05-21 13:03:15 +08:00
|
|
|
struct iqi_vars {
|
|
|
|
struct smb_rqst rqst[3];
|
|
|
|
struct kvec rsp_iov[3];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct kvec qi_iov[1];
|
|
|
|
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
|
|
|
struct kvec si_iov[SMB2_SET_INFO_IOV_SIZE];
|
|
|
|
struct kvec close_iov[1];
|
|
|
|
};
|
|
|
|
|
2018-10-08 08:19:58 +08:00
|
|
|
static int
|
|
|
|
smb2_ioctl_query_info(const unsigned int xid,
|
2018-10-17 03:47:58 +08:00
|
|
|
struct cifs_tcon *tcon,
|
2020-02-04 03:46:43 +08:00
|
|
|
struct cifs_sb_info *cifs_sb,
|
2018-10-17 03:47:58 +08:00
|
|
|
__le16 *path, int is_dir,
|
2018-10-08 08:19:58 +08:00
|
|
|
unsigned long p)
|
|
|
|
{
|
2020-05-21 13:03:15 +08:00
|
|
|
struct iqi_vars *vars;
|
|
|
|
struct smb_rqst *rqst;
|
|
|
|
struct kvec *rsp_iov;
|
2018-10-08 08:19:58 +08:00
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2020-06-01 01:38:22 +08:00
|
|
|
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
2018-10-08 08:19:58 +08:00
|
|
|
char __user *arg = (char __user *)p;
|
|
|
|
struct smb_query_info qi;
|
|
|
|
struct smb_query_info __user *pqi;
|
|
|
|
int rc = 0;
|
2021-03-08 23:00:50 +08:00
|
|
|
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
2019-03-15 07:07:22 +08:00
|
|
|
struct smb2_query_info_rsp *qi_rsp = NULL;
|
|
|
|
struct smb2_ioctl_rsp *io_rsp = NULL;
|
2018-10-17 03:47:58 +08:00
|
|
|
void *buffer = NULL;
|
|
|
|
int resp_buftype[3];
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_fid fid;
|
2019-07-25 11:08:43 +08:00
|
|
|
unsigned int size[2];
|
|
|
|
void *data[2];
|
2020-02-04 03:46:43 +08:00
|
|
|
int create_options = is_dir ? CREATE_NOT_FILE : CREATE_NOT_DIR;
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
void (*free_req1_func)(struct smb_rqst *r);
|
2018-10-17 03:47:58 +08:00
|
|
|
|
2020-05-21 13:03:15 +08:00
|
|
|
vars = kzalloc(sizeof(*vars), GFP_ATOMIC);
|
|
|
|
if (vars == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
rqst = &vars->rqst[0];
|
|
|
|
rsp_iov = &vars->rsp_iov[0];
|
|
|
|
|
2018-10-17 03:47:58 +08:00
|
|
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
2018-10-08 08:19:58 +08:00
|
|
|
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
if (copy_from_user(&qi, arg, sizeof(struct smb_query_info))) {
|
|
|
|
rc = -EFAULT;
|
|
|
|
goto free_vars;
|
|
|
|
}
|
2020-05-21 13:03:15 +08:00
|
|
|
if (qi.output_buffer_length > 1024) {
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto free_vars;
|
2020-05-21 13:03:15 +08:00
|
|
|
}
|
2018-10-08 08:19:58 +08:00
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
if (!ses || !server) {
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rc = -EIO;
|
|
|
|
goto free_vars;
|
2020-05-21 13:03:15 +08:00
|
|
|
}
|
2018-10-08 08:19:58 +08:00
|
|
|
|
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
cifs: prevent bad output lengths in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with
smb_query_info::flags=PASSTHRU_FSCTL and
smb_query_info::output_buffer_length=0, the following would return
0x10
buffer = memdup_user(arg + sizeof(struct smb_query_info),
qi.output_buffer_length);
if (IS_ERR(buffer)) {
kfree(vars);
return PTR_ERR(buffer);
}
rather than a valid pointer thus making IS_ERR() check fail. This
would then cause a NULL ptr deference in @buffer when accessing it
later in smb2_ioctl_query_ioctl(). While at it, prevent having a
@buffer smaller than 8 bytes to correctly handle SMB2_SET_INFO
FileEndOfFileInformation requests when
smb_query_info::flags=PASSTHRU_SET_INFO.
Here is a small C reproducer which triggers a NULL ptr in @buffer when
passing an invalid smb_query_info::flags
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 114.138620] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 114.139310] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 114.139775] CPU: 2 PID: 995 Comm: a.out Not tainted 5.17.0-rc8 #1
[ 114.140148] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 114.140818] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.141221] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.142348] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.142692] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.143119] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.143544] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.143983] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.144424] R13: 00000000ffffffea R14: ffff888115503228 R15: 0000000000000000
[ 114.144852] FS: 00007f7aeabdf740(0000) GS:ffff888151600000(0000) knlGS:0000000000000000
[ 114.145338] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 114.145692] CR2: 00007f7aeacfdf5e CR3: 000000012000e000 CR4: 0000000000350ee0
[ 114.146131] Call Trace:
[ 114.146291] <TASK>
[ 114.146432] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 114.146800] ? cifs_mapchar+0x460/0x460 [cifs]
[ 114.147121] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.147412] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 114.147775] ? dentry_path_raw+0xa6/0xf0
[ 114.148024] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 114.148413] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 114.148766] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.149065] cifs_ioctl+0x1577/0x3320 [cifs]
[ 114.149371] ? lock_downgrade+0x6f0/0x6f0
[ 114.149631] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 114.149956] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.150250] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 114.150562] ? __up_read+0x192/0x710
[ 114.150791] ? __ia32_sys_rseq+0xf0/0xf0
[ 114.151025] ? __x64_sys_openat+0x11f/0x1d0
[ 114.151296] __x64_sys_ioctl+0x127/0x190
[ 114.151549] do_syscall_64+0x3b/0x90
[ 114.151768] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 114.152079] RIP: 0033:0x7f7aead043df
[ 114.152306] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 114.153431] RSP: 002b:00007ffc2e0c1f80 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 114.153890] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f7aead043df
[ 114.154315] RDX: 00007ffc2e0c1ff0 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 114.154747] RBP: 00007ffc2e0c2010 R08: 00007f7aeae03db0 R09: 00007f7aeae24c4e
[ 114.155192] R10: 00007f7aeabf7d40 R11: 0000000000000246 R12: 00007ffc2e0c2128
[ 114.155642] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007f7aeae57000
[ 114.156071] </TASK>
[ 114.156218] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload
[ 114.156608] ---[ end trace 0000000000000000 ]---
[ 114.156898] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.157792] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.159293] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.159641] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.160093] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.160699] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.161196] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.155642] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007f7aeae57000
[ 114.156071] </TASK>
[ 114.156218] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload
[ 114.156608] ---[ end trace 0000000000000000 ]---
[ 114.156898] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.157792] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.159293] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.159641] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.160093] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.160699] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.161196] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.161823] R13: 00000000ffffffea R14: ffff888115503228 R15: 0000000000000000
[ 114.162274] FS: 00007f7aeabdf740(0000) GS:ffff888151600000(0000) knlGS:0000000000000000
[ 114.162853] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 114.163218] CR2: 00007f7aeacfdf5e CR3: 000000012000e000 CR4: 0000000000350ee0
[ 114.163691] Kernel panic - not syncing: Fatal exception
[ 114.164087] Kernel Offset: disabled
[ 114.164316] ---[ end Kernel panic - not syncing: Fatal exception ]---
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:05 +08:00
|
|
|
if (qi.output_buffer_length) {
|
|
|
|
buffer = memdup_user(arg + sizeof(struct smb_query_info), qi.output_buffer_length);
|
|
|
|
if (IS_ERR(buffer)) {
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rc = PTR_ERR(buffer);
|
|
|
|
goto free_vars;
|
cifs: prevent bad output lengths in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with
smb_query_info::flags=PASSTHRU_FSCTL and
smb_query_info::output_buffer_length=0, the following would return
0x10
buffer = memdup_user(arg + sizeof(struct smb_query_info),
qi.output_buffer_length);
if (IS_ERR(buffer)) {
kfree(vars);
return PTR_ERR(buffer);
}
rather than a valid pointer thus making IS_ERR() check fail. This
would then cause a NULL ptr deference in @buffer when accessing it
later in smb2_ioctl_query_ioctl(). While at it, prevent having a
@buffer smaller than 8 bytes to correctly handle SMB2_SET_INFO
FileEndOfFileInformation requests when
smb_query_info::flags=PASSTHRU_SET_INFO.
Here is a small C reproducer which triggers a NULL ptr in @buffer when
passing an invalid smb_query_info::flags
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 114.138620] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 114.139310] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 114.139775] CPU: 2 PID: 995 Comm: a.out Not tainted 5.17.0-rc8 #1
[ 114.140148] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 114.140818] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.141221] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.142348] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.142692] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.143119] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.143544] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.143983] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.144424] R13: 00000000ffffffea R14: ffff888115503228 R15: 0000000000000000
[ 114.144852] FS: 00007f7aeabdf740(0000) GS:ffff888151600000(0000) knlGS:0000000000000000
[ 114.145338] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 114.145692] CR2: 00007f7aeacfdf5e CR3: 000000012000e000 CR4: 0000000000350ee0
[ 114.146131] Call Trace:
[ 114.146291] <TASK>
[ 114.146432] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 114.146800] ? cifs_mapchar+0x460/0x460 [cifs]
[ 114.147121] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.147412] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 114.147775] ? dentry_path_raw+0xa6/0xf0
[ 114.148024] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 114.148413] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 114.148766] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.149065] cifs_ioctl+0x1577/0x3320 [cifs]
[ 114.149371] ? lock_downgrade+0x6f0/0x6f0
[ 114.149631] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 114.149956] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.150250] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 114.150562] ? __up_read+0x192/0x710
[ 114.150791] ? __ia32_sys_rseq+0xf0/0xf0
[ 114.151025] ? __x64_sys_openat+0x11f/0x1d0
[ 114.151296] __x64_sys_ioctl+0x127/0x190
[ 114.151549] do_syscall_64+0x3b/0x90
[ 114.151768] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 114.152079] RIP: 0033:0x7f7aead043df
[ 114.152306] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 114.153431] RSP: 002b:00007ffc2e0c1f80 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 114.153890] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f7aead043df
[ 114.154315] RDX: 00007ffc2e0c1ff0 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 114.154747] RBP: 00007ffc2e0c2010 R08: 00007f7aeae03db0 R09: 00007f7aeae24c4e
[ 114.155192] R10: 00007f7aeabf7d40 R11: 0000000000000246 R12: 00007ffc2e0c2128
[ 114.155642] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007f7aeae57000
[ 114.156071] </TASK>
[ 114.156218] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload
[ 114.156608] ---[ end trace 0000000000000000 ]---
[ 114.156898] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.157792] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.159293] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.159641] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.160093] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.160699] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.161196] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.155642] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007f7aeae57000
[ 114.156071] </TASK>
[ 114.156218] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload
[ 114.156608] ---[ end trace 0000000000000000 ]---
[ 114.156898] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.157792] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.159293] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.159641] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.160093] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.160699] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.161196] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.161823] R13: 00000000ffffffea R14: ffff888115503228 R15: 0000000000000000
[ 114.162274] FS: 00007f7aeabdf740(0000) GS:ffff888151600000(0000) knlGS:0000000000000000
[ 114.162853] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 114.163218] CR2: 00007f7aeacfdf5e CR3: 000000012000e000 CR4: 0000000000350ee0
[ 114.163691] Kernel panic - not syncing: Fatal exception
[ 114.164087] Kernel Offset: disabled
[ 114.164316] ---[ end Kernel panic - not syncing: Fatal exception ]---
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:05 +08:00
|
|
|
}
|
2020-05-21 13:03:15 +08:00
|
|
|
}
|
2018-10-08 08:19:58 +08:00
|
|
|
|
2018-10-17 03:47:58 +08:00
|
|
|
/* Open */
|
2020-05-21 13:03:15 +08:00
|
|
|
rqst[0].rq_iov = &vars->open_iov[0];
|
2018-10-17 03:47:58 +08:00
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
|
|
|
|
|
|
|
memset(&oparms, 0, sizeof(oparms));
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, create_options);
|
2018-10-17 03:47:58 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2019-04-11 10:20:17 +08:00
|
|
|
if (qi.flags & PASSTHRU_FSCTL) {
|
|
|
|
switch (qi.info_type & FSCTL_DEVICE_ACCESS_MASK) {
|
|
|
|
case FSCTL_DEVICE_ACCESS_FILE_READ_WRITE_ACCESS:
|
|
|
|
oparms.desired_access = FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
|
2019-04-12 02:53:17 +08:00
|
|
|
break;
|
|
|
|
case FSCTL_DEVICE_ACCESS_FILE_ANY_ACCESS:
|
|
|
|
oparms.desired_access = GENERIC_ALL;
|
|
|
|
break;
|
|
|
|
case FSCTL_DEVICE_ACCESS_FILE_READ_ACCESS:
|
|
|
|
oparms.desired_access = GENERIC_READ;
|
|
|
|
break;
|
|
|
|
case FSCTL_DEVICE_ACCESS_FILE_WRITE_ACCESS:
|
|
|
|
oparms.desired_access = GENERIC_WRITE;
|
2019-04-11 10:20:17 +08:00
|
|
|
break;
|
|
|
|
}
|
2019-07-25 11:08:43 +08:00
|
|
|
} else if (qi.flags & PASSTHRU_SET_INFO) {
|
|
|
|
oparms.desired_access = GENERIC_WRITE;
|
|
|
|
} else {
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES | READ_CONTROL;
|
2019-04-11 10:20:17 +08:00
|
|
|
}
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, path);
|
2018-10-17 03:47:58 +08:00
|
|
|
if (rc)
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto free_output_buffer;
|
2018-12-31 11:43:40 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
2018-10-17 03:47:58 +08:00
|
|
|
|
|
|
|
/* Query */
|
2019-03-13 15:40:07 +08:00
|
|
|
if (qi.flags & PASSTHRU_FSCTL) {
|
|
|
|
/* Can eventually relax perm check since server enforces too */
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
if (!capable(CAP_SYS_ADMIN)) {
|
2019-03-13 15:40:07 +08:00
|
|
|
rc = -EPERM;
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto free_open_req;
|
2019-03-15 07:07:22 +08:00
|
|
|
}
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rqst[1].rq_iov = &vars->io_iov[0];
|
|
|
|
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
|
|
|
|
|
|
|
rc = SMB2_ioctl_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
|
|
|
qi.info_type, true, buffer, qi.output_buffer_length,
|
|
|
|
CIFSMaxBufSize - MAX_SMB2_CREATE_RESPONSE_SIZE -
|
|
|
|
MAX_SMB2_CLOSE_RESPONSE_SIZE);
|
|
|
|
free_req1_func = SMB2_ioctl_free;
|
2019-07-25 11:08:43 +08:00
|
|
|
} else if (qi.flags == PASSTHRU_SET_INFO) {
|
|
|
|
/* Can eventually relax perm check since server enforces too */
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
if (!capable(CAP_SYS_ADMIN)) {
|
2019-07-25 11:08:43 +08:00
|
|
|
rc = -EPERM;
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto free_open_req;
|
|
|
|
}
|
|
|
|
if (qi.output_buffer_length < 8) {
|
cifs: prevent bad output lengths in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with
smb_query_info::flags=PASSTHRU_FSCTL and
smb_query_info::output_buffer_length=0, the following would return
0x10
buffer = memdup_user(arg + sizeof(struct smb_query_info),
qi.output_buffer_length);
if (IS_ERR(buffer)) {
kfree(vars);
return PTR_ERR(buffer);
}
rather than a valid pointer thus making IS_ERR() check fail. This
would then cause a NULL ptr deference in @buffer when accessing it
later in smb2_ioctl_query_ioctl(). While at it, prevent having a
@buffer smaller than 8 bytes to correctly handle SMB2_SET_INFO
FileEndOfFileInformation requests when
smb_query_info::flags=PASSTHRU_SET_INFO.
Here is a small C reproducer which triggers a NULL ptr in @buffer when
passing an invalid smb_query_info::flags
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 114.138620] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 114.139310] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 114.139775] CPU: 2 PID: 995 Comm: a.out Not tainted 5.17.0-rc8 #1
[ 114.140148] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 114.140818] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.141221] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.142348] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.142692] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.143119] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.143544] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.143983] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.144424] R13: 00000000ffffffea R14: ffff888115503228 R15: 0000000000000000
[ 114.144852] FS: 00007f7aeabdf740(0000) GS:ffff888151600000(0000) knlGS:0000000000000000
[ 114.145338] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 114.145692] CR2: 00007f7aeacfdf5e CR3: 000000012000e000 CR4: 0000000000350ee0
[ 114.146131] Call Trace:
[ 114.146291] <TASK>
[ 114.146432] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 114.146800] ? cifs_mapchar+0x460/0x460 [cifs]
[ 114.147121] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.147412] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 114.147775] ? dentry_path_raw+0xa6/0xf0
[ 114.148024] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 114.148413] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 114.148766] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.149065] cifs_ioctl+0x1577/0x3320 [cifs]
[ 114.149371] ? lock_downgrade+0x6f0/0x6f0
[ 114.149631] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 114.149956] ? rcu_read_lock_sched_held+0x3f/0x70
[ 114.150250] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 114.150562] ? __up_read+0x192/0x710
[ 114.150791] ? __ia32_sys_rseq+0xf0/0xf0
[ 114.151025] ? __x64_sys_openat+0x11f/0x1d0
[ 114.151296] __x64_sys_ioctl+0x127/0x190
[ 114.151549] do_syscall_64+0x3b/0x90
[ 114.151768] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 114.152079] RIP: 0033:0x7f7aead043df
[ 114.152306] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 114.153431] RSP: 002b:00007ffc2e0c1f80 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 114.153890] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f7aead043df
[ 114.154315] RDX: 00007ffc2e0c1ff0 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 114.154747] RBP: 00007ffc2e0c2010 R08: 00007f7aeae03db0 R09: 00007f7aeae24c4e
[ 114.155192] R10: 00007f7aeabf7d40 R11: 0000000000000246 R12: 00007ffc2e0c2128
[ 114.155642] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007f7aeae57000
[ 114.156071] </TASK>
[ 114.156218] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload
[ 114.156608] ---[ end trace 0000000000000000 ]---
[ 114.156898] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.157792] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.159293] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.159641] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.160093] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.160699] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.161196] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.155642] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007f7aeae57000
[ 114.156071] </TASK>
[ 114.156218] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload
[ 114.156608] ---[ end trace 0000000000000000 ]---
[ 114.156898] RIP: 0010:smb2_ioctl_query_info+0x206/0x410 [cifs]
[ 114.157792] Code: 00 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 c8 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b 7b 28 4c 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 9c 01 00 00 49 8b 3f e8 58 02 fb ff 48 8b 14 24
[ 114.159293] RSP: 0018:ffffc90000b47b00 EFLAGS: 00010256
[ 114.159641] RAX: dffffc0000000000 RBX: ffff888115503200 RCX: ffffffffa020580d
[ 114.160093] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a380
[ 114.160699] RBP: ffff888115503278 R08: 0000000000000001 R09: 0000000000000003
[ 114.161196] R10: fffffbfff4087470 R11: 0000000000000001 R12: ffff888115503288
[ 114.161823] R13: 00000000ffffffea R14: ffff888115503228 R15: 0000000000000000
[ 114.162274] FS: 00007f7aeabdf740(0000) GS:ffff888151600000(0000) knlGS:0000000000000000
[ 114.162853] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 114.163218] CR2: 00007f7aeacfdf5e CR3: 000000012000e000 CR4: 0000000000350ee0
[ 114.163691] Kernel panic - not syncing: Fatal exception
[ 114.164087] Kernel Offset: disabled
[ 114.164316] ---[ end Kernel panic - not syncing: Fatal exception ]---
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:05 +08:00
|
|
|
rc = -EINVAL;
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto free_open_req;
|
2019-07-25 11:08:43 +08:00
|
|
|
}
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rqst[1].rq_iov = &vars->si_iov[0];
|
|
|
|
rqst[1].rq_nvec = 1;
|
|
|
|
|
|
|
|
/* MS-FSCC 2.4.13 FileEndOfFileInformation */
|
|
|
|
size[0] = 8;
|
|
|
|
data[0] = buffer;
|
|
|
|
|
|
|
|
rc = SMB2_set_info_init(tcon, server, &rqst[1], COMPOUND_FID, COMPOUND_FID,
|
|
|
|
current->tgid, FILE_END_OF_FILE_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILE, 0, data, size);
|
|
|
|
free_req1_func = SMB2_set_info_free;
|
2019-03-13 15:40:07 +08:00
|
|
|
} else if (qi.flags == PASSTHRU_QUERY_INFO) {
|
2020-05-21 13:03:15 +08:00
|
|
|
rqst[1].rq_iov = &vars->qi_iov[0];
|
2019-03-13 15:40:07 +08:00
|
|
|
rqst[1].rq_nvec = 1;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[1], COMPOUND_FID,
|
2019-03-13 15:40:07 +08:00
|
|
|
COMPOUND_FID, qi.file_info_class,
|
|
|
|
qi.info_type, qi.additional_information,
|
2018-10-08 08:19:58 +08:00
|
|
|
qi.input_buffer_length,
|
|
|
|
qi.output_buffer_length, buffer);
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
free_req1_func = SMB2_query_info_free;
|
2019-03-13 15:40:07 +08:00
|
|
|
} else { /* unknown flags */
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_tcon_dbg(VFS, "Invalid passthru query flags: 0x%x\n",
|
|
|
|
qi.flags);
|
2019-03-13 15:40:07 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-10-08 08:19:58 +08:00
|
|
|
if (rc)
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto free_open_req;
|
2018-12-31 11:43:40 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[1]);
|
2018-10-17 03:47:58 +08:00
|
|
|
smb2_set_related(&rqst[1]);
|
|
|
|
|
|
|
|
/* Close */
|
2020-05-21 13:03:15 +08:00
|
|
|
rqst[2].rq_iov = &vars->close_iov[0];
|
2018-10-17 03:47:58 +08:00
|
|
|
rqst[2].rq_nvec = 1;
|
2018-10-08 08:19:58 +08:00
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
2018-10-08 08:19:58 +08:00
|
|
|
if (rc)
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto free_req_1;
|
2018-10-17 03:47:58 +08:00
|
|
|
smb2_set_related(&rqst[2]);
|
2018-10-08 08:19:58 +08:00
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, 3, rqst,
|
2018-10-17 03:47:58 +08:00
|
|
|
resp_buftype, rsp_iov);
|
|
|
|
if (rc)
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
goto out;
|
2019-09-22 13:55:46 +08:00
|
|
|
|
|
|
|
/* No need to bump num_remote_opens since handle immediately closed */
|
2019-03-15 07:07:22 +08:00
|
|
|
if (qi.flags & PASSTHRU_FSCTL) {
|
|
|
|
pqi = (struct smb_query_info __user *)arg;
|
|
|
|
io_rsp = (struct smb2_ioctl_rsp *)rsp_iov[1].iov_base;
|
|
|
|
if (le32_to_cpu(io_rsp->OutputCount) < qi.input_buffer_length)
|
|
|
|
qi.input_buffer_length = le32_to_cpu(io_rsp->OutputCount);
|
2019-04-15 10:13:52 +08:00
|
|
|
if (qi.input_buffer_length > 0 &&
|
2019-11-06 05:26:53 +08:00
|
|
|
le32_to_cpu(io_rsp->OutputOffset) + qi.input_buffer_length
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
> rsp_iov[1].iov_len) {
|
|
|
|
rc = -EFAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-11-06 05:26:53 +08:00
|
|
|
|
|
|
|
if (copy_to_user(&pqi->input_buffer_length,
|
|
|
|
&qi.input_buffer_length,
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
sizeof(qi.input_buffer_length))) {
|
|
|
|
rc = -EFAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-11-06 05:26:53 +08:00
|
|
|
|
2019-04-15 10:13:52 +08:00
|
|
|
if (copy_to_user((void __user *)pqi + sizeof(struct smb_query_info),
|
|
|
|
(const void *)io_rsp + le32_to_cpu(io_rsp->OutputOffset),
|
2019-11-06 05:26:53 +08:00
|
|
|
qi.input_buffer_length))
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rc = -EFAULT;
|
2019-03-15 07:07:22 +08:00
|
|
|
} else {
|
|
|
|
pqi = (struct smb_query_info __user *)arg;
|
|
|
|
qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
|
|
|
|
if (le32_to_cpu(qi_rsp->OutputBufferLength) < qi.input_buffer_length)
|
|
|
|
qi.input_buffer_length = le32_to_cpu(qi_rsp->OutputBufferLength);
|
2019-11-06 05:26:53 +08:00
|
|
|
if (copy_to_user(&pqi->input_buffer_length,
|
|
|
|
&qi.input_buffer_length,
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
sizeof(qi.input_buffer_length))) {
|
|
|
|
rc = -EFAULT;
|
|
|
|
goto out;
|
|
|
|
}
|
2019-11-06 05:26:53 +08:00
|
|
|
|
|
|
|
if (copy_to_user(pqi + 1, qi_rsp->Buffer,
|
|
|
|
qi.input_buffer_length))
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
rc = -EFAULT;
|
2018-10-08 08:19:58 +08:00
|
|
|
}
|
|
|
|
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
out:
|
2018-10-17 03:47:58 +08:00
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
free_req_1:
|
|
|
|
free_req1_func(&rqst[1]);
|
|
|
|
free_open_req:
|
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
free_output_buffer:
|
2021-04-09 21:47:01 +08:00
|
|
|
kfree(buffer);
|
cifs: fix NULL ptr dereference in smb2_ioctl_query_info()
When calling smb2_ioctl_query_info() with invalid
smb_query_info::flags, a NULL ptr dereference is triggered when trying
to kfree() uninitialised rqst[n].rq_iov array.
This also fixes leaked paths that are created in SMB2_open_init()
which required SMB2_open_free() to properly free them.
Here is a small C reproducer that triggers it
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define die(s) perror(s), exit(1)
#define QUERY_INFO 0xc018cf07
int main(int argc, char *argv[])
{
int fd;
if (argc < 2)
exit(1);
fd = open(argv[1], O_RDONLY);
if (fd == -1)
die("open");
if (ioctl(fd, QUERY_INFO, (uint32_t[]) { 0, 0, 0, 4, 0, 0}) == -1)
die("ioctl");
close(fd);
return 0;
}
mount.cifs //srv/share /mnt -o ...
gcc repro.c && ./a.out /mnt/f0
[ 1832.124468] CIFS: VFS: \\w22-dc.zelda.test\test Invalid passthru query flags: 0x4
[ 1832.125043] general protection fault, probably for non-canonical address 0xdffffc0000000000: 0000 [#1] PREEMPT SMP KASAN NOPTI
[ 1832.125764] KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
[ 1832.126241] CPU: 3 PID: 1133 Comm: a.out Not tainted 5.17.0-rc8 #2
[ 1832.126630] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.15.0-0-g2dd4b9b-rebuilt.opensuse.org 04/01/2014
[ 1832.127322] RIP: 0010:smb2_ioctl_query_info+0x7a3/0xe30 [cifs]
[ 1832.127749] Code: 00 00 00 fc ff df 48 c1 ea 03 80 3c 02 00 0f 85 6c 05 00 00 48 b8 00 00 00 00 00 fc ff df 4d 8b 74 24 28 4c 89 f2 48 c1 ea 03 <80> 3c 02 00 0f 85 cb 04 00 00 49 8b 3e e8 bb fc fa ff 48 89 da 48
[ 1832.128911] RSP: 0018:ffffc90000957b08 EFLAGS: 00010256
[ 1832.129243] RAX: dffffc0000000000 RBX: ffff888117e9b850 RCX: ffffffffa020580d
[ 1832.129691] RDX: 0000000000000000 RSI: 0000000000000004 RDI: ffffffffa043a2c0
[ 1832.130137] RBP: ffff888117e9b878 R08: 0000000000000001 R09: 0000000000000003
[ 1832.130585] R10: fffffbfff4087458 R11: 0000000000000001 R12: ffff888117e9b800
[ 1832.131037] R13: 00000000ffffffea R14: 0000000000000000 R15: ffff888117e9b8a8
[ 1832.131485] FS: 00007fcee9900740(0000) GS:ffff888151a00000(0000) knlGS:0000000000000000
[ 1832.131993] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 1832.132354] CR2: 00007fcee9a1ef5e CR3: 0000000114cd2000 CR4: 0000000000350ee0
[ 1832.132801] Call Trace:
[ 1832.132962] <TASK>
[ 1832.133104] ? smb2_query_reparse_tag+0x890/0x890 [cifs]
[ 1832.133489] ? cifs_mapchar+0x460/0x460 [cifs]
[ 1832.133822] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.134125] ? cifs_strndup_to_utf16+0x15b/0x250 [cifs]
[ 1832.134502] ? lock_downgrade+0x6f0/0x6f0
[ 1832.134760] ? cifs_convert_path_to_utf16+0x198/0x220 [cifs]
[ 1832.135170] ? smb2_check_message+0x1080/0x1080 [cifs]
[ 1832.135545] cifs_ioctl+0x1577/0x3320 [cifs]
[ 1832.135864] ? lock_downgrade+0x6f0/0x6f0
[ 1832.136125] ? cifs_readdir+0x2e60/0x2e60 [cifs]
[ 1832.136468] ? rcu_read_lock_sched_held+0x3f/0x70
[ 1832.136769] ? __rseq_handle_notify_resume+0x80b/0xbe0
[ 1832.137096] ? __up_read+0x192/0x710
[ 1832.137327] ? __ia32_sys_rseq+0xf0/0xf0
[ 1832.137578] ? __x64_sys_openat+0x11f/0x1d0
[ 1832.137850] __x64_sys_ioctl+0x127/0x190
[ 1832.138103] do_syscall_64+0x3b/0x90
[ 1832.138378] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ 1832.138702] RIP: 0033:0x7fcee9a253df
[ 1832.138937] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <41> 89 c0 3d 00 f0 ff ff 77 1f 48 8b 44 24 18 64 48 2b 04 25 28 00
[ 1832.140107] RSP: 002b:00007ffeba94a8a0 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
[ 1832.140606] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fcee9a253df
[ 1832.141058] RDX: 00007ffeba94a910 RSI: 00000000c018cf07 RDI: 0000000000000003
[ 1832.141503] RBP: 00007ffeba94a930 R08: 00007fcee9b24db0 R09: 00007fcee9b45c4e
[ 1832.141948] R10: 00007fcee9918d40 R11: 0000000000000246 R12: 00007ffeba94aa48
[ 1832.142396] R13: 0000000000401176 R14: 0000000000403df8 R15: 00007fcee9b78000
[ 1832.142851] </TASK>
[ 1832.142994] Modules linked in: cifs cifs_arc4 cifs_md4 bpf_preload [last unloaded: cifs]
Cc: stable@vger.kernel.org
Signed-off-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
Signed-off-by: Steve French <stfrench@microsoft.com>
2022-03-30 03:20:06 +08:00
|
|
|
free_vars:
|
|
|
|
kfree(vars);
|
2018-10-08 08:19:58 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-02-10 18:33:51 +08:00
|
|
|
static ssize_t
|
2017-04-04 15:12:04 +08:00
|
|
|
smb2_copychunk_range(const unsigned int xid,
|
2013-11-14 14:05:36 +08:00
|
|
|
struct cifsFileInfo *srcfile,
|
|
|
|
struct cifsFileInfo *trgtfile, u64 src_off,
|
|
|
|
u64 len, u64 dest_off)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned int ret_data_len;
|
|
|
|
struct copychunk_ioctl *pcchunk;
|
2013-11-17 08:05:28 +08:00
|
|
|
struct copychunk_ioctl_rsp *retbuf = NULL;
|
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
int chunks_copied = 0;
|
|
|
|
bool chunk_sizes_updated = false;
|
2017-02-10 18:33:51 +08:00
|
|
|
ssize_t bytes_written, total_bytes_written = 0;
|
2013-11-14 14:05:36 +08:00
|
|
|
|
|
|
|
pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL);
|
|
|
|
|
|
|
|
if (pcchunk == NULL)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: about to call request res key\n", __func__);
|
2013-11-14 14:05:36 +08:00
|
|
|
/* Request a key from the server to identify the source of the copy */
|
|
|
|
rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink),
|
|
|
|
srcfile->fid.persistent_fid,
|
|
|
|
srcfile->fid.volatile_fid, pcchunk);
|
|
|
|
|
|
|
|
/* Note: request_res_key sets res_key null only if rc !=0 */
|
|
|
|
if (rc)
|
2013-11-17 08:05:28 +08:00
|
|
|
goto cchunk_out;
|
2013-11-14 14:05:36 +08:00
|
|
|
|
|
|
|
/* For now array only one chunk long, will make more flexible later */
|
2014-12-11 07:41:15 +08:00
|
|
|
pcchunk->ChunkCount = cpu_to_le32(1);
|
2013-11-14 14:05:36 +08:00
|
|
|
pcchunk->Reserved = 0;
|
|
|
|
pcchunk->Reserved2 = 0;
|
|
|
|
|
2013-11-17 08:05:28 +08:00
|
|
|
tcon = tlink_tcon(trgtfile->tlink);
|
2013-11-14 14:05:36 +08:00
|
|
|
|
2013-11-17 08:05:28 +08:00
|
|
|
while (len > 0) {
|
|
|
|
pcchunk->SourceOffset = cpu_to_le64(src_off);
|
|
|
|
pcchunk->TargetOffset = cpu_to_le64(dest_off);
|
|
|
|
pcchunk->Length =
|
|
|
|
cpu_to_le32(min_t(u32, len, tcon->max_bytes_chunk));
|
2013-11-14 14:05:36 +08:00
|
|
|
|
2013-11-17 08:05:28 +08:00
|
|
|
/* Request server copy to target from src identified by key */
|
2021-05-19 06:40:11 +08:00
|
|
|
kfree(retbuf);
|
|
|
|
retbuf = NULL;
|
2013-11-17 08:05:28 +08:00
|
|
|
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
|
|
|
|
trgtfile->fid.volatile_fid, FSCTL_SRV_COPYCHUNK_WRITE,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fsctl */, (char *)pcchunk,
|
2019-03-29 11:32:49 +08:00
|
|
|
sizeof(struct copychunk_ioctl), CIFSMaxBufSize,
|
|
|
|
(char **)&retbuf, &ret_data_len);
|
2013-11-17 08:05:28 +08:00
|
|
|
if (rc == 0) {
|
|
|
|
if (ret_data_len !=
|
|
|
|
sizeof(struct copychunk_ioctl_rsp)) {
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_tcon_dbg(VFS, "Invalid cchunk response size\n");
|
2013-11-17 08:05:28 +08:00
|
|
|
rc = -EIO;
|
|
|
|
goto cchunk_out;
|
|
|
|
}
|
|
|
|
if (retbuf->TotalBytesWritten == 0) {
|
|
|
|
cifs_dbg(FYI, "no bytes copied\n");
|
|
|
|
rc = -EIO;
|
|
|
|
goto cchunk_out;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Check if server claimed to write more than we asked
|
|
|
|
*/
|
|
|
|
if (le32_to_cpu(retbuf->TotalBytesWritten) >
|
|
|
|
le32_to_cpu(pcchunk->Length)) {
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_tcon_dbg(VFS, "Invalid copy chunk response\n");
|
2013-11-17 08:05:28 +08:00
|
|
|
rc = -EIO;
|
|
|
|
goto cchunk_out;
|
|
|
|
}
|
|
|
|
if (le32_to_cpu(retbuf->ChunksWritten) != 1) {
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_tcon_dbg(VFS, "Invalid num chunks written\n");
|
2013-11-17 08:05:28 +08:00
|
|
|
rc = -EIO;
|
|
|
|
goto cchunk_out;
|
|
|
|
}
|
|
|
|
chunks_copied++;
|
|
|
|
|
2017-02-10 18:33:51 +08:00
|
|
|
bytes_written = le32_to_cpu(retbuf->TotalBytesWritten);
|
|
|
|
src_off += bytes_written;
|
|
|
|
dest_off += bytes_written;
|
|
|
|
len -= bytes_written;
|
|
|
|
total_bytes_written += bytes_written;
|
2013-11-17 08:05:28 +08:00
|
|
|
|
2017-02-10 18:33:51 +08:00
|
|
|
cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %zu\n",
|
2013-11-17 08:05:28 +08:00
|
|
|
le32_to_cpu(retbuf->ChunksWritten),
|
|
|
|
le32_to_cpu(retbuf->ChunkBytesWritten),
|
2017-02-10 18:33:51 +08:00
|
|
|
bytes_written);
|
2013-11-17 08:05:28 +08:00
|
|
|
} else if (rc == -EINVAL) {
|
|
|
|
if (ret_data_len != sizeof(struct copychunk_ioctl_rsp))
|
|
|
|
goto cchunk_out;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "MaxChunks %d BytesChunk %d MaxCopy %d\n",
|
|
|
|
le32_to_cpu(retbuf->ChunksWritten),
|
|
|
|
le32_to_cpu(retbuf->ChunkBytesWritten),
|
|
|
|
le32_to_cpu(retbuf->TotalBytesWritten));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if this is the first request using these sizes,
|
|
|
|
* (ie check if copy succeed once with original sizes
|
|
|
|
* and check if the server gave us different sizes after
|
|
|
|
* we already updated max sizes on previous request).
|
|
|
|
* if not then why is the server returning an error now
|
|
|
|
*/
|
|
|
|
if ((chunks_copied != 0) || chunk_sizes_updated)
|
|
|
|
goto cchunk_out;
|
|
|
|
|
|
|
|
/* Check that server is not asking us to grow size */
|
|
|
|
if (le32_to_cpu(retbuf->ChunkBytesWritten) <
|
|
|
|
tcon->max_bytes_chunk)
|
|
|
|
tcon->max_bytes_chunk =
|
|
|
|
le32_to_cpu(retbuf->ChunkBytesWritten);
|
|
|
|
else
|
|
|
|
goto cchunk_out; /* server gave us bogus size */
|
|
|
|
|
|
|
|
/* No need to change MaxChunks since already set to 1 */
|
|
|
|
chunk_sizes_updated = true;
|
2015-02-04 21:10:26 +08:00
|
|
|
} else
|
|
|
|
goto cchunk_out;
|
2013-11-17 08:05:28 +08:00
|
|
|
}
|
2013-11-14 14:05:36 +08:00
|
|
|
|
2013-11-17 08:05:28 +08:00
|
|
|
cchunk_out:
|
2013-11-14 14:05:36 +08:00
|
|
|
kfree(pcchunk);
|
2016-09-29 17:20:23 +08:00
|
|
|
kfree(retbuf);
|
2017-02-10 18:33:51 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
else
|
|
|
|
return total_bytes_written;
|
2013-11-14 14:05:36 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:28 +08:00
|
|
|
static int
|
|
|
|
smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_fid *fid)
|
|
|
|
{
|
|
|
|
return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:29 +08:00
|
|
|
static unsigned int
|
|
|
|
smb2_read_data_offset(char *buf)
|
|
|
|
{
|
|
|
|
struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
|
2019-05-09 03:36:25 +08:00
|
|
|
|
2012-09-19 07:20:29 +08:00
|
|
|
return rsp->DataOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned int
|
2017-11-23 08:38:46 +08:00
|
|
|
smb2_read_data_length(char *buf, bool in_remaining)
|
2012-09-19 07:20:29 +08:00
|
|
|
{
|
|
|
|
struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
|
2017-11-23 08:38:46 +08:00
|
|
|
|
|
|
|
if (in_remaining)
|
|
|
|
return le32_to_cpu(rsp->DataRemaining);
|
|
|
|
|
2012-09-19 07:20:29 +08:00
|
|
|
return le32_to_cpu(rsp->DataLength);
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:30 +08:00
|
|
|
|
|
|
|
static int
|
2014-09-22 18:13:55 +08:00
|
|
|
smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid,
|
2012-09-19 07:20:30 +08:00
|
|
|
struct cifs_io_parms *parms, unsigned int *bytes_read,
|
|
|
|
char **buf, int *buf_type)
|
|
|
|
{
|
2014-09-22 18:13:55 +08:00
|
|
|
parms->persistent_fid = pfid->persistent_fid;
|
|
|
|
parms->volatile_fid = pfid->volatile_fid;
|
2012-09-19 07:20:30 +08:00
|
|
|
return SMB2_read(xid, parms, bytes_read, buf, buf_type);
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:30 +08:00
|
|
|
static int
|
2014-09-22 18:13:55 +08:00
|
|
|
smb2_sync_write(const unsigned int xid, struct cifs_fid *pfid,
|
2012-09-19 07:20:30 +08:00
|
|
|
struct cifs_io_parms *parms, unsigned int *written,
|
|
|
|
struct kvec *iov, unsigned long nr_segs)
|
|
|
|
{
|
|
|
|
|
2014-09-22 18:13:55 +08:00
|
|
|
parms->persistent_fid = pfid->persistent_fid;
|
|
|
|
parms->volatile_fid = pfid->volatile_fid;
|
2012-09-19 07:20:30 +08:00
|
|
|
return SMB2_write(xid, parms, written, iov, nr_segs);
|
|
|
|
}
|
|
|
|
|
2014-08-14 06:16:29 +08:00
|
|
|
/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */
|
|
|
|
static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse)
|
|
|
|
{
|
|
|
|
struct cifsInodeInfo *cifsi;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
cifsi = CIFS_I(inode);
|
|
|
|
|
|
|
|
/* if file already sparse don't bother setting sparse again */
|
|
|
|
if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse)
|
|
|
|
return true; /* already sparse */
|
|
|
|
|
|
|
|
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse)
|
|
|
|
return true; /* already not sparse */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Can't check for sparse support on share the usual way via the
|
|
|
|
* FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
|
|
|
|
* since Samba server doesn't set the flag on the share, yet
|
|
|
|
* supports the set sparse FSCTL and returns sparse correctly
|
|
|
|
* in the file attributes. If we fail setting sparse though we
|
|
|
|
* mark that server does not support sparse files for this share
|
|
|
|
* to avoid repeatedly sending the unsupported fsctl to server
|
|
|
|
* if the file is repeatedly extended.
|
|
|
|
*/
|
|
|
|
if (tcon->broken_sparse_sup)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fctl */,
|
2019-03-29 11:32:49 +08:00
|
|
|
&setsparse, 1, CIFSMaxBufSize, NULL, NULL);
|
2014-08-14 06:16:29 +08:00
|
|
|
if (rc) {
|
|
|
|
tcon->broken_sparse_sup = true;
|
|
|
|
cifs_dbg(FYI, "set sparse rc = %d\n", rc);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setsparse)
|
|
|
|
cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE;
|
|
|
|
else
|
|
|
|
cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:32 +08:00
|
|
|
static int
|
|
|
|
smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
|
|
|
|
{
|
|
|
|
__le64 eof = cpu_to_le64(size);
|
2014-08-12 10:05:25 +08:00
|
|
|
struct inode *inode;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If extending file more than one page make sparse. Many Linux fs
|
|
|
|
* make files sparse by default when extending via ftruncate
|
|
|
|
*/
|
2015-03-18 06:25:59 +08:00
|
|
|
inode = d_inode(cfile->dentry);
|
2014-08-12 10:05:25 +08:00
|
|
|
|
|
|
|
if (!set_alloc && (size > inode->i_size + 8192)) {
|
|
|
|
__u8 set_sparse = 1;
|
2014-08-14 06:16:29 +08:00
|
|
|
|
|
|
|
/* whether set sparse succeeds or not, extend the file */
|
|
|
|
smb2_set_sparse(xid, tcon, cfile, inode, set_sparse);
|
2014-08-12 10:05:25 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:32 +08:00
|
|
|
return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
2018-09-03 11:33:47 +08:00
|
|
|
cfile->fid.volatile_fid, cfile->pid, &eof);
|
2012-09-19 07:20:32 +08:00
|
|
|
}
|
|
|
|
|
2015-06-28 12:18:36 +08:00
|
|
|
static int
|
|
|
|
smb2_duplicate_extents(const unsigned int xid,
|
|
|
|
struct cifsFileInfo *srcfile,
|
|
|
|
struct cifsFileInfo *trgtfile, u64 src_off,
|
|
|
|
u64 len, u64 dest_off)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned int ret_data_len;
|
2021-03-27 07:41:55 +08:00
|
|
|
struct inode *inode;
|
2015-06-28 12:18:36 +08:00
|
|
|
struct duplicate_extents_to_file dup_ext_buf;
|
|
|
|
struct cifs_tcon *tcon = tlink_tcon(trgtfile->tlink);
|
|
|
|
|
|
|
|
/* server fileays advertise duplicate extent support with this flag */
|
|
|
|
if ((le32_to_cpu(tcon->fsAttrInfo.Attributes) &
|
|
|
|
FILE_SUPPORTS_BLOCK_REFCOUNTING) == 0)
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
|
|
|
|
dup_ext_buf.VolatileFileHandle = srcfile->fid.volatile_fid;
|
|
|
|
dup_ext_buf.PersistentFileHandle = srcfile->fid.persistent_fid;
|
|
|
|
dup_ext_buf.SourceFileOffset = cpu_to_le64(src_off);
|
|
|
|
dup_ext_buf.TargetFileOffset = cpu_to_le64(dest_off);
|
|
|
|
dup_ext_buf.ByteCount = cpu_to_le64(len);
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "Duplicate extents: src off %lld dst off %lld len %lld\n",
|
2015-06-28 12:18:36 +08:00
|
|
|
src_off, dest_off, len);
|
|
|
|
|
2021-03-27 07:41:55 +08:00
|
|
|
inode = d_inode(trgtfile->dentry);
|
|
|
|
if (inode->i_size < dest_off + len) {
|
|
|
|
rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
|
|
|
|
if (rc)
|
|
|
|
goto duplicate_extents_out;
|
2015-06-28 12:18:36 +08:00
|
|
|
|
2021-03-27 07:41:55 +08:00
|
|
|
/*
|
|
|
|
* Although also could set plausible allocation size (i_blocks)
|
|
|
|
* here in addition to setting the file size, in reflink
|
|
|
|
* it is likely that the target file is sparse. Its allocation
|
|
|
|
* size will be queried on next revalidate, but it is important
|
|
|
|
* to make sure that file's cached size is updated immediately
|
|
|
|
*/
|
|
|
|
cifs_setsize(inode, dest_off + len);
|
|
|
|
}
|
2015-06-28 12:18:36 +08:00
|
|
|
rc = SMB2_ioctl(xid, tcon, trgtfile->fid.persistent_fid,
|
|
|
|
trgtfile->fid.volatile_fid,
|
|
|
|
FSCTL_DUPLICATE_EXTENTS_TO_FILE,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fsctl */,
|
2017-02-28 22:08:41 +08:00
|
|
|
(char *)&dup_ext_buf,
|
2015-06-28 12:18:36 +08:00
|
|
|
sizeof(struct duplicate_extents_to_file),
|
2019-03-29 11:32:49 +08:00
|
|
|
CIFSMaxBufSize, NULL,
|
2015-06-28 12:18:36 +08:00
|
|
|
&ret_data_len);
|
|
|
|
|
|
|
|
if (ret_data_len > 0)
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");
|
2015-06-28 12:18:36 +08:00
|
|
|
|
|
|
|
duplicate_extents_out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-10-15 04:31:32 +08:00
|
|
|
static int
|
|
|
|
smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile)
|
|
|
|
{
|
|
|
|
return SMB2_set_compression(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid);
|
|
|
|
}
|
|
|
|
|
2015-06-24 16:17:02 +08:00
|
|
|
static int
|
|
|
|
smb3_set_integrity(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile)
|
|
|
|
{
|
|
|
|
struct fsctl_set_integrity_information_req integr_info;
|
|
|
|
unsigned int ret_data_len;
|
|
|
|
|
|
|
|
integr_info.ChecksumAlgorithm = cpu_to_le16(CHECKSUM_TYPE_UNCHANGED);
|
|
|
|
integr_info.Flags = 0;
|
|
|
|
integr_info.Reserved = 0;
|
|
|
|
|
|
|
|
return SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_SET_INTEGRITY_INFORMATION,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fsctl */,
|
2017-02-28 22:08:41 +08:00
|
|
|
(char *)&integr_info,
|
2015-06-24 16:17:02 +08:00
|
|
|
sizeof(struct fsctl_set_integrity_information_req),
|
2019-03-29 11:32:49 +08:00
|
|
|
CIFSMaxBufSize, NULL,
|
2015-06-24 16:17:02 +08:00
|
|
|
&ret_data_len);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-08-10 03:33:12 +08:00
|
|
|
/* GMT Token is @GMT-YYYY.MM.DD-HH.MM.SS Unicode which is 48 bytes + null */
|
|
|
|
#define GMT_TOKEN_SIZE 50
|
|
|
|
|
2019-03-29 11:32:49 +08:00
|
|
|
#define MIN_SNAPSHOT_ARRAY_SIZE 16 /* See MS-SMB2 section 3.3.5.15.1 */
|
|
|
|
|
2018-08-10 03:33:12 +08:00
|
|
|
/*
|
|
|
|
* Input buffer contains (empty) struct smb_snapshot array with size filled in
|
|
|
|
* For output see struct SRV_SNAPSHOT_ARRAY in MS-SMB2 section 2.2.32.2
|
|
|
|
*/
|
2016-10-01 10:14:26 +08:00
|
|
|
static int
|
|
|
|
smb3_enum_snapshots(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile, void __user *ioc_buf)
|
|
|
|
{
|
|
|
|
char *retbuf = NULL;
|
|
|
|
unsigned int ret_data_len = 0;
|
|
|
|
int rc;
|
2019-03-29 11:32:49 +08:00
|
|
|
u32 max_response_size;
|
2016-10-01 10:14:26 +08:00
|
|
|
struct smb_snapshot_array snapshot_in;
|
|
|
|
|
2019-04-04 13:41:04 +08:00
|
|
|
/*
|
|
|
|
* On the first query to enumerate the list of snapshots available
|
|
|
|
* for this volume the buffer begins with 0 (number of snapshots
|
|
|
|
* which can be returned is zero since at that point we do not know
|
|
|
|
* how big the buffer needs to be). On the second query,
|
|
|
|
* it (ret_data_len) is set to number of snapshots so we can
|
|
|
|
* know to set the maximum response size larger (see below).
|
|
|
|
*/
|
2019-03-29 11:32:49 +08:00
|
|
|
if (get_user(ret_data_len, (unsigned int __user *)ioc_buf))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that for snapshot queries that servers like Azure expect that
|
|
|
|
* the first query be minimal size (and just used to get the number/size
|
|
|
|
* of previous versions) so response size must be specified as EXACTLY
|
|
|
|
* sizeof(struct snapshot_array) which is 16 when rounded up to multiple
|
|
|
|
* of eight bytes.
|
|
|
|
*/
|
|
|
|
if (ret_data_len == 0)
|
|
|
|
max_response_size = MIN_SNAPSHOT_ARRAY_SIZE;
|
|
|
|
else
|
|
|
|
max_response_size = CIFSMaxBufSize;
|
|
|
|
|
2016-10-01 10:14:26 +08:00
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_SRV_ENUMERATE_SNAPSHOTS,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fsctl */,
|
2019-03-29 11:32:49 +08:00
|
|
|
NULL, 0 /* no input data */, max_response_size,
|
2016-10-01 10:14:26 +08:00
|
|
|
(char **)&retbuf,
|
|
|
|
&ret_data_len);
|
|
|
|
cifs_dbg(FYI, "enum snaphots ioctl returned %d and ret buflen is %d\n",
|
|
|
|
rc, ret_data_len);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if (ret_data_len && (ioc_buf != NULL) && (retbuf != NULL)) {
|
|
|
|
/* Fixup buffer */
|
|
|
|
if (copy_from_user(&snapshot_in, ioc_buf,
|
|
|
|
sizeof(struct smb_snapshot_array))) {
|
|
|
|
rc = -EFAULT;
|
|
|
|
kfree(retbuf);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-08-10 03:33:12 +08:00
|
|
|
/*
|
|
|
|
* Check for min size, ie not large enough to fit even one GMT
|
|
|
|
* token (snapshot). On the first ioctl some users may pass in
|
|
|
|
* smaller size (or zero) to simply get the size of the array
|
|
|
|
* so the user space caller can allocate sufficient memory
|
|
|
|
* and retry the ioctl again with larger array size sufficient
|
|
|
|
* to hold all of the snapshot GMT tokens on the second try.
|
|
|
|
*/
|
|
|
|
if (snapshot_in.snapshot_array_size < GMT_TOKEN_SIZE)
|
|
|
|
ret_data_len = sizeof(struct smb_snapshot_array);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We return struct SRV_SNAPSHOT_ARRAY, followed by
|
|
|
|
* the snapshot array (of 50 byte GMT tokens) each
|
|
|
|
* representing an available previous version of the data
|
|
|
|
*/
|
|
|
|
if (ret_data_len > (snapshot_in.snapshot_array_size +
|
|
|
|
sizeof(struct smb_snapshot_array)))
|
|
|
|
ret_data_len = snapshot_in.snapshot_array_size +
|
|
|
|
sizeof(struct smb_snapshot_array);
|
2016-10-01 10:14:26 +08:00
|
|
|
|
|
|
|
if (copy_to_user(ioc_buf, retbuf, ret_data_len))
|
|
|
|
rc = -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(retbuf);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-02-06 20:00:14 +08:00
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
smb3_notify(const unsigned int xid, struct file *pfile,
|
|
|
|
void __user *ioc_buf)
|
|
|
|
{
|
|
|
|
struct smb3_notify notify;
|
|
|
|
struct dentry *dentry = pfile->f_path.dentry;
|
|
|
|
struct inode *inode = file_inode(pfile);
|
2021-03-06 06:36:04 +08:00
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
2020-02-06 20:00:14 +08:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_tcon *tcon;
|
2021-03-06 06:36:04 +08:00
|
|
|
const unsigned char *path;
|
|
|
|
void *page = alloc_dentry_path();
|
2020-02-06 20:00:14 +08:00
|
|
|
__le16 *utf16_path = NULL;
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
int rc = 0;
|
|
|
|
|
2021-03-06 06:36:04 +08:00
|
|
|
path = build_path_from_dentry(dentry, page);
|
|
|
|
if (IS_ERR(path)) {
|
|
|
|
rc = PTR_ERR(path);
|
|
|
|
goto notify_exit;
|
|
|
|
}
|
2020-02-06 20:00:14 +08:00
|
|
|
|
2021-04-16 15:35:30 +08:00
|
|
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
2020-02-06 20:00:14 +08:00
|
|
|
if (utf16_path == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto notify_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (copy_from_user(¬ify, ioc_buf, sizeof(struct smb3_notify))) {
|
|
|
|
rc = -EFAULT;
|
|
|
|
goto notify_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
tcon = cifs_sb_master_tcon(cifs_sb);
|
|
|
|
oparms.tcon = tcon;
|
2020-07-08 07:08:46 +08:00
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
|
2020-02-06 20:00:14 +08:00
|
|
|
oparms.disposition = FILE_OPEN;
|
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-03-03 00:53:22 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
|
|
|
|
NULL);
|
2020-02-06 20:00:14 +08:00
|
|
|
if (rc)
|
|
|
|
goto notify_exit;
|
|
|
|
|
|
|
|
rc = SMB2_change_notify(xid, tcon, fid.persistent_fid, fid.volatile_fid,
|
|
|
|
notify.watch_tree, notify.completion_filter);
|
|
|
|
|
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "change notify for path %s rc %d\n", path, rc);
|
|
|
|
|
|
|
|
notify_exit:
|
2021-03-06 06:36:04 +08:00
|
|
|
free_dentry_path(page);
|
2020-02-06 20:00:14 +08:00
|
|
|
kfree(utf16_path);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:33 +08:00
|
|
|
static int
|
|
|
|
smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
const char *path, struct cifs_sb_info *cifs_sb,
|
|
|
|
struct cifs_fid *fid, __u16 search_flags,
|
|
|
|
struct cifs_search_info *srch_inf)
|
|
|
|
{
|
|
|
|
__le16 *utf16_path;
|
2020-01-08 11:08:06 +08:00
|
|
|
struct smb_rqst rqst[2];
|
|
|
|
struct kvec rsp_iov[2];
|
|
|
|
int resp_buftype[2];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct kvec qd_iov[SMB2_QUERY_DIRECTORY_IOV_SIZE];
|
|
|
|
int rc, flags = 0;
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
2013-07-09 22:20:30 +08:00
|
|
|
struct cifs_open_parms oparms;
|
2020-01-08 11:08:06 +08:00
|
|
|
struct smb2_query_directory_rsp *qd_rsp = NULL;
|
|
|
|
struct smb2_create_rsp *op_rsp = NULL;
|
2020-06-01 01:38:22 +08:00
|
|
|
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
|
2021-06-16 00:42:56 +08:00
|
|
|
int retry_count = 0;
|
2012-09-19 07:20:33 +08:00
|
|
|
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
|
|
|
if (!utf16_path)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-01-08 11:08:06 +08:00
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
|
|
|
memset(rqst, 0, sizeof(rqst));
|
|
|
|
resp_buftype[0] = resp_buftype[1] = CIFS_NO_BUFFER;
|
|
|
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
|
|
|
|
|
|
|
/* Open */
|
|
|
|
memset(&open_iov, 0, sizeof(open_iov));
|
|
|
|
rqst[0].rq_iov = open_iov;
|
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
|
|
|
|
2013-07-09 22:20:30 +08:00
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2013-07-09 22:20:30 +08:00
|
|
|
oparms.fid = fid;
|
2013-07-09 22:40:58 +08:00
|
|
|
oparms.reconnect = false;
|
2013-07-09 22:20:30 +08:00
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, utf16_path);
|
2020-01-08 11:08:06 +08:00
|
|
|
if (rc)
|
|
|
|
goto qdf_free;
|
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
2012-09-19 07:20:33 +08:00
|
|
|
|
2020-01-08 11:08:06 +08:00
|
|
|
/* Query directory */
|
2012-09-19 07:20:33 +08:00
|
|
|
srch_inf->entries_in_buffer = 0;
|
smb2: fix missing files in root share directory listing
When mounting a Windows share that is the root of a drive (eg. C$)
the server does not return . and .. directory entries. This results in
the smb2 code path erroneously skipping the 2 first entries.
Pseudo-code of the readdir() code path:
cifs_readdir(struct file, struct dir_context)
initiate_cifs_search <-- if no reponse cached yet
server->ops->query_dir_first
dir_emit_dots
dir_emit <-- adds "." and ".." if we're at pos=0
find_cifs_entry
initiate_cifs_search <-- if pos < start of current response
(restart search)
server->ops->query_dir_next <-- if pos > end of current response
(fetch next search res)
for(...) <-- loops over cur response entries
starting at pos
cifs_filldir <-- skip . and .., emit entry
cifs_fill_dirent
dir_emit
pos++
A) dir_emit_dots() always adds . & ..
and sets the current dir pos to 2 (0 and 1 are done).
Therefore we always want the index_to_find to be 2 regardless of if
the response has . and ..
B) smb1 code initializes index_of_last_entry with a +2 offset
in cifssmb.c CIFSFindFirst():
psrch_inf->index_of_last_entry = 2 /* skip . and .. */ +
psrch_inf->entries_in_buffer;
Later in find_cifs_entry() we want to find the next dir entry at pos=2
as a result of (A)
first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
cfile->srch_inf.entries_in_buffer;
This var is the dir pos that the first entry in the buffer will
have therefore it must be 2 in the first call.
If we don't offset index_of_last_entry by 2 (like in (B)),
first_entry_in_buffer=0 but we were instructed to get pos=2 so this
code in find_cifs_entry() skips the 2 first which is ok for non-root
shares, as it skips . and .. from the response but is not ok for root
shares where the 2 first are actual files
pos_in_buf = index_to_find - first_entry_in_buffer;
// pos_in_buf=2
// we skip 2 first response entries :(
for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
/* go entry by entry figuring out which is first */
cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
cfile->srch_inf.info_level);
}
C) cifs_filldir() skips . and .. so we can safely ignore them for now.
Sample program:
int main(int argc, char **argv)
{
const char *path = argc >= 2 ? argv[1] : ".";
DIR *dh;
struct dirent *de;
printf("listing path <%s>\n", path);
dh = opendir(path);
if (!dh) {
printf("opendir error %d\n", errno);
return 1;
}
while (1) {
de = readdir(dh);
if (!de) {
if (errno) {
printf("readdir error %d\n", errno);
return 1;
}
printf("end of listing\n");
break;
}
printf("off=%lu <%s>\n", de->d_off, de->d_name);
}
return 0;
}
Before the fix with SMB1 on root shares:
<.> off=1
<..> off=2
<$Recycle.Bin> off=3
<bootmgr> off=4
and on non-root shares:
<.> off=1
<..> off=4 <-- after adding .., the offsets jumps to +2 because
<2536> off=5 we skipped . and .. from response buffer (C)
<411> off=6 but still incremented pos
<file> off=7
<fsx> off=8
Therefore the fix for smb2 is to mimic smb1 behaviour and offset the
index_of_last_entry by 2.
Test results comparing smb1 and smb2 before/after the fix on root
share, non-root shares and on large directories (ie. multi-response
dir listing):
PRE FIX
=======
pre-1-root VS pre-2-root:
ERR pre-2-root is missing [bootmgr, $Recycle.Bin]
pre-1-nonroot VS pre-2-nonroot:
OK~ same files, same order, different offsets
pre-1-nonroot-large VS pre-2-nonroot-large:
OK~ same files, same order, different offsets
POST FIX
========
post-1-root VS post-2-root:
OK same files, same order, same offsets
post-1-nonroot VS post-2-nonroot:
OK same files, same order, same offsets
post-1-nonroot-large VS post-2-nonroot-large:
OK same files, same order, same offsets
REGRESSION?
===========
pre-1-root VS post-1-root:
OK same files, same order, same offsets
pre-1-nonroot VS post-1-nonroot:
OK same files, same order, same offsets
BugLink: https://bugzilla.samba.org/show_bug.cgi?id=13107
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Paulo Alcantara <palcantara@suse.deR>
Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
CC: Stable <stable@vger.kernel.org>
2018-05-17 22:35:07 +08:00
|
|
|
srch_inf->index_of_last_entry = 2;
|
2012-09-19 07:20:33 +08:00
|
|
|
|
2020-01-08 11:08:06 +08:00
|
|
|
memset(&qd_iov, 0, sizeof(qd_iov));
|
|
|
|
rqst[1].rq_iov = qd_iov;
|
|
|
|
rqst[1].rq_nvec = SMB2_QUERY_DIRECTORY_IOV_SIZE;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_query_directory_init(xid, tcon, server,
|
|
|
|
&rqst[1],
|
2020-01-08 11:08:06 +08:00
|
|
|
COMPOUND_FID, COMPOUND_FID,
|
|
|
|
0, srch_inf->info_level);
|
|
|
|
if (rc)
|
|
|
|
goto qdf_free;
|
|
|
|
|
|
|
|
smb2_set_related(&rqst[1]);
|
|
|
|
|
2021-06-16 00:42:56 +08:00
|
|
|
again:
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, tcon->ses, server,
|
|
|
|
flags, 2, rqst,
|
2020-01-08 11:08:06 +08:00
|
|
|
resp_buftype, rsp_iov);
|
|
|
|
|
2021-06-16 00:42:56 +08:00
|
|
|
if (rc == -EAGAIN && retry_count++ < 10)
|
|
|
|
goto again;
|
|
|
|
|
2020-01-08 11:08:06 +08:00
|
|
|
/* If the open failed there is nothing to do */
|
|
|
|
op_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
|
2021-11-05 07:39:01 +08:00
|
|
|
if (op_rsp == NULL || op_rsp->hdr.Status != STATUS_SUCCESS) {
|
2020-01-08 11:08:06 +08:00
|
|
|
cifs_dbg(FYI, "query_dir_first: open failed rc=%d\n", rc);
|
|
|
|
goto qdf_free;
|
|
|
|
}
|
2022-03-22 00:08:25 +08:00
|
|
|
fid->persistent_fid = op_rsp->PersistentFileId;
|
|
|
|
fid->volatile_fid = op_rsp->VolatileFileId;
|
2020-01-08 11:08:06 +08:00
|
|
|
|
|
|
|
/* Anything else than ENODATA means a genuine error */
|
|
|
|
if (rc && rc != -ENODATA) {
|
2013-07-09 22:20:30 +08:00
|
|
|
SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
|
2020-01-08 11:08:06 +08:00
|
|
|
cifs_dbg(FYI, "query_dir_first: query directory failed rc=%d\n", rc);
|
|
|
|
trace_smb3_query_dir_err(xid, fid->persistent_fid,
|
|
|
|
tcon->tid, tcon->ses->Suid, 0, 0, rc);
|
|
|
|
goto qdf_free;
|
|
|
|
}
|
|
|
|
|
2020-03-09 16:35:09 +08:00
|
|
|
atomic_inc(&tcon->num_remote_opens);
|
|
|
|
|
2020-01-08 11:08:06 +08:00
|
|
|
qd_rsp = (struct smb2_query_directory_rsp *)rsp_iov[1].iov_base;
|
2021-11-05 07:39:01 +08:00
|
|
|
if (qd_rsp->hdr.Status == STATUS_NO_MORE_FILES) {
|
2020-01-08 11:08:06 +08:00
|
|
|
trace_smb3_query_dir_done(xid, fid->persistent_fid,
|
|
|
|
tcon->tid, tcon->ses->Suid, 0, 0);
|
|
|
|
srch_inf->endOfSearch = true;
|
|
|
|
rc = 0;
|
|
|
|
goto qdf_free;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = smb2_parse_query_directory(tcon, &rsp_iov[1], resp_buftype[1],
|
|
|
|
srch_inf);
|
|
|
|
if (rc) {
|
|
|
|
trace_smb3_query_dir_err(xid, fid->persistent_fid, tcon->tid,
|
|
|
|
tcon->ses->Suid, 0, 0, rc);
|
|
|
|
goto qdf_free;
|
2012-09-19 07:20:33 +08:00
|
|
|
}
|
2020-01-08 11:08:06 +08:00
|
|
|
resp_buftype[1] = CIFS_NO_BUFFER;
|
|
|
|
|
|
|
|
trace_smb3_query_dir_done(xid, fid->persistent_fid, tcon->tid,
|
|
|
|
tcon->ses->Suid, 0, srch_inf->entries_in_buffer);
|
|
|
|
|
|
|
|
qdf_free:
|
|
|
|
kfree(utf16_path);
|
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
SMB2_query_directory_free(&rqst[1]);
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
2012-09-19 07:20:33 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
smb2_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_fid *fid, __u16 search_flags,
|
|
|
|
struct cifs_search_info *srch_inf)
|
|
|
|
{
|
|
|
|
return SMB2_query_directory(xid, tcon, fid->persistent_fid,
|
|
|
|
fid->volatile_fid, 0, srch_inf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_fid *fid)
|
|
|
|
{
|
|
|
|
return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
|
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:33 +08:00
|
|
|
/*
|
2019-05-09 03:36:25 +08:00
|
|
|
* If we negotiate SMB2 protocol and get STATUS_PENDING - update
|
|
|
|
* the number of credits and return true. Otherwise - return false.
|
|
|
|
*/
|
2012-09-19 07:20:33 +08:00
|
|
|
static bool
|
2019-01-24 09:11:16 +08:00
|
|
|
smb2_is_status_pending(char *buf, struct TCP_Server_Info *server)
|
2012-09-19 07:20:33 +08:00
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2021-02-04 15:20:46 +08:00
|
|
|
int scredits, in_flight;
|
2012-09-19 07:20:33 +08:00
|
|
|
|
2016-10-25 06:33:04 +08:00
|
|
|
if (shdr->Status != STATUS_PENDING)
|
2012-09-19 07:20:33 +08:00
|
|
|
return false;
|
|
|
|
|
2019-01-24 09:11:16 +08:00
|
|
|
if (shdr->CreditRequest) {
|
2012-09-19 07:20:33 +08:00
|
|
|
spin_lock(&server->req_lock);
|
2016-10-25 06:33:04 +08:00
|
|
|
server->credits += le16_to_cpu(shdr->CreditRequest);
|
2020-11-13 00:56:49 +08:00
|
|
|
scredits = server->credits;
|
2021-02-04 15:20:46 +08:00
|
|
|
in_flight = server->in_flight;
|
2012-09-19 07:20:33 +08:00
|
|
|
spin_unlock(&server->req_lock);
|
|
|
|
wake_up(&server->request_q);
|
2020-11-13 00:56:49 +08:00
|
|
|
|
|
|
|
trace_smb3_add_credits(server->CurrentMid,
|
2021-02-04 15:20:46 +08:00
|
|
|
server->conn_id, server->hostname, scredits,
|
|
|
|
le16_to_cpu(shdr->CreditRequest), in_flight);
|
2020-11-13 00:56:49 +08:00
|
|
|
cifs_dbg(FYI, "%s: status pending add %u credits total=%d\n",
|
|
|
|
__func__, le16_to_cpu(shdr->CreditRequest), scredits);
|
2012-09-19 07:20:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-09 05:32:00 +08:00
|
|
|
static bool
|
|
|
|
smb2_is_session_expired(char *buf)
|
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2017-07-09 05:32:00 +08:00
|
|
|
|
2018-05-24 16:47:31 +08:00
|
|
|
if (shdr->Status != STATUS_NETWORK_SESSION_EXPIRED &&
|
|
|
|
shdr->Status != STATUS_USER_SESSION_DELETED)
|
2017-07-09 05:32:00 +08:00
|
|
|
return false;
|
|
|
|
|
2021-11-05 07:39:01 +08:00
|
|
|
trace_smb3_ses_expired(le32_to_cpu(shdr->Id.SyncId.TreeId),
|
|
|
|
le64_to_cpu(shdr->SessionId),
|
2018-07-31 03:23:58 +08:00
|
|
|
le16_to_cpu(shdr->Command),
|
|
|
|
le64_to_cpu(shdr->MessageId));
|
2018-05-24 16:47:31 +08:00
|
|
|
cifs_dbg(FYI, "Session expired or deleted\n");
|
2018-07-31 03:23:58 +08:00
|
|
|
|
2017-07-09 05:32:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-09-18 13:37:28 +08:00
|
|
|
static bool
|
|
|
|
smb2_is_status_io_timeout(char *buf)
|
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2020-09-18 13:37:28 +08:00
|
|
|
|
|
|
|
if (shdr->Status == STATUS_IO_TIMEOUT)
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-02-16 18:40:45 +08:00
|
|
|
static void
|
|
|
|
smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server)
|
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2021-02-16 18:40:45 +08:00
|
|
|
struct list_head *tmp, *tmp1;
|
|
|
|
struct cifs_ses *ses;
|
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
|
2021-02-21 08:52:15 +08:00
|
|
|
if (shdr->Status != STATUS_NETWORK_NAME_DELETED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
|
|
|
list_for_each(tmp, &server->smb_ses_list) {
|
|
|
|
ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
|
|
|
|
list_for_each(tmp1, &ses->tcon_list) {
|
|
|
|
tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
|
2021-11-05 07:39:01 +08:00
|
|
|
if (tcon->tid == le32_to_cpu(shdr->Id.SyncId.TreeId)) {
|
2021-02-21 08:52:15 +08:00
|
|
|
tcon->need_reconnect = true;
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
pr_warn_once("Server share %s deleted.\n",
|
|
|
|
tcon->treeName);
|
|
|
|
return;
|
2021-02-16 18:40:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-02-21 08:52:15 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2021-02-16 18:40:45 +08:00
|
|
|
}
|
|
|
|
|
2012-09-19 07:20:33 +08:00
|
|
|
static int
|
|
|
|
smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
|
|
|
|
struct cifsInodeInfo *cinode)
|
|
|
|
{
|
2012-09-19 21:22:45 +08:00
|
|
|
if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
|
|
|
|
return SMB2_lease_break(0, tcon, cinode->lease_key,
|
|
|
|
smb2_get_lease_state(cinode));
|
|
|
|
|
2012-09-19 07:20:33 +08:00
|
|
|
return SMB2_oplock_break(0, tcon, fid->persistent_fid,
|
|
|
|
fid->volatile_fid,
|
2013-09-05 17:01:06 +08:00
|
|
|
CIFS_CACHE_READ(cinode) ? 1 : 0);
|
2012-09-19 07:20:33 +08:00
|
|
|
}
|
|
|
|
|
2018-09-03 11:33:41 +08:00
|
|
|
void
|
2018-08-08 13:07:49 +08:00
|
|
|
smb2_set_related(struct smb_rqst *rqst)
|
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr;
|
2018-08-08 13:07:49 +08:00
|
|
|
|
2021-11-05 07:39:01 +08:00
|
|
|
shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base);
|
2019-07-16 08:41:46 +08:00
|
|
|
if (shdr == NULL) {
|
|
|
|
cifs_dbg(FYI, "shdr NULL in smb2_set_related\n");
|
|
|
|
return;
|
|
|
|
}
|
2018-08-08 13:07:49 +08:00
|
|
|
shdr->Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
|
|
|
|
}
|
|
|
|
|
|
|
|
char smb2_padding[7] = {0, 0, 0, 0, 0, 0, 0};
|
|
|
|
|
2018-09-03 11:33:41 +08:00
|
|
|
void
|
2018-12-31 11:43:40 +08:00
|
|
|
smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst)
|
2018-08-08 13:07:49 +08:00
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr;
|
2018-12-31 11:43:40 +08:00
|
|
|
struct cifs_ses *ses = tcon->ses;
|
|
|
|
struct TCP_Server_Info *server = ses->server;
|
2018-08-08 13:07:49 +08:00
|
|
|
unsigned long len = smb_rqst_len(server, rqst);
|
2018-12-31 11:43:40 +08:00
|
|
|
int i, num_padding;
|
2018-08-08 13:07:49 +08:00
|
|
|
|
2021-11-05 07:39:01 +08:00
|
|
|
shdr = (struct smb2_hdr *)(rqst->rq_iov[0].iov_base);
|
2019-07-16 08:41:46 +08:00
|
|
|
if (shdr == NULL) {
|
|
|
|
cifs_dbg(FYI, "shdr NULL in smb2_set_next_command\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-08 13:07:49 +08:00
|
|
|
/* SMB headers in a compound are 8 byte aligned. */
|
2018-12-31 11:43:40 +08:00
|
|
|
|
|
|
|
/* No padding needed */
|
|
|
|
if (!(len & 7))
|
|
|
|
goto finished;
|
|
|
|
|
|
|
|
num_padding = 8 - (len & 7);
|
|
|
|
if (!smb3_encryption_required(tcon)) {
|
|
|
|
/*
|
|
|
|
* If we do not have encryption then we can just add an extra
|
|
|
|
* iov for the padding.
|
|
|
|
*/
|
|
|
|
rqst->rq_iov[rqst->rq_nvec].iov_base = smb2_padding;
|
|
|
|
rqst->rq_iov[rqst->rq_nvec].iov_len = num_padding;
|
|
|
|
rqst->rq_nvec++;
|
|
|
|
len += num_padding;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* We can not add a small padding iov for the encryption case
|
|
|
|
* because the encryption framework can not handle the padding
|
|
|
|
* iovs.
|
|
|
|
* We have to flatten this into a single buffer and add
|
|
|
|
* the padding to it.
|
|
|
|
*/
|
|
|
|
for (i = 1; i < rqst->rq_nvec; i++) {
|
|
|
|
memcpy(rqst->rq_iov[0].iov_base +
|
|
|
|
rqst->rq_iov[0].iov_len,
|
|
|
|
rqst->rq_iov[i].iov_base,
|
|
|
|
rqst->rq_iov[i].iov_len);
|
|
|
|
rqst->rq_iov[0].iov_len += rqst->rq_iov[i].iov_len;
|
2018-12-19 07:49:05 +08:00
|
|
|
}
|
2018-12-31 11:43:40 +08:00
|
|
|
memset(rqst->rq_iov[0].iov_base + rqst->rq_iov[0].iov_len,
|
|
|
|
0, num_padding);
|
|
|
|
rqst->rq_iov[0].iov_len += num_padding;
|
|
|
|
len += num_padding;
|
|
|
|
rqst->rq_nvec = 1;
|
2018-08-08 13:07:49 +08:00
|
|
|
}
|
|
|
|
|
2018-12-31 11:43:40 +08:00
|
|
|
finished:
|
2018-08-08 13:07:49 +08:00
|
|
|
shdr->NextCommand = cpu_to_le32(len);
|
|
|
|
}
|
|
|
|
|
2018-12-21 12:03:04 +08:00
|
|
|
/*
|
|
|
|
* Passes the query info response back to the caller on success.
|
|
|
|
* Caller need to free this with free_rsp_buf().
|
|
|
|
*/
|
2018-11-27 07:52:04 +08:00
|
|
|
int
|
2018-12-21 12:03:04 +08:00
|
|
|
smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
|
2022-03-22 14:29:02 +08:00
|
|
|
const char *path, u32 desired_access,
|
2018-12-21 12:03:04 +08:00
|
|
|
u32 class, u32 type, u32 output_len,
|
2018-11-27 07:52:04 +08:00
|
|
|
struct kvec *rsp, int *buftype,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2012-09-19 07:20:34 +08:00
|
|
|
{
|
2018-12-21 12:03:04 +08:00
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2020-06-01 01:38:22 +08:00
|
|
|
struct TCP_Server_Info *server = cifs_pick_channel(ses);
|
2021-03-08 23:00:50 +08:00
|
|
|
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
2018-08-08 13:07:49 +08:00
|
|
|
struct smb_rqst rqst[3];
|
|
|
|
int resp_buftype[3];
|
|
|
|
struct kvec rsp_iov[3];
|
2018-08-21 09:49:21 +08:00
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
2018-08-08 13:07:49 +08:00
|
|
|
struct kvec qi_iov[1];
|
|
|
|
struct kvec close_iov[1];
|
2012-09-19 07:20:34 +08:00
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
2013-07-09 22:20:30 +08:00
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
2018-08-08 13:07:49 +08:00
|
|
|
int rc;
|
2022-03-22 14:29:02 +08:00
|
|
|
__le16 *utf16_path;
|
2022-03-22 14:29:03 +08:00
|
|
|
struct cached_fid *cfid = NULL;
|
2022-03-22 14:29:02 +08:00
|
|
|
|
|
|
|
if (!path)
|
|
|
|
path = "";
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
|
|
|
if (!utf16_path)
|
|
|
|
return -ENOMEM;
|
2018-08-08 13:07:49 +08:00
|
|
|
|
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
|
|
|
memset(rqst, 0, sizeof(rqst));
|
2018-09-03 11:33:41 +08:00
|
|
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
2018-08-08 13:07:49 +08:00
|
|
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
|
|
|
|
2022-03-22 14:29:03 +08:00
|
|
|
rc = open_cached_dir(xid, tcon, path, cifs_sb, &cfid);
|
|
|
|
|
2018-08-08 13:07:49 +08:00
|
|
|
memset(&open_iov, 0, sizeof(open_iov));
|
|
|
|
rqst[0].rq_iov = open_iov;
|
2018-08-21 09:49:21 +08:00
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
2013-07-09 22:20:30 +08:00
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
2018-12-21 12:03:04 +08:00
|
|
|
oparms.desired_access = desired_access;
|
2013-07-09 22:20:30 +08:00
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2013-07-09 22:20:30 +08:00
|
|
|
oparms.fid = &fid;
|
2013-07-09 22:40:58 +08:00
|
|
|
oparms.reconnect = false;
|
2012-09-19 07:20:34 +08:00
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, utf16_path);
|
2012-09-19 07:20:34 +08:00
|
|
|
if (rc)
|
2018-12-21 12:03:04 +08:00
|
|
|
goto qic_exit;
|
2018-12-31 11:43:40 +08:00
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
2018-08-08 13:07:49 +08:00
|
|
|
|
|
|
|
memset(&qi_iov, 0, sizeof(qi_iov));
|
|
|
|
rqst[1].rq_iov = qi_iov;
|
|
|
|
rqst[1].rq_nvec = 1;
|
|
|
|
|
2022-03-22 14:29:03 +08:00
|
|
|
if (cfid) {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[1],
|
|
|
|
cfid->fid->persistent_fid,
|
|
|
|
cfid->fid->volatile_fid,
|
|
|
|
class, type, 0,
|
|
|
|
output_len, 0,
|
|
|
|
NULL);
|
|
|
|
} else {
|
|
|
|
rc = SMB2_query_info_init(tcon, server,
|
|
|
|
&rqst[1],
|
|
|
|
COMPOUND_FID,
|
|
|
|
COMPOUND_FID,
|
|
|
|
class, type, 0,
|
|
|
|
output_len, 0,
|
|
|
|
NULL);
|
|
|
|
}
|
2018-08-08 13:07:49 +08:00
|
|
|
if (rc)
|
2018-12-21 12:03:04 +08:00
|
|
|
goto qic_exit;
|
2022-03-22 14:29:03 +08:00
|
|
|
if (!cfid) {
|
|
|
|
smb2_set_next_command(tcon, &rqst[1]);
|
|
|
|
smb2_set_related(&rqst[1]);
|
|
|
|
}
|
2018-08-08 13:07:49 +08:00
|
|
|
|
|
|
|
memset(&close_iov, 0, sizeof(close_iov));
|
|
|
|
rqst[2].rq_iov = close_iov;
|
|
|
|
rqst[2].rq_nvec = 1;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
2018-08-08 13:07:49 +08:00
|
|
|
if (rc)
|
2018-12-21 12:03:04 +08:00
|
|
|
goto qic_exit;
|
2018-08-08 13:07:49 +08:00
|
|
|
smb2_set_related(&rqst[2]);
|
|
|
|
|
2022-03-22 14:29:03 +08:00
|
|
|
if (cfid) {
|
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, 1, &rqst[1],
|
|
|
|
&resp_buftype[1], &rsp_iov[1]);
|
|
|
|
} else {
|
|
|
|
rc = compound_send_recv(xid, ses, server,
|
|
|
|
flags, 3, rqst,
|
|
|
|
resp_buftype, rsp_iov);
|
|
|
|
}
|
2018-11-27 07:52:04 +08:00
|
|
|
if (rc) {
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
2019-09-11 13:07:36 +08:00
|
|
|
if (rc == -EREMCHG) {
|
|
|
|
tcon->need_reconnect = true;
|
2020-04-15 13:42:53 +08:00
|
|
|
pr_warn_once("server share %s deleted\n",
|
|
|
|
tcon->treeName);
|
2019-09-11 13:07:36 +08:00
|
|
|
}
|
2018-12-21 12:03:04 +08:00
|
|
|
goto qic_exit;
|
2018-11-27 07:52:04 +08:00
|
|
|
}
|
2018-12-21 12:03:04 +08:00
|
|
|
*rsp = rsp_iov[1];
|
|
|
|
*buftype = resp_buftype[1];
|
|
|
|
|
|
|
|
qic_exit:
|
2022-03-22 14:29:02 +08:00
|
|
|
kfree(utf16_path);
|
2018-12-21 12:03:04 +08:00
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
SMB2_query_info_free(&rqst[1]);
|
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
2022-03-22 14:29:03 +08:00
|
|
|
if (cfid)
|
|
|
|
close_cached_dir(cfid);
|
2018-12-21 12:03:04 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
2020-02-04 03:46:43 +08:00
|
|
|
struct cifs_sb_info *cifs_sb, struct kstatfs *buf)
|
2018-12-21 12:03:04 +08:00
|
|
|
{
|
|
|
|
struct smb2_query_info_rsp *rsp;
|
|
|
|
struct smb2_fs_full_size_info *info = NULL;
|
|
|
|
struct kvec rsp_iov = {NULL, 0};
|
|
|
|
int buftype = CIFS_NO_BUFFER;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
2022-03-22 14:29:02 +08:00
|
|
|
rc = smb2_query_info_compound(xid, tcon, "",
|
2018-12-21 12:03:04 +08:00
|
|
|
FILE_READ_ATTRIBUTES,
|
|
|
|
FS_FULL_SIZE_INFORMATION,
|
|
|
|
SMB2_O_INFO_FILESYSTEM,
|
|
|
|
sizeof(struct smb2_fs_full_size_info),
|
2020-02-05 03:02:59 +08:00
|
|
|
&rsp_iov, &buftype, cifs_sb);
|
2018-08-08 13:07:49 +08:00
|
|
|
if (rc)
|
|
|
|
goto qfs_exit;
|
|
|
|
|
2018-12-21 12:03:04 +08:00
|
|
|
rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base;
|
2022-01-11 08:00:02 +08:00
|
|
|
buf->f_type = SMB2_SUPER_MAGIC;
|
2018-08-08 13:07:49 +08:00
|
|
|
info = (struct smb2_fs_full_size_info *)(
|
|
|
|
le16_to_cpu(rsp->OutputBufferOffset) + (char *)rsp);
|
|
|
|
rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset),
|
|
|
|
le32_to_cpu(rsp->OutputBufferLength),
|
2018-12-21 12:03:04 +08:00
|
|
|
&rsp_iov,
|
2018-08-08 13:07:49 +08:00
|
|
|
sizeof(struct smb2_fs_full_size_info));
|
|
|
|
if (!rc)
|
|
|
|
smb2_copy_fs_info_to_kstatfs(info, buf);
|
|
|
|
|
|
|
|
qfs_exit:
|
2018-12-21 12:03:04 +08:00
|
|
|
free_rsp_buf(buftype, rsp_iov.iov_base);
|
2012-09-19 07:20:34 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-06-25 12:28:12 +08:00
|
|
|
static int
|
|
|
|
smb311_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
|
2020-02-04 03:46:43 +08:00
|
|
|
struct cifs_sb_info *cifs_sb, struct kstatfs *buf)
|
2018-06-25 12:28:12 +08:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le16 srch_path = 0; /* Null - open root of share */
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
|
|
|
|
if (!tcon->posix_extensions)
|
2020-02-04 03:46:43 +08:00
|
|
|
return smb2_queryfs(xid, tcon, cifs_sb, buf);
|
2018-06-25 12:28:12 +08:00
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2018-06-25 12:28:12 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-03-03 00:53:22 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
|
|
|
|
NULL, NULL);
|
2018-06-25 12:28:12 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
rc = SMB311_posix_qfs_info(xid, tcon, fid.persistent_fid,
|
|
|
|
fid.volatile_fid, buf);
|
2022-01-11 08:00:02 +08:00
|
|
|
buf->f_type = SMB2_SUPER_MAGIC;
|
2018-06-25 12:28:12 +08:00
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-09-19 21:22:43 +08:00
|
|
|
static bool
|
|
|
|
smb2_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
|
|
|
|
{
|
|
|
|
return ob1->fid.persistent_fid == ob2->fid.persistent_fid &&
|
|
|
|
ob1->fid.volatile_fid == ob2->fid.volatile_fid;
|
|
|
|
}
|
|
|
|
|
2012-09-19 21:22:43 +08:00
|
|
|
static int
|
|
|
|
smb2_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
|
|
|
|
__u64 length, __u32 type, int lock, int unlock, bool wait)
|
|
|
|
{
|
|
|
|
if (unlock && !lock)
|
|
|
|
type = SMB2_LOCKFLAG_UNLOCK;
|
|
|
|
return SMB2_lock(xid, tlink_tcon(cfile->tlink),
|
|
|
|
cfile->fid.persistent_fid, cfile->fid.volatile_fid,
|
|
|
|
current->tgid, length, offset, type, wait);
|
|
|
|
}
|
|
|
|
|
2012-09-19 21:22:44 +08:00
|
|
|
static void
|
|
|
|
smb2_get_lease_key(struct inode *inode, struct cifs_fid *fid)
|
|
|
|
{
|
|
|
|
memcpy(fid->lease_key, CIFS_I(inode)->lease_key, SMB2_LEASE_KEY_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
smb2_set_lease_key(struct inode *inode, struct cifs_fid *fid)
|
|
|
|
{
|
|
|
|
memcpy(CIFS_I(inode)->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
smb2_new_lease_key(struct cifs_fid *fid)
|
|
|
|
{
|
2016-09-22 13:39:34 +08:00
|
|
|
generate_random_uuid(fid->lease_key);
|
2012-09-19 21:22:44 +08:00
|
|
|
}
|
|
|
|
|
2017-02-13 23:16:49 +08:00
|
|
|
static int
|
|
|
|
smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
|
|
|
|
const char *search_name,
|
|
|
|
struct dfs_info3_param **target_nodes,
|
|
|
|
unsigned int *num_of_nodes,
|
|
|
|
const struct nls_table *nls_codepage, int remap)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le16 *utf16_path = NULL;
|
|
|
|
int utf16_path_len = 0;
|
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
struct fsctl_get_dfs_referral_req *dfs_req = NULL;
|
|
|
|
struct get_dfs_referral_rsp *dfs_rsp = NULL;
|
|
|
|
u32 dfs_req_size = 0, dfs_rsp_size = 0;
|
2021-11-04 00:53:29 +08:00
|
|
|
int retry_count = 0;
|
2017-02-13 23:16:49 +08:00
|
|
|
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "%s: path: %s\n", __func__, search_name);
|
2017-02-13 23:16:49 +08:00
|
|
|
|
|
|
|
/*
|
2018-01-24 20:46:11 +08:00
|
|
|
* Try to use the IPC tcon, otherwise just use any
|
2017-02-13 23:16:49 +08:00
|
|
|
*/
|
2018-01-24 20:46:11 +08:00
|
|
|
tcon = ses->tcon_ipc;
|
|
|
|
if (tcon == NULL) {
|
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
|
|
|
tcon = list_first_entry_or_null(&ses->tcon_list,
|
|
|
|
struct cifs_tcon,
|
|
|
|
tcon_list);
|
|
|
|
if (tcon)
|
|
|
|
tcon->tc_count++;
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tcon == NULL) {
|
2017-02-13 23:16:49 +08:00
|
|
|
cifs_dbg(VFS, "session %p has no tcon available for a dfs referral request\n",
|
|
|
|
ses);
|
|
|
|
rc = -ENOTCONN;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
utf16_path = cifs_strndup_to_utf16(search_name, PATH_MAX,
|
|
|
|
&utf16_path_len,
|
|
|
|
nls_codepage, remap);
|
|
|
|
if (!utf16_path) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
dfs_req_size = sizeof(*dfs_req) + utf16_path_len;
|
|
|
|
dfs_req = kzalloc(dfs_req_size, GFP_KERNEL);
|
|
|
|
if (!dfs_req) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Highest DFS referral version understood */
|
|
|
|
dfs_req->MaxReferralLevel = DFS_VERSION;
|
|
|
|
|
|
|
|
/* Path to resolve in an UTF-16 null-terminated string */
|
|
|
|
memcpy(dfs_req->RequestFileName, utf16_path, utf16_path_len);
|
|
|
|
|
|
|
|
do {
|
|
|
|
rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID,
|
|
|
|
FSCTL_DFS_GET_REFERRALS,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fsctl */,
|
2019-03-29 11:32:49 +08:00
|
|
|
(char *)dfs_req, dfs_req_size, CIFSMaxBufSize,
|
2017-02-13 23:16:49 +08:00
|
|
|
(char **)&dfs_rsp, &dfs_rsp_size);
|
2021-11-04 00:53:29 +08:00
|
|
|
if (!is_retryable_error(rc))
|
|
|
|
break;
|
|
|
|
usleep_range(512, 2048);
|
|
|
|
} while (++retry_count < 5);
|
2017-02-13 23:16:49 +08:00
|
|
|
|
|
|
|
if (rc) {
|
2021-11-04 00:53:29 +08:00
|
|
|
if (!is_retryable_error(rc) && rc != -ENOENT && rc != -EOPNOTSUPP)
|
|
|
|
cifs_tcon_dbg(VFS, "%s: ioctl error: rc=%d\n", __func__, rc);
|
2017-02-13 23:16:49 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = parse_dfs_referrals(dfs_rsp, dfs_rsp_size,
|
|
|
|
num_of_nodes, target_nodes,
|
|
|
|
nls_codepage, remap, search_name,
|
|
|
|
true /* is_unicode */);
|
|
|
|
if (rc) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_tcon_dbg(VFS, "parse error in %s rc=%d\n", __func__, rc);
|
2017-02-13 23:16:49 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
2018-01-24 20:46:11 +08:00
|
|
|
if (tcon && !tcon->ipc) {
|
|
|
|
/* ipc tcons are not refcounted */
|
2017-02-13 23:16:49 +08:00
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
|
|
|
tcon->tc_count--;
|
2021-07-15 12:00:00 +08:00
|
|
|
/* tc_count can never go negative */
|
|
|
|
WARN_ON(tcon->tc_count < 0);
|
2017-02-13 23:16:49 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
}
|
|
|
|
kfree(utf16_path);
|
|
|
|
kfree(dfs_req);
|
|
|
|
kfree(dfs_rsp);
|
|
|
|
return rc;
|
|
|
|
}
|
2019-06-27 12:57:02 +08:00
|
|
|
|
2019-06-28 15:04:18 +08:00
|
|
|
static int
|
|
|
|
parse_reparse_posix(struct reparse_posix_data *symlink_buf,
|
|
|
|
u32 plen, char **target_path,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
|
|
|
unsigned int len;
|
|
|
|
|
|
|
|
/* See MS-FSCC 2.1.2.6 for the 'NFS' style reparse tags */
|
|
|
|
len = le16_to_cpu(symlink_buf->ReparseDataLength);
|
|
|
|
|
|
|
|
if (le64_to_cpu(symlink_buf->InodeType) != NFS_SPECFILE_LNK) {
|
|
|
|
cifs_dbg(VFS, "%lld not a supported symlink type\n",
|
|
|
|
le64_to_cpu(symlink_buf->InodeType));
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
|
|
|
*target_path = cifs_strndup_from_utf16(
|
|
|
|
symlink_buf->PathBuffer,
|
|
|
|
len, true, cifs_sb->local_nls);
|
|
|
|
if (!(*target_path))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
convert_delimiter(*target_path, '/');
|
|
|
|
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-27 12:57:02 +08:00
|
|
|
static int
|
|
|
|
parse_reparse_symlink(struct reparse_symlink_data_buffer *symlink_buf,
|
|
|
|
u32 plen, char **target_path,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
|
|
|
{
|
|
|
|
unsigned int sub_len;
|
|
|
|
unsigned int sub_offset;
|
|
|
|
|
2019-06-28 15:04:18 +08:00
|
|
|
/* We handle Symbolic Link reparse tag here. See: MS-FSCC 2.1.2.4 */
|
2019-06-27 12:57:02 +08:00
|
|
|
|
|
|
|
sub_offset = le16_to_cpu(symlink_buf->SubstituteNameOffset);
|
|
|
|
sub_len = le16_to_cpu(symlink_buf->SubstituteNameLength);
|
|
|
|
if (sub_offset + 20 > plen ||
|
|
|
|
sub_offset + sub_len + 20 > plen) {
|
|
|
|
cifs_dbg(VFS, "srv returned malformed symlink buffer\n");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
*target_path = cifs_strndup_from_utf16(
|
|
|
|
symlink_buf->PathBuffer + sub_offset,
|
|
|
|
sub_len, true, cifs_sb->local_nls);
|
|
|
|
if (!(*target_path))
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
convert_delimiter(*target_path, '/');
|
|
|
|
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-06-28 15:04:18 +08:00
|
|
|
static int
|
2019-07-07 05:45:42 +08:00
|
|
|
parse_reparse_point(struct reparse_data_buffer *buf,
|
|
|
|
u32 plen, char **target_path,
|
|
|
|
struct cifs_sb_info *cifs_sb)
|
2019-06-28 15:04:18 +08:00
|
|
|
{
|
2019-07-07 05:45:42 +08:00
|
|
|
if (plen < sizeof(struct reparse_data_buffer)) {
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_dbg(VFS, "reparse buffer is too small. Must be at least 8 bytes but was %d\n",
|
|
|
|
plen);
|
2019-07-07 05:45:42 +08:00
|
|
|
return -EIO;
|
|
|
|
}
|
2019-06-28 15:04:18 +08:00
|
|
|
|
2019-07-07 05:45:42 +08:00
|
|
|
if (plen < le16_to_cpu(buf->ReparseDataLength) +
|
|
|
|
sizeof(struct reparse_data_buffer)) {
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_dbg(VFS, "srv returned invalid reparse buf length: %d\n",
|
|
|
|
plen);
|
2019-07-07 05:45:42 +08:00
|
|
|
return -EIO;
|
|
|
|
}
|
2019-06-28 15:04:18 +08:00
|
|
|
|
2019-07-07 05:45:42 +08:00
|
|
|
/* See MS-FSCC 2.1.2 */
|
|
|
|
switch (le32_to_cpu(buf->ReparseTag)) {
|
|
|
|
case IO_REPARSE_TAG_NFS:
|
|
|
|
return parse_reparse_posix(
|
|
|
|
(struct reparse_posix_data *)buf,
|
|
|
|
plen, target_path, cifs_sb);
|
|
|
|
case IO_REPARSE_TAG_SYMLINK:
|
|
|
|
return parse_reparse_symlink(
|
|
|
|
(struct reparse_symlink_data_buffer *)buf,
|
|
|
|
plen, target_path, cifs_sb);
|
|
|
|
default:
|
2020-04-15 13:42:53 +08:00
|
|
|
cifs_dbg(VFS, "srv returned unknown symlink buffer tag:0x%08x\n",
|
|
|
|
le32_to_cpu(buf->ReparseTag));
|
2019-07-07 05:45:42 +08:00
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
2019-06-28 15:04:18 +08:00
|
|
|
}
|
|
|
|
|
2016-07-24 15:37:38 +08:00
|
|
|
#define SMB2_SYMLINK_STRUCT_SIZE \
|
|
|
|
(sizeof(struct smb2_err_rsp) - 1 + sizeof(struct smb2_symlink_err_rsp))
|
|
|
|
|
2013-08-14 23:25:21 +08:00
|
|
|
static int
|
|
|
|
smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
2019-04-10 06:44:46 +08:00
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
|
|
|
char **target_path, bool is_reparse_point)
|
2013-08-14 23:25:21 +08:00
|
|
|
{
|
|
|
|
int rc;
|
2019-04-10 06:44:46 +08:00
|
|
|
__le16 *utf16_path = NULL;
|
2013-08-14 23:25:21 +08:00
|
|
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
2018-04-13 07:03:19 +08:00
|
|
|
struct kvec err_iov = {NULL, 0};
|
2018-06-08 11:21:18 +08:00
|
|
|
struct smb2_err_rsp *err_buf = NULL;
|
2013-08-14 23:25:21 +08:00
|
|
|
struct smb2_symlink_err_rsp *symlink;
|
2020-06-01 01:38:22 +08:00
|
|
|
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
|
2016-07-24 15:37:38 +08:00
|
|
|
unsigned int sub_len;
|
|
|
|
unsigned int sub_offset;
|
|
|
|
unsigned int print_len;
|
|
|
|
unsigned int print_offset;
|
2021-03-08 23:00:50 +08:00
|
|
|
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
2019-04-10 06:44:46 +08:00
|
|
|
struct smb_rqst rqst[3];
|
|
|
|
int resp_buftype[3];
|
|
|
|
struct kvec rsp_iov[3];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
|
|
|
struct kvec close_iov[1];
|
|
|
|
struct smb2_create_rsp *create_rsp;
|
|
|
|
struct smb2_ioctl_rsp *ioctl_rsp;
|
2019-06-27 12:57:02 +08:00
|
|
|
struct reparse_data_buffer *reparse_buf;
|
2020-02-04 03:46:43 +08:00
|
|
|
int create_options = is_reparse_point ? OPEN_REPARSE_POINT : 0;
|
2019-04-10 06:44:46 +08:00
|
|
|
u32 plen;
|
2013-08-14 23:25:21 +08:00
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
|
|
|
|
2019-06-27 12:57:02 +08:00
|
|
|
*target_path = NULL;
|
|
|
|
|
2019-04-10 06:44:46 +08:00
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
|
|
|
memset(rqst, 0, sizeof(rqst));
|
|
|
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
|
|
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
|
|
|
|
2013-08-14 23:25:21 +08:00
|
|
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
|
|
|
if (!utf16_path)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2019-04-10 06:44:46 +08:00
|
|
|
/* Open */
|
|
|
|
memset(&open_iov, 0, sizeof(open_iov));
|
|
|
|
rqst[0].rq_iov = open_iov;
|
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
|
|
|
|
|
|
|
memset(&oparms, 0, sizeof(oparms));
|
2013-08-14 23:25:21 +08:00
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, create_options);
|
2013-08-14 23:25:21 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, utf16_path);
|
2019-04-10 06:44:46 +08:00
|
|
|
if (rc)
|
|
|
|
goto querty_exit;
|
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
|
|
|
|
|
|
|
|
|
|
|
/* IOCTL */
|
|
|
|
memset(&io_iov, 0, sizeof(io_iov));
|
|
|
|
rqst[1].rq_iov = io_iov;
|
|
|
|
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_ioctl_init(tcon, server,
|
|
|
|
&rqst[1], fid.persistent_fid,
|
2019-04-10 06:44:46 +08:00
|
|
|
fid.volatile_fid, FSCTL_GET_REPARSE_POINT,
|
2020-01-08 11:08:07 +08:00
|
|
|
true /* is_fctl */, NULL, 0,
|
|
|
|
CIFSMaxBufSize -
|
|
|
|
MAX_SMB2_CREATE_RESPONSE_SIZE -
|
|
|
|
MAX_SMB2_CLOSE_RESPONSE_SIZE);
|
2019-04-10 06:44:46 +08:00
|
|
|
if (rc)
|
|
|
|
goto querty_exit;
|
|
|
|
|
|
|
|
smb2_set_next_command(tcon, &rqst[1]);
|
|
|
|
smb2_set_related(&rqst[1]);
|
|
|
|
|
|
|
|
|
|
|
|
/* Close */
|
|
|
|
memset(&close_iov, 0, sizeof(close_iov));
|
|
|
|
rqst[2].rq_iov = close_iov;
|
|
|
|
rqst[2].rq_nvec = 1;
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
2019-04-10 06:44:46 +08:00
|
|
|
if (rc)
|
|
|
|
goto querty_exit;
|
|
|
|
|
|
|
|
smb2_set_related(&rqst[2]);
|
|
|
|
|
2020-06-01 01:38:22 +08:00
|
|
|
rc = compound_send_recv(xid, tcon->ses, server,
|
|
|
|
flags, 3, rqst,
|
2019-04-10 06:44:46 +08:00
|
|
|
resp_buftype, rsp_iov);
|
|
|
|
|
|
|
|
create_rsp = rsp_iov[0].iov_base;
|
2021-11-05 07:39:01 +08:00
|
|
|
if (create_rsp && create_rsp->hdr.Status)
|
2019-04-10 06:44:46 +08:00
|
|
|
err_iov = rsp_iov[0];
|
|
|
|
ioctl_rsp = rsp_iov[1].iov_base;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open was successful and we got an ioctl response.
|
|
|
|
*/
|
|
|
|
if ((rc == 0) && (is_reparse_point)) {
|
|
|
|
/* See MS-FSCC 2.3.23 */
|
|
|
|
|
2019-06-27 12:57:02 +08:00
|
|
|
reparse_buf = (struct reparse_data_buffer *)
|
|
|
|
((char *)ioctl_rsp +
|
|
|
|
le32_to_cpu(ioctl_rsp->OutputOffset));
|
2019-04-10 06:44:46 +08:00
|
|
|
plen = le32_to_cpu(ioctl_rsp->OutputCount);
|
|
|
|
|
|
|
|
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
|
|
|
|
rsp_iov[1].iov_len) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
|
2019-06-27 12:57:02 +08:00
|
|
|
plen);
|
|
|
|
rc = -EIO;
|
|
|
|
goto querty_exit;
|
|
|
|
}
|
|
|
|
|
2019-07-07 05:45:42 +08:00
|
|
|
rc = parse_reparse_point(reparse_buf, plen, target_path,
|
|
|
|
cifs_sb);
|
2019-04-10 06:44:46 +08:00
|
|
|
goto querty_exit;
|
|
|
|
}
|
|
|
|
|
2018-04-13 23:13:29 +08:00
|
|
|
if (!rc || !err_iov.iov_base) {
|
2018-06-08 11:21:18 +08:00
|
|
|
rc = -ENOENT;
|
2019-04-10 06:44:46 +08:00
|
|
|
goto querty_exit;
|
2013-08-14 23:25:21 +08:00
|
|
|
}
|
2016-07-24 15:37:38 +08:00
|
|
|
|
2018-04-13 07:03:19 +08:00
|
|
|
err_buf = err_iov.iov_base;
|
2016-07-24 15:37:38 +08:00
|
|
|
if (le32_to_cpu(err_buf->ByteCount) < sizeof(struct smb2_symlink_err_rsp) ||
|
2018-06-01 08:53:07 +08:00
|
|
|
err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE) {
|
2019-07-09 16:41:11 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto querty_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
|
|
|
|
if (le32_to_cpu(symlink->SymLinkErrorTag) != SYMLINK_ERROR_TAG ||
|
|
|
|
le32_to_cpu(symlink->ReparseTag) != IO_REPARSE_TAG_SYMLINK) {
|
|
|
|
rc = -EINVAL;
|
2018-06-08 11:21:18 +08:00
|
|
|
goto querty_exit;
|
2016-07-24 15:37:38 +08:00
|
|
|
}
|
|
|
|
|
2013-08-14 23:25:21 +08:00
|
|
|
/* open must fail on symlink - reset rc */
|
|
|
|
rc = 0;
|
|
|
|
sub_len = le16_to_cpu(symlink->SubstituteNameLength);
|
|
|
|
sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
|
2016-07-24 15:37:38 +08:00
|
|
|
print_len = le16_to_cpu(symlink->PrintNameLength);
|
|
|
|
print_offset = le16_to_cpu(symlink->PrintNameOffset);
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
if (err_iov.iov_len < SMB2_SYMLINK_STRUCT_SIZE + sub_offset + sub_len) {
|
2019-07-09 16:41:11 +08:00
|
|
|
rc = -EINVAL;
|
2018-06-08 11:21:18 +08:00
|
|
|
goto querty_exit;
|
2016-07-24 15:37:38 +08:00
|
|
|
}
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
if (err_iov.iov_len <
|
|
|
|
SMB2_SYMLINK_STRUCT_SIZE + print_offset + print_len) {
|
2019-07-09 16:41:11 +08:00
|
|
|
rc = -EINVAL;
|
2018-06-08 11:21:18 +08:00
|
|
|
goto querty_exit;
|
2016-07-24 15:37:38 +08:00
|
|
|
}
|
|
|
|
|
2013-08-14 23:25:21 +08:00
|
|
|
*target_path = cifs_strndup_from_utf16(
|
|
|
|
(char *)symlink->PathBuffer + sub_offset,
|
|
|
|
sub_len, true, cifs_sb->local_nls);
|
|
|
|
if (!(*target_path)) {
|
2018-06-08 11:21:18 +08:00
|
|
|
rc = -ENOMEM;
|
|
|
|
goto querty_exit;
|
2013-08-14 23:25:21 +08:00
|
|
|
}
|
|
|
|
convert_delimiter(*target_path, '/');
|
|
|
|
cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
|
2018-06-08 11:21:18 +08:00
|
|
|
|
|
|
|
querty_exit:
|
2019-04-10 06:44:46 +08:00
|
|
|
cifs_dbg(FYI, "query symlink rc %d\n", rc);
|
2013-08-14 23:25:21 +08:00
|
|
|
kfree(utf16_path);
|
2019-04-10 06:44:46 +08:00
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
SMB2_ioctl_free(&rqst[1]);
|
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
2013-08-14 23:25:21 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2020-10-23 11:03:14 +08:00
|
|
|
int
|
|
|
|
smb2_query_reparse_tag(const unsigned int xid, struct cifs_tcon *tcon,
|
|
|
|
struct cifs_sb_info *cifs_sb, const char *full_path,
|
|
|
|
__u32 *tag)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
__le16 *utf16_path = NULL;
|
|
|
|
__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
|
2021-03-08 23:00:50 +08:00
|
|
|
int flags = CIFS_CP_CREATE_CLOSE_OP;
|
2020-10-23 11:03:14 +08:00
|
|
|
struct smb_rqst rqst[3];
|
|
|
|
int resp_buftype[3];
|
|
|
|
struct kvec rsp_iov[3];
|
|
|
|
struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
|
|
|
|
struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
|
|
|
|
struct kvec close_iov[1];
|
|
|
|
struct smb2_ioctl_rsp *ioctl_rsp;
|
|
|
|
struct reparse_data_buffer *reparse_buf;
|
|
|
|
u32 plen;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
|
|
|
|
|
|
|
|
if (smb3_encryption_required(tcon))
|
|
|
|
flags |= CIFS_TRANSFORM_REQ;
|
|
|
|
|
|
|
|
memset(rqst, 0, sizeof(rqst));
|
|
|
|
resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
|
|
|
|
memset(rsp_iov, 0, sizeof(rsp_iov));
|
|
|
|
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
|
|
|
|
if (!utf16_path)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* setup smb2open - TODO add optimization to call cifs_get_readable_path
|
|
|
|
* to see if there is a handle already open that we can use
|
|
|
|
*/
|
|
|
|
memset(&open_iov, 0, sizeof(open_iov));
|
|
|
|
rqst[0].rq_iov = open_iov;
|
|
|
|
rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
|
|
|
|
|
|
|
|
memset(&oparms, 0, sizeof(oparms));
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = FILE_READ_ATTRIBUTES;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT);
|
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
|
|
rc = SMB2_open_init(tcon, server,
|
|
|
|
&rqst[0], &oplock, &oparms, utf16_path);
|
|
|
|
if (rc)
|
|
|
|
goto query_rp_exit;
|
|
|
|
smb2_set_next_command(tcon, &rqst[0]);
|
|
|
|
|
|
|
|
|
|
|
|
/* IOCTL */
|
|
|
|
memset(&io_iov, 0, sizeof(io_iov));
|
|
|
|
rqst[1].rq_iov = io_iov;
|
|
|
|
rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
|
|
|
|
|
|
|
|
rc = SMB2_ioctl_init(tcon, server,
|
2020-12-03 11:31:36 +08:00
|
|
|
&rqst[1], COMPOUND_FID,
|
|
|
|
COMPOUND_FID, FSCTL_GET_REPARSE_POINT,
|
2020-10-23 11:03:14 +08:00
|
|
|
true /* is_fctl */, NULL, 0,
|
|
|
|
CIFSMaxBufSize -
|
|
|
|
MAX_SMB2_CREATE_RESPONSE_SIZE -
|
|
|
|
MAX_SMB2_CLOSE_RESPONSE_SIZE);
|
|
|
|
if (rc)
|
|
|
|
goto query_rp_exit;
|
|
|
|
|
|
|
|
smb2_set_next_command(tcon, &rqst[1]);
|
|
|
|
smb2_set_related(&rqst[1]);
|
|
|
|
|
|
|
|
|
|
|
|
/* Close */
|
|
|
|
memset(&close_iov, 0, sizeof(close_iov));
|
|
|
|
rqst[2].rq_iov = close_iov;
|
|
|
|
rqst[2].rq_nvec = 1;
|
|
|
|
|
|
|
|
rc = SMB2_close_init(tcon, server,
|
|
|
|
&rqst[2], COMPOUND_FID, COMPOUND_FID, false);
|
|
|
|
if (rc)
|
|
|
|
goto query_rp_exit;
|
|
|
|
|
|
|
|
smb2_set_related(&rqst[2]);
|
|
|
|
|
|
|
|
rc = compound_send_recv(xid, tcon->ses, server,
|
|
|
|
flags, 3, rqst,
|
|
|
|
resp_buftype, rsp_iov);
|
|
|
|
|
|
|
|
ioctl_rsp = rsp_iov[1].iov_base;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Open was successful and we got an ioctl response.
|
|
|
|
*/
|
|
|
|
if (rc == 0) {
|
|
|
|
/* See MS-FSCC 2.3.23 */
|
|
|
|
|
|
|
|
reparse_buf = (struct reparse_data_buffer *)
|
|
|
|
((char *)ioctl_rsp +
|
|
|
|
le32_to_cpu(ioctl_rsp->OutputOffset));
|
|
|
|
plen = le32_to_cpu(ioctl_rsp->OutputCount);
|
|
|
|
|
|
|
|
if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
|
|
|
|
rsp_iov[1].iov_len) {
|
|
|
|
cifs_tcon_dbg(FYI, "srv returned invalid ioctl len: %d\n",
|
|
|
|
plen);
|
|
|
|
rc = -EIO;
|
|
|
|
goto query_rp_exit;
|
|
|
|
}
|
|
|
|
*tag = le32_to_cpu(reparse_buf->ReparseTag);
|
|
|
|
}
|
|
|
|
|
|
|
|
query_rp_exit:
|
|
|
|
kfree(utf16_path);
|
|
|
|
SMB2_open_free(&rqst[0]);
|
|
|
|
SMB2_ioctl_free(&rqst[1]);
|
|
|
|
SMB2_close_free(&rqst[2]);
|
|
|
|
free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
|
|
|
|
free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-06-23 11:52:05 +08:00
|
|
|
static struct cifs_ntsd *
|
|
|
|
get_smb2_acl_by_fid(struct cifs_sb_info *cifs_sb,
|
2020-12-19 01:30:12 +08:00
|
|
|
const struct cifs_fid *cifsfid, u32 *pacllen, u32 info)
|
2017-06-23 11:52:05 +08:00
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
|
|
|
unsigned int xid;
|
|
|
|
int rc = -EOPNOTSUPP;
|
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
|
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return ERR_CAST(tlink);
|
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
cifs_dbg(FYI, "trying to get acl\n");
|
|
|
|
|
|
|
|
rc = SMB2_query_acl(xid, tlink_tcon(tlink), cifsfid->persistent_fid,
|
2020-12-19 01:30:12 +08:00
|
|
|
cifsfid->volatile_fid, (void **)&pntsd, pacllen,
|
|
|
|
info);
|
2017-06-23 11:52:05 +08:00
|
|
|
free_xid(xid);
|
|
|
|
|
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
|
|
|
|
if (rc)
|
|
|
|
return ERR_PTR(rc);
|
|
|
|
return pntsd;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct cifs_ntsd *
|
|
|
|
get_smb2_acl_by_path(struct cifs_sb_info *cifs_sb,
|
2020-12-19 01:30:12 +08:00
|
|
|
const char *path, u32 *pacllen, u32 info)
|
2017-06-23 11:52:05 +08:00
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
unsigned int xid;
|
|
|
|
int rc;
|
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
__le16 *utf16_path;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "get smb3 acl for path %s\n", path);
|
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return ERR_CAST(tlink);
|
|
|
|
|
|
|
|
tcon = tlink_tcon(tlink);
|
|
|
|
xid = get_xid();
|
|
|
|
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
2018-05-19 15:04:55 +08:00
|
|
|
if (!utf16_path) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
free_xid(xid);
|
|
|
|
return ERR_PTR(rc);
|
|
|
|
}
|
2017-06-23 11:52:05 +08:00
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = READ_CONTROL;
|
|
|
|
oparms.disposition = FILE_OPEN;
|
2020-10-22 02:12:08 +08:00
|
|
|
/*
|
|
|
|
* When querying an ACL, even if the file is a symlink we want to open
|
|
|
|
* the source not the target, and so the protocol requires that the
|
|
|
|
* client specify this flag when opening a reparse point
|
|
|
|
*/
|
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0) | OPEN_REPARSE_POINT;
|
2017-06-23 11:52:05 +08:00
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-12-19 01:30:12 +08:00
|
|
|
if (info & SACL_SECINFO)
|
|
|
|
oparms.desired_access |= SYSTEM_SECURITY;
|
|
|
|
|
2020-03-03 00:53:22 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
|
|
|
|
NULL);
|
2017-06-23 11:52:05 +08:00
|
|
|
kfree(utf16_path);
|
|
|
|
if (!rc) {
|
|
|
|
rc = SMB2_query_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
|
2020-12-19 01:30:12 +08:00
|
|
|
fid.volatile_fid, (void **)&pntsd, pacllen,
|
|
|
|
info);
|
2017-06-23 11:52:05 +08:00
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
|
|
}
|
|
|
|
|
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
free_xid(xid);
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "%s: rc = %d ACL len %d\n", __func__, rc, *pacllen);
|
|
|
|
if (rc)
|
|
|
|
return ERR_PTR(rc);
|
|
|
|
return pntsd;
|
|
|
|
}
|
|
|
|
|
2017-06-29 11:37:32 +08:00
|
|
|
static int
|
|
|
|
set_smb2_acl(struct cifs_ntsd *pnntsd, __u32 acllen,
|
|
|
|
struct inode *inode, const char *path, int aclflag)
|
|
|
|
{
|
|
|
|
u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
|
|
|
|
unsigned int xid;
|
|
|
|
int rc, access_flags = 0;
|
|
|
|
struct cifs_tcon *tcon;
|
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
__le16 *utf16_path;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "set smb3 acl for path %s\n", path);
|
|
|
|
if (IS_ERR(tlink))
|
|
|
|
return PTR_ERR(tlink);
|
|
|
|
|
|
|
|
tcon = tlink_tcon(tlink);
|
|
|
|
xid = get_xid();
|
|
|
|
|
2020-12-19 01:30:12 +08:00
|
|
|
if (aclflag & CIFS_ACL_OWNER || aclflag & CIFS_ACL_GROUP)
|
|
|
|
access_flags |= WRITE_OWNER;
|
|
|
|
if (aclflag & CIFS_ACL_SACL)
|
|
|
|
access_flags |= SYSTEM_SECURITY;
|
|
|
|
if (aclflag & CIFS_ACL_DACL)
|
|
|
|
access_flags |= WRITE_DAC;
|
2017-06-29 11:37:32 +08:00
|
|
|
|
|
|
|
utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
|
2018-05-19 15:04:55 +08:00
|
|
|
if (!utf16_path) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
2017-06-29 11:37:32 +08:00
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.desired_access = access_flags;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, 0);
|
2017-06-29 11:37:32 +08:00
|
|
|
oparms.disposition = FILE_OPEN;
|
|
|
|
oparms.path = path;
|
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
2020-03-03 00:53:22 +08:00
|
|
|
rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
|
|
|
|
NULL, NULL);
|
2017-06-29 11:37:32 +08:00
|
|
|
kfree(utf16_path);
|
|
|
|
if (!rc) {
|
|
|
|
rc = SMB2_set_acl(xid, tlink_tcon(tlink), fid.persistent_fid,
|
|
|
|
fid.volatile_fid, pnntsd, acllen, aclflag);
|
|
|
|
SMB2_close(xid, tcon, fid.persistent_fid, fid.volatile_fid);
|
|
|
|
}
|
|
|
|
|
|
|
|
cifs_put_tlink(tlink);
|
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2017-06-23 11:52:05 +08:00
|
|
|
/* Retrieve an ACL from the server */
|
|
|
|
static struct cifs_ntsd *
|
|
|
|
get_smb2_acl(struct cifs_sb_info *cifs_sb,
|
2020-12-19 01:30:12 +08:00
|
|
|
struct inode *inode, const char *path,
|
|
|
|
u32 *pacllen, u32 info)
|
2017-06-23 11:52:05 +08:00
|
|
|
{
|
|
|
|
struct cifs_ntsd *pntsd = NULL;
|
|
|
|
struct cifsFileInfo *open_file = NULL;
|
|
|
|
|
2020-12-18 04:58:08 +08:00
|
|
|
if (inode && !(info & SACL_SECINFO))
|
2017-06-23 11:52:05 +08:00
|
|
|
open_file = find_readable_file(CIFS_I(inode), true);
|
2020-12-18 04:58:08 +08:00
|
|
|
if (!open_file || (info & SACL_SECINFO))
|
2020-12-19 01:30:12 +08:00
|
|
|
return get_smb2_acl_by_path(cifs_sb, path, pacllen, info);
|
2017-06-23 11:52:05 +08:00
|
|
|
|
2020-12-19 01:30:12 +08:00
|
|
|
pntsd = get_smb2_acl_by_fid(cifs_sb, &open_file->fid, pacllen, info);
|
2017-06-23 11:52:05 +08:00
|
|
|
cifsFileInfo_put(open_file);
|
|
|
|
return pntsd;
|
|
|
|
}
|
|
|
|
|
2014-08-18 07:16:40 +08:00
|
|
|
static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
|
|
|
loff_t offset, loff_t len, bool keep_size)
|
|
|
|
{
|
2019-03-13 12:37:49 +08:00
|
|
|
struct cifs_ses *ses = tcon->ses;
|
2014-08-18 07:16:40 +08:00
|
|
|
struct inode *inode;
|
|
|
|
struct cifsInodeInfo *cifsi;
|
|
|
|
struct cifsFileInfo *cfile = file->private_data;
|
|
|
|
struct file_zero_data_information fsctl_buf;
|
|
|
|
long rc;
|
|
|
|
unsigned int xid;
|
2019-03-13 12:37:49 +08:00
|
|
|
__le64 eof;
|
2014-08-18 07:16:40 +08:00
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
inode = d_inode(cfile->dentry);
|
2014-08-18 07:16:40 +08:00
|
|
|
cifsi = CIFS_I(inode);
|
|
|
|
|
2019-05-09 03:36:25 +08:00
|
|
|
trace_smb3_zero_enter(xid, cfile->fid.persistent_fid, tcon->tid,
|
2019-03-13 14:41:49 +08:00
|
|
|
ses->Suid, offset, len);
|
|
|
|
|
2020-06-23 19:31:54 +08:00
|
|
|
/*
|
|
|
|
* We zero the range through ioctl, so we need remove the page caches
|
|
|
|
* first, otherwise the data may be inconsistent with the server.
|
|
|
|
*/
|
|
|
|
truncate_pagecache_range(inode, offset, offset + len - 1);
|
2019-03-13 14:41:49 +08:00
|
|
|
|
2014-08-18 07:16:40 +08:00
|
|
|
/* if file not oplocked can't be sure whether asking to extend size */
|
|
|
|
if (!CIFS_CACHE_READ(cifsi))
|
2018-05-19 15:04:55 +08:00
|
|
|
if (keep_size == false) {
|
|
|
|
rc = -EOPNOTSUPP;
|
2019-03-13 14:41:49 +08:00
|
|
|
trace_smb3_zero_err(xid, cfile->fid.persistent_fid,
|
|
|
|
tcon->tid, ses->Suid, offset, len, rc);
|
2018-05-19 15:04:55 +08:00
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
2014-08-18 07:16:40 +08:00
|
|
|
|
2019-05-09 13:09:37 +08:00
|
|
|
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
|
2014-08-18 07:16:40 +08:00
|
|
|
|
|
|
|
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
|
|
|
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
|
|
|
|
2019-05-02 13:52:57 +08:00
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA, true,
|
|
|
|
(char *)&fsctl_buf,
|
|
|
|
sizeof(struct file_zero_data_information),
|
|
|
|
0, NULL, NULL);
|
2019-03-13 12:37:49 +08:00
|
|
|
if (rc)
|
|
|
|
goto zero_range_exit;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* do we also need to change the size of the file?
|
|
|
|
*/
|
|
|
|
if (keep_size == false && i_size_read(inode) < offset + len) {
|
|
|
|
eof = cpu_to_le64(offset + len);
|
2019-05-02 13:52:57 +08:00
|
|
|
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, cfile->pid, &eof);
|
2019-03-13 12:37:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
zero_range_exit:
|
2014-08-18 07:16:40 +08:00
|
|
|
free_xid(xid);
|
2019-03-13 14:41:49 +08:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_zero_err(xid, cfile->fid.persistent_fid, tcon->tid,
|
|
|
|
ses->Suid, offset, len, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_zero_done(xid, cfile->fid.persistent_fid, tcon->tid,
|
|
|
|
ses->Suid, offset, len);
|
2014-08-18 07:16:40 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-08-17 21:38:47 +08:00
|
|
|
static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
|
|
|
loff_t offset, loff_t len)
|
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct cifsFileInfo *cfile = file->private_data;
|
|
|
|
struct file_zero_data_information fsctl_buf;
|
|
|
|
long rc;
|
|
|
|
unsigned int xid;
|
|
|
|
__u8 set_sparse = 1;
|
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
inode = d_inode(cfile->dentry);
|
2014-08-17 21:38:47 +08:00
|
|
|
|
|
|
|
/* Need to make file sparse, if not already, before freeing range. */
|
|
|
|
/* Consider adding equivalent for compressed since it could also work */
|
2018-05-19 15:04:55 +08:00
|
|
|
if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse)) {
|
|
|
|
rc = -EOPNOTSUPP;
|
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
2014-08-17 21:38:47 +08:00
|
|
|
|
2021-04-22 22:52:32 +08:00
|
|
|
filemap_invalidate_lock(inode->i_mapping);
|
cifs/smb3: Fix data inconsistent when punch hole
When punch hole success, we also can read old data from file:
# strace -e trace=pread64,fallocate xfs_io -f -c "pread 20 40" \
-c "fpunch 20 40" -c"pread 20 40" file
pread64(3, " version 5.8.0-rc1+"..., 40, 20) = 40
fallocate(3, FALLOC_FL_KEEP_SIZE|FALLOC_FL_PUNCH_HOLE, 20, 40) = 0
pread64(3, " version 5.8.0-rc1+"..., 40, 20) = 40
CIFS implements the fallocate(FALLOCATE_FL_PUNCH_HOLE) with send SMB
ioctl(FSCTL_SET_ZERO_DATA) to server. It just set the range of the
remote file to zero, but local page caches not updated, then the
local page caches inconsistent with server.
Also can be found by xfstests generic/316.
So, we need to remove the page caches before send the SMB
ioctl(FSCTL_SET_ZERO_DATA) to server.
Fixes: 31742c5a33176 ("enable fallocate punch hole ("fallocate -p") for SMB3")
Suggested-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5@huawei.com>
Cc: stable@vger.kernel.org # v3.17
Signed-off-by: Steve French <stfrench@microsoft.com>
2020-06-23 19:31:53 +08:00
|
|
|
/*
|
|
|
|
* We implement the punch hole through ioctl, so we need remove the page
|
|
|
|
* caches first, otherwise the data may be inconsistent with the server.
|
|
|
|
*/
|
|
|
|
truncate_pagecache_range(inode, offset, offset + len - 1);
|
|
|
|
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "Offset %lld len %lld\n", offset, len);
|
2014-08-17 21:38:47 +08:00
|
|
|
|
|
|
|
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
|
|
|
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
|
|
|
|
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
|
2018-01-24 20:46:11 +08:00
|
|
|
true /* is_fctl */, (char *)&fsctl_buf,
|
2019-03-29 11:32:49 +08:00
|
|
|
sizeof(struct file_zero_data_information),
|
|
|
|
CIFSMaxBufSize, NULL, NULL);
|
2014-08-17 21:38:47 +08:00
|
|
|
free_xid(xid);
|
2021-04-22 22:52:32 +08:00
|
|
|
filemap_invalidate_unlock(inode->i_mapping);
|
2014-08-17 21:38:47 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-06-03 13:31:01 +08:00
|
|
|
static int smb3_simple_fallocate_write_range(unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile,
|
|
|
|
loff_t off, loff_t len,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct cifs_io_parms io_parms = {0};
|
2021-07-27 05:22:55 +08:00
|
|
|
int nbytes;
|
|
|
|
int rc = 0;
|
2021-06-03 13:31:01 +08:00
|
|
|
struct kvec iov[2];
|
|
|
|
|
|
|
|
io_parms.netfid = cfile->fid.netfid;
|
|
|
|
io_parms.pid = current->tgid;
|
|
|
|
io_parms.tcon = tcon;
|
|
|
|
io_parms.persistent_fid = cfile->fid.persistent_fid;
|
|
|
|
io_parms.volatile_fid = cfile->fid.volatile_fid;
|
|
|
|
|
2021-07-22 12:53:32 +08:00
|
|
|
while (len) {
|
|
|
|
io_parms.offset = off;
|
|
|
|
io_parms.length = len;
|
|
|
|
if (io_parms.length > SMB2_MAX_BUFFER_SIZE)
|
|
|
|
io_parms.length = SMB2_MAX_BUFFER_SIZE;
|
|
|
|
/* iov[0] is reserved for smb header */
|
|
|
|
iov[1].iov_base = buf;
|
|
|
|
iov[1].iov_len = io_parms.length;
|
|
|
|
rc = SMB2_write(xid, &io_parms, &nbytes, iov, 1);
|
|
|
|
if (rc)
|
|
|
|
break;
|
|
|
|
if (nbytes > len)
|
|
|
|
return -EINVAL;
|
|
|
|
buf += nbytes;
|
|
|
|
off += nbytes;
|
|
|
|
len -= nbytes;
|
|
|
|
}
|
|
|
|
return rc;
|
2021-06-03 13:31:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int smb3_simple_fallocate_range(unsigned int xid,
|
|
|
|
struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile,
|
|
|
|
loff_t off, loff_t len)
|
|
|
|
{
|
|
|
|
struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data;
|
|
|
|
u32 out_data_len;
|
|
|
|
char *buf = NULL;
|
|
|
|
loff_t l;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
in_data.file_offset = cpu_to_le64(off);
|
|
|
|
in_data.length = cpu_to_le64(len);
|
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_QUERY_ALLOCATED_RANGES, true,
|
|
|
|
(char *)&in_data, sizeof(in_data),
|
|
|
|
1024 * sizeof(struct file_allocated_range_buffer),
|
|
|
|
(char **)&out_data, &out_data_len);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
buf = kzalloc(1024 * 1024, GFP_KERNEL);
|
|
|
|
if (buf == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmp_data = out_data;
|
|
|
|
while (len) {
|
|
|
|
/*
|
|
|
|
* The rest of the region is unmapped so write it all.
|
|
|
|
*/
|
|
|
|
if (out_data_len == 0) {
|
|
|
|
rc = smb3_simple_fallocate_write_range(xid, tcon,
|
|
|
|
cfile, off, len, buf);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (off < le64_to_cpu(tmp_data->file_offset)) {
|
|
|
|
/*
|
|
|
|
* We are at a hole. Write until the end of the region
|
|
|
|
* or until the next allocated data,
|
|
|
|
* whichever comes next.
|
|
|
|
*/
|
|
|
|
l = le64_to_cpu(tmp_data->file_offset) - off;
|
|
|
|
if (len < l)
|
|
|
|
l = len;
|
|
|
|
rc = smb3_simple_fallocate_write_range(xid, tcon,
|
|
|
|
cfile, off, l, buf);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
off = off + l;
|
|
|
|
len = len - l;
|
|
|
|
if (len == 0)
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We are at a section of allocated data, just skip forward
|
|
|
|
* until the end of the data or the end of the region
|
|
|
|
* we are supposed to fallocate, whichever comes first.
|
|
|
|
*/
|
|
|
|
l = le64_to_cpu(tmp_data->length);
|
|
|
|
if (len < l)
|
|
|
|
l = len;
|
|
|
|
off += l;
|
|
|
|
len -= l;
|
|
|
|
|
|
|
|
tmp_data = &tmp_data[1];
|
|
|
|
out_data_len -= sizeof(struct file_allocated_range_buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
kfree(out_data);
|
|
|
|
kfree(buf);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-10-19 06:01:15 +08:00
|
|
|
static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
|
|
|
|
loff_t off, loff_t len, bool keep_size)
|
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct cifsInodeInfo *cifsi;
|
|
|
|
struct cifsFileInfo *cfile = file->private_data;
|
|
|
|
long rc = -EOPNOTSUPP;
|
|
|
|
unsigned int xid;
|
2019-03-14 22:08:48 +08:00
|
|
|
__le64 eof;
|
2014-10-19 06:01:15 +08:00
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
|
2015-03-18 06:25:59 +08:00
|
|
|
inode = d_inode(cfile->dentry);
|
2014-10-19 06:01:15 +08:00
|
|
|
cifsi = CIFS_I(inode);
|
|
|
|
|
2019-03-13 14:41:49 +08:00
|
|
|
trace_smb3_falloc_enter(xid, cfile->fid.persistent_fid, tcon->tid,
|
|
|
|
tcon->ses->Suid, off, len);
|
2014-10-19 06:01:15 +08:00
|
|
|
/* if file not oplocked can't be sure whether asking to extend size */
|
|
|
|
if (!CIFS_CACHE_READ(cifsi))
|
2018-05-19 15:04:55 +08:00
|
|
|
if (keep_size == false) {
|
2019-03-13 14:41:49 +08:00
|
|
|
trace_smb3_falloc_err(xid, cfile->fid.persistent_fid,
|
|
|
|
tcon->tid, tcon->ses->Suid, off, len, rc);
|
2018-05-19 15:04:55 +08:00
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
2014-10-19 06:01:15 +08:00
|
|
|
|
2020-01-17 09:45:02 +08:00
|
|
|
/*
|
|
|
|
* Extending the file
|
|
|
|
*/
|
|
|
|
if ((keep_size == false) && i_size_read(inode) < off + len) {
|
2020-03-18 20:43:38 +08:00
|
|
|
rc = inode_newsize_ok(inode, off + len);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
2020-01-17 09:45:02 +08:00
|
|
|
if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0)
|
|
|
|
smb2_set_sparse(xid, tcon, cfile, inode, false);
|
|
|
|
|
|
|
|
eof = cpu_to_le64(off + len);
|
|
|
|
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, cfile->pid, &eof);
|
|
|
|
if (rc == 0) {
|
|
|
|
cifsi->server_eof = off + len;
|
|
|
|
cifs_setsize(inode, off + len);
|
|
|
|
cifs_truncate_page(inode->i_mapping, inode->i_size);
|
|
|
|
truncate_setsize(inode, off + len);
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-10-19 06:01:15 +08:00
|
|
|
/*
|
|
|
|
* Files are non-sparse by default so falloc may be a no-op
|
2020-01-17 09:45:02 +08:00
|
|
|
* Must check if file sparse. If not sparse, and since we are not
|
|
|
|
* extending then no need to do anything since file already allocated
|
2014-10-19 06:01:15 +08:00
|
|
|
*/
|
|
|
|
if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) {
|
2020-01-17 09:45:02 +08:00
|
|
|
rc = 0;
|
|
|
|
goto out;
|
2014-10-19 06:01:15 +08:00
|
|
|
}
|
|
|
|
|
2021-07-23 09:21:24 +08:00
|
|
|
if (keep_size == true) {
|
|
|
|
/*
|
|
|
|
* We can not preallocate pages beyond the end of the file
|
|
|
|
* in SMB2
|
|
|
|
*/
|
|
|
|
if (off >= i_size_read(inode)) {
|
|
|
|
rc = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* For fallocates that are partially beyond the end of file,
|
|
|
|
* clamp len so we only fallocate up to the end of file.
|
|
|
|
*/
|
|
|
|
if (off + len > i_size_read(inode)) {
|
|
|
|
len = i_size_read(inode) - off;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-19 06:01:15 +08:00
|
|
|
if ((keep_size == true) || (i_size_read(inode) >= off + len)) {
|
2021-06-03 13:31:01 +08:00
|
|
|
/*
|
|
|
|
* At this point, we are trying to fallocate an internal
|
|
|
|
* regions of a sparse file. Since smb2 does not have a
|
|
|
|
* fallocate command we have two otions on how to emulate this.
|
|
|
|
* We can either turn the entire file to become non-sparse
|
|
|
|
* which we only do if the fallocate is for virtually
|
|
|
|
* the whole file, or we can overwrite the region with zeroes
|
|
|
|
* using SMB2_write, which could be prohibitevly expensive
|
|
|
|
* if len is large.
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* We are only trying to fallocate a small region so
|
|
|
|
* just write it with zero.
|
|
|
|
*/
|
|
|
|
if (len <= 1024 * 1024) {
|
|
|
|
rc = smb3_simple_fallocate_range(xid, tcon, cfile,
|
|
|
|
off, len);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-10-19 06:01:15 +08:00
|
|
|
/*
|
|
|
|
* Check if falloc starts within first few pages of file
|
|
|
|
* and ends within a few pages of the end of file to
|
|
|
|
* ensure that most of file is being forced to be
|
|
|
|
* fallocated now. If so then setting whole file sparse
|
|
|
|
* ie potentially making a few extra pages at the beginning
|
|
|
|
* or end of the file non-sparse via set_sparse is harmless.
|
|
|
|
*/
|
2018-05-19 15:04:55 +08:00
|
|
|
if ((off > 8192) || (off + len + 8192 < i_size_read(inode))) {
|
|
|
|
rc = -EOPNOTSUPP;
|
2020-01-17 09:45:02 +08:00
|
|
|
goto out;
|
2019-03-14 22:08:48 +08:00
|
|
|
}
|
2014-10-19 06:01:15 +08:00
|
|
|
}
|
|
|
|
|
2020-01-17 09:45:02 +08:00
|
|
|
smb2_set_sparse(xid, tcon, cfile, inode, false);
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
out:
|
2019-03-13 14:41:49 +08:00
|
|
|
if (rc)
|
|
|
|
trace_smb3_falloc_err(xid, cfile->fid.persistent_fid, tcon->tid,
|
|
|
|
tcon->ses->Suid, off, len, rc);
|
|
|
|
else
|
|
|
|
trace_smb3_falloc_done(xid, cfile->fid.persistent_fid, tcon->tid,
|
|
|
|
tcon->ses->Suid, off, len);
|
2014-10-19 06:01:15 +08:00
|
|
|
|
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-03-27 03:52:29 +08:00
|
|
|
static long smb3_collapse_range(struct file *file, struct cifs_tcon *tcon,
|
|
|
|
loff_t off, loff_t len)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned int xid;
|
2022-02-23 09:14:16 +08:00
|
|
|
struct inode *inode;
|
2021-03-27 03:52:29 +08:00
|
|
|
struct cifsFileInfo *cfile = file->private_data;
|
2022-02-23 09:14:16 +08:00
|
|
|
struct cifsInodeInfo *cifsi;
|
2021-03-27 03:52:29 +08:00
|
|
|
__le64 eof;
|
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
|
2022-02-23 09:14:16 +08:00
|
|
|
inode = d_inode(cfile->dentry);
|
|
|
|
cifsi = CIFS_I(inode);
|
|
|
|
|
|
|
|
if (off >= i_size_read(inode) ||
|
|
|
|
off + len >= i_size_read(inode)) {
|
2021-03-27 03:52:29 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = smb2_copychunk_range(xid, cfile, cfile, off + len,
|
2022-02-23 09:14:16 +08:00
|
|
|
i_size_read(inode) - off - len, off);
|
2021-03-27 03:52:29 +08:00
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
|
|
|
|
2022-02-23 09:14:16 +08:00
|
|
|
eof = cpu_to_le64(i_size_read(inode) - len);
|
2021-03-27 03:52:29 +08:00
|
|
|
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, cfile->pid, &eof);
|
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = 0;
|
2022-02-23 09:14:16 +08:00
|
|
|
|
|
|
|
cifsi->server_eof = i_size_read(inode) - len;
|
|
|
|
truncate_setsize(inode, cifsi->server_eof);
|
|
|
|
fscache_resize_cookie(cifs_inode_cookie(inode), cifsi->server_eof);
|
2021-03-27 03:52:29 +08:00
|
|
|
out:
|
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2021-03-27 04:31:30 +08:00
|
|
|
static long smb3_insert_range(struct file *file, struct cifs_tcon *tcon,
|
|
|
|
loff_t off, loff_t len)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
unsigned int xid;
|
|
|
|
struct cifsFileInfo *cfile = file->private_data;
|
|
|
|
__le64 eof;
|
|
|
|
__u64 count;
|
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
|
|
|
|
if (off >= i_size_read(file->f_inode)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
count = i_size_read(file->f_inode) - off;
|
|
|
|
eof = cpu_to_le64(i_size_read(file->f_inode) + len);
|
|
|
|
|
|
|
|
rc = SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid, cfile->pid, &eof);
|
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = smb2_copychunk_range(xid, cfile, cfile, off, count, off + len);
|
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = smb3_zero_range(file, tcon, off, len, 1);
|
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
out:
|
|
|
|
free_xid(xid);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-05-15 05:17:02 +08:00
|
|
|
static loff_t smb3_llseek(struct file *file, struct cifs_tcon *tcon, loff_t offset, int whence)
|
|
|
|
{
|
|
|
|
struct cifsFileInfo *wrcfile, *cfile = file->private_data;
|
|
|
|
struct cifsInodeInfo *cifsi;
|
|
|
|
struct inode *inode;
|
|
|
|
int rc = 0;
|
|
|
|
struct file_allocated_range_buffer in_data, *out_data = NULL;
|
|
|
|
u32 out_data_len;
|
|
|
|
unsigned int xid;
|
|
|
|
|
|
|
|
if (whence != SEEK_HOLE && whence != SEEK_DATA)
|
|
|
|
return generic_file_llseek(file, offset, whence);
|
|
|
|
|
|
|
|
inode = d_inode(cfile->dentry);
|
|
|
|
cifsi = CIFS_I(inode);
|
|
|
|
|
|
|
|
if (offset < 0 || offset >= i_size_read(inode))
|
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
/*
|
|
|
|
* We need to be sure that all dirty pages are written as they
|
|
|
|
* might fill holes on the server.
|
|
|
|
* Note that we also MUST flush any written pages since at least
|
|
|
|
* some servers (Windows2016) will not reflect recent writes in
|
|
|
|
* QUERY_ALLOCATED_RANGES until SMB2_flush is called.
|
|
|
|
*/
|
cifs: fix rename() by ensuring source handle opened with DELETE bit
To rename a file in SMB2 we open it with the DELETE access and do a
special SetInfo on it. If the handle is missing the DELETE bit the
server will fail the SetInfo with STATUS_ACCESS_DENIED.
We currently try to reuse any existing opened handle we have with
cifs_get_writable_path(). That function looks for handles with WRITE
access but doesn't check for DELETE, making rename() fail if it finds
a handle to reuse. Simple reproducer below.
To select handles with the DELETE bit, this patch adds a flag argument
to cifs_get_writable_path() and find_writable_file() and the existing
'bool fsuid_only' argument is converted to a flag.
The cifsFileInfo struct only stores the UNIX open mode but not the
original SMB access flags. Since the DELETE bit is not mapped in that
mode, this patch stores the access mask in cifs_fid on file open,
which is accessible from cifsFileInfo.
Simple reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define E(s) perror(s), exit(1)
int main(int argc, char *argv[])
{
int fd, ret;
if (argc != 3) {
fprintf(stderr, "Usage: %s A B\n"
"create&open A in write mode, "
"rename A to B, close A\n", argv[0]);
return 0;
}
fd = openat(AT_FDCWD, argv[1], O_WRONLY|O_CREAT|O_SYNC, 0666);
if (fd == -1) E("openat()");
ret = rename(argv[1], argv[2]);
if (ret) E("rename()");
ret = close(fd);
if (ret) E("close()");
return ret;
}
$ gcc -o bugrename bugrename.c
$ ./bugrename /mnt/a /mnt/b
rename(): Permission denied
Fixes: 8de9e86c67ba ("cifs: create a helper to find a writeable handle by path name")
CC: Stable <stable@vger.kernel.org>
Signed-off-by: Aurelien Aptel <aaptel@suse.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
2020-02-21 18:19:06 +08:00
|
|
|
wrcfile = find_writable_file(cifsi, FIND_WR_ANY);
|
2019-05-15 05:17:02 +08:00
|
|
|
if (wrcfile) {
|
|
|
|
filemap_write_and_wait(inode->i_mapping);
|
|
|
|
smb2_flush_file(xid, tcon, &wrcfile->fid);
|
|
|
|
cifsFileInfo_put(wrcfile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)) {
|
|
|
|
if (whence == SEEK_HOLE)
|
|
|
|
offset = i_size_read(inode);
|
|
|
|
goto lseek_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
in_data.file_offset = cpu_to_le64(offset);
|
|
|
|
in_data.length = cpu_to_le64(i_size_read(inode));
|
|
|
|
|
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_QUERY_ALLOCATED_RANGES, true,
|
|
|
|
(char *)&in_data, sizeof(in_data),
|
|
|
|
sizeof(struct file_allocated_range_buffer),
|
|
|
|
(char **)&out_data, &out_data_len);
|
|
|
|
if (rc == -E2BIG)
|
|
|
|
rc = 0;
|
|
|
|
if (rc)
|
|
|
|
goto lseek_exit;
|
|
|
|
|
|
|
|
if (whence == SEEK_HOLE && out_data_len == 0)
|
|
|
|
goto lseek_exit;
|
|
|
|
|
|
|
|
if (whence == SEEK_DATA && out_data_len == 0) {
|
|
|
|
rc = -ENXIO;
|
|
|
|
goto lseek_exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (out_data_len < sizeof(struct file_allocated_range_buffer)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto lseek_exit;
|
|
|
|
}
|
|
|
|
if (whence == SEEK_DATA) {
|
|
|
|
offset = le64_to_cpu(out_data->file_offset);
|
|
|
|
goto lseek_exit;
|
|
|
|
}
|
|
|
|
if (offset < le64_to_cpu(out_data->file_offset))
|
|
|
|
goto lseek_exit;
|
|
|
|
|
|
|
|
offset = le64_to_cpu(out_data->file_offset) + le64_to_cpu(out_data->length);
|
|
|
|
|
|
|
|
lseek_exit:
|
|
|
|
free_xid(xid);
|
|
|
|
kfree(out_data);
|
|
|
|
if (!rc)
|
|
|
|
return vfs_setpos(file, offset, inode->i_sb->s_maxbytes);
|
|
|
|
else
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2019-04-25 14:45:29 +08:00
|
|
|
static int smb3_fiemap(struct cifs_tcon *tcon,
|
|
|
|
struct cifsFileInfo *cfile,
|
|
|
|
struct fiemap_extent_info *fei, u64 start, u64 len)
|
|
|
|
{
|
|
|
|
unsigned int xid;
|
|
|
|
struct file_allocated_range_buffer in_data, *out_data;
|
|
|
|
u32 out_data_len;
|
|
|
|
int i, num, rc, flags, last_blob;
|
|
|
|
u64 next;
|
|
|
|
|
2020-05-23 15:30:14 +08:00
|
|
|
rc = fiemap_prep(d_inode(cfile->dentry), fei, start, &len, 0);
|
2020-05-23 15:30:13 +08:00
|
|
|
if (rc)
|
|
|
|
return rc;
|
2019-04-25 14:45:29 +08:00
|
|
|
|
|
|
|
xid = get_xid();
|
|
|
|
again:
|
|
|
|
in_data.file_offset = cpu_to_le64(start);
|
|
|
|
in_data.length = cpu_to_le64(len);
|
|
|
|
|
|
|
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
|
|
|
cfile->fid.volatile_fid,
|
|
|
|
FSCTL_QUERY_ALLOCATED_RANGES, true,
|
|
|
|
(char *)&in_data, sizeof(in_data),
|
|
|
|
1024 * sizeof(struct file_allocated_range_buffer),
|
|
|
|
(char **)&out_data, &out_data_len);
|
|
|
|
if (rc == -E2BIG) {
|
|
|
|
last_blob = 0;
|
|
|
|
rc = 0;
|
|
|
|
} else
|
|
|
|
last_blob = 1;
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
2020-03-14 11:38:31 +08:00
|
|
|
if (out_data_len && out_data_len < sizeof(struct file_allocated_range_buffer)) {
|
2019-04-25 14:45:29 +08:00
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (out_data_len % sizeof(struct file_allocated_range_buffer)) {
|
|
|
|
rc = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
num = out_data_len / sizeof(struct file_allocated_range_buffer);
|
|
|
|
for (i = 0; i < num; i++) {
|
|
|
|
flags = 0;
|
|
|
|
if (i == num - 1 && last_blob)
|
|
|
|
flags |= FIEMAP_EXTENT_LAST;
|
|
|
|
|
|
|
|
rc = fiemap_fill_next_extent(fei,
|
|
|
|
le64_to_cpu(out_data[i].file_offset),
|
|
|
|
le64_to_cpu(out_data[i].file_offset),
|
|
|
|
le64_to_cpu(out_data[i].length),
|
|
|
|
flags);
|
|
|
|
if (rc < 0)
|
|
|
|
goto out;
|
|
|
|
if (rc == 1) {
|
|
|
|
rc = 0;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!last_blob) {
|
|
|
|
next = le64_to_cpu(out_data[num - 1].file_offset) +
|
|
|
|
le64_to_cpu(out_data[num - 1].length);
|
|
|
|
len = len - (next - start);
|
|
|
|
start = next;
|
|
|
|
goto again;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
free_xid(xid);
|
|
|
|
kfree(out_data);
|
|
|
|
return rc;
|
|
|
|
}
|
2014-10-19 06:01:15 +08:00
|
|
|
|
2014-08-17 21:38:47 +08:00
|
|
|
static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
|
|
|
|
loff_t off, loff_t len)
|
|
|
|
{
|
|
|
|
/* KEEP_SIZE already checked for by do_fallocate */
|
|
|
|
if (mode & FALLOC_FL_PUNCH_HOLE)
|
|
|
|
return smb3_punch_hole(file, tcon, off, len);
|
2014-08-18 07:16:40 +08:00
|
|
|
else if (mode & FALLOC_FL_ZERO_RANGE) {
|
|
|
|
if (mode & FALLOC_FL_KEEP_SIZE)
|
|
|
|
return smb3_zero_range(file, tcon, off, len, true);
|
|
|
|
return smb3_zero_range(file, tcon, off, len, false);
|
2014-10-19 06:01:15 +08:00
|
|
|
} else if (mode == FALLOC_FL_KEEP_SIZE)
|
|
|
|
return smb3_simple_falloc(file, tcon, off, len, true);
|
2021-03-27 03:52:29 +08:00
|
|
|
else if (mode == FALLOC_FL_COLLAPSE_RANGE)
|
|
|
|
return smb3_collapse_range(file, tcon, off, len);
|
2021-03-27 04:31:30 +08:00
|
|
|
else if (mode == FALLOC_FL_INSERT_RANGE)
|
|
|
|
return smb3_insert_range(file, tcon, off, len);
|
2014-10-19 06:01:15 +08:00
|
|
|
else if (mode == 0)
|
|
|
|
return smb3_simple_falloc(file, tcon, off, len, false);
|
2014-08-17 21:38:47 +08:00
|
|
|
|
|
|
|
return -EOPNOTSUPP;
|
|
|
|
}
|
|
|
|
|
2014-03-12 00:11:47 +08:00
|
|
|
static void
|
|
|
|
smb2_downgrade_oplock(struct TCP_Server_Info *server,
|
2019-10-30 07:51:19 +08:00
|
|
|
struct cifsInodeInfo *cinode, __u32 oplock,
|
|
|
|
unsigned int epoch, bool *purge_cache)
|
2014-03-12 00:11:47 +08:00
|
|
|
{
|
2019-10-30 07:51:19 +08:00
|
|
|
server->ops->set_oplock_level(cinode, oplock, 0, NULL);
|
2014-03-12 00:11:47 +08:00
|
|
|
}
|
|
|
|
|
2019-02-14 07:43:08 +08:00
|
|
|
static void
|
2019-10-30 07:51:19 +08:00
|
|
|
smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
|
|
|
unsigned int epoch, bool *purge_cache);
|
|
|
|
|
|
|
|
static void
|
|
|
|
smb3_downgrade_oplock(struct TCP_Server_Info *server,
|
|
|
|
struct cifsInodeInfo *cinode, __u32 oplock,
|
|
|
|
unsigned int epoch, bool *purge_cache)
|
2019-02-14 07:43:08 +08:00
|
|
|
{
|
2019-10-30 07:51:19 +08:00
|
|
|
unsigned int old_state = cinode->oplock;
|
|
|
|
unsigned int old_epoch = cinode->epoch;
|
|
|
|
unsigned int new_state;
|
|
|
|
|
|
|
|
if (epoch > old_epoch) {
|
|
|
|
smb21_set_oplock_level(cinode, oplock, 0, NULL);
|
|
|
|
cinode->epoch = epoch;
|
|
|
|
}
|
|
|
|
|
|
|
|
new_state = cinode->oplock;
|
|
|
|
*purge_cache = false;
|
|
|
|
|
|
|
|
if ((old_state & CIFS_CACHE_READ_FLG) != 0 &&
|
|
|
|
(new_state & CIFS_CACHE_READ_FLG) == 0)
|
|
|
|
*purge_cache = true;
|
|
|
|
else if (old_state == new_state && (epoch - old_epoch > 1))
|
|
|
|
*purge_cache = true;
|
2019-02-14 07:43:08 +08:00
|
|
|
}
|
|
|
|
|
2013-09-05 20:11:28 +08:00
|
|
|
static void
|
2013-09-06 01:30:16 +08:00
|
|
|
smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
|
|
|
unsigned int epoch, bool *purge_cache)
|
2013-09-05 20:11:28 +08:00
|
|
|
{
|
|
|
|
oplock &= 0xFF;
|
2021-05-17 19:28:34 +08:00
|
|
|
cinode->lease_granted = false;
|
2013-09-05 20:11:28 +08:00
|
|
|
if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
|
|
|
|
return;
|
|
|
|
if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
|
2013-09-06 01:30:16 +08:00
|
|
|
cinode->oplock = CIFS_CACHE_RHW_FLG;
|
2013-09-05 20:11:28 +08:00
|
|
|
cifs_dbg(FYI, "Batch Oplock granted on inode %p\n",
|
|
|
|
&cinode->vfs_inode);
|
|
|
|
} else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
|
2013-09-06 01:30:16 +08:00
|
|
|
cinode->oplock = CIFS_CACHE_RW_FLG;
|
2013-09-05 20:11:28 +08:00
|
|
|
cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
|
|
|
|
&cinode->vfs_inode);
|
|
|
|
} else if (oplock == SMB2_OPLOCK_LEVEL_II) {
|
|
|
|
cinode->oplock = CIFS_CACHE_READ_FLG;
|
|
|
|
cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
|
|
|
|
&cinode->vfs_inode);
|
|
|
|
} else
|
|
|
|
cinode->oplock = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-09-06 01:30:16 +08:00
|
|
|
smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
|
|
|
unsigned int epoch, bool *purge_cache)
|
2013-09-05 20:11:28 +08:00
|
|
|
{
|
|
|
|
char message[5] = {0};
|
2019-05-07 23:16:40 +08:00
|
|
|
unsigned int new_oplock = 0;
|
2013-09-05 20:11:28 +08:00
|
|
|
|
|
|
|
oplock &= 0xFF;
|
2021-05-17 19:28:34 +08:00
|
|
|
cinode->lease_granted = true;
|
2013-09-05 20:11:28 +08:00
|
|
|
if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
|
|
|
|
return;
|
|
|
|
|
2019-09-27 03:31:20 +08:00
|
|
|
/* Check if the server granted an oplock rather than a lease */
|
|
|
|
if (oplock & SMB2_OPLOCK_LEVEL_EXCLUSIVE)
|
|
|
|
return smb2_set_oplock_level(cinode, oplock, epoch,
|
|
|
|
purge_cache);
|
|
|
|
|
2013-09-05 20:11:28 +08:00
|
|
|
if (oplock & SMB2_LEASE_READ_CACHING_HE) {
|
2019-05-07 23:16:40 +08:00
|
|
|
new_oplock |= CIFS_CACHE_READ_FLG;
|
2013-09-05 20:11:28 +08:00
|
|
|
strcat(message, "R");
|
|
|
|
}
|
|
|
|
if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) {
|
2019-05-07 23:16:40 +08:00
|
|
|
new_oplock |= CIFS_CACHE_HANDLE_FLG;
|
2013-09-05 20:11:28 +08:00
|
|
|
strcat(message, "H");
|
|
|
|
}
|
|
|
|
if (oplock & SMB2_LEASE_WRITE_CACHING_HE) {
|
2019-05-07 23:16:40 +08:00
|
|
|
new_oplock |= CIFS_CACHE_WRITE_FLG;
|
2013-09-05 20:11:28 +08:00
|
|
|
strcat(message, "W");
|
|
|
|
}
|
2019-05-07 23:16:40 +08:00
|
|
|
if (!new_oplock)
|
|
|
|
strncpy(message, "None", sizeof(message));
|
|
|
|
|
|
|
|
cinode->oplock = new_oplock;
|
2013-09-05 20:11:28 +08:00
|
|
|
cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
|
|
|
|
&cinode->vfs_inode);
|
|
|
|
}
|
|
|
|
|
2013-09-06 01:30:16 +08:00
|
|
|
static void
|
|
|
|
smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
|
|
|
|
unsigned int epoch, bool *purge_cache)
|
|
|
|
{
|
|
|
|
unsigned int old_oplock = cinode->oplock;
|
|
|
|
|
|
|
|
smb21_set_oplock_level(cinode, oplock, epoch, purge_cache);
|
|
|
|
|
|
|
|
if (purge_cache) {
|
|
|
|
*purge_cache = false;
|
|
|
|
if (old_oplock == CIFS_CACHE_READ_FLG) {
|
|
|
|
if (cinode->oplock == CIFS_CACHE_READ_FLG &&
|
|
|
|
(epoch - cinode->epoch > 0))
|
|
|
|
*purge_cache = true;
|
|
|
|
else if (cinode->oplock == CIFS_CACHE_RH_FLG &&
|
|
|
|
(epoch - cinode->epoch > 1))
|
|
|
|
*purge_cache = true;
|
|
|
|
else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
|
|
|
|
(epoch - cinode->epoch > 1))
|
|
|
|
*purge_cache = true;
|
|
|
|
else if (cinode->oplock == 0 &&
|
|
|
|
(epoch - cinode->epoch > 0))
|
|
|
|
*purge_cache = true;
|
|
|
|
} else if (old_oplock == CIFS_CACHE_RH_FLG) {
|
|
|
|
if (cinode->oplock == CIFS_CACHE_RH_FLG &&
|
|
|
|
(epoch - cinode->epoch > 0))
|
|
|
|
*purge_cache = true;
|
|
|
|
else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
|
|
|
|
(epoch - cinode->epoch > 1))
|
|
|
|
*purge_cache = true;
|
|
|
|
}
|
|
|
|
cinode->epoch = epoch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-05 20:11:28 +08:00
|
|
|
static bool
|
|
|
|
smb2_is_read_op(__u32 oplock)
|
|
|
|
{
|
|
|
|
return oplock == SMB2_OPLOCK_LEVEL_II;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
smb21_is_read_op(__u32 oplock)
|
|
|
|
{
|
|
|
|
return (oplock & SMB2_LEASE_READ_CACHING_HE) &&
|
|
|
|
!(oplock & SMB2_LEASE_WRITE_CACHING_HE);
|
|
|
|
}
|
|
|
|
|
2013-09-04 17:44:05 +08:00
|
|
|
static __le32
|
|
|
|
map_oplock_to_lease(u8 oplock)
|
|
|
|
{
|
|
|
|
if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
|
2022-03-25 11:09:29 +08:00
|
|
|
return SMB2_LEASE_WRITE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE;
|
2013-09-04 17:44:05 +08:00
|
|
|
else if (oplock == SMB2_OPLOCK_LEVEL_II)
|
2022-03-25 11:09:29 +08:00
|
|
|
return SMB2_LEASE_READ_CACHING_LE;
|
2013-09-04 17:44:05 +08:00
|
|
|
else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
|
2022-03-25 11:09:29 +08:00
|
|
|
return SMB2_LEASE_HANDLE_CACHING_LE | SMB2_LEASE_READ_CACHING_LE |
|
|
|
|
SMB2_LEASE_WRITE_CACHING_LE;
|
2013-09-04 17:44:05 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-09-04 17:07:41 +08:00
|
|
|
static char *
|
|
|
|
smb2_create_lease_buf(u8 *lease_key, u8 oplock)
|
|
|
|
{
|
|
|
|
struct create_lease *buf;
|
|
|
|
|
|
|
|
buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL);
|
|
|
|
if (!buf)
|
|
|
|
return NULL;
|
|
|
|
|
2018-07-05 21:10:02 +08:00
|
|
|
memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
|
2013-09-04 17:44:05 +08:00
|
|
|
buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
|
2013-09-04 17:07:41 +08:00
|
|
|
|
|
|
|
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
|
|
|
(struct create_lease, lcontext));
|
|
|
|
buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));
|
|
|
|
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
|
|
|
(struct create_lease, Name));
|
|
|
|
buf->ccontext.NameLength = cpu_to_le16(4);
|
2014-05-14 20:29:40 +08:00
|
|
|
/* SMB2_CREATE_REQUEST_LEASE is "RqLs" */
|
2013-09-04 17:07:41 +08:00
|
|
|
buf->Name[0] = 'R';
|
|
|
|
buf->Name[1] = 'q';
|
|
|
|
buf->Name[2] = 'L';
|
|
|
|
buf->Name[3] = 's';
|
|
|
|
return (char *)buf;
|
|
|
|
}
|
|
|
|
|
2013-09-04 17:44:05 +08:00
|
|
|
static char *
|
|
|
|
smb3_create_lease_buf(u8 *lease_key, u8 oplock)
|
|
|
|
{
|
|
|
|
struct create_lease_v2 *buf;
|
|
|
|
|
|
|
|
buf = kzalloc(sizeof(struct create_lease_v2), GFP_KERNEL);
|
|
|
|
if (!buf)
|
|
|
|
return NULL;
|
|
|
|
|
2018-07-05 21:10:02 +08:00
|
|
|
memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE);
|
2013-09-04 17:44:05 +08:00
|
|
|
buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
|
|
|
|
|
|
|
|
buf->ccontext.DataOffset = cpu_to_le16(offsetof
|
|
|
|
(struct create_lease_v2, lcontext));
|
|
|
|
buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));
|
|
|
|
buf->ccontext.NameOffset = cpu_to_le16(offsetof
|
|
|
|
(struct create_lease_v2, Name));
|
|
|
|
buf->ccontext.NameLength = cpu_to_le16(4);
|
2014-05-14 20:29:40 +08:00
|
|
|
/* SMB2_CREATE_REQUEST_LEASE is "RqLs" */
|
2013-09-04 17:44:05 +08:00
|
|
|
buf->Name[0] = 'R';
|
|
|
|
buf->Name[1] = 'q';
|
|
|
|
buf->Name[2] = 'L';
|
|
|
|
buf->Name[3] = 's';
|
|
|
|
return (char *)buf;
|
|
|
|
}
|
|
|
|
|
2013-09-06 00:16:45 +08:00
|
|
|
static __u8
|
2018-04-26 22:10:18 +08:00
|
|
|
smb2_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key)
|
2013-09-06 00:16:45 +08:00
|
|
|
{
|
|
|
|
struct create_lease *lc = (struct create_lease *)buf;
|
|
|
|
|
2013-09-06 01:30:16 +08:00
|
|
|
*epoch = 0; /* not used */
|
2022-03-25 11:09:29 +08:00
|
|
|
if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE)
|
2013-09-06 00:16:45 +08:00
|
|
|
return SMB2_OPLOCK_LEVEL_NOCHANGE;
|
|
|
|
return le32_to_cpu(lc->lcontext.LeaseState);
|
|
|
|
}
|
|
|
|
|
2013-09-04 17:44:05 +08:00
|
|
|
static __u8
|
2018-04-26 22:10:18 +08:00
|
|
|
smb3_parse_lease_buf(void *buf, unsigned int *epoch, char *lease_key)
|
2013-09-04 17:44:05 +08:00
|
|
|
{
|
|
|
|
struct create_lease_v2 *lc = (struct create_lease_v2 *)buf;
|
|
|
|
|
2013-09-06 01:30:16 +08:00
|
|
|
*epoch = le16_to_cpu(lc->lcontext.Epoch);
|
2022-03-25 11:09:29 +08:00
|
|
|
if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE)
|
2013-09-04 17:44:05 +08:00
|
|
|
return SMB2_OPLOCK_LEVEL_NOCHANGE;
|
2018-04-26 22:10:18 +08:00
|
|
|
if (lease_key)
|
2018-07-05 21:10:02 +08:00
|
|
|
memcpy(lease_key, &lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
|
2013-09-04 17:44:05 +08:00
|
|
|
return le32_to_cpu(lc->lcontext.LeaseState);
|
|
|
|
}
|
|
|
|
|
2014-06-22 15:03:22 +08:00
|
|
|
static unsigned int
|
|
|
|
smb2_wp_retry_size(struct inode *inode)
|
|
|
|
{
|
2020-12-14 14:40:17 +08:00
|
|
|
return min_t(unsigned int, CIFS_SB(inode->i_sb)->ctx->wsize,
|
2014-06-22 15:03:22 +08:00
|
|
|
SMB2_MAX_BUFFER_SIZE);
|
|
|
|
}
|
|
|
|
|
2014-08-19 00:49:57 +08:00
|
|
|
static bool
|
|
|
|
smb2_dir_needs_close(struct cifsFileInfo *cfile)
|
|
|
|
{
|
|
|
|
return !cfile->invalidHandle;
|
|
|
|
}
|
|
|
|
|
2016-11-04 07:47:37 +08:00
|
|
|
static void
|
2018-06-01 08:53:02 +08:00
|
|
|
fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_len,
|
2019-06-08 04:16:10 +08:00
|
|
|
struct smb_rqst *old_rq, __le16 cipher_type)
|
2016-11-04 07:47:37 +08:00
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr =
|
|
|
|
(struct smb2_hdr *)old_rq->rq_iov[0].iov_base;
|
2016-11-04 07:47:37 +08:00
|
|
|
|
|
|
|
memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr));
|
|
|
|
tr_hdr->ProtocolId = SMB2_TRANSFORM_PROTO_NUM;
|
|
|
|
tr_hdr->OriginalMessageSize = cpu_to_le32(orig_len);
|
|
|
|
tr_hdr->Flags = cpu_to_le16(0x01);
|
2020-10-16 12:41:40 +08:00
|
|
|
if ((cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
|
|
|
|
(cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
2020-10-15 13:25:02 +08:00
|
|
|
get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
|
2019-06-08 04:16:10 +08:00
|
|
|
else
|
2020-10-15 13:25:02 +08:00
|
|
|
get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
|
2016-11-04 07:47:37 +08:00
|
|
|
memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8);
|
|
|
|
}
|
|
|
|
|
2018-02-20 09:45:21 +08:00
|
|
|
/* We can not use the normal sg_set_buf() as we will sometimes pass a
|
|
|
|
* stack object as buf.
|
|
|
|
*/
|
|
|
|
static inline void smb2_sg_set_buf(struct scatterlist *sg, const void *buf,
|
|
|
|
unsigned int buflen)
|
|
|
|
{
|
2019-08-02 01:06:08 +08:00
|
|
|
void *addr;
|
|
|
|
/*
|
|
|
|
* VMAP_STACK (at least) puts stack into the vmalloc address space
|
|
|
|
*/
|
|
|
|
if (is_vmalloc_addr(buf))
|
|
|
|
addr = vmalloc_to_page(buf);
|
|
|
|
else
|
|
|
|
addr = virt_to_page(buf);
|
|
|
|
sg_set_page(sg, addr, buflen, offset_in_page(buf));
|
2018-02-20 09:45:21 +08:00
|
|
|
}
|
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
/* 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
|
2018-06-01 08:53:02 +08:00
|
|
|
*/
|
2016-11-04 07:47:37 +08:00
|
|
|
static struct scatterlist *
|
2018-08-01 07:26:11 +08:00
|
|
|
init_sg(int num_rqst, struct smb_rqst *rqst, u8 *sign)
|
2016-11-04 07:47:37 +08:00
|
|
|
{
|
2018-08-01 07:26:11 +08:00
|
|
|
unsigned int sg_len;
|
2016-11-04 07:47:37 +08:00
|
|
|
struct scatterlist *sg;
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int j;
|
2018-08-01 07:26:11 +08:00
|
|
|
unsigned int idx = 0;
|
|
|
|
int skip;
|
|
|
|
|
|
|
|
sg_len = 1;
|
|
|
|
for (i = 0; i < num_rqst; i++)
|
|
|
|
sg_len += rqst[i].rq_nvec + rqst[i].rq_npages;
|
2016-11-04 07:47:37 +08:00
|
|
|
|
|
|
|
sg = kmalloc_array(sg_len, sizeof(struct scatterlist), GFP_KERNEL);
|
|
|
|
if (!sg)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
sg_init_table(sg, sg_len);
|
2018-08-01 07:26:11 +08:00
|
|
|
for (i = 0; i < num_rqst; i++) {
|
|
|
|
for (j = 0; j < rqst[i].rq_nvec; j++) {
|
|
|
|
/*
|
|
|
|
* The first rqst has a transform header where the
|
|
|
|
* first 20 bytes are not part of the encrypted blob
|
|
|
|
*/
|
|
|
|
skip = (i == 0) && (j == 0) ? 20 : 0;
|
|
|
|
smb2_sg_set_buf(&sg[idx++],
|
|
|
|
rqst[i].rq_iov[j].iov_base + skip,
|
|
|
|
rqst[i].rq_iov[j].iov_len - skip);
|
2018-12-31 11:43:40 +08:00
|
|
|
}
|
2018-08-01 07:26:11 +08:00
|
|
|
|
|
|
|
for (j = 0; j < rqst[i].rq_npages; j++) {
|
|
|
|
unsigned int len, offset;
|
2018-06-06 06:46:24 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
rqst_page_get_length(&rqst[i], j, &len, &offset);
|
|
|
|
sg_set_page(&sg[idx++], rqst[i].rq_pages[j], len, offset);
|
|
|
|
}
|
2016-11-04 07:47:37 +08:00
|
|
|
}
|
2018-08-01 07:26:11 +08:00
|
|
|
smb2_sg_set_buf(&sg[idx], sign, SMB2_SIGNATURE_SIZE);
|
2016-11-04 07:47:37 +08:00
|
|
|
return sg;
|
|
|
|
}
|
|
|
|
|
2017-03-01 08:05:19 +08:00
|
|
|
static int
|
|
|
|
smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8 *key)
|
|
|
|
{
|
|
|
|
struct cifs_ses *ses;
|
|
|
|
u8 *ses_enc_key;
|
|
|
|
|
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
2019-09-20 12:31:10 +08:00
|
|
|
list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
|
|
|
|
list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
|
|
|
|
if (ses->Suid == ses_id) {
|
|
|
|
ses_enc_key = enc ? ses->smb3encryptionkey :
|
|
|
|
ses->smb3decryptionkey;
|
2021-03-25 20:34:54 +08:00
|
|
|
memcpy(key, ses_enc_key, SMB3_ENC_DEC_KEY_SIZE);
|
2019-09-20 12:31:10 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2017-03-01 08:05:19 +08:00
|
|
|
}
|
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
|
|
|
|
2021-04-14 05:25:27 +08:00
|
|
|
return -EAGAIN;
|
2017-03-01 08:05:19 +08:00
|
|
|
}
|
2016-11-04 07:47:37 +08:00
|
|
|
/*
|
2018-06-12 06:00:58 +08:00
|
|
|
* Encrypt or decrypt @rqst message. @rqst[0] has the following format:
|
|
|
|
* iov[0] - transform header (associate data),
|
|
|
|
* iov[1-N] - SMB2 header and pages - data to encrypt.
|
|
|
|
* On success return encrypted data in iov[1-N] and pages, leave iov[0]
|
2016-11-04 07:47:37 +08:00
|
|
|
* untouched.
|
|
|
|
*/
|
|
|
|
static int
|
2018-08-01 07:26:11 +08:00
|
|
|
crypt_message(struct TCP_Server_Info *server, int num_rqst,
|
|
|
|
struct smb_rqst *rqst, int enc)
|
2016-11-04 07:47:37 +08:00
|
|
|
{
|
|
|
|
struct smb2_transform_hdr *tr_hdr =
|
2018-08-01 07:26:11 +08:00
|
|
|
(struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base;
|
2018-06-01 08:53:07 +08:00
|
|
|
unsigned int assoc_data_len = sizeof(struct smb2_transform_hdr) - 20;
|
2016-11-04 07:47:37 +08:00
|
|
|
int rc = 0;
|
|
|
|
struct scatterlist *sg;
|
|
|
|
u8 sign[SMB2_SIGNATURE_SIZE] = {};
|
2021-03-25 20:34:54 +08:00
|
|
|
u8 key[SMB3_ENC_DEC_KEY_SIZE];
|
2016-11-04 07:47:37 +08:00
|
|
|
struct aead_request *req;
|
|
|
|
char *iv;
|
|
|
|
unsigned int iv_len;
|
2017-10-18 15:00:46 +08:00
|
|
|
DECLARE_CRYPTO_WAIT(wait);
|
2016-11-04 07:47:37 +08:00
|
|
|
struct crypto_aead *tfm;
|
|
|
|
unsigned int crypt_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
|
|
|
|
2021-11-05 07:39:01 +08:00
|
|
|
rc = smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key);
|
2017-03-01 08:05:19 +08:00
|
|
|
if (rc) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: Could not get %scryption key\n", __func__,
|
2017-03-01 08:05:19 +08:00
|
|
|
enc ? "en" : "de");
|
2020-10-16 01:41:31 +08:00
|
|
|
return rc;
|
2016-11-04 07:47:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
rc = smb3_crypto_aead_allocate(server);
|
|
|
|
if (rc) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
|
2016-11-04 07:47:37 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
tfm = enc ? server->secmech.ccmaesencrypt :
|
|
|
|
server->secmech.ccmaesdecrypt;
|
2020-10-16 12:41:40 +08:00
|
|
|
|
2021-03-25 20:34:54 +08:00
|
|
|
if ((server->cipher_type == SMB2_ENCRYPTION_AES256_CCM) ||
|
|
|
|
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
2020-10-16 12:41:40 +08:00
|
|
|
rc = crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE);
|
|
|
|
else
|
2021-03-25 20:34:54 +08:00
|
|
|
rc = crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE);
|
2020-10-16 12:41:40 +08:00
|
|
|
|
2016-11-04 07:47:37 +08:00
|
|
|
if (rc) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc);
|
2016-11-04 07:47:37 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE);
|
|
|
|
if (rc) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc);
|
2016-11-04 07:47:37 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
req = aead_request_alloc(tfm, GFP_KERNEL);
|
|
|
|
if (!req) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: Failed to alloc aead request\n", __func__);
|
2016-11-04 07:47:37 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!enc) {
|
|
|
|
memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE);
|
|
|
|
crypt_len += SMB2_SIGNATURE_SIZE;
|
|
|
|
}
|
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
sg = init_sg(num_rqst, rqst, sign);
|
2016-11-04 07:47:37 +08:00
|
|
|
if (!sg) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: Failed to init sg\n", __func__);
|
2017-06-11 15:12:47 +08:00
|
|
|
rc = -ENOMEM;
|
2016-11-04 07:47:37 +08:00
|
|
|
goto free_req;
|
|
|
|
}
|
|
|
|
|
|
|
|
iv_len = crypto_aead_ivsize(tfm);
|
|
|
|
iv = kzalloc(iv_len, GFP_KERNEL);
|
|
|
|
if (!iv) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "%s: Failed to alloc iv\n", __func__);
|
2017-06-11 15:12:47 +08:00
|
|
|
rc = -ENOMEM;
|
2016-11-04 07:47:37 +08:00
|
|
|
goto free_sg;
|
|
|
|
}
|
2019-06-08 04:16:10 +08:00
|
|
|
|
2020-10-16 12:41:40 +08:00
|
|
|
if ((server->cipher_type == SMB2_ENCRYPTION_AES128_GCM) ||
|
|
|
|
(server->cipher_type == SMB2_ENCRYPTION_AES256_GCM))
|
2020-10-15 13:25:02 +08:00
|
|
|
memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE);
|
2019-06-08 04:16:10 +08:00
|
|
|
else {
|
|
|
|
iv[0] = 3;
|
2020-10-15 13:25:02 +08:00
|
|
|
memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE);
|
2019-06-08 04:16:10 +08:00
|
|
|
}
|
2016-11-04 07:47:37 +08:00
|
|
|
|
|
|
|
aead_request_set_crypt(req, sg, sg, crypt_len, iv);
|
|
|
|
aead_request_set_ad(req, assoc_data_len);
|
|
|
|
|
|
|
|
aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
|
2017-10-18 15:00:46 +08:00
|
|
|
crypto_req_done, &wait);
|
2016-11-04 07:47:37 +08:00
|
|
|
|
2017-10-18 15:00:46 +08:00
|
|
|
rc = crypto_wait_req(enc ? crypto_aead_encrypt(req)
|
|
|
|
: crypto_aead_decrypt(req), &wait);
|
2016-11-04 07:47:37 +08:00
|
|
|
|
|
|
|
if (!rc && enc)
|
|
|
|
memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE);
|
|
|
|
|
|
|
|
kfree(iv);
|
|
|
|
free_sg:
|
|
|
|
kfree(sg);
|
|
|
|
free_req:
|
|
|
|
kfree(req);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
void
|
|
|
|
smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst)
|
|
|
|
{
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < num_rqst; i++) {
|
|
|
|
if (rqst[i].rq_pages) {
|
|
|
|
for (j = rqst[i].rq_npages - 1; j >= 0; j--)
|
|
|
|
put_page(rqst[i].rq_pages[j]);
|
|
|
|
kfree(rqst[i].rq_pages);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This function will initialize new_rq and encrypt the content.
|
|
|
|
* The first entry, new_rq[0], only contains a single iov which contains
|
|
|
|
* a smb2_transform_hdr and is pre-allocated by the caller.
|
|
|
|
* This function then populates new_rq[1+] with the content from olq_rq[0+].
|
|
|
|
*
|
|
|
|
* The end result is an array of smb_rqst structures where the first structure
|
|
|
|
* only contains a single iov for the transform header which we then can pass
|
|
|
|
* to crypt_message().
|
|
|
|
*
|
|
|
|
* new_rq[0].rq_iov[0] : smb2_transform_hdr pre-allocated by the caller
|
|
|
|
* new_rq[1+].rq_iov[*] == old_rq[0+].rq_iov[*] : SMB2/3 requests
|
|
|
|
*/
|
2016-11-04 07:47:37 +08:00
|
|
|
static int
|
2018-08-01 07:26:11 +08:00
|
|
|
smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst,
|
|
|
|
struct smb_rqst *new_rq, struct smb_rqst *old_rq)
|
2016-11-04 07:47:37 +08:00
|
|
|
{
|
|
|
|
struct page **pages;
|
2018-08-01 07:26:11 +08:00
|
|
|
struct smb2_transform_hdr *tr_hdr = new_rq[0].rq_iov[0].iov_base;
|
|
|
|
unsigned int npages;
|
|
|
|
unsigned int orig_len = 0;
|
|
|
|
int i, j;
|
2016-11-04 07:47:37 +08:00
|
|
|
int rc = -ENOMEM;
|
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
for (i = 1; i < num_rqst; i++) {
|
|
|
|
npages = old_rq[i - 1].rq_npages;
|
|
|
|
pages = kmalloc_array(npages, sizeof(struct page *),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!pages)
|
|
|
|
goto err_free;
|
|
|
|
|
|
|
|
new_rq[i].rq_pages = pages;
|
|
|
|
new_rq[i].rq_npages = npages;
|
|
|
|
new_rq[i].rq_offset = old_rq[i - 1].rq_offset;
|
|
|
|
new_rq[i].rq_pagesz = old_rq[i - 1].rq_pagesz;
|
|
|
|
new_rq[i].rq_tailsz = old_rq[i - 1].rq_tailsz;
|
|
|
|
new_rq[i].rq_iov = old_rq[i - 1].rq_iov;
|
|
|
|
new_rq[i].rq_nvec = old_rq[i - 1].rq_nvec;
|
|
|
|
|
|
|
|
orig_len += smb_rqst_len(server, &old_rq[i - 1]);
|
|
|
|
|
|
|
|
for (j = 0; j < npages; j++) {
|
|
|
|
pages[j] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
|
|
|
|
if (!pages[j])
|
|
|
|
goto err_free;
|
|
|
|
}
|
2016-11-04 07:47:37 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
/* copy pages form the old */
|
|
|
|
for (j = 0; j < npages; j++) {
|
|
|
|
char *dst, *src;
|
|
|
|
unsigned int offset, len;
|
2018-06-01 08:53:02 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
rqst_page_get_length(&new_rq[i], j, &len, &offset);
|
2016-11-04 07:47:37 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
dst = (char *) kmap(new_rq[i].rq_pages[j]) + offset;
|
|
|
|
src = (char *) kmap(old_rq[i - 1].rq_pages[j]) + offset;
|
2016-11-04 07:47:37 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
memcpy(dst, src, len);
|
|
|
|
kunmap(new_rq[i].rq_pages[j]);
|
|
|
|
kunmap(old_rq[i - 1].rq_pages[j]);
|
|
|
|
}
|
|
|
|
}
|
2018-06-15 21:22:44 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
/* fill the 1st iov with a transform header */
|
2019-06-08 04:16:10 +08:00
|
|
|
fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type);
|
2018-06-06 06:46:24 +08:00
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
rc = crypt_message(server, num_rqst, new_rq, 1);
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "Encrypt message returned %d\n", rc);
|
2016-11-04 07:47:37 +08:00
|
|
|
if (rc)
|
2018-08-01 07:26:11 +08:00
|
|
|
goto err_free;
|
2016-11-04 07:47:37 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
err_free:
|
|
|
|
smb3_free_compound_rqst(num_rqst - 1, &new_rq[1]);
|
2016-11-04 07:47:37 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-11-18 07:24:46 +08:00
|
|
|
static int
|
|
|
|
smb3_is_transform_hdr(void *buf)
|
|
|
|
{
|
|
|
|
struct smb2_transform_hdr *trhdr = buf;
|
|
|
|
|
|
|
|
return trhdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
decrypt_raw_data(struct TCP_Server_Info *server, char *buf,
|
|
|
|
unsigned int buf_data_size, struct page **pages,
|
2020-10-08 17:58:41 +08:00
|
|
|
unsigned int npages, unsigned int page_data_size,
|
|
|
|
bool is_offloaded)
|
2016-11-18 07:24:46 +08:00
|
|
|
{
|
2018-06-12 06:00:58 +08:00
|
|
|
struct kvec iov[2];
|
2016-11-18 07:24:46 +08:00
|
|
|
struct smb_rqst rqst = {NULL};
|
|
|
|
int rc;
|
|
|
|
|
2018-06-12 06:00:58 +08:00
|
|
|
iov[0].iov_base = buf;
|
|
|
|
iov[0].iov_len = sizeof(struct smb2_transform_hdr);
|
|
|
|
iov[1].iov_base = buf + sizeof(struct smb2_transform_hdr);
|
|
|
|
iov[1].iov_len = buf_data_size;
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
rqst.rq_iov = iov;
|
2018-06-12 06:00:58 +08:00
|
|
|
rqst.rq_nvec = 2;
|
2016-11-18 07:24:46 +08:00
|
|
|
rqst.rq_pages = pages;
|
|
|
|
rqst.rq_npages = npages;
|
|
|
|
rqst.rq_pagesz = PAGE_SIZE;
|
|
|
|
rqst.rq_tailsz = (page_data_size % PAGE_SIZE) ? : PAGE_SIZE;
|
|
|
|
|
2018-08-01 07:26:11 +08:00
|
|
|
rc = crypt_message(server, 1, &rqst, 0);
|
2019-05-09 03:36:25 +08:00
|
|
|
cifs_dbg(FYI, "Decrypt message returned %d\n", rc);
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
2018-06-12 06:00:58 +08:00
|
|
|
memmove(buf, iov[1].iov_base, buf_data_size);
|
2018-06-01 08:53:02 +08:00
|
|
|
|
2020-10-08 17:58:41 +08:00
|
|
|
if (!is_offloaded)
|
|
|
|
server->total_read = buf_data_size + page_data_size;
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-11-18 08:20:23 +08:00
|
|
|
static int
|
|
|
|
read_data_into_pages(struct TCP_Server_Info *server, struct page **pages,
|
|
|
|
unsigned int npages, unsigned int len)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int length;
|
|
|
|
|
|
|
|
for (i = 0; i < npages; i++) {
|
|
|
|
struct page *page = pages[i];
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
n = len;
|
|
|
|
if (len >= PAGE_SIZE) {
|
|
|
|
/* enough data to fill the page */
|
|
|
|
n = PAGE_SIZE;
|
|
|
|
len -= n;
|
|
|
|
} else {
|
|
|
|
zero_user(page, len, PAGE_SIZE - len);
|
|
|
|
len = 0;
|
|
|
|
}
|
2018-05-31 03:47:55 +08:00
|
|
|
length = cifs_read_page_from_socket(server, page, 0, n);
|
2016-11-18 08:20:23 +08:00
|
|
|
if (length < 0)
|
|
|
|
return length;
|
|
|
|
server->total_read += length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
init_read_bvec(struct page **pages, unsigned int npages, unsigned int data_size,
|
|
|
|
unsigned int cur_off, struct bio_vec **page_vec)
|
|
|
|
{
|
|
|
|
struct bio_vec *bvec;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
bvec = kcalloc(npages, sizeof(struct bio_vec), GFP_KERNEL);
|
|
|
|
if (!bvec)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for (i = 0; i < npages; i++) {
|
|
|
|
bvec[i].bv_page = pages[i];
|
|
|
|
bvec[i].bv_offset = (i == 0) ? cur_off : 0;
|
|
|
|
bvec[i].bv_len = min_t(unsigned int, PAGE_SIZE, data_size);
|
|
|
|
data_size -= bvec[i].bv_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data_size != 0) {
|
|
|
|
cifs_dbg(VFS, "%s: something went wrong\n", __func__);
|
|
|
|
kfree(bvec);
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
*page_vec = bvec;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-18 07:24:46 +08:00
|
|
|
static int
|
|
|
|
handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid,
|
|
|
|
char *buf, unsigned int buf_len, struct page **pages,
|
2020-10-28 21:42:21 +08:00
|
|
|
unsigned int npages, unsigned int page_data_size,
|
|
|
|
bool is_offloaded)
|
2016-11-18 07:24:46 +08:00
|
|
|
{
|
|
|
|
unsigned int data_offset;
|
|
|
|
unsigned int data_len;
|
2016-11-18 08:20:23 +08:00
|
|
|
unsigned int cur_off;
|
|
|
|
unsigned int cur_page_idx;
|
|
|
|
unsigned int pad_len;
|
2016-11-18 07:24:46 +08:00
|
|
|
struct cifs_readdata *rdata = mid->callback_data;
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr = (struct smb2_hdr *)buf;
|
2016-11-18 07:24:46 +08:00
|
|
|
struct bio_vec *bvec = NULL;
|
|
|
|
struct iov_iter iter;
|
|
|
|
struct kvec iov;
|
|
|
|
int length;
|
2017-11-23 08:38:46 +08:00
|
|
|
bool use_rdma_mr = false;
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
if (shdr->Command != SMB2_READ) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "only big read responses are supported\n");
|
2016-11-18 07:24:46 +08:00
|
|
|
return -ENOTSUPP;
|
|
|
|
}
|
|
|
|
|
2017-07-09 05:32:00 +08:00
|
|
|
if (server->ops->is_session_expired &&
|
|
|
|
server->ops->is_session_expired(buf)) {
|
2020-10-28 21:42:21 +08:00
|
|
|
if (!is_offloaded)
|
2021-07-19 22:14:46 +08:00
|
|
|
cifs_reconnect(server, true);
|
2017-07-09 05:32:00 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-11-18 07:24:46 +08:00
|
|
|
if (server->ops->is_status_pending &&
|
2019-01-24 09:11:16 +08:00
|
|
|
server->ops->is_status_pending(buf, server))
|
2016-11-18 07:24:46 +08:00
|
|
|
return -1;
|
|
|
|
|
2019-01-19 07:38:11 +08:00
|
|
|
/* set up first two iov to get credits */
|
|
|
|
rdata->iov[0].iov_base = buf;
|
2019-01-18 08:18:38 +08:00
|
|
|
rdata->iov[0].iov_len = 0;
|
|
|
|
rdata->iov[1].iov_base = buf;
|
2019-01-19 07:38:11 +08:00
|
|
|
rdata->iov[1].iov_len =
|
2019-01-18 08:18:38 +08:00
|
|
|
min_t(unsigned int, buf_len, server->vals->read_rsp_size);
|
2019-01-19 07:38:11 +08:00
|
|
|
cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n",
|
|
|
|
rdata->iov[0].iov_base, rdata->iov[0].iov_len);
|
|
|
|
cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n",
|
|
|
|
rdata->iov[1].iov_base, rdata->iov[1].iov_len);
|
|
|
|
|
|
|
|
rdata->result = server->ops->map_error(buf, true);
|
2016-11-18 07:24:46 +08:00
|
|
|
if (rdata->result != 0) {
|
|
|
|
cifs_dbg(FYI, "%s: server returned error %d\n",
|
|
|
|
__func__, rdata->result);
|
2019-01-19 07:38:11 +08:00
|
|
|
/* normal error on read response */
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_RECEIVED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, false);
|
2016-11-18 07:24:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
data_offset = server->ops->read_data_offset(buf);
|
2017-11-23 08:38:46 +08:00
|
|
|
#ifdef CONFIG_CIFS_SMB_DIRECT
|
|
|
|
use_rdma_mr = rdata->mr;
|
|
|
|
#endif
|
|
|
|
data_len = server->ops->read_data_length(buf, use_rdma_mr);
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
if (data_offset < server->vals->read_rsp_size) {
|
|
|
|
/*
|
|
|
|
* win2k8 sometimes sends an offset of 0 when the read
|
|
|
|
* is beyond the EOF. Treat it as if the data starts just after
|
|
|
|
* the header.
|
|
|
|
*/
|
|
|
|
cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n",
|
|
|
|
__func__, data_offset);
|
|
|
|
data_offset = server->vals->read_rsp_size;
|
|
|
|
} else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
|
|
|
/* data_offset is beyond the end of smallbuf */
|
|
|
|
cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n",
|
|
|
|
__func__, data_offset);
|
|
|
|
rdata->result = -EIO;
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_MALFORMED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, rdata->result);
|
2016-11-18 07:24:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-11-18 08:20:23 +08:00
|
|
|
pad_len = data_offset - server->vals->read_rsp_size;
|
|
|
|
|
2016-11-18 07:24:46 +08:00
|
|
|
if (buf_len <= data_offset) {
|
|
|
|
/* read response payload is in pages */
|
2016-11-18 08:20:23 +08:00
|
|
|
cur_page_idx = pad_len / PAGE_SIZE;
|
|
|
|
cur_off = pad_len % PAGE_SIZE;
|
|
|
|
|
|
|
|
if (cur_page_idx != 0) {
|
|
|
|
/* data offset is beyond the 1st page of response */
|
|
|
|
cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n",
|
|
|
|
__func__, data_offset);
|
|
|
|
rdata->result = -EIO;
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_MALFORMED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, rdata->result);
|
2016-11-18 08:20:23 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data_len > page_data_size - pad_len) {
|
|
|
|
/* data_len is corrupt -- discard frame */
|
|
|
|
rdata->result = -EIO;
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_MALFORMED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, rdata->result);
|
2016-11-18 08:20:23 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdata->result = init_read_bvec(pages, npages, page_data_size,
|
|
|
|
cur_off, &bvec);
|
|
|
|
if (rdata->result != 0) {
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_MALFORMED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, rdata->result);
|
2016-11-18 08:20:23 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-10-20 07:57:56 +08:00
|
|
|
iov_iter_bvec(&iter, WRITE, bvec, npages, data_len);
|
2016-11-18 07:24:46 +08:00
|
|
|
} else if (buf_len >= data_offset + data_len) {
|
|
|
|
/* read response payload is in buf */
|
|
|
|
WARN_ONCE(npages > 0, "read data can be either in buf or in pages");
|
|
|
|
iov.iov_base = buf + data_offset;
|
|
|
|
iov.iov_len = data_len;
|
2018-10-20 07:57:56 +08:00
|
|
|
iov_iter_kvec(&iter, WRITE, &iov, 1, data_len);
|
2016-11-18 07:24:46 +08:00
|
|
|
} else {
|
|
|
|
/* read response payload cannot be in both buf and pages */
|
|
|
|
WARN_ONCE(1, "buf can not contain only a part of read data");
|
|
|
|
rdata->result = -EIO;
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_MALFORMED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, rdata->result);
|
2016-11-18 07:24:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
length = rdata->copy_into_pages(server, rdata, &iter);
|
|
|
|
|
|
|
|
kfree(bvec);
|
|
|
|
|
|
|
|
if (length < 0)
|
|
|
|
return length;
|
|
|
|
|
2020-10-29 13:03:10 +08:00
|
|
|
if (is_offloaded)
|
|
|
|
mid->mid_state = MID_RESPONSE_RECEIVED;
|
|
|
|
else
|
|
|
|
dequeue_mid(mid, false);
|
2016-11-18 07:24:46 +08:00
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
2019-09-07 14:09:49 +08:00
|
|
|
struct smb2_decrypt_work {
|
|
|
|
struct work_struct decrypt;
|
|
|
|
struct TCP_Server_Info *server;
|
|
|
|
struct page **ppages;
|
|
|
|
char *buf;
|
|
|
|
unsigned int npages;
|
|
|
|
unsigned int len;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void smb2_decrypt_offload(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct smb2_decrypt_work *dw = container_of(work,
|
|
|
|
struct smb2_decrypt_work, decrypt);
|
|
|
|
int i, rc;
|
|
|
|
struct mid_q_entry *mid;
|
|
|
|
|
|
|
|
rc = decrypt_raw_data(dw->server, dw->buf, dw->server->vals->read_rsp_size,
|
2020-10-08 17:58:41 +08:00
|
|
|
dw->ppages, dw->npages, dw->len, true);
|
2019-09-07 14:09:49 +08:00
|
|
|
if (rc) {
|
|
|
|
cifs_dbg(VFS, "error decrypting rc=%d\n", rc);
|
|
|
|
goto free_pages;
|
|
|
|
}
|
|
|
|
|
2019-09-14 05:47:31 +08:00
|
|
|
dw->server->lstrp = jiffies;
|
2020-10-29 13:03:10 +08:00
|
|
|
mid = smb2_find_dequeue_mid(dw->server, dw->buf);
|
2019-09-07 14:09:49 +08:00
|
|
|
if (mid == NULL)
|
|
|
|
cifs_dbg(FYI, "mid not found\n");
|
|
|
|
else {
|
|
|
|
mid->decrypted = true;
|
|
|
|
rc = handle_read_data(dw->server, mid, dw->buf,
|
|
|
|
dw->server->vals->read_rsp_size,
|
2020-10-28 21:42:21 +08:00
|
|
|
dw->ppages, dw->npages, dw->len,
|
|
|
|
true);
|
2020-10-29 14:07:56 +08:00
|
|
|
if (rc >= 0) {
|
|
|
|
#ifdef CONFIG_CIFS_STATS2
|
|
|
|
mid->when_received = jiffies;
|
|
|
|
#endif
|
2021-02-16 18:40:45 +08:00
|
|
|
if (dw->server->ops->is_network_name_deleted)
|
|
|
|
dw->server->ops->is_network_name_deleted(dw->buf,
|
|
|
|
dw->server);
|
|
|
|
|
2020-10-29 14:07:56 +08:00
|
|
|
mid->callback(mid);
|
|
|
|
} else {
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_lock(&cifs_tcp_ses_lock);
|
2020-10-29 14:07:56 +08:00
|
|
|
spin_lock(&GlobalMid_Lock);
|
|
|
|
if (dw->server->tcpStatus == CifsNeedReconnect) {
|
|
|
|
mid->mid_state = MID_RETRY_NEEDED;
|
|
|
|
spin_unlock(&GlobalMid_Lock);
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2020-10-29 14:07:56 +08:00
|
|
|
mid->callback(mid);
|
|
|
|
} else {
|
|
|
|
mid->mid_state = MID_REQUEST_SUBMITTED;
|
|
|
|
mid->mid_flags &= ~(MID_DELETED);
|
|
|
|
list_add_tail(&mid->qhead,
|
|
|
|
&dw->server->pending_mid_q);
|
|
|
|
spin_unlock(&GlobalMid_Lock);
|
2021-07-20 01:05:53 +08:00
|
|
|
spin_unlock(&cifs_tcp_ses_lock);
|
2020-10-29 14:07:56 +08:00
|
|
|
}
|
|
|
|
}
|
2019-09-14 05:47:31 +08:00
|
|
|
cifs_mid_q_entry_release(mid);
|
2019-09-07 14:09:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
free_pages:
|
|
|
|
for (i = dw->npages-1; i >= 0; i--)
|
|
|
|
put_page(dw->ppages[i]);
|
|
|
|
|
|
|
|
kfree(dw->ppages);
|
|
|
|
cifs_small_buf_release(dw->buf);
|
2019-10-27 05:00:44 +08:00
|
|
|
kfree(dw);
|
2019-09-07 14:09:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-18 08:20:23 +08:00
|
|
|
static int
|
2019-09-07 14:09:49 +08:00
|
|
|
receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid,
|
|
|
|
int *num_mids)
|
2016-11-18 08:20:23 +08:00
|
|
|
{
|
|
|
|
char *buf = server->smallbuf;
|
|
|
|
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
|
|
|
unsigned int npages;
|
|
|
|
struct page **pages;
|
|
|
|
unsigned int len;
|
2018-06-01 08:53:07 +08:00
|
|
|
unsigned int buflen = server->pdu_size;
|
2016-11-18 08:20:23 +08:00
|
|
|
int rc;
|
|
|
|
int i = 0;
|
2019-09-07 14:09:49 +08:00
|
|
|
struct smb2_decrypt_work *dw;
|
2016-11-18 08:20:23 +08:00
|
|
|
|
2019-09-07 14:09:49 +08:00
|
|
|
*num_mids = 1;
|
2018-06-01 08:53:07 +08:00
|
|
|
len = min_t(unsigned int, buflen, server->vals->read_rsp_size +
|
2016-11-18 08:20:23 +08:00
|
|
|
sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1;
|
|
|
|
|
|
|
|
rc = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
server->total_read += rc;
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
len = le32_to_cpu(tr_hdr->OriginalMessageSize) -
|
2018-03-31 08:45:31 +08:00
|
|
|
server->vals->read_rsp_size;
|
2016-11-18 08:20:23 +08:00
|
|
|
npages = DIV_ROUND_UP(len, PAGE_SIZE);
|
|
|
|
|
|
|
|
pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
|
|
|
|
if (!pages) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto discard_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; i < npages; i++) {
|
|
|
|
pages[i] = alloc_page(GFP_KERNEL|__GFP_HIGHMEM);
|
|
|
|
if (!pages[i]) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto discard_data;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* read read data into pages */
|
|
|
|
rc = read_data_into_pages(server, pages, npages, len);
|
|
|
|
if (rc)
|
|
|
|
goto free_pages;
|
|
|
|
|
2017-04-11 01:31:33 +08:00
|
|
|
rc = cifs_discard_remaining_data(server);
|
2016-11-18 08:20:23 +08:00
|
|
|
if (rc)
|
|
|
|
goto free_pages;
|
|
|
|
|
2019-09-07 14:09:49 +08:00
|
|
|
/*
|
|
|
|
* For large reads, offload to different thread for better performance,
|
|
|
|
* use more cores decrypting which can be expensive
|
|
|
|
*/
|
|
|
|
|
2019-09-10 02:30:15 +08:00
|
|
|
if ((server->min_offload) && (server->in_flight > 1) &&
|
2019-09-09 12:22:02 +08:00
|
|
|
(server->pdu_size >= server->min_offload)) {
|
2019-09-07 14:09:49 +08:00
|
|
|
dw = kmalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL);
|
|
|
|
if (dw == NULL)
|
|
|
|
goto non_offloaded_decrypt;
|
|
|
|
|
|
|
|
dw->buf = server->smallbuf;
|
|
|
|
server->smallbuf = (char *)cifs_small_buf_get();
|
|
|
|
|
|
|
|
INIT_WORK(&dw->decrypt, smb2_decrypt_offload);
|
|
|
|
|
|
|
|
dw->npages = npages;
|
|
|
|
dw->server = server;
|
|
|
|
dw->ppages = pages;
|
|
|
|
dw->len = len;
|
2019-10-27 05:00:44 +08:00
|
|
|
queue_work(decrypt_wq, &dw->decrypt);
|
2019-09-07 14:09:49 +08:00
|
|
|
*num_mids = 0; /* worker thread takes care of finding mid */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
non_offloaded_decrypt:
|
2018-06-01 08:53:07 +08:00
|
|
|
rc = decrypt_raw_data(server, buf, server->vals->read_rsp_size,
|
2020-10-08 17:58:41 +08:00
|
|
|
pages, npages, len, false);
|
2016-11-18 08:20:23 +08:00
|
|
|
if (rc)
|
|
|
|
goto free_pages;
|
|
|
|
|
|
|
|
*mid = smb2_find_mid(server, buf);
|
|
|
|
if (*mid == NULL)
|
|
|
|
cifs_dbg(FYI, "mid not found\n");
|
|
|
|
else {
|
|
|
|
cifs_dbg(FYI, "mid found\n");
|
|
|
|
(*mid)->decrypted = true;
|
|
|
|
rc = handle_read_data(server, *mid, buf,
|
|
|
|
server->vals->read_rsp_size,
|
2020-10-28 21:42:21 +08:00
|
|
|
pages, npages, len, false);
|
2021-02-16 18:40:45 +08:00
|
|
|
if (rc >= 0) {
|
|
|
|
if (server->ops->is_network_name_deleted) {
|
|
|
|
server->ops->is_network_name_deleted(buf,
|
|
|
|
server);
|
|
|
|
}
|
|
|
|
}
|
2016-11-18 08:20:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
free_pages:
|
|
|
|
for (i = i - 1; i >= 0; i--)
|
|
|
|
put_page(pages[i]);
|
|
|
|
kfree(pages);
|
|
|
|
return rc;
|
|
|
|
discard_data:
|
2017-04-11 01:31:33 +08:00
|
|
|
cifs_discard_remaining_data(server);
|
2016-11-18 08:20:23 +08:00
|
|
|
goto free_pages;
|
|
|
|
}
|
|
|
|
|
2016-11-18 07:24:46 +08:00
|
|
|
static int
|
|
|
|
receive_encrypted_standard(struct TCP_Server_Info *server,
|
2018-08-08 13:07:45 +08:00
|
|
|
struct mid_q_entry **mids, char **bufs,
|
|
|
|
int *num_mids)
|
2016-11-18 07:24:46 +08:00
|
|
|
{
|
2018-08-08 13:07:45 +08:00
|
|
|
int ret, length;
|
2016-11-18 07:24:46 +08:00
|
|
|
char *buf = server->smallbuf;
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *shdr;
|
2018-04-09 16:06:26 +08:00
|
|
|
unsigned int pdu_length = server->pdu_size;
|
2016-11-18 07:24:46 +08:00
|
|
|
unsigned int buf_size;
|
|
|
|
struct mid_q_entry *mid_entry;
|
2018-08-08 13:07:45 +08:00
|
|
|
int next_is_large;
|
|
|
|
char *next_buffer = NULL;
|
|
|
|
|
|
|
|
*num_mids = 0;
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
/* switch to large buffer if too big for a small one */
|
2018-06-01 08:53:07 +08:00
|
|
|
if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) {
|
2016-11-18 07:24:46 +08:00
|
|
|
server->large_buf = true;
|
|
|
|
memcpy(server->bigbuf, buf, server->total_read);
|
|
|
|
buf = server->bigbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now read the rest */
|
|
|
|
length = cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1,
|
2018-06-01 08:53:07 +08:00
|
|
|
pdu_length - HEADER_SIZE(server) + 1);
|
2016-11-18 07:24:46 +08:00
|
|
|
if (length < 0)
|
|
|
|
return length;
|
|
|
|
server->total_read += length;
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
buf_size = pdu_length - sizeof(struct smb2_transform_hdr);
|
2020-10-08 17:58:41 +08:00
|
|
|
length = decrypt_raw_data(server, buf, buf_size, NULL, 0, 0, false);
|
2016-11-18 07:24:46 +08:00
|
|
|
if (length)
|
|
|
|
return length;
|
|
|
|
|
2018-08-08 13:07:45 +08:00
|
|
|
next_is_large = server->large_buf;
|
2019-07-23 02:38:22 +08:00
|
|
|
one_more:
|
2021-11-05 07:39:01 +08:00
|
|
|
shdr = (struct smb2_hdr *)buf;
|
2018-08-08 13:07:45 +08:00
|
|
|
if (shdr->NextCommand) {
|
2019-07-23 02:38:22 +08:00
|
|
|
if (next_is_large)
|
2018-08-08 13:07:45 +08:00
|
|
|
next_buffer = (char *)cifs_buf_get();
|
2019-07-23 02:38:22 +08:00
|
|
|
else
|
2018-08-08 13:07:45 +08:00
|
|
|
next_buffer = (char *)cifs_small_buf_get();
|
|
|
|
memcpy(next_buffer,
|
2019-07-23 02:38:22 +08:00
|
|
|
buf + le32_to_cpu(shdr->NextCommand),
|
2018-08-08 13:07:45 +08:00
|
|
|
pdu_length - le32_to_cpu(shdr->NextCommand));
|
|
|
|
}
|
|
|
|
|
2016-11-18 07:24:46 +08:00
|
|
|
mid_entry = smb2_find_mid(server, buf);
|
|
|
|
if (mid_entry == NULL)
|
|
|
|
cifs_dbg(FYI, "mid not found\n");
|
|
|
|
else {
|
|
|
|
cifs_dbg(FYI, "mid found\n");
|
|
|
|
mid_entry->decrypted = true;
|
2018-08-08 13:07:45 +08:00
|
|
|
mid_entry->resp_buf_size = server->pdu_size;
|
2016-11-18 07:24:46 +08:00
|
|
|
}
|
|
|
|
|
2018-08-08 13:07:45 +08:00
|
|
|
if (*num_mids >= MAX_COMPOUND) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "too many PDUs in compound\n");
|
2018-08-08 13:07:45 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
bufs[*num_mids] = buf;
|
|
|
|
mids[(*num_mids)++] = mid_entry;
|
2016-11-18 07:24:46 +08:00
|
|
|
|
|
|
|
if (mid_entry && mid_entry->handle)
|
2018-08-08 13:07:45 +08:00
|
|
|
ret = mid_entry->handle(server, mid_entry);
|
|
|
|
else
|
|
|
|
ret = cifs_handle_standard(server, mid_entry);
|
|
|
|
|
|
|
|
if (ret == 0 && shdr->NextCommand) {
|
|
|
|
pdu_length -= le32_to_cpu(shdr->NextCommand);
|
|
|
|
server->large_buf = next_is_large;
|
|
|
|
if (next_is_large)
|
2019-07-23 02:38:22 +08:00
|
|
|
server->bigbuf = buf = next_buffer;
|
2018-08-08 13:07:45 +08:00
|
|
|
else
|
2019-07-23 02:38:22 +08:00
|
|
|
server->smallbuf = buf = next_buffer;
|
2018-08-08 13:07:45 +08:00
|
|
|
goto one_more;
|
2019-07-23 02:38:22 +08:00
|
|
|
} else if (ret != 0) {
|
|
|
|
/*
|
|
|
|
* ret != 0 here means that we didn't get to handle_mid() thus
|
|
|
|
* server->smallbuf and server->bigbuf are still valid. We need
|
|
|
|
* to free next_buffer because it is not going to be used
|
|
|
|
* anywhere.
|
|
|
|
*/
|
|
|
|
if (next_is_large)
|
|
|
|
free_rsp_buf(CIFS_LARGE_BUFFER, next_buffer);
|
|
|
|
else
|
|
|
|
free_rsp_buf(CIFS_SMALL_BUFFER, next_buffer);
|
2018-08-08 13:07:45 +08:00
|
|
|
}
|
2016-11-18 07:24:46 +08:00
|
|
|
|
2018-08-08 13:07:45 +08:00
|
|
|
return ret;
|
2016-11-18 07:24:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2018-08-08 13:07:45 +08:00
|
|
|
smb3_receive_transform(struct TCP_Server_Info *server,
|
|
|
|
struct mid_q_entry **mids, char **bufs, int *num_mids)
|
2016-11-18 07:24:46 +08:00
|
|
|
{
|
|
|
|
char *buf = server->smallbuf;
|
2018-04-09 16:06:26 +08:00
|
|
|
unsigned int pdu_length = server->pdu_size;
|
2016-11-18 07:24:46 +08:00
|
|
|
struct smb2_transform_hdr *tr_hdr = (struct smb2_transform_hdr *)buf;
|
|
|
|
unsigned int orig_len = le32_to_cpu(tr_hdr->OriginalMessageSize);
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
if (pdu_length < sizeof(struct smb2_transform_hdr) +
|
2021-11-05 07:39:01 +08:00
|
|
|
sizeof(struct smb2_hdr)) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "Transform message is too small (%u)\n",
|
2016-11-18 07:24:46 +08:00
|
|
|
pdu_length);
|
2021-07-19 22:14:46 +08:00
|
|
|
cifs_reconnect(server, true);
|
2016-11-18 07:24:46 +08:00
|
|
|
return -ECONNABORTED;
|
|
|
|
}
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) {
|
2019-09-04 10:32:41 +08:00
|
|
|
cifs_server_dbg(VFS, "Transform message is broken\n");
|
2021-07-19 22:14:46 +08:00
|
|
|
cifs_reconnect(server, true);
|
2016-11-18 07:24:46 +08:00
|
|
|
return -ECONNABORTED;
|
|
|
|
}
|
|
|
|
|
2018-08-08 13:07:45 +08:00
|
|
|
/* TODO: add support for compounds containing READ. */
|
2019-01-01 06:13:34 +08:00
|
|
|
if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) {
|
2019-09-07 14:09:49 +08:00
|
|
|
return receive_encrypted_read(server, &mids[0], num_mids);
|
2019-01-01 06:13:34 +08:00
|
|
|
}
|
2016-11-18 07:24:46 +08:00
|
|
|
|
2018-08-08 13:07:45 +08:00
|
|
|
return receive_encrypted_standard(server, mids, bufs, num_mids);
|
2016-11-18 07:24:46 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid)
|
|
|
|
{
|
|
|
|
char *buf = server->large_buf ? server->bigbuf : server->smallbuf;
|
|
|
|
|
2018-06-01 08:53:07 +08:00
|
|
|
return handle_read_data(server, mid, buf, server->pdu_size,
|
2020-10-28 21:42:21 +08:00
|
|
|
NULL, 0, 0, false);
|
2016-11-18 07:24:46 +08:00
|
|
|
}
|
|
|
|
|
2018-06-01 08:53:08 +08:00
|
|
|
static int
|
|
|
|
smb2_next_header(char *buf)
|
|
|
|
{
|
2021-11-05 07:39:01 +08:00
|
|
|
struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
|
2018-06-01 08:53:08 +08:00
|
|
|
struct smb2_transform_hdr *t_hdr = (struct smb2_transform_hdr *)buf;
|
|
|
|
|
|
|
|
if (hdr->ProtocolId == SMB2_TRANSFORM_PROTO_NUM)
|
|
|
|
return sizeof(struct smb2_transform_hdr) +
|
|
|
|
le32_to_cpu(t_hdr->OriginalMessageSize);
|
|
|
|
|
|
|
|
return le32_to_cpu(hdr->NextCommand);
|
|
|
|
}
|
|
|
|
|
2019-03-14 13:29:17 +08:00
|
|
|
static int
|
|
|
|
smb2_make_node(unsigned int xid, struct inode *inode,
|
|
|
|
struct dentry *dentry, struct cifs_tcon *tcon,
|
2021-03-18 13:38:53 +08:00
|
|
|
const char *full_path, umode_t mode, dev_t dev)
|
2019-03-14 13:29:17 +08:00
|
|
|
{
|
|
|
|
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
|
|
|
int rc = -EPERM;
|
|
|
|
FILE_ALL_INFO *buf = NULL;
|
2020-06-04 23:23:55 +08:00
|
|
|
struct cifs_io_parms io_parms = {0};
|
2019-03-14 13:29:17 +08:00
|
|
|
__u32 oplock = 0;
|
|
|
|
struct cifs_fid fid;
|
|
|
|
struct cifs_open_parms oparms;
|
|
|
|
unsigned int bytes_written;
|
|
|
|
struct win_dev *pdev;
|
|
|
|
struct kvec iov[2];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if mounted with mount parm 'sfu' mount parm.
|
|
|
|
* SFU emulation should work with all servers, but only
|
|
|
|
* supports block and char device (no socket & fifo),
|
|
|
|
* and was used by default in earlier versions of Windows
|
|
|
|
*/
|
|
|
|
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO: Add ability to create instead via reparse point. Windows (e.g.
|
|
|
|
* their current NFS server) uses this approach to expose special files
|
|
|
|
* over SMB2/SMB3 and Samba will do this with SMB3.1.1 POSIX Extensions
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!S_ISCHR(mode) && !S_ISBLK(mode))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
cifs_dbg(FYI, "sfu compat create special file\n");
|
|
|
|
|
|
|
|
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
|
|
|
if (buf == NULL) {
|
|
|
|
rc = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
oparms.tcon = tcon;
|
|
|
|
oparms.cifs_sb = cifs_sb;
|
|
|
|
oparms.desired_access = GENERIC_WRITE;
|
2020-02-04 03:46:43 +08:00
|
|
|
oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
|
|
|
|
CREATE_OPTION_SPECIAL);
|
2019-03-14 13:29:17 +08:00
|
|
|
oparms.disposition = FILE_CREATE;
|
|
|
|
oparms.path = full_path;
|
|
|
|
oparms.fid = &fid;
|
|
|
|
oparms.reconnect = false;
|
|
|
|
|
|
|
|
if (tcon->ses->server->oplocks)
|
|
|
|
oplock = REQ_OPLOCK;
|
|
|
|
else
|
|
|
|
oplock = 0;
|
|
|
|
rc = tcon->ses->server->ops->open(xid, &oparms, &oplock, buf);
|
|
|
|
if (rc)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* BB Do not bother to decode buf since no local inode yet to put
|
|
|
|
* timestamps in, but we can reuse it safely.
|
|
|
|
*/
|
|
|
|
|
|
|
|
pdev = (struct win_dev *)buf;
|
|
|
|
io_parms.pid = current->tgid;
|
|
|
|
io_parms.tcon = tcon;
|
|
|
|
io_parms.offset = 0;
|
|
|
|
io_parms.length = sizeof(struct win_dev);
|
|
|
|
iov[1].iov_base = buf;
|
|
|
|
iov[1].iov_len = sizeof(struct win_dev);
|
|
|
|
if (S_ISCHR(mode)) {
|
|
|
|
memcpy(pdev->type, "IntxCHR", 8);
|
|
|
|
pdev->major = cpu_to_le64(MAJOR(dev));
|
|
|
|
pdev->minor = cpu_to_le64(MINOR(dev));
|
|
|
|
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
|
|
|
&bytes_written, iov, 1);
|
|
|
|
} else if (S_ISBLK(mode)) {
|
|
|
|
memcpy(pdev->type, "IntxBLK", 8);
|
|
|
|
pdev->major = cpu_to_le64(MAJOR(dev));
|
|
|
|
pdev->minor = cpu_to_le64(MINOR(dev));
|
|
|
|
rc = tcon->ses->server->ops->sync_write(xid, &fid, &io_parms,
|
|
|
|
&bytes_written, iov, 1);
|
|
|
|
}
|
|
|
|
tcon->ses->server->ops->close(xid, tcon, &fid);
|
|
|
|
d_drop(dentry);
|
|
|
|
|
|
|
|
/* FIXME: add code here to set EAs */
|
|
|
|
out:
|
|
|
|
kfree(buf);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-05 20:11:28 +08:00
|
|
|
struct smb_version_operations smb20_operations = {
|
2012-09-19 21:22:43 +08:00
|
|
|
.compare_fids = smb2_compare_fids,
|
2011-12-27 02:53:34 +08:00
|
|
|
.setup_request = smb2_setup_request,
|
2012-07-11 18:45:28 +08:00
|
|
|
.setup_async_request = smb2_setup_async_request,
|
2011-12-27 02:53:34 +08:00
|
|
|
.check_receive = smb2_check_receive,
|
2012-05-23 20:18:00 +08:00
|
|
|
.add_credits = smb2_add_credits,
|
|
|
|
.set_credits = smb2_set_credits,
|
|
|
|
.get_credits_field = smb2_get_credits_field,
|
|
|
|
.get_credits = smb2_get_credits,
|
2014-06-05 23:03:27 +08:00
|
|
|
.wait_mtu_credits = cifs_wait_mtu_credits,
|
2011-12-27 02:53:34 +08:00
|
|
|
.get_next_mid = smb2_get_next_mid,
|
2019-03-05 06:02:50 +08:00
|
|
|
.revert_current_mid = smb2_revert_current_mid,
|
2012-09-19 07:20:29 +08:00
|
|
|
.read_data_offset = smb2_read_data_offset,
|
|
|
|
.read_data_length = smb2_read_data_length,
|
|
|
|
.map_error = map_smb2_to_linux_error,
|
2011-06-08 19:51:07 +08:00
|
|
|
.find_mid = smb2_find_mid,
|
|
|
|
.check_message = smb2_check_message,
|
|
|
|
.dump_detail = smb2_dump_detail,
|
2012-05-28 19:19:39 +08:00
|
|
|
.clear_stats = smb2_clear_stats,
|
|
|
|
.print_stats = smb2_print_stats,
|
2012-09-19 07:20:33 +08:00
|
|
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
2017-03-04 07:41:38 +08:00
|
|
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
2014-03-12 00:11:47 +08:00
|
|
|
.downgrade_oplock = smb2_downgrade_oplock,
|
2011-12-27 20:12:43 +08:00
|
|
|
.need_neg = smb2_need_neg,
|
|
|
|
.negotiate = smb2_negotiate,
|
2012-09-19 07:20:28 +08:00
|
|
|
.negotiate_wsize = smb2_negotiate_wsize,
|
|
|
|
.negotiate_rsize = smb2_negotiate_rsize,
|
2011-12-27 20:22:00 +08:00
|
|
|
.sess_setup = SMB2_sess_setup,
|
|
|
|
.logoff = SMB2_logoff,
|
2011-12-27 20:04:00 +08:00
|
|
|
.tree_connect = SMB2_tcon,
|
|
|
|
.tree_disconnect = SMB2_tdis,
|
2013-10-09 15:07:00 +08:00
|
|
|
.qfs_tcon = smb2_qfs_tcon,
|
2011-12-27 02:58:46 +08:00
|
|
|
.is_path_accessible = smb2_is_path_accessible,
|
2012-07-12 22:30:44 +08:00
|
|
|
.can_echo = smb2_can_echo,
|
|
|
|
.echo = SMB2_echo,
|
2011-12-29 21:06:33 +08:00
|
|
|
.query_path_info = smb2_query_path_info,
|
|
|
|
.get_srv_inum = smb2_get_srv_inum,
|
2012-09-19 07:20:27 +08:00
|
|
|
.query_file_info = smb2_query_file_info,
|
2012-09-19 07:20:32 +08:00
|
|
|
.set_path_size = smb2_set_path_size,
|
|
|
|
.set_file_size = smb2_set_file_size,
|
2012-09-19 07:20:32 +08:00
|
|
|
.set_file_info = smb2_set_file_info,
|
2013-10-15 04:31:32 +08:00
|
|
|
.set_compression = smb2_set_compression,
|
2011-07-19 16:56:37 +08:00
|
|
|
.mkdir = smb2_mkdir,
|
|
|
|
.mkdir_setinfo = smb2_mkdir_setinfo,
|
2012-07-10 20:14:38 +08:00
|
|
|
.rmdir = smb2_rmdir,
|
2012-09-19 07:20:25 +08:00
|
|
|
.unlink = smb2_unlink,
|
2012-09-19 07:20:31 +08:00
|
|
|
.rename = smb2_rename_path,
|
2012-09-19 07:20:31 +08:00
|
|
|
.create_hardlink = smb2_create_hardlink,
|
2013-08-14 23:25:21 +08:00
|
|
|
.query_symlink = smb2_query_symlink,
|
2016-07-11 23:53:20 +08:00
|
|
|
.query_mf_symlink = smb3_query_mf_symlink,
|
|
|
|
.create_mf_symlink = smb3_create_mf_symlink,
|
2012-09-19 07:20:26 +08:00
|
|
|
.open = smb2_open_file,
|
|
|
|
.set_fid = smb2_set_fid,
|
|
|
|
.close = smb2_close_file,
|
2012-09-19 07:20:28 +08:00
|
|
|
.flush = smb2_flush_file,
|
2012-09-19 07:20:29 +08:00
|
|
|
.async_readv = smb2_async_readv,
|
2012-09-19 07:20:29 +08:00
|
|
|
.async_writev = smb2_async_writev,
|
2012-09-19 07:20:30 +08:00
|
|
|
.sync_read = smb2_sync_read,
|
2012-09-19 07:20:30 +08:00
|
|
|
.sync_write = smb2_sync_write,
|
2012-09-19 07:20:33 +08:00
|
|
|
.query_dir_first = smb2_query_dir_first,
|
|
|
|
.query_dir_next = smb2_query_dir_next,
|
|
|
|
.close_dir = smb2_close_dir,
|
|
|
|
.calc_smb_size = smb2_calc_size,
|
2012-09-19 07:20:33 +08:00
|
|
|
.is_status_pending = smb2_is_status_pending,
|
2017-07-09 05:32:00 +08:00
|
|
|
.is_session_expired = smb2_is_session_expired,
|
2012-09-19 07:20:33 +08:00
|
|
|
.oplock_response = smb2_oplock_response,
|
2012-09-19 07:20:34 +08:00
|
|
|
.queryfs = smb2_queryfs,
|
2012-09-19 21:22:43 +08:00
|
|
|
.mand_lock = smb2_mand_lock,
|
|
|
|
.mand_unlock_range = smb2_unlock_range,
|
2012-09-19 21:22:44 +08:00
|
|
|
.push_mand_locks = smb2_push_mandatory_locks,
|
2012-09-19 21:22:44 +08:00
|
|
|
.get_lease_key = smb2_get_lease_key,
|
|
|
|
.set_lease_key = smb2_set_lease_key,
|
|
|
|
.new_lease_key = smb2_new_lease_key,
|
2012-12-09 12:08:06 +08:00
|
|
|
.calc_signature = smb2_calc_signature,
|
2013-09-05 20:11:28 +08:00
|
|
|
.is_read_op = smb2_is_read_op,
|
|
|
|
.set_oplock_level = smb2_set_oplock_level,
|
2013-09-04 17:07:41 +08:00
|
|
|
.create_lease_buf = smb2_create_lease_buf,
|
2013-09-06 00:16:45 +08:00
|
|
|
.parse_lease_buf = smb2_parse_lease_buf,
|
2017-04-04 15:12:04 +08:00
|
|
|
.copychunk_range = smb2_copychunk_range,
|
2014-06-22 15:03:22 +08:00
|
|
|
.wp_retry_size = smb2_wp_retry_size,
|
2014-08-19 00:49:57 +08:00
|
|
|
.dir_needs_close = smb2_dir_needs_close,
|
2017-02-13 23:16:49 +08:00
|
|
|
.get_dfs_refer = smb2_get_dfs_refer,
|
2017-01-18 18:05:57 +08:00
|
|
|
.select_sectype = smb2_select_sectype,
|
2017-08-24 09:24:55 +08:00
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
|
|
|
.query_all_EAs = smb2_query_eas,
|
2017-08-24 09:24:56 +08:00
|
|
|
.set_EA = smb2_set_ea,
|
2017-08-24 09:24:55 +08:00
|
|
|
#endif /* CIFS_XATTR */
|
2017-06-23 11:52:05 +08:00
|
|
|
.get_acl = get_smb2_acl,
|
|
|
|
.get_acl_by_fid = get_smb2_acl_by_fid,
|
2017-06-29 11:37:32 +08:00
|
|
|
.set_acl = set_smb2_acl,
|
2018-06-01 08:53:08 +08:00
|
|
|
.next_header = smb2_next_header,
|
2018-10-08 08:19:58 +08:00
|
|
|
.ioctl_query_info = smb2_ioctl_query_info,
|
2019-03-14 13:29:17 +08:00
|
|
|
.make_node = smb2_make_node,
|
2019-04-25 14:45:29 +08:00
|
|
|
.fiemap = smb3_fiemap,
|
2019-05-15 05:17:02 +08:00
|
|
|
.llseek = smb3_llseek,
|
2020-09-18 13:37:28 +08:00
|
|
|
.is_status_io_timeout = smb2_is_status_io_timeout,
|
2021-02-16 18:40:45 +08:00
|
|
|
.is_network_name_deleted = smb2_is_network_name_deleted,
|
2012-12-09 12:08:06 +08:00
|
|
|
};
|
|
|
|
|
2013-09-05 20:11:28 +08:00
|
|
|
struct smb_version_operations smb21_operations = {
|
|
|
|
.compare_fids = smb2_compare_fids,
|
|
|
|
.setup_request = smb2_setup_request,
|
|
|
|
.setup_async_request = smb2_setup_async_request,
|
|
|
|
.check_receive = smb2_check_receive,
|
|
|
|
.add_credits = smb2_add_credits,
|
|
|
|
.set_credits = smb2_set_credits,
|
|
|
|
.get_credits_field = smb2_get_credits_field,
|
|
|
|
.get_credits = smb2_get_credits,
|
2014-06-05 23:03:27 +08:00
|
|
|
.wait_mtu_credits = smb2_wait_mtu_credits,
|
2019-01-24 10:15:52 +08:00
|
|
|
.adjust_credits = smb2_adjust_credits,
|
2013-09-05 20:11:28 +08:00
|
|
|
.get_next_mid = smb2_get_next_mid,
|
2019-03-05 06:02:50 +08:00
|
|
|
.revert_current_mid = smb2_revert_current_mid,
|
2013-09-05 20:11:28 +08:00
|
|
|
.read_data_offset = smb2_read_data_offset,
|
|
|
|
.read_data_length = smb2_read_data_length,
|
|
|
|
.map_error = map_smb2_to_linux_error,
|
|
|
|
.find_mid = smb2_find_mid,
|
|
|
|
.check_message = smb2_check_message,
|
|
|
|
.dump_detail = smb2_dump_detail,
|
|
|
|
.clear_stats = smb2_clear_stats,
|
|
|
|
.print_stats = smb2_print_stats,
|
|
|
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
2017-03-04 07:41:38 +08:00
|
|
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
2019-10-30 07:51:19 +08:00
|
|
|
.downgrade_oplock = smb2_downgrade_oplock,
|
2013-09-05 20:11:28 +08:00
|
|
|
.need_neg = smb2_need_neg,
|
|
|
|
.negotiate = smb2_negotiate,
|
|
|
|
.negotiate_wsize = smb2_negotiate_wsize,
|
|
|
|
.negotiate_rsize = smb2_negotiate_rsize,
|
|
|
|
.sess_setup = SMB2_sess_setup,
|
|
|
|
.logoff = SMB2_logoff,
|
|
|
|
.tree_connect = SMB2_tcon,
|
|
|
|
.tree_disconnect = SMB2_tdis,
|
2013-10-09 15:07:00 +08:00
|
|
|
.qfs_tcon = smb2_qfs_tcon,
|
2013-09-05 20:11:28 +08:00
|
|
|
.is_path_accessible = smb2_is_path_accessible,
|
|
|
|
.can_echo = smb2_can_echo,
|
|
|
|
.echo = SMB2_echo,
|
|
|
|
.query_path_info = smb2_query_path_info,
|
|
|
|
.get_srv_inum = smb2_get_srv_inum,
|
|
|
|
.query_file_info = smb2_query_file_info,
|
|
|
|
.set_path_size = smb2_set_path_size,
|
|
|
|
.set_file_size = smb2_set_file_size,
|
|
|
|
.set_file_info = smb2_set_file_info,
|
2013-10-15 04:31:32 +08:00
|
|
|
.set_compression = smb2_set_compression,
|
2013-09-05 20:11:28 +08:00
|
|
|
.mkdir = smb2_mkdir,
|
|
|
|
.mkdir_setinfo = smb2_mkdir_setinfo,
|
|
|
|
.rmdir = smb2_rmdir,
|
|
|
|
.unlink = smb2_unlink,
|
|
|
|
.rename = smb2_rename_path,
|
|
|
|
.create_hardlink = smb2_create_hardlink,
|
|
|
|
.query_symlink = smb2_query_symlink,
|
2014-09-16 20:18:19 +08:00
|
|
|
.query_mf_symlink = smb3_query_mf_symlink,
|
2014-09-15 17:49:28 +08:00
|
|
|
.create_mf_symlink = smb3_create_mf_symlink,
|
2013-09-05 20:11:28 +08:00
|
|
|
.open = smb2_open_file,
|
|
|
|
.set_fid = smb2_set_fid,
|
|
|
|
.close = smb2_close_file,
|
|
|
|
.flush = smb2_flush_file,
|
|
|
|
.async_readv = smb2_async_readv,
|
|
|
|
.async_writev = smb2_async_writev,
|
|
|
|
.sync_read = smb2_sync_read,
|
|
|
|
.sync_write = smb2_sync_write,
|
|
|
|
.query_dir_first = smb2_query_dir_first,
|
|
|
|
.query_dir_next = smb2_query_dir_next,
|
|
|
|
.close_dir = smb2_close_dir,
|
|
|
|
.calc_smb_size = smb2_calc_size,
|
|
|
|
.is_status_pending = smb2_is_status_pending,
|
2017-07-09 05:32:00 +08:00
|
|
|
.is_session_expired = smb2_is_session_expired,
|
2013-09-05 20:11:28 +08:00
|
|
|
.oplock_response = smb2_oplock_response,
|
|
|
|
.queryfs = smb2_queryfs,
|
|
|
|
.mand_lock = smb2_mand_lock,
|
|
|
|
.mand_unlock_range = smb2_unlock_range,
|
|
|
|
.push_mand_locks = smb2_push_mandatory_locks,
|
|
|
|
.get_lease_key = smb2_get_lease_key,
|
|
|
|
.set_lease_key = smb2_set_lease_key,
|
|
|
|
.new_lease_key = smb2_new_lease_key,
|
|
|
|
.calc_signature = smb2_calc_signature,
|
|
|
|
.is_read_op = smb21_is_read_op,
|
|
|
|
.set_oplock_level = smb21_set_oplock_level,
|
2013-09-04 17:07:41 +08:00
|
|
|
.create_lease_buf = smb2_create_lease_buf,
|
2013-09-06 00:16:45 +08:00
|
|
|
.parse_lease_buf = smb2_parse_lease_buf,
|
2017-04-04 15:12:04 +08:00
|
|
|
.copychunk_range = smb2_copychunk_range,
|
2014-06-22 15:03:22 +08:00
|
|
|
.wp_retry_size = smb2_wp_retry_size,
|
2014-08-19 00:49:57 +08:00
|
|
|
.dir_needs_close = smb2_dir_needs_close,
|
2016-10-01 10:14:26 +08:00
|
|
|
.enum_snapshots = smb3_enum_snapshots,
|
2020-02-13 12:37:08 +08:00
|
|
|
.notify = smb3_notify,
|
2017-02-13 23:16:49 +08:00
|
|
|
.get_dfs_refer = smb2_get_dfs_refer,
|
2017-01-18 18:05:57 +08:00
|
|
|
.select_sectype = smb2_select_sectype,
|
2017-08-24 09:24:55 +08:00
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
|
|
|
.query_all_EAs = smb2_query_eas,
|
2017-08-24 09:24:56 +08:00
|
|
|
.set_EA = smb2_set_ea,
|
2017-08-24 09:24:55 +08:00
|
|
|
#endif /* CIFS_XATTR */
|
2017-06-23 11:52:05 +08:00
|
|
|
.get_acl = get_smb2_acl,
|
|
|
|
.get_acl_by_fid = get_smb2_acl_by_fid,
|
2017-06-29 11:37:32 +08:00
|
|
|
.set_acl = set_smb2_acl,
|
2018-06-01 08:53:08 +08:00
|
|
|
.next_header = smb2_next_header,
|
2018-10-08 08:19:58 +08:00
|
|
|
.ioctl_query_info = smb2_ioctl_query_info,
|
2019-03-14 13:29:17 +08:00
|
|
|
.make_node = smb2_make_node,
|
2019-04-25 14:45:29 +08:00
|
|
|
.fiemap = smb3_fiemap,
|
2019-05-15 05:17:02 +08:00
|
|
|
.llseek = smb3_llseek,
|
2020-09-18 13:37:28 +08:00
|
|
|
.is_status_io_timeout = smb2_is_status_io_timeout,
|
2021-02-16 18:40:45 +08:00
|
|
|
.is_network_name_deleted = smb2_is_network_name_deleted,
|
2013-09-05 20:11:28 +08:00
|
|
|
};
|
2012-12-09 12:08:06 +08:00
|
|
|
|
|
|
|
struct smb_version_operations smb30_operations = {
|
|
|
|
.compare_fids = smb2_compare_fids,
|
|
|
|
.setup_request = smb2_setup_request,
|
|
|
|
.setup_async_request = smb2_setup_async_request,
|
|
|
|
.check_receive = smb2_check_receive,
|
|
|
|
.add_credits = smb2_add_credits,
|
|
|
|
.set_credits = smb2_set_credits,
|
|
|
|
.get_credits_field = smb2_get_credits_field,
|
|
|
|
.get_credits = smb2_get_credits,
|
2014-06-05 23:03:27 +08:00
|
|
|
.wait_mtu_credits = smb2_wait_mtu_credits,
|
2019-01-24 10:15:52 +08:00
|
|
|
.adjust_credits = smb2_adjust_credits,
|
2012-12-09 12:08:06 +08:00
|
|
|
.get_next_mid = smb2_get_next_mid,
|
2019-03-05 06:02:50 +08:00
|
|
|
.revert_current_mid = smb2_revert_current_mid,
|
2012-12-09 12:08:06 +08:00
|
|
|
.read_data_offset = smb2_read_data_offset,
|
|
|
|
.read_data_length = smb2_read_data_length,
|
|
|
|
.map_error = map_smb2_to_linux_error,
|
|
|
|
.find_mid = smb2_find_mid,
|
|
|
|
.check_message = smb2_check_message,
|
|
|
|
.dump_detail = smb2_dump_detail,
|
|
|
|
.clear_stats = smb2_clear_stats,
|
|
|
|
.print_stats = smb2_print_stats,
|
2013-06-20 03:15:30 +08:00
|
|
|
.dump_share_caps = smb2_dump_share_caps,
|
2012-12-09 12:08:06 +08:00
|
|
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
2017-03-04 07:41:38 +08:00
|
|
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
2019-10-30 07:51:19 +08:00
|
|
|
.downgrade_oplock = smb3_downgrade_oplock,
|
2012-12-09 12:08:06 +08:00
|
|
|
.need_neg = smb2_need_neg,
|
|
|
|
.negotiate = smb2_negotiate,
|
2018-09-26 04:33:47 +08:00
|
|
|
.negotiate_wsize = smb3_negotiate_wsize,
|
|
|
|
.negotiate_rsize = smb3_negotiate_rsize,
|
2012-12-09 12:08:06 +08:00
|
|
|
.sess_setup = SMB2_sess_setup,
|
|
|
|
.logoff = SMB2_logoff,
|
|
|
|
.tree_connect = SMB2_tcon,
|
|
|
|
.tree_disconnect = SMB2_tdis,
|
2013-10-10 09:55:53 +08:00
|
|
|
.qfs_tcon = smb3_qfs_tcon,
|
2012-12-09 12:08:06 +08:00
|
|
|
.is_path_accessible = smb2_is_path_accessible,
|
|
|
|
.can_echo = smb2_can_echo,
|
|
|
|
.echo = SMB2_echo,
|
|
|
|
.query_path_info = smb2_query_path_info,
|
2020-10-23 11:03:14 +08:00
|
|
|
/* WSL tags introduced long after smb2.1, enable for SMB3, 3.11 only */
|
|
|
|
.query_reparse_tag = smb2_query_reparse_tag,
|
2012-12-09 12:08:06 +08:00
|
|
|
.get_srv_inum = smb2_get_srv_inum,
|
|
|
|
.query_file_info = smb2_query_file_info,
|
|
|
|
.set_path_size = smb2_set_path_size,
|
|
|
|
.set_file_size = smb2_set_file_size,
|
|
|
|
.set_file_info = smb2_set_file_info,
|
2013-10-15 04:31:32 +08:00
|
|
|
.set_compression = smb2_set_compression,
|
2012-12-09 12:08:06 +08:00
|
|
|
.mkdir = smb2_mkdir,
|
|
|
|
.mkdir_setinfo = smb2_mkdir_setinfo,
|
|
|
|
.rmdir = smb2_rmdir,
|
|
|
|
.unlink = smb2_unlink,
|
|
|
|
.rename = smb2_rename_path,
|
|
|
|
.create_hardlink = smb2_create_hardlink,
|
2013-08-14 23:25:21 +08:00
|
|
|
.query_symlink = smb2_query_symlink,
|
2014-09-16 20:18:19 +08:00
|
|
|
.query_mf_symlink = smb3_query_mf_symlink,
|
2014-09-15 17:49:28 +08:00
|
|
|
.create_mf_symlink = smb3_create_mf_symlink,
|
2012-12-09 12:08:06 +08:00
|
|
|
.open = smb2_open_file,
|
|
|
|
.set_fid = smb2_set_fid,
|
|
|
|
.close = smb2_close_file,
|
2019-12-03 11:46:54 +08:00
|
|
|
.close_getattr = smb2_close_getattr,
|
2012-12-09 12:08:06 +08:00
|
|
|
.flush = smb2_flush_file,
|
|
|
|
.async_readv = smb2_async_readv,
|
|
|
|
.async_writev = smb2_async_writev,
|
|
|
|
.sync_read = smb2_sync_read,
|
|
|
|
.sync_write = smb2_sync_write,
|
|
|
|
.query_dir_first = smb2_query_dir_first,
|
|
|
|
.query_dir_next = smb2_query_dir_next,
|
|
|
|
.close_dir = smb2_close_dir,
|
|
|
|
.calc_smb_size = smb2_calc_size,
|
|
|
|
.is_status_pending = smb2_is_status_pending,
|
2017-07-09 05:32:00 +08:00
|
|
|
.is_session_expired = smb2_is_session_expired,
|
2012-12-09 12:08:06 +08:00
|
|
|
.oplock_response = smb2_oplock_response,
|
|
|
|
.queryfs = smb2_queryfs,
|
|
|
|
.mand_lock = smb2_mand_lock,
|
|
|
|
.mand_unlock_range = smb2_unlock_range,
|
|
|
|
.push_mand_locks = smb2_push_mandatory_locks,
|
|
|
|
.get_lease_key = smb2_get_lease_key,
|
|
|
|
.set_lease_key = smb2_set_lease_key,
|
|
|
|
.new_lease_key = smb2_new_lease_key,
|
2015-12-19 03:05:30 +08:00
|
|
|
.generate_signingkey = generate_smb30signingkey,
|
2012-12-09 12:08:06 +08:00
|
|
|
.calc_signature = smb3_calc_signature,
|
2015-06-24 16:17:02 +08:00
|
|
|
.set_integrity = smb3_set_integrity,
|
2013-09-05 20:11:28 +08:00
|
|
|
.is_read_op = smb21_is_read_op,
|
2013-09-06 01:30:16 +08:00
|
|
|
.set_oplock_level = smb3_set_oplock_level,
|
2013-09-04 17:44:05 +08:00
|
|
|
.create_lease_buf = smb3_create_lease_buf,
|
|
|
|
.parse_lease_buf = smb3_parse_lease_buf,
|
2017-04-04 15:12:04 +08:00
|
|
|
.copychunk_range = smb2_copychunk_range,
|
2015-10-02 10:40:10 +08:00
|
|
|
.duplicate_extents = smb2_duplicate_extents,
|
2013-11-20 13:44:46 +08:00
|
|
|
.validate_negotiate = smb3_validate_negotiate,
|
2014-06-22 15:03:22 +08:00
|
|
|
.wp_retry_size = smb2_wp_retry_size,
|
2014-08-19 00:49:57 +08:00
|
|
|
.dir_needs_close = smb2_dir_needs_close,
|
2014-08-17 21:38:47 +08:00
|
|
|
.fallocate = smb3_fallocate,
|
2016-10-01 10:14:26 +08:00
|
|
|
.enum_snapshots = smb3_enum_snapshots,
|
2020-02-06 20:00:14 +08:00
|
|
|
.notify = smb3_notify,
|
2016-11-04 07:47:37 +08:00
|
|
|
.init_transform_rq = smb3_init_transform_rq,
|
2016-11-18 07:24:46 +08:00
|
|
|
.is_transform_hdr = smb3_is_transform_hdr,
|
|
|
|
.receive_transform = smb3_receive_transform,
|
2017-02-13 23:16:49 +08:00
|
|
|
.get_dfs_refer = smb2_get_dfs_refer,
|
2017-01-18 18:05:57 +08:00
|
|
|
.select_sectype = smb2_select_sectype,
|
2017-08-24 09:24:55 +08:00
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
|
|
|
.query_all_EAs = smb2_query_eas,
|
2017-08-24 09:24:56 +08:00
|
|
|
.set_EA = smb2_set_ea,
|
2017-08-24 09:24:55 +08:00
|
|
|
#endif /* CIFS_XATTR */
|
2017-06-23 11:52:05 +08:00
|
|
|
.get_acl = get_smb2_acl,
|
|
|
|
.get_acl_by_fid = get_smb2_acl_by_fid,
|
2017-06-29 11:37:32 +08:00
|
|
|
.set_acl = set_smb2_acl,
|
2018-06-01 08:53:08 +08:00
|
|
|
.next_header = smb2_next_header,
|
2018-10-08 08:19:58 +08:00
|
|
|
.ioctl_query_info = smb2_ioctl_query_info,
|
2019-03-14 13:29:17 +08:00
|
|
|
.make_node = smb2_make_node,
|
2019-04-25 14:45:29 +08:00
|
|
|
.fiemap = smb3_fiemap,
|
2019-05-15 05:17:02 +08:00
|
|
|
.llseek = smb3_llseek,
|
2020-09-18 13:37:28 +08:00
|
|
|
.is_status_io_timeout = smb2_is_status_io_timeout,
|
2021-02-16 18:40:45 +08:00
|
|
|
.is_network_name_deleted = smb2_is_network_name_deleted,
|
2011-02-25 02:07:19 +08:00
|
|
|
};
|
|
|
|
|
2015-06-24 12:37:11 +08:00
|
|
|
struct smb_version_operations smb311_operations = {
|
|
|
|
.compare_fids = smb2_compare_fids,
|
|
|
|
.setup_request = smb2_setup_request,
|
|
|
|
.setup_async_request = smb2_setup_async_request,
|
|
|
|
.check_receive = smb2_check_receive,
|
|
|
|
.add_credits = smb2_add_credits,
|
|
|
|
.set_credits = smb2_set_credits,
|
|
|
|
.get_credits_field = smb2_get_credits_field,
|
|
|
|
.get_credits = smb2_get_credits,
|
|
|
|
.wait_mtu_credits = smb2_wait_mtu_credits,
|
2019-01-24 10:15:52 +08:00
|
|
|
.adjust_credits = smb2_adjust_credits,
|
2015-06-24 12:37:11 +08:00
|
|
|
.get_next_mid = smb2_get_next_mid,
|
2019-03-05 06:02:50 +08:00
|
|
|
.revert_current_mid = smb2_revert_current_mid,
|
2015-06-24 12:37:11 +08:00
|
|
|
.read_data_offset = smb2_read_data_offset,
|
|
|
|
.read_data_length = smb2_read_data_length,
|
|
|
|
.map_error = map_smb2_to_linux_error,
|
|
|
|
.find_mid = smb2_find_mid,
|
|
|
|
.check_message = smb2_check_message,
|
|
|
|
.dump_detail = smb2_dump_detail,
|
|
|
|
.clear_stats = smb2_clear_stats,
|
|
|
|
.print_stats = smb2_print_stats,
|
|
|
|
.dump_share_caps = smb2_dump_share_caps,
|
|
|
|
.is_oplock_break = smb2_is_valid_oplock_break,
|
2017-03-04 07:41:38 +08:00
|
|
|
.handle_cancelled_mid = smb2_handle_cancelled_mid,
|
2019-10-30 07:51:19 +08:00
|
|
|
.downgrade_oplock = smb3_downgrade_oplock,
|
2015-06-24 12:37:11 +08:00
|
|
|
.need_neg = smb2_need_neg,
|
|
|
|
.negotiate = smb2_negotiate,
|
2018-09-26 04:33:47 +08:00
|
|
|
.negotiate_wsize = smb3_negotiate_wsize,
|
|
|
|
.negotiate_rsize = smb3_negotiate_rsize,
|
2015-06-24 12:37:11 +08:00
|
|
|
.sess_setup = SMB2_sess_setup,
|
|
|
|
.logoff = SMB2_logoff,
|
|
|
|
.tree_connect = SMB2_tcon,
|
|
|
|
.tree_disconnect = SMB2_tdis,
|
|
|
|
.qfs_tcon = smb3_qfs_tcon,
|
|
|
|
.is_path_accessible = smb2_is_path_accessible,
|
|
|
|
.can_echo = smb2_can_echo,
|
|
|
|
.echo = SMB2_echo,
|
|
|
|
.query_path_info = smb2_query_path_info,
|
2020-10-23 11:03:14 +08:00
|
|
|
.query_reparse_tag = smb2_query_reparse_tag,
|
2015-06-24 12:37:11 +08:00
|
|
|
.get_srv_inum = smb2_get_srv_inum,
|
|
|
|
.query_file_info = smb2_query_file_info,
|
|
|
|
.set_path_size = smb2_set_path_size,
|
|
|
|
.set_file_size = smb2_set_file_size,
|
|
|
|
.set_file_info = smb2_set_file_info,
|
|
|
|
.set_compression = smb2_set_compression,
|
|
|
|
.mkdir = smb2_mkdir,
|
|
|
|
.mkdir_setinfo = smb2_mkdir_setinfo,
|
2018-06-15 10:56:32 +08:00
|
|
|
.posix_mkdir = smb311_posix_mkdir,
|
2015-06-24 12:37:11 +08:00
|
|
|
.rmdir = smb2_rmdir,
|
|
|
|
.unlink = smb2_unlink,
|
|
|
|
.rename = smb2_rename_path,
|
|
|
|
.create_hardlink = smb2_create_hardlink,
|
|
|
|
.query_symlink = smb2_query_symlink,
|
|
|
|
.query_mf_symlink = smb3_query_mf_symlink,
|
|
|
|
.create_mf_symlink = smb3_create_mf_symlink,
|
|
|
|
.open = smb2_open_file,
|
|
|
|
.set_fid = smb2_set_fid,
|
|
|
|
.close = smb2_close_file,
|
2019-12-03 11:46:54 +08:00
|
|
|
.close_getattr = smb2_close_getattr,
|
2015-06-24 12:37:11 +08:00
|
|
|
.flush = smb2_flush_file,
|
|
|
|
.async_readv = smb2_async_readv,
|
|
|
|
.async_writev = smb2_async_writev,
|
|
|
|
.sync_read = smb2_sync_read,
|
|
|
|
.sync_write = smb2_sync_write,
|
|
|
|
.query_dir_first = smb2_query_dir_first,
|
|
|
|
.query_dir_next = smb2_query_dir_next,
|
|
|
|
.close_dir = smb2_close_dir,
|
|
|
|
.calc_smb_size = smb2_calc_size,
|
|
|
|
.is_status_pending = smb2_is_status_pending,
|
2017-07-09 05:32:00 +08:00
|
|
|
.is_session_expired = smb2_is_session_expired,
|
2015-06-24 12:37:11 +08:00
|
|
|
.oplock_response = smb2_oplock_response,
|
2018-06-25 12:28:12 +08:00
|
|
|
.queryfs = smb311_queryfs,
|
2015-06-24 12:37:11 +08:00
|
|
|
.mand_lock = smb2_mand_lock,
|
|
|
|
.mand_unlock_range = smb2_unlock_range,
|
|
|
|
.push_mand_locks = smb2_push_mandatory_locks,
|
|
|
|
.get_lease_key = smb2_get_lease_key,
|
|
|
|
.set_lease_key = smb2_set_lease_key,
|
|
|
|
.new_lease_key = smb2_new_lease_key,
|
2015-12-19 03:05:30 +08:00
|
|
|
.generate_signingkey = generate_smb311signingkey,
|
2015-06-24 12:37:11 +08:00
|
|
|
.calc_signature = smb3_calc_signature,
|
2015-06-24 16:17:02 +08:00
|
|
|
.set_integrity = smb3_set_integrity,
|
2015-06-24 12:37:11 +08:00
|
|
|
.is_read_op = smb21_is_read_op,
|
|
|
|
.set_oplock_level = smb3_set_oplock_level,
|
|
|
|
.create_lease_buf = smb3_create_lease_buf,
|
|
|
|
.parse_lease_buf = smb3_parse_lease_buf,
|
2017-04-04 15:12:04 +08:00
|
|
|
.copychunk_range = smb2_copychunk_range,
|
2015-06-28 12:18:36 +08:00
|
|
|
.duplicate_extents = smb2_duplicate_extents,
|
2015-06-24 12:37:11 +08:00
|
|
|
/* .validate_negotiate = smb3_validate_negotiate, */ /* not used in 3.11 */
|
|
|
|
.wp_retry_size = smb2_wp_retry_size,
|
|
|
|
.dir_needs_close = smb2_dir_needs_close,
|
|
|
|
.fallocate = smb3_fallocate,
|
2016-10-01 10:14:26 +08:00
|
|
|
.enum_snapshots = smb3_enum_snapshots,
|
2020-02-06 20:00:14 +08:00
|
|
|
.notify = smb3_notify,
|
2016-11-04 07:47:37 +08:00
|
|
|
.init_transform_rq = smb3_init_transform_rq,
|
2016-11-18 07:24:46 +08:00
|
|
|
.is_transform_hdr = smb3_is_transform_hdr,
|
|
|
|
.receive_transform = smb3_receive_transform,
|
2017-02-13 23:16:49 +08:00
|
|
|
.get_dfs_refer = smb2_get_dfs_refer,
|
2017-01-18 18:05:57 +08:00
|
|
|
.select_sectype = smb2_select_sectype,
|
2017-08-24 09:24:55 +08:00
|
|
|
#ifdef CONFIG_CIFS_XATTR
|
|
|
|
.query_all_EAs = smb2_query_eas,
|
2017-08-24 09:24:56 +08:00
|
|
|
.set_EA = smb2_set_ea,
|
2017-08-24 09:24:55 +08:00
|
|
|
#endif /* CIFS_XATTR */
|
2018-08-10 09:03:55 +08:00
|
|
|
.get_acl = get_smb2_acl,
|
|
|
|
.get_acl_by_fid = get_smb2_acl_by_fid,
|
|
|
|
.set_acl = set_smb2_acl,
|
2018-06-01 08:53:08 +08:00
|
|
|
.next_header = smb2_next_header,
|
2018-10-08 08:19:58 +08:00
|
|
|
.ioctl_query_info = smb2_ioctl_query_info,
|
2019-03-14 13:29:17 +08:00
|
|
|
.make_node = smb2_make_node,
|
2019-04-25 14:45:29 +08:00
|
|
|
.fiemap = smb3_fiemap,
|
2019-05-15 05:17:02 +08:00
|
|
|
.llseek = smb3_llseek,
|
2020-09-18 13:37:28 +08:00
|
|
|
.is_status_io_timeout = smb2_is_status_io_timeout,
|
2021-02-16 18:40:45 +08:00
|
|
|
.is_network_name_deleted = smb2_is_network_name_deleted,
|
2015-06-24 12:37:11 +08:00
|
|
|
};
|
|
|
|
|
2012-11-29 13:21:06 +08:00
|
|
|
struct smb_version_values smb20_values = {
|
|
|
|
.version_string = SMB20_VERSION_STRING,
|
|
|
|
.protocol_id = SMB20_PROT_ID,
|
|
|
|
.req_capabilities = 0, /* MBZ */
|
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2012-11-29 13:21:06 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2012-11-29 13:21:06 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
|
|
|
.lock_cmd = SMB2_LOCK,
|
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
2013-06-28 00:45:00 +08:00
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
2013-09-04 17:07:41 +08:00
|
|
|
.create_lease_size = sizeof(struct create_lease),
|
2012-11-29 13:21:06 +08:00
|
|
|
};
|
|
|
|
|
2011-02-25 02:07:19 +08:00
|
|
|
struct smb_version_values smb21_values = {
|
|
|
|
.version_string = SMB21_VERSION_STRING,
|
2012-10-02 01:26:22 +08:00
|
|
|
.protocol_id = SMB21_PROT_ID,
|
|
|
|
.req_capabilities = 0, /* MBZ on negotiate req until SMB3 dialect */
|
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2012-10-02 01:26:22 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2012-10-02 01:26:22 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
|
|
|
.lock_cmd = SMB2_LOCK,
|
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
2013-06-28 00:45:00 +08:00
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
2013-09-04 17:07:41 +08:00
|
|
|
.create_lease_size = sizeof(struct create_lease),
|
2012-10-02 01:26:22 +08:00
|
|
|
};
|
|
|
|
|
2017-09-17 23:41:35 +08:00
|
|
|
struct smb_version_values smb3any_values = {
|
|
|
|
.version_string = SMB3ANY_VERSION_STRING,
|
|
|
|
.protocol_id = SMB302_PROT_ID, /* doesn't matter, send protocol array */
|
2018-09-01 04:12:10 +08:00
|
|
|
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION | SMB2_GLOBAL_CAP_DIRECTORY_LEASING,
|
2017-09-17 23:41:35 +08:00
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2017-09-17 23:41:35 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2017-09-17 23:41:35 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
|
|
|
.lock_cmd = SMB2_LOCK,
|
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.create_lease_size = sizeof(struct create_lease_v2),
|
|
|
|
};
|
|
|
|
|
|
|
|
struct smb_version_values smbdefault_values = {
|
|
|
|
.version_string = SMBDEFAULT_VERSION_STRING,
|
|
|
|
.protocol_id = SMB302_PROT_ID, /* doesn't matter, send protocol array */
|
2018-09-01 04:12:10 +08:00
|
|
|
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION | SMB2_GLOBAL_CAP_DIRECTORY_LEASING,
|
2017-09-17 23:41:35 +08:00
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2017-09-17 23:41:35 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2017-09-17 23:41:35 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
|
|
|
.lock_cmd = SMB2_LOCK,
|
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.create_lease_size = sizeof(struct create_lease_v2),
|
|
|
|
};
|
|
|
|
|
2012-10-02 01:26:22 +08:00
|
|
|
struct smb_version_values smb30_values = {
|
|
|
|
.version_string = SMB30_VERSION_STRING,
|
|
|
|
.protocol_id = SMB30_PROT_ID,
|
2018-09-01 04:12:10 +08:00
|
|
|
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION | SMB2_GLOBAL_CAP_DIRECTORY_LEASING,
|
2012-09-19 21:22:43 +08:00
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2012-09-19 21:22:43 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2011-06-08 19:51:07 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
2012-09-19 07:20:29 +08:00
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
2011-12-27 02:53:34 +08:00
|
|
|
.lock_cmd = SMB2_LOCK,
|
2012-07-13 17:58:14 +08:00
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
2013-06-28 00:45:00 +08:00
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
2013-09-04 17:44:05 +08:00
|
|
|
.create_lease_size = sizeof(struct create_lease_v2),
|
2011-02-25 02:07:19 +08:00
|
|
|
};
|
2013-06-13 11:48:41 +08:00
|
|
|
|
|
|
|
struct smb_version_values smb302_values = {
|
|
|
|
.version_string = SMB302_VERSION_STRING,
|
|
|
|
.protocol_id = SMB302_PROT_ID,
|
2018-09-01 04:12:10 +08:00
|
|
|
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION | SMB2_GLOBAL_CAP_DIRECTORY_LEASING,
|
2013-06-13 11:48:41 +08:00
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2013-06-13 11:48:41 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2013-06-13 11:48:41 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
|
|
|
.lock_cmd = SMB2_LOCK,
|
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
2013-06-28 00:45:00 +08:00
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
2013-09-04 17:44:05 +08:00
|
|
|
.create_lease_size = sizeof(struct create_lease_v2),
|
2013-06-13 11:48:41 +08:00
|
|
|
};
|
2014-12-18 12:52:58 +08:00
|
|
|
|
|
|
|
struct smb_version_values smb311_values = {
|
|
|
|
.version_string = SMB311_VERSION_STRING,
|
|
|
|
.protocol_id = SMB311_PROT_ID,
|
2018-09-01 04:12:10 +08:00
|
|
|
.req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES | SMB2_GLOBAL_CAP_ENCRYPTION | SMB2_GLOBAL_CAP_DIRECTORY_LEASING,
|
2014-12-18 12:52:58 +08:00
|
|
|
.large_lock_type = 0,
|
2022-03-27 05:17:03 +08:00
|
|
|
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE,
|
|
|
|
.shared_lock_type = SMB2_LOCKFLAG_SHARED,
|
2014-12-18 12:52:58 +08:00
|
|
|
.unlock_lock_type = SMB2_LOCKFLAG_UNLOCK,
|
2021-11-05 07:39:01 +08:00
|
|
|
.header_size = sizeof(struct smb2_hdr),
|
2018-06-01 08:53:02 +08:00
|
|
|
.header_preamble_size = 0,
|
2014-12-18 12:52:58 +08:00
|
|
|
.max_header_size = MAX_SMB2_HDR_SIZE,
|
|
|
|
.read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
|
|
|
|
.lock_cmd = SMB2_LOCK,
|
|
|
|
.cap_unix = 0,
|
|
|
|
.cap_nt_find = SMB2_NT_FIND,
|
|
|
|
.cap_large_files = SMB2_LARGE_FILES,
|
|
|
|
.signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
|
|
|
|
.create_lease_size = sizeof(struct create_lease_v2),
|
|
|
|
};
|