How to kill a user process in kernel

这篇博客探讨了在Linux内核中如何杀死一个包含多个线程的进程,以及在进程被信号杀死时文件资源的清理过程。通过示例代码展示了获取进程PID、加载内核模块传递PID、验证进程被逐个杀死的过程。实验表明,线程的死亡顺序是随机的,不是按特定顺序进行。文章还详细解释了内核如何处理文件关闭,包括引用计数、文件关闭的上下文和释放机制。最后讨论了fork、execve以及多线程进程在执行execve后的状态变化,以及pthread_exit对其他线程的影响。
摘要由CSDN通过智能技术生成

demo codes:


#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/stat.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/seq_file.h>
#include <linux/sched/signal.h>
#include <linux/proc_fs.h>
#include <linux/pid.h>
#include <linux/pci.h>
#include <linux/usb.h>
#include <linux/kobject.h>
#include <linux/sched/mm.h>
#include <linux/platform_device.h>
 
MODULE_AUTHOR("zlcao");
MODULE_LICENSE("GPL");
 
int seqfile_debug_mode = 0;
EXPORT_SYMBOL(seqfile_debug_mode);
module_param(seqfile_debug_mode, int, 0664);

int pid_number = -1;
EXPORT_SYMBOL(pid_number);
module_param(pid_number, int, 0664);
 
static void kill_processes(int pid_nr);
// 开始输出任务列表
// my_seq_ops_start()的返回值,会传递给my_seq_ops_next()的v参数
static void *my_seq_ops_start(struct seq_file *m, loff_t *pos)
{
    loff_t index = *pos;
    struct task_struct *task;
 
    printk("%s line %d, index %lld.count %ld, size %ld here.\n", __func__, __LINE__, index, m->count, m->size);
 
    if(seqfile_debug_mode == 0) {
        // 如果缓冲区不足, seq_file可能会重新调用start()函数,
        // 并且传入的pos是之前已经遍历到的位置,
        // 这里需要根据pos重新计算开始的位置
        for_each_process(task) {
            if (index-- == 0) {
                return task;
            }
        }
    } else {
        return NULL + (*pos == 0);
    }
 
    return NULL;
}
 
// 继续遍历, 直到my_seq_ops_next()放回NULL或者错误
static void *my_seq_ops_next(struct seq_file *m, void *v, loff_t *pos)
{
    struct task_struct *task = NULL;
 
    if(seqfile_debug_mode == 0) {
        task = next_task((struct task_struct *)v);
 
        // 这里加不加好像都没有作用
        ++ *pos;
 
        // 返回NULL, 遍历结束
        if(task == &init_task) {
            return NULL;
        }
    } else {
        ++ *pos;
    }
 
    return task;
}
 
// 遍历完成/出错时seq_file会调用stop()函数
static void my_seq_ops_stop(struct seq_file *m, void *v)
{
 
}
 
static int lookup_pci_devices(struct device *dev, void *data)
{
    struct seq_file *m = (struct seq_file *)data;
    struct pci_dev *pdev = to_pci_dev(dev);
 
    seq_printf(m, "vendor id 0x%x, device id 0x%x, devname %s.\n", pdev->vendor, pdev->device, dev_name(&pdev->dev));
 
    return 0;
}
 
static int lookup_pci_drivers(struct device_driver *drv, void *data)
{
    struct seq_file *m = (struct seq_file *)data;
    seq_printf(m, "driver name %s.\n", drv->name);
 
    return 0;
}

static int lookup_platform_devices(struct device *dev, void *data)
{
    struct seq_file *m = (struct seq_file *)data;
    struct platform_device *platdev = to_platform_device(dev);
 
    seq_printf(m, "devpath %s.\n", platdev->name);
 
    return 0;
}
 
static int lookup_platform_drivers(struct device_driver *drv, void *data)
{
    struct seq_file *m = (struct seq_file *)data;
    seq_printf(m, "driver name %s.\n", drv->name);
 
    return 0;
}
 
static int list_device_belongs_todriver_pci(struct device *dev, void *p) 
{
    struct seq_file *m = (struct seq_file *)p;
    struct pci_dev *pdev = to_pci_dev(dev);
 
    seq_printf(m, "vendor id 0x%x, device id 0x%x, devname %s.\n", pdev->vendor, pdev->device, dev_name(&pdev->dev));
 
    return 0;
}

static int list_device_belongs_todriver_platform(struct device *dev, void *p) 
{
    struct seq_file *m = (struct seq_file *)p;
    struct platform_device *platdev = to_platform_device(dev);
 
    seq_printf(m, "platdevname %s.\n", platdev->name);
 
    return 0;
}
 
