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

user_session.c (8045B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *   Copyright (C) 2018 Samsung Electronics Co., Ltd.
      4 */
      5
      6#include <linux/list.h>
      7#include <linux/slab.h>
      8#include <linux/rwsem.h>
      9#include <linux/xarray.h>
     10
     11#include "ksmbd_ida.h"
     12#include "user_session.h"
     13#include "user_config.h"
     14#include "tree_connect.h"
     15#include "../transport_ipc.h"
     16#include "../connection.h"
     17#include "../vfs_cache.h"
     18
     19static DEFINE_IDA(session_ida);
     20
     21#define SESSION_HASH_BITS		3
     22static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS);
     23static DECLARE_RWSEM(sessions_table_lock);
     24
     25struct ksmbd_session_rpc {
     26	int			id;
     27	unsigned int		method;
     28	struct list_head	list;
     29};
     30
     31static void free_channel_list(struct ksmbd_session *sess)
     32{
     33	struct channel *chann, *tmp;
     34
     35	list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
     36				 chann_list) {
     37		list_del(&chann->chann_list);
     38		kfree(chann);
     39	}
     40}
     41
     42static void __session_rpc_close(struct ksmbd_session *sess,
     43				struct ksmbd_session_rpc *entry)
     44{
     45	struct ksmbd_rpc_command *resp;
     46
     47	resp = ksmbd_rpc_close(sess, entry->id);
     48	if (!resp)
     49		pr_err("Unable to close RPC pipe %d\n", entry->id);
     50
     51	kvfree(resp);
     52	ksmbd_rpc_id_free(entry->id);
     53	kfree(entry);
     54}
     55
     56static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess)
     57{
     58	struct ksmbd_session_rpc *entry;
     59
     60	while (!list_empty(&sess->rpc_handle_list)) {
     61		entry = list_entry(sess->rpc_handle_list.next,
     62				   struct ksmbd_session_rpc,
     63				   list);
     64
     65		list_del(&entry->list);
     66		__session_rpc_close(sess, entry);
     67	}
     68}
     69
     70static int __rpc_method(char *rpc_name)
     71{
     72	if (!strcmp(rpc_name, "\\srvsvc") || !strcmp(rpc_name, "srvsvc"))
     73		return KSMBD_RPC_SRVSVC_METHOD_INVOKE;
     74
     75	if (!strcmp(rpc_name, "\\wkssvc") || !strcmp(rpc_name, "wkssvc"))
     76		return KSMBD_RPC_WKSSVC_METHOD_INVOKE;
     77
     78	if (!strcmp(rpc_name, "LANMAN") || !strcmp(rpc_name, "lanman"))
     79		return KSMBD_RPC_RAP_METHOD;
     80
     81	if (!strcmp(rpc_name, "\\samr") || !strcmp(rpc_name, "samr"))
     82		return KSMBD_RPC_SAMR_METHOD_INVOKE;
     83
     84	if (!strcmp(rpc_name, "\\lsarpc") || !strcmp(rpc_name, "lsarpc"))
     85		return KSMBD_RPC_LSARPC_METHOD_INVOKE;
     86
     87	pr_err("Unsupported RPC: %s\n", rpc_name);
     88	return 0;
     89}
     90
     91int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name)
     92{
     93	struct ksmbd_session_rpc *entry;
     94	struct ksmbd_rpc_command *resp;
     95	int method;
     96
     97	method = __rpc_method(rpc_name);
     98	if (!method)
     99		return -EINVAL;
    100
    101	entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL);
    102	if (!entry)
    103		return -EINVAL;
    104
    105	list_add(&entry->list, &sess->rpc_handle_list);
    106	entry->method = method;
    107	entry->id = ksmbd_ipc_id_alloc();
    108	if (entry->id < 0)
    109		goto error;
    110
    111	resp = ksmbd_rpc_open(sess, entry->id);
    112	if (!resp)
    113		goto error;
    114
    115	kvfree(resp);
    116	return entry->id;
    117error:
    118	list_del(&entry->list);
    119	kfree(entry);
    120	return -EINVAL;
    121}
    122
    123void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id)
    124{
    125	struct ksmbd_session_rpc *entry;
    126
    127	list_for_each_entry(entry, &sess->rpc_handle_list, list) {
    128		if (entry->id == id) {
    129			list_del(&entry->list);
    130			__session_rpc_close(sess, entry);
    131			break;
    132		}
    133	}
    134}
    135
    136int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id)
    137{
    138	struct ksmbd_session_rpc *entry;
    139
    140	list_for_each_entry(entry, &sess->rpc_handle_list, list) {
    141		if (entry->id == id)
    142			return entry->method;
    143	}
    144	return 0;
    145}
    146
    147void ksmbd_session_destroy(struct ksmbd_session *sess)
    148{
    149	if (!sess)
    150		return;
    151
    152	if (!atomic_dec_and_test(&sess->refcnt))
    153		return;
    154
    155	list_del(&sess->sessions_entry);
    156
    157	down_write(&sessions_table_lock);
    158	hash_del(&sess->hlist);
    159	up_write(&sessions_table_lock);
    160
    161	if (sess->user)
    162		ksmbd_free_user(sess->user);
    163
    164	ksmbd_tree_conn_session_logoff(sess);
    165	ksmbd_destroy_file_table(&sess->file_table);
    166	ksmbd_session_rpc_clear_list(sess);
    167	free_channel_list(sess);
    168	kfree(sess->Preauth_HashValue);
    169	ksmbd_release_id(&session_ida, sess->id);
    170	kfree(sess);
    171}
    172
    173static struct ksmbd_session *__session_lookup(unsigned long long id)
    174{
    175	struct ksmbd_session *sess;
    176
    177	hash_for_each_possible(sessions_table, sess, hlist, id) {
    178		if (id == sess->id)
    179			return sess;
    180	}
    181	return NULL;
    182}
    183
    184void ksmbd_session_register(struct ksmbd_conn *conn,
    185			    struct ksmbd_session *sess)
    186{
    187	sess->conn = conn;
    188	list_add(&sess->sessions_entry, &conn->sessions);
    189}
    190
    191void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
    192{
    193	struct ksmbd_session *sess;
    194
    195	while (!list_empty(&conn->sessions)) {
    196		sess = list_entry(conn->sessions.next,
    197				  struct ksmbd_session,
    198				  sessions_entry);
    199
    200		ksmbd_session_destroy(sess);
    201	}
    202}
    203
    204static bool ksmbd_session_id_match(struct ksmbd_session *sess,
    205				   unsigned long long id)
    206{
    207	return sess->id == id;
    208}
    209
    210struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
    211					   unsigned long long id)
    212{
    213	struct ksmbd_session *sess = NULL;
    214
    215	list_for_each_entry(sess, &conn->sessions, sessions_entry) {
    216		if (ksmbd_session_id_match(sess, id))
    217			return sess;
    218	}
    219	return NULL;
    220}
    221
    222int get_session(struct ksmbd_session *sess)
    223{
    224	return atomic_inc_not_zero(&sess->refcnt);
    225}
    226
    227void put_session(struct ksmbd_session *sess)
    228{
    229	if (atomic_dec_and_test(&sess->refcnt))
    230		pr_err("get/%s seems to be mismatched.", __func__);
    231}
    232
    233struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id)
    234{
    235	struct ksmbd_session *sess;
    236
    237	down_read(&sessions_table_lock);
    238	sess = __session_lookup(id);
    239	if (sess) {
    240		if (!get_session(sess))
    241			sess = NULL;
    242	}
    243	up_read(&sessions_table_lock);
    244
    245	return sess;
    246}
    247
    248struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
    249					       unsigned long long id)
    250{
    251	struct ksmbd_session *sess;
    252
    253	sess = ksmbd_session_lookup(conn, id);
    254	if (!sess && conn->binding)
    255		sess = ksmbd_session_lookup_slowpath(id);
    256	return sess;
    257}
    258
    259struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
    260						    u64 sess_id)
    261{
    262	struct preauth_session *sess;
    263
    264	sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL);
    265	if (!sess)
    266		return NULL;
    267
    268	sess->id = sess_id;
    269	memcpy(sess->Preauth_HashValue, conn->preauth_info->Preauth_HashValue,
    270	       PREAUTH_HASHVALUE_SIZE);
    271	list_add(&sess->preauth_entry, &conn->preauth_sess_table);
    272
    273	return sess;
    274}
    275
    276static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
    277					   unsigned long long id)
    278{
    279	return sess->id == id;
    280}
    281
    282struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
    283						     unsigned long long id)
    284{
    285	struct preauth_session *sess = NULL;
    286
    287	list_for_each_entry(sess, &conn->preauth_sess_table, preauth_entry) {
    288		if (ksmbd_preauth_session_id_match(sess, id))
    289			return sess;
    290	}
    291	return NULL;
    292}
    293
    294static int __init_smb2_session(struct ksmbd_session *sess)
    295{
    296	int id = ksmbd_acquire_smb2_uid(&session_ida);
    297
    298	if (id < 0)
    299		return -EINVAL;
    300	sess->id = id;
    301	return 0;
    302}
    303
    304static struct ksmbd_session *__session_create(int protocol)
    305{
    306	struct ksmbd_session *sess;
    307	int ret;
    308
    309	sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
    310	if (!sess)
    311		return NULL;
    312
    313	if (ksmbd_init_file_table(&sess->file_table))
    314		goto error;
    315
    316	set_session_flag(sess, protocol);
    317	INIT_LIST_HEAD(&sess->sessions_entry);
    318	xa_init(&sess->tree_conns);
    319	INIT_LIST_HEAD(&sess->ksmbd_chann_list);
    320	INIT_LIST_HEAD(&sess->rpc_handle_list);
    321	sess->sequence_number = 1;
    322	atomic_set(&sess->refcnt, 1);
    323
    324	switch (protocol) {
    325	case CIFDS_SESSION_FLAG_SMB2:
    326		ret = __init_smb2_session(sess);
    327		break;
    328	default:
    329		ret = -EINVAL;
    330		break;
    331	}
    332
    333	if (ret)
    334		goto error;
    335
    336	ida_init(&sess->tree_conn_ida);
    337
    338	if (protocol == CIFDS_SESSION_FLAG_SMB2) {
    339		down_write(&sessions_table_lock);
    340		hash_add(sessions_table, &sess->hlist, sess->id);
    341		up_write(&sessions_table_lock);
    342	}
    343	return sess;
    344
    345error:
    346	ksmbd_session_destroy(sess);
    347	return NULL;
    348}
    349
    350struct ksmbd_session *ksmbd_smb2_session_create(void)
    351{
    352	return __session_create(CIFDS_SESSION_FLAG_SMB2);
    353}
    354
    355int ksmbd_acquire_tree_conn_id(struct ksmbd_session *sess)
    356{
    357	int id = -EINVAL;
    358
    359	if (test_session_flag(sess, CIFDS_SESSION_FLAG_SMB2))
    360		id = ksmbd_acquire_smb2_tid(&sess->tree_conn_ida);
    361
    362	return id;
    363}
    364
    365void ksmbd_release_tree_conn_id(struct ksmbd_session *sess, int id)
    366{
    367	if (id >= 0)
    368		ksmbd_release_id(&sess->tree_conn_ida, id);
    369}