SmartAudio/lichee/linux-4.9/drivers/char/oases/sysfs.c

290 lines
6.5 KiB
C
Raw Normal View History

2018-12-29 07:13:35 +00:00
/*
* Sysfs for OASES framework
*
* Copyright (C) 2016 Baidu, Inc. All Rights Reserved.
*
* You should have received a copy of license along with this program;
* if not, ask for it from Baidu, Inc.
*
*/
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/sysfs.h>
#include <linux/mutex.h>
#include <linux/kobject.h>
#include <asm/page.h>
#include "util.h"
#include "patch_info.h"
#include "patch_base.h"
#include "patch_api.h"
#include "patch_mgr.h"
#ifdef CONFIG_OASES_PERSIST_MEMORY
#include "pmem.h"
#endif
/*
* Oases Sysfs Interface
*
* /sys/kernel/oases
* /sys/kernel/oases/boot
* /sys/kernel/oases/state
* /sys/kernel/oases/version
*
* /sys/kernel/oases/<patch>
* /sys/kernel/oases/<patch>/enabled (0/1)
* /sys/kernel/oases/<patch>/log
* /sys/kernel/oases/<patch>/info
*
* patch: $VENDOR-$NAME-$ID
*/
#define PROC_OASES_STATE "state"
#define SYSFS_OASES "oases"
#define SYSFS_OASES_VERSION "version"
#define SYSFS_PATCH_ENABLED "enabled"
#define SYSFS_PATCH_LOG "log"
#define ARCH_ARM "arm"
#define ARCH_AARCH64 "aarch64"
extern struct list_head patchinfo_list;
extern struct mutex oases_mutex;
static struct kobject *sysfs_oases = NULL;
static ssize_t enabled_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct oases_patch_info *info;
info = container_of(kobj, struct oases_patch_info, kobj);
return snprintf(buf, 16, "%u\n", info->status);
}
static ssize_t enabled_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t count)
{
int ret;
long enabled = 0;
struct oases_patch_info *info;
/* oases_debug("buf=%s, count=%ld\n", buf, count); buf=1\x0a, count=2 */
ret = kstrtol(buf, 10, &enabled);
if (ret < 0)
return -EINVAL;
if (enabled != STATUS_ENABLED && enabled != STATUS_DISABLED)
return -EINVAL;
if (!mutex_trylock(&oases_mutex))
return -EBUSY;
/* treat it like success if trying to update info->status with same value */
info = container_of(kobj, struct oases_patch_info, kobj);
if (info->status == enabled) {
ret = count;
oases_debug("Warning: updating info->status(%d) with enabled(%ld)\n",
info->status, enabled);
goto end;
}
if (enabled == STATUS_DISABLED)
ret = oases_insn_unpatch(info);
else /* STATUS_ENABLED */
ret = oases_insn_patch(info);
if (ret) {
oases_error("%s %d -> %ld failed with %d\n",
info->id, info->status, enabled, ret);
goto end;
}
info->status = enabled;
ret = count;
end:
mutex_unlock(&oases_mutex);
return ret;
}
static ssize_t log_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct oases_patch_info *info;
struct oases_attack_log *cur;
int i;
ssize_t ret = 0;
unsigned long flags;
info = container_of(kobj, struct oases_patch_info, kobj);
spin_lock_irqsave(&info->log_lock, flags);
for (i = 0; i < info->log_index; i++) {
cur = info->plog + i;
if (!cur->count)
continue;
ret += scnprintf(buf + ret, PAGE_SIZE - ret - 1, "%ld %ld %ld %ld\n", cur->uid,
cur->count, cur->start_time, cur->end_time);
}
spin_unlock_irqrestore(&info->log_lock, flags);
return ret;
}
static ssize_t info_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct oases_patch_info *ctx;
struct oases_patch_entry *patch, *p;
int count = 0;
ctx = container_of(kobj, struct oases_patch_info, kobj);
list_for_each_entry_safe(patch, p, &ctx->patches, list) {
count += kp_vtab(patch)->show_info(patch, kobj, attr, buf, count);
}
return count;
}
static ssize_t version_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return snprintf(buf, 16, "%u\n", OASES_VERSION);
}
static ssize_t arch_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
#ifdef CONFIG_ARM
return snprintf(buf, 16, "%s\n", ARCH_ARM);
#else /* aarch 64 */
return snprintf(buf, 16, "%s\n", ARCH_AARCH64);
#endif
}
static ssize_t state_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct oases_patch_info *info;
ssize_t ret = 0;
mutex_lock(&oases_mutex);
list_for_each_entry(info, &patchinfo_list, list) {
ret += scnprintf(buf + ret, PAGE_SIZE - ret - 1, "%s %s\n",
info->id, info->status ? "enabled" : "disabled");
}
mutex_unlock(&oases_mutex);
return ret;
}
#ifdef CONFIG_OASES_PERSIST_MEMORY
static ssize_t boot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
int ret;
ret = scnprintf(buf, PAGE_SIZE, "%d\n", oases_boot_reason);
return ret;
}
#endif
static struct kobj_attribute attribute_version =
__ATTR(version, S_IRUGO, version_show, NULL);
static struct kobj_attribute attribute_state =
__ATTR(state, S_IRUGO, state_show, NULL);
static struct kobj_attribute attribute_arch =
__ATTR(arch, S_IRUGO, arch_show, NULL);
#ifdef CONFIG_OASES_PERSIST_MEMORY
static struct kobj_attribute attribute_boot =
__ATTR(boot, S_IRUGO, boot_show, NULL);
#endif
static struct attribute *attrs[] = {
&attribute_version.attr,
&attribute_state.attr,
&attribute_arch.attr,
#ifdef CONFIG_OASES_PERSIST_MEMORY
&attribute_boot.attr,
#endif
NULL
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static struct kobj_attribute attribute_enabled =
__ATTR(enabled, S_IWUSR | S_IRUGO, enabled_show, enabled_store);
static struct kobj_attribute attribute_log =
__ATTR(log, S_IRUGO, log_show, NULL);
static struct kobj_attribute attribute_info =
__ATTR(info, S_IRUGO, info_show, NULL);
static struct attribute *attrs_patch[] = {
&attribute_enabled.attr,
&attribute_log.attr,
&attribute_info.attr,
NULL
};
static void kobj_release_oases_patch(struct kobject *kobj)
{
struct oases_patch_info *ctx;
ctx = container_of(kobj, struct oases_patch_info, kobj);
oases_free_patch(ctx);
}
static struct kobj_type ktype_oases_patch = {
.release = kobj_release_oases_patch,
.sysfs_ops = &kobj_sysfs_ops,
.default_attrs = attrs_patch
};
void oases_sysfs_init_patch(struct oases_patch_info *info)
{
kobject_init(&info->kobj, &ktype_oases_patch);
}
int oases_sysfs_add_patch(struct oases_patch_info *info)
{
return kobject_add(&info->kobj, sysfs_oases, "%s", info->id);
}
void oases_sysfs_del_patch(struct oases_patch_info *info)
{
kobject_put(&info->kobj);
}
int __init oases_sysfs_init(void)
{
int ret;
sysfs_oases = kobject_create_and_add(SYSFS_OASES, kernel_kobj);
if (!sysfs_oases) {
return -ENOMEM;
}
ret = sysfs_create_group(sysfs_oases, &attr_group);
if (ret)
goto create_group_fail;
return 0;
create_group_fail:
kobject_put(sysfs_oases);
return ret;
}
void oases_sysfs_destroy(void)
{
sysfs_remove_group(sysfs_oases, &attr_group);
kobject_put(sysfs_oases);
}