static int pcie_device_info(struct pci_dev *pdev, void *data)
{
    struct seq_file *m = (struct seq_file *)data;
 
    seq_printf(m, "vendor id 0x%04x, device id 0x%04x, devname %s, belongs to bus %16s, parent bus name %6s subordinate 0x%p.\n", \
            pdev->vendor, pdev->device, dev_name(&pdev->dev), pdev->bus->name, pdev->bus->parent? pdev->bus->parent->name : "null", pdev->subordinate);
 
    if(pdev->subordinate) {
        seq_printf(m, "    subordinate have bus name %s.\n", pdev->subordinate->name);
        if(pdev->subordinate->self) {
            seq_printf(m, "        subordinate have dev name %s.\n", dev_name(&pdev->subordinate->self->dev));
            if(pdev->subordinate->self != pdev) {
                seq_printf(m, "            cant happend!\n");
            } else {
                seq_printf(m, "            surely!\n");
            }
        }
 
    } else {
        seq_printf(m, "    subordinate not have.\n");
    }
    
    if(pdev->bus->self) {
        seq_printf(m, "    device belongs to child pci bus %s.\n", dev_name(&pdev->bus->self->dev));
    } else {
        seq_printf(m, "    device belongs to top lvl pci bus.\n");
    }
 
    seq_printf(m, "\n");
    return 0;
}

static ssize_t zilong_attr_show(struct kobject *kobj, struct attribute *attr,char *buf)
{
    return 0;
}

static ssize_t zilong_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t count)
{
    return 0;
}

static const struct sysfs_ops zilong_sysfs_ops = {
    .show   = zilong_attr_show,
    .store  = zilong_attr_store,
};

static struct kobj_type zilong_ktype = {
    .release        = NULL,
    .sysfs_ops      = &zilong_sysfs_ops,
    .namespace      = NULL,
    .get_ownership  = NULL,
};
 
