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

server.c (14244B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *   Copyright (C) 2016 Namjae Jeon <linkinjeon@kernel.org>
      4 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
      5 */
      6
      7#include "glob.h"
      8#include "oplock.h"
      9#include "misc.h"
     10#include <linux/sched/signal.h>
     11#include <linux/workqueue.h>
     12#include <linux/sysfs.h>
     13#include <linux/module.h>
     14#include <linux/moduleparam.h>
     15
     16#include "server.h"
     17#include "smb_common.h"
     18#include "smbstatus.h"
     19#include "connection.h"
     20#include "transport_ipc.h"
     21#include "mgmt/user_session.h"
     22#include "crypto_ctx.h"
     23#include "auth.h"
     24
     25int ksmbd_debug_types;
     26
     27struct ksmbd_server_config server_conf;
     28
     29enum SERVER_CTRL_TYPE {
     30	SERVER_CTRL_TYPE_INIT,
     31	SERVER_CTRL_TYPE_RESET,
     32};
     33
     34struct server_ctrl_struct {
     35	int			type;
     36	struct work_struct	ctrl_work;
     37};
     38
     39static DEFINE_MUTEX(ctrl_lock);
     40
     41static int ___server_conf_set(int idx, char *val)
     42{
     43	if (idx >= ARRAY_SIZE(server_conf.conf))
     44		return -EINVAL;
     45
     46	if (!val || val[0] == 0x00)
     47		return -EINVAL;
     48
     49	kfree(server_conf.conf[idx]);
     50	server_conf.conf[idx] = kstrdup(val, GFP_KERNEL);
     51	if (!server_conf.conf[idx])
     52		return -ENOMEM;
     53	return 0;
     54}
     55
     56int ksmbd_set_netbios_name(char *v)
     57{
     58	return ___server_conf_set(SERVER_CONF_NETBIOS_NAME, v);
     59}
     60
     61int ksmbd_set_server_string(char *v)
     62{
     63	return ___server_conf_set(SERVER_CONF_SERVER_STRING, v);
     64}
     65
     66int ksmbd_set_work_group(char *v)
     67{
     68	return ___server_conf_set(SERVER_CONF_WORK_GROUP, v);
     69}
     70
     71char *ksmbd_netbios_name(void)
     72{
     73	return server_conf.conf[SERVER_CONF_NETBIOS_NAME];
     74}
     75
     76char *ksmbd_server_string(void)
     77{
     78	return server_conf.conf[SERVER_CONF_SERVER_STRING];
     79}
     80
     81char *ksmbd_work_group(void)
     82{
     83	return server_conf.conf[SERVER_CONF_WORK_GROUP];
     84}
     85
     86/**
     87 * check_conn_state() - check state of server thread connection
     88 * @work:     smb work containing server thread information
     89 *
     90 * Return:	0 on valid connection, otherwise 1 to reconnect
     91 */
     92static inline int check_conn_state(struct ksmbd_work *work)
     93{
     94	struct smb_hdr *rsp_hdr;
     95
     96	if (ksmbd_conn_exiting(work) || ksmbd_conn_need_reconnect(work)) {
     97		rsp_hdr = work->response_buf;
     98		rsp_hdr->Status.CifsError = STATUS_CONNECTION_DISCONNECTED;
     99		return 1;
    100	}
    101	return 0;
    102}
    103
    104#define SERVER_HANDLER_CONTINUE		0
    105#define SERVER_HANDLER_ABORT		1
    106
    107static int __process_request(struct ksmbd_work *work, struct ksmbd_conn *conn,
    108			     u16 *cmd)
    109{
    110	struct smb_version_cmds *cmds;
    111	u16 command;
    112	int ret;
    113
    114	if (check_conn_state(work))
    115		return SERVER_HANDLER_CONTINUE;
    116
    117	if (ksmbd_verify_smb_message(work))
    118		return SERVER_HANDLER_ABORT;
    119
    120	command = conn->ops->get_cmd_val(work);
    121	*cmd = command;
    122
    123andx_again:
    124	if (command >= conn->max_cmds) {
    125		conn->ops->set_rsp_status(work, STATUS_INVALID_PARAMETER);
    126		return SERVER_HANDLER_CONTINUE;
    127	}
    128
    129	cmds = &conn->cmds[command];
    130	if (!cmds->proc) {
    131		ksmbd_debug(SMB, "*** not implemented yet cmd = %x\n", command);
    132		conn->ops->set_rsp_status(work, STATUS_NOT_IMPLEMENTED);
    133		return SERVER_HANDLER_CONTINUE;
    134	}
    135
    136	if (work->sess && conn->ops->is_sign_req(work, command)) {
    137		ret = conn->ops->check_sign_req(work);
    138		if (!ret) {
    139			conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED);
    140			return SERVER_HANDLER_CONTINUE;
    141		}
    142	}
    143
    144	ret = cmds->proc(work);
    145
    146	if (ret < 0)
    147		ksmbd_debug(CONN, "Failed to process %u [%d]\n", command, ret);
    148	/* AndX commands - chained request can return positive values */
    149	else if (ret > 0) {
    150		command = ret;
    151		*cmd = command;
    152		goto andx_again;
    153	}
    154
    155	if (work->send_no_response)
    156		return SERVER_HANDLER_ABORT;
    157	return SERVER_HANDLER_CONTINUE;
    158}
    159
    160static void __handle_ksmbd_work(struct ksmbd_work *work,
    161				struct ksmbd_conn *conn)
    162{
    163	u16 command = 0;
    164	int rc;
    165
    166	if (conn->ops->allocate_rsp_buf(work))
    167		return;
    168
    169	if (conn->ops->is_transform_hdr &&
    170	    conn->ops->is_transform_hdr(work->request_buf)) {
    171		rc = conn->ops->decrypt_req(work);
    172		if (rc < 0) {
    173			conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
    174			goto send;
    175		}
    176
    177		work->encrypted = true;
    178	}
    179
    180	rc = conn->ops->init_rsp_hdr(work);
    181	if (rc) {
    182		/* either uid or tid is not correct */
    183		conn->ops->set_rsp_status(work, STATUS_INVALID_HANDLE);
    184		goto send;
    185	}
    186
    187	if (conn->ops->check_user_session) {
    188		rc = conn->ops->check_user_session(work);
    189		if (rc < 0) {
    190			command = conn->ops->get_cmd_val(work);
    191			conn->ops->set_rsp_status(work,
    192					STATUS_USER_SESSION_DELETED);
    193			goto send;
    194		} else if (rc > 0) {
    195			rc = conn->ops->get_ksmbd_tcon(work);
    196			if (rc < 0) {
    197				conn->ops->set_rsp_status(work,
    198					STATUS_NETWORK_NAME_DELETED);
    199				goto send;
    200			}
    201		}
    202	}
    203
    204	do {
    205		rc = __process_request(work, conn, &command);
    206		if (rc == SERVER_HANDLER_ABORT)
    207			break;
    208
    209		/*
    210		 * Call smb2_set_rsp_credits() function to set number of credits
    211		 * granted in hdr of smb2 response.
    212		 */
    213		if (conn->ops->set_rsp_credits) {
    214			spin_lock(&conn->credits_lock);
    215			rc = conn->ops->set_rsp_credits(work);
    216			spin_unlock(&conn->credits_lock);
    217			if (rc < 0) {
    218				conn->ops->set_rsp_status(work,
    219					STATUS_INVALID_PARAMETER);
    220				goto send;
    221			}
    222		}
    223
    224		if (work->sess &&
    225		    (work->sess->sign || smb3_11_final_sess_setup_resp(work) ||
    226		     conn->ops->is_sign_req(work, command)))
    227			conn->ops->set_sign_rsp(work);
    228	} while (is_chained_smb2_message(work));
    229
    230	if (work->send_no_response)
    231		return;
    232
    233send:
    234	smb3_preauth_hash_rsp(work);
    235	if (work->sess && work->sess->enc && work->encrypted &&
    236	    conn->ops->encrypt_resp) {
    237		rc = conn->ops->encrypt_resp(work);
    238		if (rc < 0) {
    239			conn->ops->set_rsp_status(work, STATUS_DATA_ERROR);
    240			goto send;
    241		}
    242	}
    243
    244	ksmbd_conn_write(work);
    245}
    246
    247/**
    248 * handle_ksmbd_work() - process pending smb work requests
    249 * @wk:	smb work containing request command buffer
    250 *
    251 * called by kworker threads to processing remaining smb work requests
    252 */
    253static void handle_ksmbd_work(struct work_struct *wk)
    254{
    255	struct ksmbd_work *work = container_of(wk, struct ksmbd_work, work);
    256	struct ksmbd_conn *conn = work->conn;
    257
    258	atomic64_inc(&conn->stats.request_served);
    259
    260	__handle_ksmbd_work(work, conn);
    261
    262	ksmbd_conn_try_dequeue_request(work);
    263	ksmbd_free_work_struct(work);
    264	atomic_dec(&conn->r_count);
    265}
    266
    267/**
    268 * queue_ksmbd_work() - queue a smb request to worker thread queue
    269 *		for proccessing smb command and sending response
    270 * @conn:	connection instance
    271 *
    272 * read remaining data from socket create and submit work.
    273 */
    274static int queue_ksmbd_work(struct ksmbd_conn *conn)
    275{
    276	struct ksmbd_work *work;
    277
    278	work = ksmbd_alloc_work_struct();
    279	if (!work) {
    280		pr_err("allocation for work failed\n");
    281		return -ENOMEM;
    282	}
    283
    284	work->conn = conn;
    285	work->request_buf = conn->request_buf;
    286	conn->request_buf = NULL;
    287
    288	if (ksmbd_init_smb_server(work)) {
    289		ksmbd_free_work_struct(work);
    290		return -EINVAL;
    291	}
    292
    293	ksmbd_conn_enqueue_request(work);
    294	atomic_inc(&conn->r_count);
    295	/* update activity on connection */
    296	conn->last_active = jiffies;
    297	INIT_WORK(&work->work, handle_ksmbd_work);
    298	ksmbd_queue_work(work);
    299	return 0;
    300}
    301
    302static int ksmbd_server_process_request(struct ksmbd_conn *conn)
    303{
    304	return queue_ksmbd_work(conn);
    305}
    306
    307static int ksmbd_server_terminate_conn(struct ksmbd_conn *conn)
    308{
    309	ksmbd_sessions_deregister(conn);
    310	destroy_lease_table(conn);
    311	return 0;
    312}
    313
    314static void ksmbd_server_tcp_callbacks_init(void)
    315{
    316	struct ksmbd_conn_ops ops;
    317
    318	ops.process_fn = ksmbd_server_process_request;
    319	ops.terminate_fn = ksmbd_server_terminate_conn;
    320
    321	ksmbd_conn_init_server_callbacks(&ops);
    322}
    323
    324static void server_conf_free(void)
    325{
    326	int i;
    327
    328	for (i = 0; i < ARRAY_SIZE(server_conf.conf); i++) {
    329		kfree(server_conf.conf[i]);
    330		server_conf.conf[i] = NULL;
    331	}
    332}
    333
    334static int server_conf_init(void)
    335{
    336	WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
    337	server_conf.enforced_signing = 0;
    338	server_conf.min_protocol = ksmbd_min_protocol();
    339	server_conf.max_protocol = ksmbd_max_protocol();
    340	server_conf.auth_mechs = KSMBD_AUTH_NTLMSSP;
    341#ifdef CONFIG_SMB_SERVER_KERBEROS5
    342	server_conf.auth_mechs |= KSMBD_AUTH_KRB5 |
    343				KSMBD_AUTH_MSKRB5;
    344#endif
    345	return 0;
    346}
    347
    348static void server_ctrl_handle_init(struct server_ctrl_struct *ctrl)
    349{
    350	int ret;
    351
    352	ret = ksmbd_conn_transport_init();
    353	if (ret) {
    354		server_queue_ctrl_reset_work();
    355		return;
    356	}
    357
    358	WRITE_ONCE(server_conf.state, SERVER_STATE_RUNNING);
    359}
    360
    361static void server_ctrl_handle_reset(struct server_ctrl_struct *ctrl)
    362{
    363	ksmbd_ipc_soft_reset();
    364	ksmbd_conn_transport_destroy();
    365	server_conf_free();
    366	server_conf_init();
    367	WRITE_ONCE(server_conf.state, SERVER_STATE_STARTING_UP);
    368}
    369
    370static void server_ctrl_handle_work(struct work_struct *work)
    371{
    372	struct server_ctrl_struct *ctrl;
    373
    374	ctrl = container_of(work, struct server_ctrl_struct, ctrl_work);
    375
    376	mutex_lock(&ctrl_lock);
    377	switch (ctrl->type) {
    378	case SERVER_CTRL_TYPE_INIT:
    379		server_ctrl_handle_init(ctrl);
    380		break;
    381	case SERVER_CTRL_TYPE_RESET:
    382		server_ctrl_handle_reset(ctrl);
    383		break;
    384	default:
    385		pr_err("Unknown server work type: %d\n", ctrl->type);
    386	}
    387	mutex_unlock(&ctrl_lock);
    388	kfree(ctrl);
    389	module_put(THIS_MODULE);
    390}
    391
    392static int __queue_ctrl_work(int type)
    393{
    394	struct server_ctrl_struct *ctrl;
    395
    396	ctrl = kmalloc(sizeof(struct server_ctrl_struct), GFP_KERNEL);
    397	if (!ctrl)
    398		return -ENOMEM;
    399
    400	__module_get(THIS_MODULE);
    401	ctrl->type = type;
    402	INIT_WORK(&ctrl->ctrl_work, server_ctrl_handle_work);
    403	queue_work(system_long_wq, &ctrl->ctrl_work);
    404	return 0;
    405}
    406
    407int server_queue_ctrl_init_work(void)
    408{
    409	return __queue_ctrl_work(SERVER_CTRL_TYPE_INIT);
    410}
    411
    412int server_queue_ctrl_reset_work(void)
    413{
    414	return __queue_ctrl_work(SERVER_CTRL_TYPE_RESET);
    415}
    416
    417static ssize_t stats_show(struct class *class, struct class_attribute *attr,
    418			  char *buf)
    419{
    420	/*
    421	 * Inc this each time you change stats output format,
    422	 * so user space will know what to do.
    423	 */
    424	static int stats_version = 2;
    425	static const char * const state[] = {
    426		"startup",
    427		"running",
    428		"reset",
    429		"shutdown"
    430	};
    431
    432	ssize_t sz = scnprintf(buf, PAGE_SIZE, "%d %s %d %lu\n", stats_version,
    433			       state[server_conf.state], server_conf.tcp_port,
    434			       server_conf.ipc_last_active / HZ);
    435	return sz;
    436}
    437
    438static ssize_t kill_server_store(struct class *class,
    439				 struct class_attribute *attr, const char *buf,
    440				 size_t len)
    441{
    442	if (!sysfs_streq(buf, "hard"))
    443		return len;
    444
    445	pr_info("kill command received\n");
    446	mutex_lock(&ctrl_lock);
    447	WRITE_ONCE(server_conf.state, SERVER_STATE_RESETTING);
    448	__module_get(THIS_MODULE);
    449	server_ctrl_handle_reset(NULL);
    450	module_put(THIS_MODULE);
    451	mutex_unlock(&ctrl_lock);
    452	return len;
    453}
    454
    455static const char * const debug_type_strings[] = {"smb", "auth", "vfs",
    456						  "oplock", "ipc", "conn",
    457						  "rdma"};
    458
    459static ssize_t debug_show(struct class *class, struct class_attribute *attr,
    460			  char *buf)
    461{
    462	ssize_t sz = 0;
    463	int i, pos = 0;
    464
    465	for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) {
    466		if ((ksmbd_debug_types >> i) & 1) {
    467			pos = scnprintf(buf + sz,
    468					PAGE_SIZE - sz,
    469					"[%s] ",
    470					debug_type_strings[i]);
    471		} else {
    472			pos = scnprintf(buf + sz,
    473					PAGE_SIZE - sz,
    474					"%s ",
    475					debug_type_strings[i]);
    476		}
    477		sz += pos;
    478	}
    479	sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
    480	return sz;
    481}
    482
    483static ssize_t debug_store(struct class *class, struct class_attribute *attr,
    484			   const char *buf, size_t len)
    485{
    486	int i;
    487
    488	for (i = 0; i < ARRAY_SIZE(debug_type_strings); i++) {
    489		if (sysfs_streq(buf, "all")) {
    490			if (ksmbd_debug_types == KSMBD_DEBUG_ALL)
    491				ksmbd_debug_types = 0;
    492			else
    493				ksmbd_debug_types = KSMBD_DEBUG_ALL;
    494			break;
    495		}
    496
    497		if (sysfs_streq(buf, debug_type_strings[i])) {
    498			if (ksmbd_debug_types & (1 << i))
    499				ksmbd_debug_types &= ~(1 << i);
    500			else
    501				ksmbd_debug_types |= (1 << i);
    502			break;
    503		}
    504	}
    505
    506	return len;
    507}
    508
    509static CLASS_ATTR_RO(stats);
    510static CLASS_ATTR_WO(kill_server);
    511static CLASS_ATTR_RW(debug);
    512
    513static struct attribute *ksmbd_control_class_attrs[] = {
    514	&class_attr_stats.attr,
    515	&class_attr_kill_server.attr,
    516	&class_attr_debug.attr,
    517	NULL,
    518};
    519ATTRIBUTE_GROUPS(ksmbd_control_class);
    520
    521static struct class ksmbd_control_class = {
    522	.name		= "ksmbd-control",
    523	.owner		= THIS_MODULE,
    524	.class_groups	= ksmbd_control_class_groups,
    525};
    526
    527static int ksmbd_server_shutdown(void)
    528{
    529	WRITE_ONCE(server_conf.state, SERVER_STATE_SHUTTING_DOWN);
    530
    531	class_unregister(&ksmbd_control_class);
    532	ksmbd_workqueue_destroy();
    533	ksmbd_ipc_release();
    534	ksmbd_conn_transport_destroy();
    535	ksmbd_crypto_destroy();
    536	ksmbd_free_global_file_table();
    537	destroy_lease_table(NULL);
    538	ksmbd_work_pool_destroy();
    539	ksmbd_exit_file_cache();
    540	server_conf_free();
    541	return 0;
    542}
    543
    544static int __init ksmbd_server_init(void)
    545{
    546	int ret;
    547
    548	ret = class_register(&ksmbd_control_class);
    549	if (ret) {
    550		pr_err("Unable to register ksmbd-control class\n");
    551		return ret;
    552	}
    553
    554	ksmbd_server_tcp_callbacks_init();
    555
    556	ret = server_conf_init();
    557	if (ret)
    558		goto err_unregister;
    559
    560	ret = ksmbd_work_pool_init();
    561	if (ret)
    562		goto err_unregister;
    563
    564	ret = ksmbd_init_file_cache();
    565	if (ret)
    566		goto err_destroy_work_pools;
    567
    568	ret = ksmbd_ipc_init();
    569	if (ret)
    570		goto err_exit_file_cache;
    571
    572	ret = ksmbd_init_global_file_table();
    573	if (ret)
    574		goto err_ipc_release;
    575
    576	ret = ksmbd_inode_hash_init();
    577	if (ret)
    578		goto err_destroy_file_table;
    579
    580	ret = ksmbd_crypto_create();
    581	if (ret)
    582		goto err_release_inode_hash;
    583
    584	ret = ksmbd_workqueue_init();
    585	if (ret)
    586		goto err_crypto_destroy;
    587
    588	pr_warn_once("The ksmbd server is experimental\n");
    589
    590	return 0;
    591
    592err_crypto_destroy:
    593	ksmbd_crypto_destroy();
    594err_release_inode_hash:
    595	ksmbd_release_inode_hash();
    596err_destroy_file_table:
    597	ksmbd_free_global_file_table();
    598err_ipc_release:
    599	ksmbd_ipc_release();
    600err_exit_file_cache:
    601	ksmbd_exit_file_cache();
    602err_destroy_work_pools:
    603	ksmbd_work_pool_destroy();
    604err_unregister:
    605	class_unregister(&ksmbd_control_class);
    606
    607	return ret;
    608}
    609
    610/**
    611 * ksmbd_server_exit() - shutdown forker thread and free memory at module exit
    612 */
    613static void __exit ksmbd_server_exit(void)
    614{
    615	ksmbd_server_shutdown();
    616	ksmbd_release_inode_hash();
    617}
    618
    619MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>");
    620MODULE_VERSION(KSMBD_VERSION);
    621MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
    622MODULE_LICENSE("GPL");
    623MODULE_SOFTDEP("pre: ecb");
    624MODULE_SOFTDEP("pre: hmac");
    625MODULE_SOFTDEP("pre: md5");
    626MODULE_SOFTDEP("pre: nls");
    627MODULE_SOFTDEP("pre: aes");
    628MODULE_SOFTDEP("pre: cmac");
    629MODULE_SOFTDEP("pre: sha256");
    630MODULE_SOFTDEP("pre: sha512");
    631MODULE_SOFTDEP("pre: aead2");
    632MODULE_SOFTDEP("pre: ccm");
    633MODULE_SOFTDEP("pre: gcm");
    634MODULE_SOFTDEP("pre: crc32");
    635module_init(ksmbd_server_init)
    636module_exit(ksmbd_server_exit)