diff --git a/newip/tools/wireshark_cfg_for_newip.lua b/newip/tools/wireshark_cfg_for_newip.lua index 7a4eaf7..652dd4c 100644 --- a/newip/tools/wireshark_cfg_for_newip.lua +++ b/newip/tools/wireshark_cfg_for_newip.lua @@ -256,8 +256,8 @@ function nip_dissector(tvb, pinfo, treeitem) offset = offset + 1 nd_icmp_tree:add(_code, tvb(offset, 1)) offset = offset + 1 - nd_icmp_tree:add(_checksum, tvb(offset, 1)) - offset = offset + 1 + nd_icmp_tree:add(_checksum, tvb(offset, 2)) + offset = offset + 2 if type == 1 then local first_addr = tvb(offset, 1):uint() local addr_len = get_nip_addr_len (first_addr) diff --git a/ucollection/Kconfig b/ucollection/Kconfig new file mode 100644 index 0000000..d60e708 --- /dev/null +++ b/ucollection/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +config UNIFIED_COLLECTION + def_bool $(success,$(srctree)/scripts/ohos-check-dir.sh $(srctree)/drivers/staging/ucollection) + tristate "Enable unified collection" + help + unified collection \ No newline at end of file diff --git a/ucollection/Makefile b/ucollection/Makefile new file mode 100644 index 0000000..5d1b45e --- /dev/null +++ b/ucollection/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_UNIFIED_COLLECTION) += ucollection_process_cpu.o +obj-$(CONFIG_UNIFIED_COLLECTION) += unified_collection_driver.o \ No newline at end of file diff --git a/ucollection/README_zh.md b/ucollection/README_zh.md new file mode 100644 index 0000000..3b94e8e --- /dev/null +++ b/ucollection/README_zh.md @@ -0,0 +1,32 @@ +## 背景 +当前系统需要获取进程的CPU维测数据,支持开发者性能问题分析,通过遍例所有进程的结点虽然可以获取所有进程的CPU使用率,但是该方法性能相对较差,为了提升获取效率,因此开僻了内核的设备结点,通过结点可能快速获取CPU的数据。 + +## ucollection(unified collection)模块 +通过ioctl的方式向设备结点/dev/uncollection发送命令,内核根据不同的命令做不同的处理,返回相应的维测数据。 +![framework](figures/collector_framework.png) + +## 目录 +统一采集设备的主要代码目录结构如下: + +``` +# 代码路径 /kernel/linux/common_modules/xpm +├── apply_ucollection.sh # XPM 头文件 +├── figures # ReadMe 内嵌图例 +├── Konfig +├── Makefile +├── README_zh.md +├── ucollection_process_cpu.c # 获取进程CPU数据 +├── ucollection_process_cpu.h +├── unified_collection_data.h +├── unified_collection_driver.c # 注册/dev/ucollection设备 +``` + +## 相关仓 + +[内核子系统](https://gitee.com/openharmony/docs/blob/master/zh-cn/readme/%E5%86%85%E6%A0%B8%E5%AD%90%E7%B3%BB%E7%BB%9F.md) + +[kernel_linux_5.10](https://gitee.com/openharmony/kernel_linux_5.10) + +[kernel_linux_config](https://gitee.com/openharmony/kernel_linux_config) + +[kernel_linux_build](https://gitee.com/openharmony/kernel_linux_build) diff --git a/ucollection/apply_ucollection.sh b/ucollection/apply_ucollection.sh new file mode 100755 index 0000000..96af21c --- /dev/null +++ b/ucollection/apply_ucollection.sh @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Copyright (c) 2023 Huawei Device Co., Ltd. +# +# Description: Create a symbolic link for Unified Collection Driver in Linux 5.10 +# + +set -e + +OHOS_SOURCE_ROOT=$1 +KERNEL_BUILD_ROOT=$2 +PRODUCT_NAME=$3 +KERNEL_VERSION=$4 +UNIFIED_COLLECTION_SOURCE_ROOT=$OHOS_SOURCE_ROOT/kernel/linux/common_modules/ucollection + +function main() +{ + pushd . + + echo "create link $KERNEL_BUILD_ROOT/drivers/staging/ucollection/" + if [ ! -d "$KERNEL_BUILD_ROOT/drivers/staging/ucollection" ]; then + mkdir $KERNEL_BUILD_ROOT/drivers/staging/ucollection + fi + + cd $KERNEL_BUILD_ROOT/drivers/staging/ucollection/ + ln -s -f $(realpath --relative-to=$KERNEL_BUILD_ROOT/drivers/staging/ucollection/ $UNIFIED_COLLECTION_SOURCE_ROOT)/* ./ + + popd +} + +main diff --git a/ucollection/figures/collector_framework.png b/ucollection/figures/collector_framework.png new file mode 100644 index 0000000..b56e1ac Binary files /dev/null and b/ucollection/figures/collector_framework.png differ diff --git a/ucollection/ucollection_process_cpu.c b/ucollection/ucollection_process_cpu.c new file mode 100644 index 0000000..bba8422 --- /dev/null +++ b/ucollection/ucollection_process_cpu.c @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#include "ucollection_process_cpu.h" + +#include +#ifdef CONFIG_CPU_FREQ_TIMES +#include +#endif // CONFIG_CPU_FREQ_TIMES +#include +#include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) +#include +#include +#include +#endif // LINUX_VERSION_CODE +#ifdef CONFIG_SMT_MODE_GOV +#include +#endif // CONFIG_SMT_MODE_GOV + +#include "unified_collection_data.h" + +#define NS_TO_MS 1000000 +static char dmips_values[DMIPS_NUM]; + +unsigned long long __attribute__((weak)) get_proc_cpu_load(struct task_struct *task, char dmips[], + unsigned int dmips_num) +{ + return 0; +} + +static int get_cpu_num(void) +{ + int core_num = 0; + int i = 0; + for_each_possible_cpu(i) + core_num++; + return core_num; +} + +static unsigned long long get_process_load_cputime(struct task_struct *task) +{ + unsigned long long proc_load_cputime = 0; + proc_load_cputime = get_proc_cpu_load(task, dmips_values, DMIPS_NUM); + return proc_load_cputime; +} + +static void get_process_usage_cputime(struct task_struct *task, unsigned long long *ut, unsigned long long *st) +{ + unsigned long long utime, stime; + + thread_group_cputime_adjusted(task, &utime, &stime); + utime = utime + task->signal->cutime; + stime = stime + task->signal->cstime; + do_div(utime, NS_TO_MS); + do_div(stime, NS_TO_MS); + *ut = utime; + *st = stime; +} + +static void get_process_load(struct task_struct *task, int cpu_num, int cur_count, + struct ucollection_process_cpu_entry __user *entry) +{ + struct ucollection_process_cpu_item proc_cpu_entry; + memset(&proc_cpu_entry, 0, sizeof(struct ucollection_process_cpu_item)); + proc_cpu_entry.pid = task->pid; + proc_cpu_entry.cpu_load_time = get_process_load_cputime(task); + get_process_usage_cputime(task, &proc_cpu_entry.cpu_usage_utime, &proc_cpu_entry.cpu_usage_stime); + (void)copy_to_user(&entry->datas[cur_count], &proc_cpu_entry, sizeof(struct ucollection_process_cpu_item)); +} + +static long ioctrl_collect_process_cpu(void __user *argp) +{ + int cpu_num = 0; + struct task_struct *task = NULL; + struct ucollection_process_cpu_entry kentry; + struct ucollection_process_cpu_entry __user *entry = argp; + if (entry == NULL) { + pr_err("cpu entry is null"); + return -EINVAL; + } + + memset(&kentry, 0, sizeof(struct ucollection_process_cpu_entry)); + (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_process_cpu_entry)); + + cpu_num = get_cpu_num(); + rcu_read_lock(); + task = &init_task; + for_each_process(task) { + if (task->pid != task->tgid) + continue; + + if (kentry.cur_count >= kentry.total_count) { + pr_err("process over total count"); + break; + } + + get_process_load(task, cpu_num, kentry.cur_count, entry); + kentry.cur_count++; + } + put_user(kentry.cur_count, &entry->cur_count); + rcu_read_unlock(); + return 0; +} + +static bool is_pid_alive(int pid) +{ + struct task_struct *task = NULL; + task = pid_task(find_vpid(pid), PIDTYPE_PID); + if (task == NULL) + return false; + + return pid_alive(task); +} + +static long ioctrl_collect_the_process_cpu(void __user *argp) +{ + int cpu_num = 0; + struct task_struct *task = NULL; + struct ucollection_process_cpu_entry kentry; + struct ucollection_process_cpu_entry __user *entry = argp; + if (entry == NULL) { + pr_err("cpu entry is null"); + return -EINVAL; + } + + memset(&kentry, 0, sizeof(struct ucollection_process_cpu_entry)); + (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_process_cpu_entry)); + + if (kentry.cur_count >= kentry.total_count) { + pr_err("current count over total count"); + return -EINVAL; + } + + rcu_read_lock(); + if (!is_pid_alive(kentry.filter.pid)) { + pr_err("pid=%d is not alive", kentry.filter.pid); + rcu_read_unlock(); + return -EINVAL; + } + + task = find_task_by_vpid(kentry.filter.pid); + if (task == NULL) { + pr_err("can not get pid=%d", task->pid); + rcu_read_unlock(); + return -EINVAL; + } + + cpu_num = get_cpu_num(); + get_process_load(task, cpu_num, kentry.cur_count, entry); + kentry.cur_count++; + put_user(kentry.cur_count, &entry->cur_count); + rcu_read_unlock(); + return 0; +} + +static long ioctrl_set_cpu_dmips(void __user *argp) +{ + int i; + struct ucollection_cpu_dmips kentry; + struct ucollection_cpu_dmips __user *entry = argp; + memset(&kentry, 0, sizeof(struct ucollection_cpu_dmips)); + (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_cpu_dmips)); + pr_info("set dimps %d cpus\n", kentry.total_count); + for (i = 0; i < DMIPS_NUM; i++) { + if (i >= kentry.total_count) + break; + get_user(dmips_values[i], &entry->dmips[i]); + pr_info("set dimps cpu[%d]=%d\n", i, dmips_values[i]); + } + return 0; +} + +long unified_collection_collect_process_cpu(unsigned int cmd, void __user *argp) +{ + long ret = 0; + switch(cmd) { + case IOCTRL_COLLECT_ALL_PROC_CPU: + ret = ioctrl_collect_process_cpu(argp); + break; + case IOCTRL_COLLECT_THE_PROC_CPU: + ret = ioctrl_collect_the_process_cpu(argp); + break; + case IOCTRL_SET_CPU_DMIPS: + ret = ioctrl_set_cpu_dmips(argp); + break; + default: + pr_err("handle ioctrl cmd %u, _IOC_TYPE(cmd)=%d", cmd, _IOC_TYPE(cmd)); + ret = 0; + } + return ret; +} \ No newline at end of file diff --git a/ucollection/ucollection_process_cpu.h b/ucollection/ucollection_process_cpu.h new file mode 100644 index 0000000..09076aa --- /dev/null +++ b/ucollection/ucollection_process_cpu.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#ifndef __UCOLLECTION_PROCESS_CPU__ +#define __UCOLLECTION_PROCESS_CPU__ + +long unified_collection_collect_process_cpu(unsigned int cmd, void __user *argp); +#endif // __UCOLLECTION_PROCESS_CPU__ diff --git a/ucollection/unified_collection_data.h b/ucollection/unified_collection_data.h new file mode 100644 index 0000000..ddd2050 --- /dev/null +++ b/ucollection/unified_collection_data.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#ifndef __UNIFIED_COLLECTION_DATA__ +#define __UNIFIED_COLLECTION_DATA__ + +#include + +// kernel struct, modify at the same time +struct ucollection_process_cpu_item { + int pid; + unsigned long long cpu_usage_utime; + unsigned long long cpu_usage_stime; + unsigned long long cpu_load_time; +}; + +struct ucollection_process_filter { + int uid; + int pid; + int tid; +}; + +struct ucollection_process_cpu_entry { + int magic; + int total_count; + int cur_count; + struct ucollection_process_filter filter; + struct ucollection_process_cpu_item datas[]; +}; + +struct ucollection_cpu_dmips { + int magic; + int total_count; + char dmips[]; +}; + +#define IOCTRL_COLLECT_ALL_PROC_CPU_MAGIC 1 +#define IOCTRL_COLLECT_THE_PROC_CPU_MAGIC 1 +#define IOCTRL_SET_CPU_DMIPS_MAGIC 1 +#define DMIPS_NUM 128 + +#define IOCTRL_COLLECT_CPU_BASE 0 +#define IOCTRL_COLLECT_ALL_PROC_CPU _IOR(IOCTRL_COLLECT_CPU_BASE, 1, struct ucollection_process_cpu_entry) +#define IOCTRL_COLLECT_THE_PROC_CPU _IOR(IOCTRL_COLLECT_CPU_BASE, 2, struct ucollection_process_cpu_entry) +#define IOCTRL_SET_CPU_DMIPS _IOW(IOCTRL_COLLECT_CPU_BASE, 3, struct ucollection_cpu_dmips) +#endif // __UNIFIED_COLLECTION_DATA__ \ No newline at end of file diff --git a/ucollection/unified_collection_driver.c b/ucollection/unified_collection_driver.c new file mode 100644 index 0000000..be70a17 --- /dev/null +++ b/ucollection/unified_collection_driver.c @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ +#include +#include +#include +#include + +#ifdef CONFIG_COMPAT +#include +#endif // CONFIG_COMPAT + +#include "ucollection_process_cpu.h" + +static long (*unified_collection_ioctl_cb[])(unsigned int cmd, void __user *argp) = { + unified_collection_collect_process_cpu /* IOCTRL_COLLECT_CPU */ +}; + +static long unified_collection_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + void __user *argp = u64_to_user_ptr(arg); + const char *comm = NULL; + + if ((_IOC_TYPE(cmd) >= ARRAY_SIZE(unified_collection_ioctl_cb)) || + (unified_collection_ioctl_cb[_IOC_TYPE(cmd)] == NULL)) { + pr_err("invalid ioctrl cmd %u, _IOC_TYPE(cmd)=%d", cmd, _IOC_TYPE(cmd)); + return -EINVAL; + } + + return unified_collection_ioctl_cb[_IOC_TYPE(cmd)](cmd, argp); +} + +#ifdef CONFIG_COMPAT +static long unified_collection_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return unified_collection_ioctl(filp, cmd, (unsigned long) compat_ptr(arg)); +} +#endif // CONFIG_COMPAT + +static int unified_collection_open(struct inode *inode, struct file *filp) +{ + return 0; +} + +static int unified_collection_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +static const struct file_operations unified_collection_device_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = unified_collection_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = unified_collection_compat_ioctl, +#endif // CONFIG_COMPAT + .open = unified_collection_open, + .release = unified_collection_release, +}; + +static struct miscdevice unified_collection_device = { + .name = "ucollection", + .fops = &unified_collection_device_fops, + .minor = MISC_DYNAMIC_MINOR, +}; + +static int __init unified_collection_init(void) +{ + int ret = misc_register(&unified_collection_device); + if (ret) { + pr_err("failed to register unified collection device"); + return ret; + } + + pr_info("register unified collection device successful"); + return 0; +} + +static void __exit unified_collection_exit(void) +{ + pr_info("deregister unified collection device successful"); + misc_deregister(&unified_collection_device); +} + +module_init(unified_collection_init); +module_exit(unified_collection_exit); + +MODULE_AUTHOR("OHOS"); +MODULE_DESCRIPTION("Unified Collection Driver"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/xpm/Kconfig b/xpm/Kconfig index c83c625..e74ba0d 100755 --- a/xpm/Kconfig +++ b/xpm/Kconfig @@ -15,6 +15,15 @@ config SECURITY_XPM mmap and etc. It can control not to execute an illegal signature process. +config DSMM_DEVELOPER_ENABLE + bool "Enables device developer mode feature" + depends on SECURITY_XPM + default n + help + This option should only be enabled for the device support developer + mode feature. But whether or not developer mode is enabled on the + device ultimately depends on the developer_mode valude in cmdline. + config SECURITY_XPM_DEBUG bool "Enables excutable permission manager debug mode" depends on SECURITY_XPM diff --git a/xpm/Makefile b/xpm/Makefile index 3f94ecd..36494c3 100755 --- a/xpm/Makefile +++ b/xpm/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_SECURITY_XPM) += \ core/xpm_misc.o \ core/xpm_hck.o \ core/xpm_report.o \ + core/dsmm_developer.o \ validator/elf_code_segment_info.o \ validator/exec_signature_info.o diff --git a/xpm/core/dsmm_developer.c b/xpm/core/dsmm_developer.c new file mode 100644 index 0000000..66b10f8 --- /dev/null +++ b/xpm/core/dsmm_developer.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#include +#include "dsmm_developer.h" +#include "xpm_log.h" + +#define DSMM_DIR "dsmm" +#define DSMM_DEVELOPER_FILE "developer" +#define DSMM_DEVELOPER_PARAM_NAME "const.security.developermode.state" + +static struct proc_dir_entry *g_dsmm_dir; + +static const char *g_developer_status[BUILD_VARIANT_MAX][DEVELOPER_PROC_STATUS_MAX] = { + { DEVELOPER_STATUS_OFF, DEVELOPER_STATUS_ON, DEVELOPER_STATUS_OFF }, + { DEVELOPER_STATUS_ON, DEVELOPER_STATUS_ON, DEVELOPER_STATUS_OFF }, +}; + +static int get_developer_status(uint32_t *status) +{ + if (!strstr(saved_command_line, "developer_mode=")) { + *status = DEVELOPER_PROC_STATUS_NA; + } else if (strstr(saved_command_line, "developer_mode=1")) { + *status = DEVELOPER_PROC_STATUS_ON; + } else if (strstr(saved_command_line, "developer_mode=0")) { + *status = DEVELOPER_PROC_STATUS_OFF; + } else { + xpm_log_error("invalid developer_mode value in cmdline"); + return -EINVAL; + } + + return 0; +} + +static int get_build_variant(uint32_t *variant) +{ + if (strstr(saved_command_line, "buildvariant=user")) { + *variant = BUILD_VARIANT_USER; + } else if (strstr(saved_command_line, "buildvariant=eng")) { + *variant = BUILD_VARIANT_ENG; + } else { + xpm_log_error("invalid buildvariant value in cmdline"); + return -EINVAL; + } + + return 0; +} + +const char *developer_mode_state(void) +{ + uint32_t variant, status; + +#ifdef CONFIG_DSMM_DEVELOPER_ENABLE + if (get_build_variant(&variant) || get_developer_status(&status)) { + xpm_log_error("get build variant or developer status failed"); + return NULL; + } + + return g_developer_status[variant][status]; +#else + return DEVELOPER_STATUS_ON; +#endif +} + +#define PROC_DEVELOPER_LEN 50 +static ssize_t dsmm_read_developer_proc(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + size_t len; + char proc_developer[PROC_DEVELOPER_LEN] = {0}; + const char *developer_state = developer_mode_state(); + + if (!developer_state) { + xpm_log_error("developer mode state invalid"); + return 0; + } + + len = snprintf(proc_developer, PROC_DEVELOPER_LEN - 1, + DSMM_DEVELOPER_PARAM_NAME"=%s", developer_state); + + return simple_read_from_buffer(buf, count, pos, proc_developer, len); +} + +static const struct proc_ops dsmm_proc_fops_developer = { + .proc_read = dsmm_read_developer_proc, +}; + +void dsmm_developer_proc_create(void) +{ + g_dsmm_dir = proc_mkdir(DSMM_DIR, NULL); + if (!g_dsmm_dir) { + xpm_log_error("[%s] proc dir create failed", DSMM_DIR); + return; + } + + if(!proc_create(DSMM_DEVELOPER_FILE, S_IRUGO, g_dsmm_dir, + &dsmm_proc_fops_developer)) { + xpm_log_error("[%s] proc file create failed", + DSMM_DEVELOPER_FILE); + } +} + +void dsmm_developer_proc_clean(void) +{ + if (!g_dsmm_dir) + return; + + remove_proc_entry(DSMM_DEVELOPER_FILE, g_dsmm_dir); + remove_proc_entry(DSMM_DIR, NULL); +} diff --git a/xpm/core/xpm_module.c b/xpm/core/xpm_module.c index 498932c..d2fcb50 100755 --- a/xpm/core/xpm_module.c +++ b/xpm/core/xpm_module.c @@ -12,6 +12,7 @@ #include "xpm_misc.h" #include "xpm_report.h" #include "xpm_debugfs.h" +#include "dsmm_developer.h" static int __init xpm_module_init(void) { @@ -35,6 +36,8 @@ static int __init xpm_module_init(void) xpm_register_xpm_hooks(); xpm_register_hck_hooks(); + dsmm_developer_proc_create(); + xpm_log_info("xpm module init success"); return 0; } @@ -43,6 +46,9 @@ static void __exit xpm_module_exit(void) { xpm_deregister_misc_device(); xpm_debugfs_exit(); + + dsmm_developer_proc_clean(); + xpm_log_info("xpm module exit success"); } diff --git a/xpm/include/dsmm_developer.h b/xpm/include/dsmm_developer.h new file mode 100644 index 0000000..5f19bec --- /dev/null +++ b/xpm/include/dsmm_developer.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + */ + +#ifndef DSMM_DEVELOPER_H +#define DSMM_DEVELOPER_H + +#define DEVELOPER_STATUS_ON "true" +#define DEVELOPER_STATUS_OFF "false" + +enum build_variant { + BUILD_VARIANT_USER = 0, + BUILD_VARIANT_ENG, + BUILD_VARIANT_MAX, +}; + +enum developer_proc_status { + DEVELOPER_PROC_STATUS_NA = 0, + DEVELOPER_PROC_STATUS_ON, + DEVELOPER_PROC_STATUS_OFF, + DEVELOPER_PROC_STATUS_MAX, +}; + +const char *developer_mode_state(void); + +void dsmm_developer_proc_create(void); + +void dsmm_developer_proc_clean(void); + +#endif // DSMM_DEVELOPER_H