cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

connection.c (9724B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *   Copyright (C) 2016 Namjae Jeon <namjae.jeon@protocolfreedom.org>
      4 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
      5 */
      6
      7#include <linux/mutex.h>
      8#include <linux/freezer.h>
      9#include <linux/module.h>
     10
     11#include "server.h"
     12#include "smb_common.h"
     13#include "mgmt/ksmbd_ida.h"
     14#include "connection.h"
     15#include "transport_tcp.h"
     16#include "transport_rdma.h"
     17
     18static DEFINE_MUTEX(init_lock);
     19
     20static struct ksmbd_conn_ops default_conn_ops;
     21
     22LIST_HEAD(conn_list);
     23DEFINE_RWLOCK(conn_list_lock);
     24
     25/**
     26 * ksmbd_conn_free() - free resources of the connection instance
     27 *
     28 * @conn:	connection instance to be cleand up
     29 *
     30 * During the thread termination, the corresponding conn instance
     31 * resources(sock/memory) are released and finally the conn object is freed.
     32 */
     33void ksmbd_conn_free(struct ksmbd_conn *conn)
     34{
     35	write_lock(&conn_list_lock);
     36	list_del(&conn->conns_list);
     37	write_unlock(&conn_list_lock);
     38
     39	kvfree(conn->request_buf);
     40	kfree(conn->preauth_info);
     41	kfree(conn);
     42}
     43
     44/**
     45 * ksmbd_conn_alloc() - initialize a new connection instance
     46 *
     47 * Return:	ksmbd_conn struct on success, otherwise NULL
     48 */
     49struct ksmbd_conn *ksmbd_conn_alloc(void)
     50{
     51	struct ksmbd_conn *conn;
     52
     53	conn = kzalloc(sizeof(struct ksmbd_conn), GFP_KERNEL);
     54	if (!conn)
     55		return NULL;
     56
     57	conn->need_neg = true;
     58	conn->status = KSMBD_SESS_NEW;
     59	conn->local_nls = load_nls("utf8");
     60	if (!conn->local_nls)
     61		conn->local_nls = load_nls_default();
     62	atomic_set(&conn->req_running, 0);
     63	atomic_set(&conn->r_count, 0);
     64	conn->total_credits = 1;
     65	conn->outstanding_credits = 0;
     66
     67	init_waitqueue_head(&conn->req_running_q);
     68	INIT_LIST_HEAD(&conn->conns_list);
     69	INIT_LIST_HEAD(&conn->sessions);
     70	INIT_LIST_HEAD(&conn->requests);
     71	INIT_LIST_HEAD(&conn->async_requests);
     72	spin_lock_init(&conn->request_lock);
     73	spin_lock_init(&conn->credits_lock);
     74	ida_init(&conn->async_ida);
     75
     76	spin_lock_init(&conn->llist_lock);
     77	INIT_LIST_HEAD(&conn->lock_list);
     78
     79	write_lock(&conn_list_lock);
     80	list_add(&conn->conns_list, &conn_list);
     81	write_unlock(&conn_list_lock);
     82	return conn;
     83}
     84
     85bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c)
     86{
     87	struct ksmbd_conn *t;
     88	bool ret = false;
     89
     90	read_lock(&conn_list_lock);
     91	list_for_each_entry(t, &conn_list, conns_list) {
     92		if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE))
     93			continue;
     94
     95		ret = true;
     96		break;
     97	}
     98	read_unlock(&conn_list_lock);
     99	return ret;
    100}
    101
    102void ksmbd_conn_enqueue_request(struct ksmbd_work *work)
    103{
    104	struct ksmbd_conn *conn = work->conn;
    105	struct list_head *requests_queue = NULL;
    106
    107	if (conn->ops->get_cmd_val(work) != SMB2_CANCEL_HE) {
    108		requests_queue = &conn->requests;
    109		work->syncronous = true;
    110	}
    111
    112	if (requests_queue) {
    113		atomic_inc(&conn->req_running);
    114		spin_lock(&conn->request_lock);
    115		list_add_tail(&work->request_entry, requests_queue);
    116		spin_unlock(&conn->request_lock);
    117	}
    118}
    119
    120int ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
    121{
    122	struct ksmbd_conn *conn = work->conn;
    123	int ret = 1;
    124
    125	if (list_empty(&work->request_entry) &&
    126	    list_empty(&work->async_request_entry))
    127		return 0;
    128
    129	if (!work->multiRsp)
    130		atomic_dec(&conn->req_running);
    131	spin_lock(&conn->request_lock);
    132	if (!work->multiRsp) {
    133		list_del_init(&work->request_entry);
    134		if (work->syncronous == false)
    135			list_del_init(&work->async_request_entry);
    136		ret = 0;
    137	}
    138	spin_unlock(&conn->request_lock);
    139
    140	wake_up_all(&conn->req_running_q);
    141	return ret;
    142}
    143
    144static void ksmbd_conn_lock(struct ksmbd_conn *conn)
    145{
    146	mutex_lock(&conn->srv_mutex);
    147}
    148
    149static void ksmbd_conn_unlock(struct ksmbd_conn *conn)
    150{
    151	mutex_unlock(&conn->srv_mutex);
    152}
    153
    154void ksmbd_conn_wait_idle(struct ksmbd_conn *conn)
    155{
    156	wait_event(conn->req_running_q, atomic_read(&conn->req_running) < 2);
    157}
    158
    159int ksmbd_conn_write(struct ksmbd_work *work)
    160{
    161	struct ksmbd_conn *conn = work->conn;
    162	size_t len = 0;
    163	int sent;
    164	struct kvec iov[3];
    165	int iov_idx = 0;
    166
    167	ksmbd_conn_try_dequeue_request(work);
    168	if (!work->response_buf) {
    169		pr_err("NULL response header\n");
    170		return -EINVAL;
    171	}
    172
    173	if (work->tr_buf) {
    174		iov[iov_idx] = (struct kvec) { work->tr_buf,
    175				sizeof(struct smb2_transform_hdr) + 4 };
    176		len += iov[iov_idx++].iov_len;
    177	}
    178
    179	if (work->aux_payload_sz) {
    180		iov[iov_idx] = (struct kvec) { work->response_buf, work->resp_hdr_sz };
    181		len += iov[iov_idx++].iov_len;
    182		iov[iov_idx] = (struct kvec) { work->aux_payload_buf, work->aux_payload_sz };
    183		len += iov[iov_idx++].iov_len;
    184	} else {
    185		if (work->tr_buf)
    186			iov[iov_idx].iov_len = work->resp_hdr_sz;
    187		else
    188			iov[iov_idx].iov_len = get_rfc1002_len(work->response_buf) + 4;
    189		iov[iov_idx].iov_base = work->response_buf;
    190		len += iov[iov_idx++].iov_len;
    191	}
    192
    193	ksmbd_conn_lock(conn);
    194	sent = conn->transport->ops->writev(conn->transport, &iov[0],
    195					iov_idx, len,
    196					work->need_invalidate_rkey,
    197					work->remote_key);
    198	ksmbd_conn_unlock(conn);
    199
    200	if (sent < 0) {
    201		pr_err("Failed to send message: %d\n", sent);
    202		return sent;
    203	}
    204
    205	return 0;
    206}
    207
    208int ksmbd_conn_rdma_read(struct ksmbd_conn *conn,
    209			 void *buf, unsigned int buflen,
    210			 struct smb2_buffer_desc_v1 *desc,
    211			 unsigned int desc_len)
    212{
    213	int ret = -EINVAL;
    214
    215	if (conn->transport->ops->rdma_read)
    216		ret = conn->transport->ops->rdma_read(conn->transport,
    217						      buf, buflen,
    218						      desc, desc_len);
    219	return ret;
    220}
    221
    222int ksmbd_conn_rdma_write(struct ksmbd_conn *conn,
    223			  void *buf, unsigned int buflen,
    224			  struct smb2_buffer_desc_v1 *desc,
    225			  unsigned int desc_len)
    226{
    227	int ret = -EINVAL;
    228
    229	if (conn->transport->ops->rdma_write)
    230		ret = conn->transport->ops->rdma_write(conn->transport,
    231						       buf, buflen,
    232						       desc, desc_len);
    233	return ret;
    234}
    235
    236bool ksmbd_conn_alive(struct ksmbd_conn *conn)
    237{
    238	if (!ksmbd_server_running())
    239		return false;
    240
    241	if (conn->status == KSMBD_SESS_EXITING)
    242		return false;
    243
    244	if (kthread_should_stop())
    245		return false;
    246
    247	if (atomic_read(&conn->stats.open_files_count) > 0)
    248		return true;
    249
    250	/*
    251	 * Stop current session if the time that get last request from client
    252	 * is bigger than deadtime user configured and opening file count is
    253	 * zero.
    254	 */
    255	if (server_conf.deadtime > 0 &&
    256	    time_after(jiffies, conn->last_active + server_conf.deadtime)) {
    257		ksmbd_debug(CONN, "No response from client in %lu minutes\n",
    258			    server_conf.deadtime / SMB_ECHO_INTERVAL);
    259		return false;
    260	}
    261	return true;
    262}
    263
    264/**
    265 * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
    266 * @p:		connection instance
    267 *
    268 * One thread each per connection
    269 *
    270 * Return:	0 on success
    271 */
    272int ksmbd_conn_handler_loop(void *p)
    273{
    274	struct ksmbd_conn *conn = (struct ksmbd_conn *)p;
    275	struct ksmbd_transport *t = conn->transport;
    276	unsigned int pdu_size;
    277	char hdr_buf[4] = {0,};
    278	int size;
    279
    280	mutex_init(&conn->srv_mutex);
    281	__module_get(THIS_MODULE);
    282
    283	if (t->ops->prepare && t->ops->prepare(t))
    284		goto out;
    285
    286	conn->last_active = jiffies;
    287	while (ksmbd_conn_alive(conn)) {
    288		if (try_to_freeze())
    289			continue;
    290
    291		kvfree(conn->request_buf);
    292		conn->request_buf = NULL;
    293
    294		size = t->ops->read(t, hdr_buf, sizeof(hdr_buf));
    295		if (size != sizeof(hdr_buf))
    296			break;
    297
    298		pdu_size = get_rfc1002_len(hdr_buf);
    299		ksmbd_debug(CONN, "RFC1002 header %u bytes\n", pdu_size);
    300
    301		/*
    302		 * Check if pdu size is valid (min : smb header size,
    303		 * max : 0x00FFFFFF).
    304		 */
    305		if (pdu_size < __SMB2_HEADER_STRUCTURE_SIZE ||
    306		    pdu_size > MAX_STREAM_PROT_LEN) {
    307			continue;
    308		}
    309
    310		/* 4 for rfc1002 length field */
    311		size = pdu_size + 4;
    312		conn->request_buf = kvmalloc(size, GFP_KERNEL);
    313		if (!conn->request_buf)
    314			continue;
    315
    316		memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
    317		if (!ksmbd_smb_request(conn))
    318			break;
    319
    320		/*
    321		 * We already read 4 bytes to find out PDU size, now
    322		 * read in PDU
    323		 */
    324		size = t->ops->read(t, conn->request_buf + 4, pdu_size);
    325		if (size < 0) {
    326			pr_err("sock_read failed: %d\n", size);
    327			break;
    328		}
    329
    330		if (size != pdu_size) {
    331			pr_err("PDU error. Read: %d, Expected: %d\n",
    332			       size, pdu_size);
    333			continue;
    334		}
    335
    336		if (!default_conn_ops.process_fn) {
    337			pr_err("No connection request callback\n");
    338			break;
    339		}
    340
    341		if (default_conn_ops.process_fn(conn)) {
    342			pr_err("Cannot handle request\n");
    343			break;
    344		}
    345	}
    346
    347out:
    348	/* Wait till all reference dropped to the Server object*/
    349	while (atomic_read(&conn->r_count) > 0)
    350		schedule_timeout(HZ);
    351
    352	unload_nls(conn->local_nls);
    353	if (default_conn_ops.terminate_fn)
    354		default_conn_ops.terminate_fn(conn);
    355	t->ops->disconnect(t);
    356	module_put(THIS_MODULE);
    357	return 0;
    358}
    359
    360void ksmbd_conn_init_server_callbacks(struct ksmbd_conn_ops *ops)
    361{
    362	default_conn_ops.process_fn = ops->process_fn;
    363	default_conn_ops.terminate_fn = ops->terminate_fn;
    364}
    365
    366int ksmbd_conn_transport_init(void)
    367{
    368	int ret;
    369
    370	mutex_lock(&init_lock);
    371	ret = ksmbd_tcp_init();
    372	if (ret) {
    373		pr_err("Failed to init TCP subsystem: %d\n", ret);
    374		goto out;
    375	}
    376
    377	ret = ksmbd_rdma_init();
    378	if (ret) {
    379		pr_err("Failed to init RDMA subsystem: %d\n", ret);
    380		goto out;
    381	}
    382out:
    383	mutex_unlock(&init_lock);
    384	return ret;
    385}
    386
    387static void stop_sessions(void)
    388{
    389	struct ksmbd_conn *conn;
    390	struct ksmbd_transport *t;
    391
    392again:
    393	read_lock(&conn_list_lock);
    394	list_for_each_entry(conn, &conn_list, conns_list) {
    395		struct task_struct *task;
    396
    397		t = conn->transport;
    398		task = t->handler;
    399		if (task)
    400			ksmbd_debug(CONN, "Stop session handler %s/%d\n",
    401				    task->comm, task_pid_nr(task));
    402		conn->status = KSMBD_SESS_EXITING;
    403		if (t->ops->shutdown) {
    404			read_unlock(&conn_list_lock);
    405			t->ops->shutdown(t);
    406			read_lock(&conn_list_lock);
    407		}
    408	}
    409	read_unlock(&conn_list_lock);
    410
    411	if (!list_empty(&conn_list)) {
    412		schedule_timeout_interruptible(HZ / 10); /* 100ms */
    413		goto again;
    414	}
    415}
    416
    417void ksmbd_conn_transport_destroy(void)
    418{
    419	mutex_lock(&init_lock);
    420	ksmbd_tcp_destroy();
    421	ksmbd_rdma_destroy();
    422	stop_sessions();
    423	mutex_unlock(&init_lock);
    424}