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

inode.c (10015B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* inode.c: /proc/openprom handling routines
      3 *
      4 * Copyright (C) 1996-1999 Jakub Jelinek  (jakub@redhat.com)
      5 * Copyright (C) 1998      Eddie C. Dost  (ecd@skynet.be)
      6 */
      7
      8#include <linux/module.h>
      9#include <linux/types.h>
     10#include <linux/string.h>
     11#include <linux/fs.h>
     12#include <linux/fs_context.h>
     13#include <linux/init.h>
     14#include <linux/slab.h>
     15#include <linux/seq_file.h>
     16#include <linux/magic.h>
     17
     18#include <asm/openprom.h>
     19#include <asm/oplib.h>
     20#include <asm/prom.h>
     21#include <linux/uaccess.h>
     22
     23static DEFINE_MUTEX(op_mutex);
     24
     25#define OPENPROM_ROOT_INO	0
     26
     27enum op_inode_type {
     28	op_inode_node,
     29	op_inode_prop,
     30};
     31
     32union op_inode_data {
     33	struct device_node	*node;
     34	struct property		*prop;
     35};
     36
     37struct op_inode_info {
     38	struct inode		vfs_inode;
     39	enum op_inode_type	type;
     40	union op_inode_data	u;
     41};
     42
     43static struct inode *openprom_iget(struct super_block *sb, ino_t ino);
     44
     45static inline struct op_inode_info *OP_I(struct inode *inode)
     46{
     47	return container_of(inode, struct op_inode_info, vfs_inode);
     48}
     49
     50static int is_string(unsigned char *p, int len)
     51{
     52	int i;
     53
     54	for (i = 0; i < len; i++) {
     55		unsigned char val = p[i];
     56
     57		if ((i && !val) ||
     58		    (val >= ' ' && val <= '~'))
     59			continue;
     60
     61		return 0;
     62	}
     63
     64	return 1;
     65}
     66
     67static int property_show(struct seq_file *f, void *v)
     68{
     69	struct property *prop = f->private;
     70	void *pval;
     71	int len;
     72
     73	len = prop->length;
     74	pval = prop->value;
     75
     76	if (is_string(pval, len)) {
     77		while (len > 0) {
     78			int n = strlen(pval);
     79
     80			seq_printf(f, "%s", (char *) pval);
     81
     82			/* Skip over the NULL byte too.  */
     83			pval += n + 1;
     84			len -= n + 1;
     85
     86			if (len > 0)
     87				seq_printf(f, " + ");
     88		}
     89	} else {
     90		if (len & 3) {
     91			while (len) {
     92				len--;
     93				if (len)
     94					seq_printf(f, "%02x.",
     95						   *(unsigned char *) pval);
     96				else
     97					seq_printf(f, "%02x",
     98						   *(unsigned char *) pval);
     99				pval++;
    100			}
    101		} else {
    102			while (len >= 4) {
    103				len -= 4;
    104
    105				if (len)
    106					seq_printf(f, "%08x.",
    107						   *(unsigned int *) pval);
    108				else
    109					seq_printf(f, "%08x",
    110						   *(unsigned int *) pval);
    111				pval += 4;
    112			}
    113		}
    114	}
    115	seq_printf(f, "\n");
    116
    117	return 0;
    118}
    119
    120static void *property_start(struct seq_file *f, loff_t *pos)
    121{
    122	if (*pos == 0)
    123		return pos;
    124	return NULL;
    125}
    126
    127static void *property_next(struct seq_file *f, void *v, loff_t *pos)
    128{
    129	(*pos)++;
    130	return NULL;
    131}
    132
    133static void property_stop(struct seq_file *f, void *v)
    134{
    135	/* Nothing to do */
    136}
    137
    138static const struct seq_operations property_op = {
    139	.start		= property_start,
    140	.next		= property_next,
    141	.stop		= property_stop,
    142	.show		= property_show
    143};
    144
    145static int property_open(struct inode *inode, struct file *file)
    146{
    147	struct op_inode_info *oi = OP_I(inode);
    148	int ret;
    149
    150	BUG_ON(oi->type != op_inode_prop);
    151
    152	ret = seq_open(file, &property_op);
    153	if (!ret) {
    154		struct seq_file *m = file->private_data;
    155		m->private = oi->u.prop;
    156	}
    157	return ret;
    158}
    159
    160static const struct file_operations openpromfs_prop_ops = {
    161	.open		= property_open,
    162	.read		= seq_read,
    163	.llseek		= seq_lseek,
    164	.release	= seq_release,
    165};
    166
    167static int openpromfs_readdir(struct file *, struct dir_context *);
    168
    169static const struct file_operations openprom_operations = {
    170	.read		= generic_read_dir,
    171	.iterate_shared	= openpromfs_readdir,
    172	.llseek		= generic_file_llseek,
    173};
    174
    175static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, unsigned int);
    176
    177static const struct inode_operations openprom_inode_operations = {
    178	.lookup		= openpromfs_lookup,
    179};
    180
    181static struct dentry *openpromfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
    182{
    183	struct op_inode_info *ent_oi, *oi = OP_I(dir);
    184	struct device_node *dp, *child;
    185	struct property *prop;
    186	enum op_inode_type ent_type;
    187	union op_inode_data ent_data;
    188	const char *name;
    189	struct inode *inode;
    190	unsigned int ino;
    191	int len;
    192	
    193	BUG_ON(oi->type != op_inode_node);
    194
    195	dp = oi->u.node;
    196
    197	name = dentry->d_name.name;
    198	len = dentry->d_name.len;
    199
    200	mutex_lock(&op_mutex);
    201
    202	child = dp->child;
    203	while (child) {
    204		const char *node_name = kbasename(child->full_name);
    205		int n = strlen(node_name);
    206
    207		if (len == n &&
    208		    !strncmp(node_name, name, len)) {
    209			ent_type = op_inode_node;
    210			ent_data.node = child;
    211			ino = child->unique_id;
    212			goto found;
    213		}
    214		child = child->sibling;
    215	}
    216
    217	prop = dp->properties;
    218	while (prop) {
    219		int n = strlen(prop->name);
    220
    221		if (len == n && !strncmp(prop->name, name, len)) {
    222			ent_type = op_inode_prop;
    223			ent_data.prop = prop;
    224			ino = prop->unique_id;
    225			goto found;
    226		}
    227
    228		prop = prop->next;
    229	}
    230
    231	mutex_unlock(&op_mutex);
    232	return ERR_PTR(-ENOENT);
    233
    234found:
    235	inode = openprom_iget(dir->i_sb, ino);
    236	mutex_unlock(&op_mutex);
    237	if (IS_ERR(inode))
    238		return ERR_CAST(inode);
    239	if (inode->i_state & I_NEW) {
    240		inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
    241		ent_oi = OP_I(inode);
    242		ent_oi->type = ent_type;
    243		ent_oi->u = ent_data;
    244
    245		switch (ent_type) {
    246		case op_inode_node:
    247			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
    248			inode->i_op = &openprom_inode_operations;
    249			inode->i_fop = &openprom_operations;
    250			set_nlink(inode, 2);
    251			break;
    252		case op_inode_prop:
    253			if (of_node_name_eq(dp, "options") && (len == 17) &&
    254			    !strncmp (name, "security-password", 17))
    255				inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
    256			else
    257				inode->i_mode = S_IFREG | S_IRUGO;
    258			inode->i_fop = &openpromfs_prop_ops;
    259			set_nlink(inode, 1);
    260			inode->i_size = ent_oi->u.prop->length;
    261			break;
    262		}
    263		unlock_new_inode(inode);
    264	}
    265
    266	return d_splice_alias(inode, dentry);
    267}
    268
    269static int openpromfs_readdir(struct file *file, struct dir_context *ctx)
    270{
    271	struct inode *inode = file_inode(file);
    272	struct op_inode_info *oi = OP_I(inode);
    273	struct device_node *dp = oi->u.node;
    274	struct device_node *child;
    275	struct property *prop;
    276	int i;
    277
    278	mutex_lock(&op_mutex);
    279	
    280	if (ctx->pos == 0) {
    281		if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR))
    282			goto out;
    283		ctx->pos = 1;
    284	}
    285	if (ctx->pos == 1) {
    286		if (!dir_emit(ctx, "..", 2,
    287			    (dp->parent == NULL ?
    288			     OPENPROM_ROOT_INO :
    289			     dp->parent->unique_id), DT_DIR))
    290			goto out;
    291		ctx->pos = 2;
    292	}
    293	i = ctx->pos - 2;
    294
    295	/* First, the children nodes as directories.  */
    296	child = dp->child;
    297	while (i && child) {
    298		child = child->sibling;
    299		i--;
    300	}
    301	while (child) {
    302		if (!dir_emit(ctx,
    303			    kbasename(child->full_name),
    304			    strlen(kbasename(child->full_name)),
    305			    child->unique_id, DT_DIR))
    306			goto out;
    307
    308		ctx->pos++;
    309		child = child->sibling;
    310	}
    311
    312	/* Next, the properties as files.  */
    313	prop = dp->properties;
    314	while (i && prop) {
    315		prop = prop->next;
    316		i--;
    317	}
    318	while (prop) {
    319		if (!dir_emit(ctx, prop->name, strlen(prop->name),
    320			    prop->unique_id, DT_REG))
    321			goto out;
    322
    323		ctx->pos++;
    324		prop = prop->next;
    325	}
    326
    327out:
    328	mutex_unlock(&op_mutex);
    329	return 0;
    330}
    331
    332static struct kmem_cache *op_inode_cachep;
    333
    334static struct inode *openprom_alloc_inode(struct super_block *sb)
    335{
    336	struct op_inode_info *oi;
    337
    338	oi = alloc_inode_sb(sb, op_inode_cachep, GFP_KERNEL);
    339	if (!oi)
    340		return NULL;
    341
    342	return &oi->vfs_inode;
    343}
    344
    345static void openprom_free_inode(struct inode *inode)
    346{
    347	kmem_cache_free(op_inode_cachep, OP_I(inode));
    348}
    349
    350static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
    351{
    352	struct inode *inode = iget_locked(sb, ino);
    353	if (!inode)
    354		inode = ERR_PTR(-ENOMEM);
    355	return inode;
    356}
    357
    358static int openprom_remount(struct super_block *sb, int *flags, char *data)
    359{
    360	sync_filesystem(sb);
    361	*flags |= SB_NOATIME;
    362	return 0;
    363}
    364
    365static const struct super_operations openprom_sops = {
    366	.alloc_inode	= openprom_alloc_inode,
    367	.free_inode	= openprom_free_inode,
    368	.statfs		= simple_statfs,
    369	.remount_fs	= openprom_remount,
    370};
    371
    372static int openprom_fill_super(struct super_block *s, struct fs_context *fc)
    373{
    374	struct inode *root_inode;
    375	struct op_inode_info *oi;
    376	int ret;
    377
    378	s->s_flags |= SB_NOATIME;
    379	s->s_blocksize = 1024;
    380	s->s_blocksize_bits = 10;
    381	s->s_magic = OPENPROM_SUPER_MAGIC;
    382	s->s_op = &openprom_sops;
    383	s->s_time_gran = 1;
    384	root_inode = openprom_iget(s, OPENPROM_ROOT_INO);
    385	if (IS_ERR(root_inode)) {
    386		ret = PTR_ERR(root_inode);
    387		goto out_no_root;
    388	}
    389
    390	root_inode->i_mtime = root_inode->i_atime =
    391		root_inode->i_ctime = current_time(root_inode);
    392	root_inode->i_op = &openprom_inode_operations;
    393	root_inode->i_fop = &openprom_operations;
    394	root_inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
    395	oi = OP_I(root_inode);
    396	oi->type = op_inode_node;
    397	oi->u.node = of_find_node_by_path("/");
    398	unlock_new_inode(root_inode);
    399
    400	s->s_root = d_make_root(root_inode);
    401	if (!s->s_root)
    402		goto out_no_root_dentry;
    403	return 0;
    404
    405out_no_root_dentry:
    406	ret = -ENOMEM;
    407out_no_root:
    408	printk("openprom_fill_super: get root inode failed\n");
    409	return ret;
    410}
    411
    412static int openpromfs_get_tree(struct fs_context *fc)
    413{
    414	return get_tree_single(fc, openprom_fill_super);
    415}
    416
    417static const struct fs_context_operations openpromfs_context_ops = {
    418	.get_tree	= openpromfs_get_tree,
    419};
    420
    421static int openpromfs_init_fs_context(struct fs_context *fc)
    422{
    423	fc->ops = &openpromfs_context_ops;
    424	return 0;
    425}
    426
    427static struct file_system_type openprom_fs_type = {
    428	.owner		= THIS_MODULE,
    429	.name		= "openpromfs",
    430	.init_fs_context = openpromfs_init_fs_context,
    431	.kill_sb	= kill_anon_super,
    432};
    433MODULE_ALIAS_FS("openpromfs");
    434
    435static void op_inode_init_once(void *data)
    436{
    437	struct op_inode_info *oi = (struct op_inode_info *) data;
    438
    439	inode_init_once(&oi->vfs_inode);
    440}
    441
    442static int __init init_openprom_fs(void)
    443{
    444	int err;
    445
    446	op_inode_cachep = kmem_cache_create("op_inode_cache",
    447					    sizeof(struct op_inode_info),
    448					    0,
    449					    (SLAB_RECLAIM_ACCOUNT |
    450					     SLAB_MEM_SPREAD | SLAB_ACCOUNT),
    451					    op_inode_init_once);
    452	if (!op_inode_cachep)
    453		return -ENOMEM;
    454
    455	err = register_filesystem(&openprom_fs_type);
    456	if (err)
    457		kmem_cache_destroy(op_inode_cachep);
    458
    459	return err;
    460}
    461
    462static void __exit exit_openprom_fs(void)
    463{
    464	unregister_filesystem(&openprom_fs_type);
    465	/*
    466	 * Make sure all delayed rcu free inodes are flushed before we
    467	 * destroy cache.
    468	 */
    469	rcu_barrier();
    470	kmem_cache_destroy(op_inode_cachep);
    471}
    472
    473module_init(init_openprom_fs)
    474module_exit(exit_openprom_fs)
    475MODULE_LICENSE("GPL");