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

share_config.c (5110B)


      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/jhash.h>
      8#include <linux/slab.h>
      9#include <linux/rwsem.h>
     10#include <linux/parser.h>
     11#include <linux/namei.h>
     12#include <linux/sched.h>
     13#include <linux/mm.h>
     14
     15#include "share_config.h"
     16#include "user_config.h"
     17#include "user_session.h"
     18#include "../transport_ipc.h"
     19
     20#define SHARE_HASH_BITS		3
     21static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS);
     22static DECLARE_RWSEM(shares_table_lock);
     23
     24struct ksmbd_veto_pattern {
     25	char			*pattern;
     26	struct list_head	list;
     27};
     28
     29static unsigned int share_name_hash(char *name)
     30{
     31	return jhash(name, strlen(name), 0);
     32}
     33
     34static void kill_share(struct ksmbd_share_config *share)
     35{
     36	while (!list_empty(&share->veto_list)) {
     37		struct ksmbd_veto_pattern *p;
     38
     39		p = list_entry(share->veto_list.next,
     40			       struct ksmbd_veto_pattern,
     41			       list);
     42		list_del(&p->list);
     43		kfree(p->pattern);
     44		kfree(p);
     45	}
     46
     47	if (share->path)
     48		path_put(&share->vfs_path);
     49	kfree(share->name);
     50	kfree(share->path);
     51	kfree(share);
     52}
     53
     54void __ksmbd_share_config_put(struct ksmbd_share_config *share)
     55{
     56	down_write(&shares_table_lock);
     57	hash_del(&share->hlist);
     58	up_write(&shares_table_lock);
     59
     60	kill_share(share);
     61}
     62
     63static struct ksmbd_share_config *
     64__get_share_config(struct ksmbd_share_config *share)
     65{
     66	if (!atomic_inc_not_zero(&share->refcount))
     67		return NULL;
     68	return share;
     69}
     70
     71static struct ksmbd_share_config *__share_lookup(char *name)
     72{
     73	struct ksmbd_share_config *share;
     74	unsigned int key = share_name_hash(name);
     75
     76	hash_for_each_possible(shares_table, share, hlist, key) {
     77		if (!strcmp(name, share->name))
     78			return share;
     79	}
     80	return NULL;
     81}
     82
     83static int parse_veto_list(struct ksmbd_share_config *share,
     84			   char *veto_list,
     85			   int veto_list_sz)
     86{
     87	int sz = 0;
     88
     89	if (!veto_list_sz)
     90		return 0;
     91
     92	while (veto_list_sz > 0) {
     93		struct ksmbd_veto_pattern *p;
     94
     95		sz = strlen(veto_list);
     96		if (!sz)
     97			break;
     98
     99		p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL);
    100		if (!p)
    101			return -ENOMEM;
    102
    103		p->pattern = kstrdup(veto_list, GFP_KERNEL);
    104		if (!p->pattern) {
    105			kfree(p);
    106			return -ENOMEM;
    107		}
    108
    109		list_add(&p->list, &share->veto_list);
    110
    111		veto_list += sz + 1;
    112		veto_list_sz -= (sz + 1);
    113	}
    114
    115	return 0;
    116}
    117
    118static struct ksmbd_share_config *share_config_request(char *name)
    119{
    120	struct ksmbd_share_config_response *resp;
    121	struct ksmbd_share_config *share = NULL;
    122	struct ksmbd_share_config *lookup;
    123	int ret;
    124
    125	resp = ksmbd_ipc_share_config_request(name);
    126	if (!resp)
    127		return NULL;
    128
    129	if (resp->flags == KSMBD_SHARE_FLAG_INVALID)
    130		goto out;
    131
    132	share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL);
    133	if (!share)
    134		goto out;
    135
    136	share->flags = resp->flags;
    137	atomic_set(&share->refcount, 1);
    138	INIT_LIST_HEAD(&share->veto_list);
    139	share->name = kstrdup(name, GFP_KERNEL);
    140
    141	if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) {
    142		share->path = kstrdup(ksmbd_share_config_path(resp),
    143				      GFP_KERNEL);
    144		if (share->path)
    145			share->path_sz = strlen(share->path);
    146		share->create_mask = resp->create_mask;
    147		share->directory_mask = resp->directory_mask;
    148		share->force_create_mode = resp->force_create_mode;
    149		share->force_directory_mode = resp->force_directory_mode;
    150		share->force_uid = resp->force_uid;
    151		share->force_gid = resp->force_gid;
    152		ret = parse_veto_list(share,
    153				      KSMBD_SHARE_CONFIG_VETO_LIST(resp),
    154				      resp->veto_list_sz);
    155		if (!ret && share->path) {
    156			ret = kern_path(share->path, 0, &share->vfs_path);
    157			if (ret) {
    158				ksmbd_debug(SMB, "failed to access '%s'\n",
    159					    share->path);
    160				/* Avoid put_path() */
    161				kfree(share->path);
    162				share->path = NULL;
    163			}
    164		}
    165		if (ret || !share->name) {
    166			kill_share(share);
    167			share = NULL;
    168			goto out;
    169		}
    170	}
    171
    172	down_write(&shares_table_lock);
    173	lookup = __share_lookup(name);
    174	if (lookup)
    175		lookup = __get_share_config(lookup);
    176	if (!lookup) {
    177		hash_add(shares_table, &share->hlist, share_name_hash(name));
    178	} else {
    179		kill_share(share);
    180		share = lookup;
    181	}
    182	up_write(&shares_table_lock);
    183
    184out:
    185	kvfree(resp);
    186	return share;
    187}
    188
    189static void strtolower(char *share_name)
    190{
    191	while (*share_name) {
    192		*share_name = tolower(*share_name);
    193		share_name++;
    194	}
    195}
    196
    197struct ksmbd_share_config *ksmbd_share_config_get(char *name)
    198{
    199	struct ksmbd_share_config *share;
    200
    201	strtolower(name);
    202
    203	down_read(&shares_table_lock);
    204	share = __share_lookup(name);
    205	if (share)
    206		share = __get_share_config(share);
    207	up_read(&shares_table_lock);
    208
    209	if (share)
    210		return share;
    211	return share_config_request(name);
    212}
    213
    214bool ksmbd_share_veto_filename(struct ksmbd_share_config *share,
    215			       const char *filename)
    216{
    217	struct ksmbd_veto_pattern *p;
    218
    219	list_for_each_entry(p, &share->veto_list, list) {
    220		if (match_wildcard(p->pattern, filename))
    221			return true;
    222	}
    223	return false;
    224}
    225
    226void ksmbd_share_configs_cleanup(void)
    227{
    228	struct ksmbd_share_config *share;
    229	struct hlist_node *tmp;
    230	int i;
    231
    232	down_write(&shares_table_lock);
    233	hash_for_each_safe(shares_table, i, tmp, share, hlist) {
    234		hash_del(&share->hlist);
    235		kill_share(share);
    236	}
    237	up_write(&shares_table_lock);
    238}