// 此函数将数据写入`seq_file`内部的缓冲区
// `seq_file`会在合适的时候把缓冲区的数据拷贝到应用层
// 参数@V是start/next函数的返回值
static int my_seq_ops_show(struct seq_file *m, void *v)
{
    struct task_struct *task = NULL;
    struct task_struct *tsk = NULL;
    struct task_struct *p = NULL;
    struct file *file = m->private;
    struct pid *session = NULL;
 
    if(seqfile_debug_mode == 0) {
        seq_puts(m, " file=");
        seq_file_path(m, file, "\n");
        seq_putc(m, ' ');
 
        task = (struct task_struct *)v;
        session = task_session(task);
        tsk = pid_task(session, PIDTYPE_PID);
        if(task->flags & PF_KTHREAD) {
            seq_printf(m, "Kernel thread: PID=%u, task: %s, index=%lld, read_pos=%lld, %s.\n", task->tgid, task->comm, m->index, m->read_pos, tsk? "has session" : "no session");
        } else {
            seq_printf(m, "User thread: PID=%u, task: %s, index=%lld, read_pos=%lld %s.\n", task->tgid, task->comm, m->index, m->read_pos, tsk? "has session" : "no session");
        }
    } else if(seqfile_debug_mode == 1) {
        struct task_struct *g, *p;
        static int oldcount = 0;
        static int entercount = 0;
        char *str;
 
        printk("%s line %d here enter %d times.\n", __func__, __LINE__, ++ entercount);
        seq_printf(m, "%s line %d here enter %d times.\n", __func__, __LINE__, ++ entercount);
 
        rcu_read_lock();
        for_each_process_thread(g, p) {
            struct task_struct *session = pid_task(task_session(g), PIDTYPE_PID);
            struct task_struct *thread = pid_task(task_session(p), PIDTYPE_PID);
            struct task_struct *ggroup = pid_task(task_pgrp(g), PIDTYPE_PID);
            struct task_struct *pgroup = pid_task(task_pgrp(p), PIDTYPE_PID);
            struct pid * pid = task_session(g);
 
            if(list_empty(&p->tasks)) {
                str = "empty";
            } else {
                str = "not empty";
            }
            seq_printf(m, "process %s(pid %d tgid %d,cpu%d) thread %s(pid %d tgid %d,cpu%d),threadnum %d, %d. tasks->prev = %p, tasks->next = %p, p->tasks=%p, %s, process parent %s(pid %d tgid %d), thread parent%s(pid %d, tgid %d, files %p\n)",
                    g->comm, task_pid_nr(g), task_tgid_nr(g), task_cpu(g), \
                    p->comm, task_pid_nr(p), task_tgid_nr(p), task_cpu(p), \
                    get_nr_threads(g), get_nr_threads(p), p->tasks.prev, p->tasks.next, &p->tasks, str, g->real_parent->comm, \
                    task_pid_nr(g->real_parent),task_tgid_nr(g->real_parent), p->real_parent->comm, task_pid_nr(p->real_parent), task_tgid_nr(p->real_parent), p->files);
 
            if(ggroup) {
                seq_printf(m, "ggroup(pid %d tgid %d).", task_pid_nr(ggroup),task_tgid_nr(ggroup));
            }
 
            if(pgroup) {
                seq_printf(m, "pgroup(pid %d tgid %d).", task_pid_nr(pgroup),task_tgid_nr(pgroup));
            }
 
            seq_printf(m, "current smp processor id %d.", smp_processor_id());
            if(thread) {
                seq_printf(m, "thread session %s(%d).", thread->comm, task_pid_nr(thread));
            }
            if(session) {
                seq_printf(m, "process session %s(%d).", session->comm, task_pid_nr(session));
            }
 
            if(oldcount == 0 || oldcount != m->size) {
                printk("%s line %d, m->count %ld, m->size %ld.", __func__, __LINE__, m->count, m->size);
                oldcount = m->size;
            }
 
            if(pid){
                seq_printf(m, "pid task %p,pgid task %p, psid_task %p", pid_task(pid, PIDTYPE_PID), pid_task(pid, PIDTYPE_PGID), pid_task(pid, PIDTYPE_SID));
                seq_printf(m, "pid task %s,pgid task %s, psid_task %s", pid_task(pid, PIDTYPE_PID)->comm, pid_task(pid, PIDTYPE_PGID)->comm, pid_task(pid, PIDTYPE_SID)->comm);
            }
            seq_printf(m, "\n");
        }
 
        rcu_read_unlock();
    } else if(seqfile_debug_mode == 2) {
        for_each_process(task) {
            struct pid *pgrp = task_pgrp(task);
 
            seq_printf(m, "Group Header %s(%d,cpu%d):\n", task->comm, task_pid_nr(task), task_cpu(task));
            do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
                seq_printf(m, "      process %s(%d,cpu%d) thread %s(%d,cpu%d),threadnum %d, %d.\n",
                    task->comm, task_pid_nr(task), task_cpu(task), \
                    p->comm, task_pid_nr(p), task_cpu(p), \
                    get_nr_threads(task), get_nr_threads(p));
            } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
        }
    } else if (seqfile_debug_mode == 3) {
        for_each_process(task) {
            struct pid *session = task_session(task);
            struct task_struct *tsk = pid_task(session, PIDTYPE_PID);
            if(tsk) {
                seq_printf(m, "session task %s(%d,cpu%d):", tsk->comm, task_pid_nr(tsk), task_cpu(tsk));
            } else {
                seq_printf(m, "process %s(%d,cpu%d) has no session task.", task->comm, task_pid_nr(task), task_cpu(task));
            }
 
            seq_printf(m, "session header %s(%d,cpu%d):\n", task->comm, task_pid_nr(task), task_cpu(task));
            do_each_pid_task(session, PIDTYPE_SID, p) {
                seq_printf(m, "      process %s(%d,cpu%d) thread %s(%d,cpu%d),threadnum %d, %d, spidtask %s(%d,%d).\n",
                    task->comm, task_pid_nr(task), task_cpu(task), \
                    p->comm, task_pid_nr(p), task_cpu(p), \
                    get_nr_threads(task), get_nr_threads(p), pid_task(session, PIDTYPE_SID)->comm, pid_task(session, PIDTYPE_SID)->tgid, pid_task(session, PIDTYPE_SID)->pid);
                if(pid_task(session, PIDTYPE_PID)) {
                    seq_printf(m, "pidtask %s(%d,%d).\n", pid_task(session, PIDTYPE_PID)->comm, pid_task(session, PIDTYPE_PID)->tgid, pid_task(session, PIDTYPE_PID)->pid);
                }
            } while_each_pid_task(pgrp, PIDTYPE_SID, p);
        }
    } else if(seqfile_debug_mode == 4) {
        struct task_struct *thread, *child;
        for_each_process(task) {
            seq_printf(m, "process %s(%d,cpu%d):\n", task->comm, task_pid_nr(task), task_cpu(task));
            for_each_thread(task, thread) {
                list_for_each_entry(child, &thread->children, sibling) {
                    seq_printf(m, "      thread %s(%d,cpu%d) child %s(%d,cpu%d),threadnum %d, %d.\n",
                        thread->comm, task_pid_nr(thread), task_cpu(thread), \
                        child->comm, task_pid_nr(child), task_cpu(child), \
                        get_nr_threads(thread), get_nr_threads(child));
                }
            }
        }
    } else if(seqfile_debug_mode == 5) { 
        struct task_struct *g, *t;
        do_each_thread (g, t) {
            seq_printf(m, "Process %s(%d cpu%d), thread %s(%d cpu%d), threadnum %d.\n", g->comm, task_pid_nr(g), task_cpu(g), t->comm, task_pid_nr(t), task_cpu(t), get_nr_threads(g));
        } while_each_thread (g, t);
    } else if(seqfile_debug_mode == 6) {
        for_each_process(task) {
            struct pid *pid = task_pid(task);
 
            seq_printf(m, "Process %s(%d,cpu%d) pid %d, tgid %d:\n", task->comm, task_pid_nr(task), task_cpu(task), task_pid_vnr(task), task_tgid_vnr(task));
            do_each_pid_task(pid, PIDTYPE_TGID, p) {
                seq_printf(m, "      process %s(%d,cpu%d) thread %s(%d,cpu%d),threadnum %d, %d. pid %d, tgid %d\n",
                        task->comm, task_pid_nr(task), task_cpu(task), \
                        p->comm, task_pid_nr(p), task_cpu(p), \
                        get_nr_threads(task), get_nr_threads(p), task_pid_vnr(p), task_tgid_vnr(p));
            } while_each_pid_task(pid, PIDTYPE_TGID, p);
        }
    } else if(seqfile_debug_mode == 7) {
        for_each_process(task) {
            struct pid *pid = task_pid(task);
 
            seq_printf(m, "Process %s(%d,cpu%d) pid %d, tgid %d:\n", task->comm, task_pid_nr(task), task_cpu(task), task_pid_vnr(task), task_tgid_vnr(task));
            do_each_pid_task(pid, PIDTYPE_PID, p) {
                seq_printf(m, "      process %s(%d,cpu%d) thread %s(%d,cpu%d),threadnum %d, %d. pid %d, tgid %d\n",
                    task->comm, task_pid_nr(task), task_cpu(task), \
                    p->comm, task_pid_nr(p), task_cpu(p), \
                    get_nr_threads(task), get_nr_threads(p), task_pid_vnr(p), task_tgid_vnr(p));
            } while_each_pid_task(pid, PIDTYPE_PID, p);
        }
    } else if(seqfile_debug_mode == 8) {
        bus_for_each_dev(&pci_bus_type, NULL, (void*)m, lookup_pci_devices);
        bus_for_each_drv(&pci_bus_type, NULL, (void*)m, lookup_pci_drivers);
    } else if(seqfile_debug_mode == 9) {
        struct device_driver *drv; 
        drv = driver_find("pcieport", &pci_bus_type);
        driver_for_each_device(drv, NULL, (void*)m, list_device_belongs_todriver_pci);
    } else if(seqfile_debug_mode == 10) {
        for_each_process(task) {
            seq_printf(m, "Process %s(%d),state 0x%08lx, exit_state 0x%08x, refcount %d, usage %d rcucount %d.", \
                task->comm, task->tgid, task->state, task->exit_state, refcount_read(&task->stack_refcount), refcount_read(&task->usage), refcount_read(&task->rcu_users));
        if(task->parent) {
                seq_printf(m, "parent name %s pid %d.\n", task->parent->comm, task->parent->tgid);
        } else {
                seq_printf(m, "no parent.\n");
        }
        }
    } else if(seqfile_debug_mode == 11) {
        struct pci_bus *bus;
        list_for_each_entry(bus, &pci_root_buses, node) {
            seq_printf(m, "pcibus name %s.\n", bus->name);
            pci_walk_bus(bus, pcie_device_info, (void*)m);
        }
    } else if(seqfile_debug_mode == 12) {
        struct device_driver *drv; 
        // EXPORT_SYMBOL(usb_bus_type);
        // bus_for_each_dev(&usb_bus_type, NULL, (void*)m, lookup_usb_devices);
        // bus_for_each_drv(&usb_bus_type, NULL, (void*)m, lookup_usb_drivers);
        bus_for_each_dev(&platform_bus_type, NULL, (void*)m, lookup_platform_devices);
        bus_for_each_drv(&platform_bus_type, NULL, (void*)m, lookup_platform_drivers);

        drv = driver_find("demo_platform", &platform_bus_type);
        driver_for_each_device(drv, NULL, (void*)m, list_device_belongs_todriver_platform);
    } else if(seqfile_debug_mode == 13) {
        static struct kset *class_zilong;
        static struct kobject kobj;
        int ret;

        class_zilong = kset_create_and_add("zilong_class", NULL, NULL);
        if (!class_zilong) {
            printk("%s line %d, fatal error, create class failure.\n", __func__, __LINE__);
            return -ENOMEM;
        }

        ret = kobject_init_and_add(&kobj, &zilong_ktype, &class_zilong->kobj, "%s-%d", "zilong", 1);
        if(ret < 0) {
            printk("%s line %d, fatal error, create class failure.\n", __func__, __LINE__);
            return -ENOMEM;
        }
    } else if(seqfile_debug_mode == 14) {
        // cad pid is process 1 pid.
        int ret = kill_cad_pid(SIGINT, 1);
        printk("%s lne %d ret %d.\n", __func__, __LINE__, ret);
    } else if(seqfile_debug_mode == 15) {
        kill_processes(pid_number);
    } else {
        printk("%s line %d,cant be here, seqfile_debug_mode = %d.\n", __func__, __LINE__, seqfile_debug_mode);
    }
 
    return 0;
}

