kmscan
// 必备头函数
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/time.h>
// 该模块的LICENSE
MODULE_LICENSE("GPL");
// 该模块的作者
MODULE_AUTHOR("ZSH");
// 该模块的说明
MODULE_DESCRIPTION("This is ZSH's lab3!/n");
// 该模块需要传递的参数
static int func = -1;
static int pid = -1;
static struct timer_list zsh_timer;
module_param(func, int, 0644);
module_param(pid, int, 0644);
void timer_function(struct timer_list* t){
int counter = 0;
struct task_struct *temp;
for_each_process(temp){
if(temp->mm==NULL)counter++;
}
printk(KERN_ALERT"The number of kernel process is %d",counter);
mod_timer(t, jiffies + 5*HZ);
return;
}
// 初始化入口
// 模块安装时执行
// 这里的__init 同样是宏定义,主要的目的在于
// 告诉内核,加载该模块之后,可以回收init.text的区间
static int __init zsh_init(void)
{
int pid1;
int state;
char comm[16];
struct task_struct * task;
printk(KERN_ALERT" module zsh init!\n");
if(func==1){
printk(KERN_ALERT"func=1\nPID STATE COMMAND");
for_each_process(task){
if(task->mm==NULL){
pid1 = task->pid;
state = task->state;
strcpy(comm,task->comm);
printk(KERN_ALERT"%-8d%-8d[%s]\n",pid1,state,comm);
}
}
}
else if(func==2){//Every 5s get the total number of processes
printk(KERN_ALERT"func=2\n");
timer_setup(&zsh_timer, timer_function, 0);
zsh_timer.expires = jiffies + (HZ*5);//5s
add_timer(&zsh_timer);
}
else if(func==3){//process information
printk(KERN_ALERT"func=3\n");
printk(KERN_ALERT"pid receive successfully: %d\n",pid);
struct pid* kpid = find_get_pid(pid);
task = pid_task(kpid,PIDTYPE_PID);
printk(KERN_ALERT"He is: pid=%d,state=%ld,comm=%s\n",pid,task->state,task->comm);
printk(KERN_ALERT"His father is: pid=%d,state=%ld,comm=%s\n",task->parent->pid,task->parent->state,task->parent->comm);
struct task_struct *child,*sibling,*thread;
struct list_head *list;
list_for_each(list,&task->children){
child=list_entry(list,struct task_struct,sibling);
printk(KERN_ALERT"His child is: pid=%d,state=%ld,comm=%s\n",child->pid,child->state,child->comm);
}
list_for_each(list,&task->parent->children){
sibling=list_entry(list,struct task_struct,sibling);
printk(KERN_ALERT"His sibling is: pid=%d,state=%ld,comm=%s\n",sibling->pid,sibling->state,sibling->comm);
}
thread=task->group_leader;
while_each_thread(task->group_leader,thread){
printk(KERN_ALERT"His thread is: pid=%d,state=%ld,comm=%s\n",thread->pid,thread->state,thread->comm);
}
}
else{
printk(KERN_ALERT"No more functions!\n");
}
}
// 模块卸载时执行
// 同上
static void __exit zsh_exit(void)
{
del_timer_sync(&zsh_timer);
printk(KERN_ALERT" module zsh exit!\n");
}
// 模块初始化宏,用于加载该模块
module_init(zsh_init);
// 模块卸载宏,用于卸载该模块
module_exit(zsh_exit);
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/freezer.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pid.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/mm.h>
#include <linux/signal.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/rmap.h>
typedef typeof(follow_page)* my_follow_page;
typedef typeof(page_referenced)* my_page_referenced;
MODULE_LICENSE("GPL");
MODULE_AUTHOR("OS2021");
MODULE_DESCRIPTION("SYSFS_TEST!");
MODULE_VERSION("1.0");
//sysfs
#define SYSFS_TEST_RUN_STOP 0
#define SYSFS_TEST_RUN_START 1
// /sys/kerbel/mm/sysfs_test/pid
static unsigned int pid = 0;
// /sys/kerbel/mm/sysfs_test/func
static unsigned int sysfs_test_func = 0;
// /sys/kernel/mm/sysfs_test/sysfs_test_run
static unsigned int sysfs_test_run = SYSFS_TEST_RUN_STOP;
// /sys/kernel/mm/sysfs_test/sleep_millisecs
static unsigned int sysfs_test_thread_sleep_millisecs = 5000;
struct proc_ops test_ops;
static struct proc_dir_entry* proc_test=NULL;
static int count;
static int count1;
static int count2;
static int count3;
static int count4;
static struct vm_area_struct* vma=NULL;
static struct vm_area_struct* firstvma=NULL;
static struct task_struct* sysfs_test_thread=NULL;
static struct task_struct* task=NULL;
static DECLARE_WAIT_QUEUE_HEAD(sysfs_test_thread_wait);
static DEFINE_MUTEX(sysfs_test_thread_mutex);
static int sysfs_testd_should_run(void)
{
return (sysfs_test_run & SYSFS_TEST_RUN_START);
}
static void func_1(void)
{
count=0;
task = pid_task(find_vpid(pid),PIDTYPE_PID);
if(!task)
return;
vma = task->mm->mmap;
count++;
vma = vma->vm_next;
while(vma!=task->mm->mmap){
count++;
vma = vma->vm_next;
if(!vma)
break;
}
}
static void func_2(void)
{
my_follow_page mfollow_page;
my_page_referenced mpage_referenced;
mfollow_page = (my_follow_page)0xffffffffb2e73af0 ;
mpage_referenced = (my_page_referenced)0xffffffffb2e8e030 ;
count1=count2=count3=count4=0;
task = pid_task(find_vpid(pid),PIDTYPE_PID);
if(!task)
return;
vma = task->mm->mmap;
//unsigned int foll_flags=0x04;
unsigned long addr;
while(vma){
addr=vma->vm_start;
if(!addr)
break;
//printk("addr=%ld\n",addr);
struct page* page=NULL;
while(addr!=vma->vm_end){
page=mfollow_page(vma,addr,FOLL_GET);
if(!page){
addr+=PAGE_SIZE;
continue;
}
//printk("page: %p\n",page);
count1++;
if(mpage_referenced(page, 0, page->mem_cgroup, &vma->vm_flags))
count2++;
if(PageAnon(page)){
count3++;
if(mpage_referenced(page, 0, page->mem_cgroup, &vma->vm_flags))
count4++;
}
addr+=PAGE_SIZE;
//printk("addr=%ld\n",addr);
}
vma = vma->vm_next;
//printk("next vma\n\n");
}
}
static void timer_func1(void){
func_1();
printk(KERN_ALERT"Test:func1 VMA count = %d\n", count);
return;
}
static void timer_func2(void){
func_2();
printk(KERN_ALERT"Test func 2\n");
printk(KERN_ALERT"file count= %d\n", count1);
printk(KERN_ALERT"active_file count = %d\n", count2);
printk(KERN_ALERT"anon count = %d\n", count3);
printk(KERN_ALERT"active_anon count = %d\n", count4);
return;
}
static int test_show(struct seq_file* m, void* v)
{
pid_t* pid_n = (pid_t*)m->private;
if (pid_n != NULL)
{
seq_printf(m, "%d\n", *pid_n);
}
return 0;
}
static int test_open(struct inode* inode, struct file* file)
{
return single_open(file, test_show, PDE_DATA(inode));
}
struct proc_ops test_ops = {
.proc_open = test_open,
.proc_read = seq_read,
.proc_release = single_release,
};
static void int2string(int x, char* c) {
int temp = x, len=0;
int i;
while (temp >= 10) {
len++;
temp = temp / 10;
}
temp = x;
for (i = len; i >= 0; i--) {
c[i] = 48 + temp % 10;
temp = temp / 10;
}
c[len+1] = '\0';
for(i=len+4;i>=4;i--)
c[i]=c[i-4];
c[0]='p';
c[1]='i';
c[2]='d';
c[3]='_';
return;
}
static void sysfs_test_to_do(void)
{
char s[20];
int2string(pid,s);
printk("s=%s\n",s);
if(proc_test != NULL)
{
proc_remove(proc_test);
// printk(KERN_ALERT"remove proc_pid successfully\n");
}
proc_test = proc_mkdir(s, NULL);
if (proc_test == NULL) {
printk("%d proc create %d failed\n",sysfs_test_func , pid);
return -EINVAL;
}
if (sysfs_test_func == 1){
timer_func1();
proc_create_data("vma_count", 0664, proc_test, &test_ops, &count);
return;
}
else if (sysfs_test_func == 2){
timer_func2();
proc_create_data("file", 0664, proc_test, &test_ops, &count1);
proc_create_data("active_file", 0664, proc_test, &test_ops, &count2);
proc_create_data("anon", 0664, proc_test, &test_ops, &count3);
proc_create_data("active_anon", 0664, proc_test, &test_ops, &count4);
return;
}
}
static int sysfs_testd_thread(void* nothing)
{
set_freezable();
set_user_nice(current, 5);
while (!kthread_should_stop())
{
mutex_lock(&sysfs_test_thread_mutex);
if (sysfs_testd_should_run())
sysfs_test_to_do();
mutex_unlock(&sysfs_test_thread_mutex);
try_to_freeze();
if (sysfs_testd_should_run())
{
schedule_timeout_interruptible(
msecs_to_jiffies(sysfs_test_thread_sleep_millisecs));
}
else
{
wait_event_freezable(sysfs_test_thread_wait,
sysfs_testd_should_run() || kthread_should_stop());
}
}
return 0;
}
#ifdef CONFIG_SYSFS
/*
* This all compiles without CONFIG_SYSFS, but is a waste of space.
*/
#define SYSFS_TEST_ATTR_RO(_name) \
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
#define SYSFS_TEST_ATTR(_name) \
static struct kobj_attribute _name##_attr = \
__ATTR(_name, 0644, _name##_show, _name##_store)
static ssize_t sleep_millisecs_show(struct kobject* kobj,
struct kobj_attribute* attr, char* buf)
{
return sprintf(buf, "%u\n", sysfs_test_thread_sleep_millisecs);
}
static ssize_t sleep_millisecs_store(struct kobject* kobj,
struct kobj_attribute* attr,
const char* buf, size_t count)
{
unsigned long msecs;
int err;
err = kstrtoul(buf, 10, &msecs);
if (err || msecs > UINT_MAX)
return -EINVAL;
sysfs_test_thread_sleep_millisecs = msecs;
return count;
}
SYSFS_TEST_ATTR(sleep_millisecs);
static ssize_t pid_show(struct kobject* kobj,
struct kobj_attribute* attr, char* buf)
{
return sprintf(buf, "%u\n", pid);
}
static ssize_t pid_store(struct kobject* kobj,
struct kobj_attribute* attr,
const char* buf, size_t count)
{
unsigned long tmp;
int err;
err = kstrtoul(buf, 10, &tmp);
if (err || tmp > UINT_MAX)
return -EINVAL;
pid = tmp;
return count;
}
SYSFS_TEST_ATTR(pid);
static ssize_t func_show(struct kobject* kobj,
struct kobj_attribute* attr, char* buf)
{
return sprintf(buf, "%u\n", sysfs_test_func);
}
static ssize_t func_store(struct kobject* kobj,
struct kobj_attribute* attr,
const char* buf, size_t count)
{
unsigned long tmp;
int err;
err = kstrtoul(buf, 10, &tmp);
if (err || tmp > UINT_MAX)
return -EINVAL;
sysfs_test_func = tmp;
return count;
}
SYSFS_TEST_ATTR(func);
static ssize_t run_show(struct kobject* kobj, struct kobj_attribute* attr,
char* buf)
{
return sprintf(buf, "%u\n", sysfs_test_run);
}
static ssize_t run_store(struct kobject* kobj, struct kobj_attribute* attr,
const char* buf, size_t count)
{
int err;
unsigned long flags;
err = kstrtoul(buf, 10, &flags);
if (err || flags > UINT_MAX)
return -EINVAL;
if (flags > SYSFS_TEST_RUN_START)
return -EINVAL;
mutex_lock(&sysfs_test_thread_mutex);
if (sysfs_test_run != flags)
{
sysfs_test_run = flags;
}
mutex_unlock(&sysfs_test_thread_mutex);
if (flags & SYSFS_TEST_RUN_START)
wake_up_interruptible(&sysfs_test_thread_wait);
return count;
}
SYSFS_TEST_ATTR(run);
static struct attribute* sysfs_test_attrs[] = {
// 扫描进程的扫描间隔 默认为20秒
&sleep_millisecs_attr.attr,
&pid_attr.attr,
&func_attr.attr,
&run_attr.attr,
NULL,
};
static struct attribute_group sysfs_test_attr_group = {
.attrs = sysfs_test_attrs,
.name = "sysfs_test",
};
#endif /* CONFIG_SYSFS */
static int sysfs_test_init(void)
{
int err;
sysfs_test_thread = kthread_run(sysfs_testd_thread, NULL, "sysfs_test");
if (IS_ERR(sysfs_test_thread))
{
pr_err("sysfs_test: creating kthread failed\n");
err = PTR_ERR(sysfs_test_thread);
goto out;
}
#ifdef CONFIG_SYSFS
err = sysfs_create_group(mm_kobj, &sysfs_test_attr_group);
if (err)
{
pr_err("sysfs_test: register sysfs failed\n");
kthread_stop(sysfs_test_thread);
goto out;
}
#else
sysfs_test_run = KSCAN_RUN_STOP;
#endif /* CONFIG_SYSFS */
out:
return err;
}
static void sysfs_test_exit(void)
{
proc_remove(proc_test);
if (sysfs_test_thread)
{
kthread_stop(sysfs_test_thread);
sysfs_test_thread = NULL;
}
#ifdef CONFIG_SYSFS
sysfs_remove_group(mm_kobj, &sysfs_test_attr_group);
#endif
printk("sysfs_test exit success!\n");
}
/* --- 随内核启动 --- */
// subsys_initcall(kscan_init);
module_init(sysfs_test_init);
module_exit(sysfs_test_exit);