static struct task_struct *find_lock_task_mm(struct task_struct *p)
{
    struct task_struct *t;

    rcu_read_lock();
    for_each_thread(p, t) {
        task_lock(t);
        if (likely(t->mm))
            goto found;
        task_unlock(t);
    }

    t = NULL;
found:
    rcu_read_unlock();
    return t;
}  

static bool process_shares_task_mm(struct task_struct *p, struct mm_struct *mm)
{
    struct task_struct *t;
    for_each_thread(p, t) {
        struct mm_struct *t_mm = READ_ONCE(t->mm);
        if (t_mm)
            return t_mm == mm;
    }
    return false;
} 

static void kill_processes(int pid_nr)
{
    struct task_struct *victim;
    struct task_struct *p;
    struct mm_struct *mm;

    victim = get_pid_task(find_vpid(pid_nr), PIDTYPE_PID);
    if(victim == NULL) {
        printk("%s line %d,return.\n", __func__, __LINE__);
        return;
    }

    printk("%s line %d, task has live %d threads total.\n", __func__, __LINE__, atomic_read(&victim->signal->live));

    p = find_lock_task_mm(victim);
    if (!p) {
        put_task_struct(victim);
        return;
    } else {
        get_task_struct(p);
        put_task_struct(victim);
        victim = p;
    }

    mm = victim->mm;
    mmgrab(mm);

    kill_pid(find_vpid(pid_nr), SIGKILL, 1);
    task_unlock(victim);

    rcu_read_lock();
    for_each_process(p) {
        if (!process_shares_task_mm(p, mm))
            continue;
        if (same_thread_group(p, victim))
            continue;
        if (unlikely(p->flags & PF_KTHREAD))
            continue;
        kill_pid(get_pid(task_pid(p)), SIGKILL, 1);
   }

   rcu_read_unlock(); 
   mmdrop(mm);
   while(atomic_read(&victim->signal->live)) {
        printk("%s line %d, live %d.\n", __func__, __LINE__, atomic_read(&victim->signal->live));
   }
   put_task_struct(victim);
}

 
static const struct seq_operations my_seq_ops = {
    .start  = my_seq_ops_start,
    .next   = my_seq_ops_next,
    .stop   = my_seq_ops_stop,
    .show   = my_seq_ops_show,
};
 
static int proc_seq_open(struct inode *inode, struct file *file)
{
    int ret;
    struct seq_file *m;
 
    ret = seq_open(file, &my_seq_ops);
    if(!ret) {
        m = file->private_data; 
        m->private = file;
    }
 
    return ret;
}
 
static ssize_t proc_seq_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos)
{
    char debug_string[16];
    int debug_no;
 
    memset(debug_string, 0x00, sizeof(debug_string));
    if (count >= sizeof(debug_string)) {
        printk("%s line %d, fata error, write count exceed max buffer size.\n", __func__, __LINE__);
        return -EINVAL;
    }
 
    if (copy_from_user(debug_string, buffer, count)) {
        printk("%s line %d, fata error, copy from user failure.\n", __func__, __LINE__);
        return -EFAULT;
    }
 
    if (sscanf(debug_string, "%d", &debug_no) <= 0) {
        printk("%s line %d, fata error, read debugno failure.\n", __func__, __LINE__);
        return -EFAULT;
    }
 
    seqfile_debug_mode = debug_no;
 
    //printk("%s line %d, debug_no %d.\n", __func__, __LINE__, debug_no);
 
    return count;
}
 
static ssize_t proc_seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    ssize_t ret;
 
    printk("%s line %d enter, fuck size %lld size %ld.\n"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值