Changing the PID of a process in Linux using a kernel module.


Attention! after changing the PID, our drivers will not be suitable for oscill. Others will be needed. If you forget this, attempts to install oscill on a new PC will be unsuccessful.

PID - Product IDentifier/number product characteristics USB devices, together with VID (Vendor IDentifier - manufacturer number) uniquely characterizes this device from the host side. Drivers for each connected device are installed and run using VID/PID.

Oscilloscope usb.oscill assigned a unique VID+PID, accordingly they are supplied with drivers for Windows 98, 98SE, ME, 2000, XP, Vista, Seven (and are available for download on this site). However, for the following cases:

  • using oscill in Linux OS (software in virtual machine) - option for FreeBSD
  • connecting oscill to Pocket PC / Windows Mobile via virtual COM port
  • Windows Seven 64bit with mandatory driver signing

You may need to use standard Silabs drivers, which will require replacing the PID oscill on PID Silabs. It can be done special utility SetPID:

It is recommended to change the PID on EA61, and use the new version of the software and DLL driver Silabs v3.X. This software provides automatic and manual USB selection drivers between v2.0 and v3.X. For manual selection you need to do: Link-Setup-Port-Driver-V3

Attention! Changing the PID with this utility is only possible on a PC running Windows control, where the driver corresponding to the current PID is already installed. Otherwise, SetPID will not see oscill. That is, oscill must be present in the "Device Manager" of the "Control Panel". Algorithm:

  1. if the USB (or VCP) driver from this section is already installed, the setpid utility will show PID=840E, and you can change the PID to generic SILABS;
  2. SetPID will lose oscill, it will also disappear in Device Manager;
  3. Windows will find a new device for which you need to download a standard driver from Silabs for PID EA60 or for PID EA61
  4. this driver is signed and the shell should start working with it.

Reverse procedure:

  1. after installation standard driver, the SetPID utility detects oscill with PID=EA60 or EA61
  2. you can return custom OSCILL PID by pressing the corresponding button
  3. SetPID will show the original PID oscill= 840E

In addition to setpid, to change the PID you can use the utility from Silabs: on this page select an144.pdf And an144sw.zip

Note: User Usatenko on the forum published a recipe for changing PID on a single computer with Win7 64

  • Abnormal programming,
  • Programming
  • In this article we will try to create a kernel module that can change the PID already running process in Linux OS, and also experiment with processes that have received a changed PID.


    Warning: Changing the PID is a non-standard process, and under certain circumstances can lead to a kernel panic.

    Our test module will implement the /dev/test character device, which will change the process's PID when reading from it. Thanks to the article for the example of implementing a character device. The full module code is given at the end of the article. Of course, the most correct solution was to add a system call to the kernel itself, but this would require recompiling the kernel.

    Environment

    All module testing activities were performed in a virtual VirtualBox machine with 64-bit LInux distribution and kernel version 4.14.4-1. Communication with the machine was carried out using SSH.

    Attempt #1 simple solution

    A few words about current: the current variable points to a task_struct structure with a description of the process in the kernel (PID, UID, GID, cmdline, namespaces, etc.)

    The first idea was to simply change the current->pid parameter from the kernel module to the desired one.

    Static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset) ( printk("PID: %d.\n",current->pid); current->pid = 1; printk("new PID: %d.\n",current->pid); , )
    To check the functionality of the module, I wrote a program in C++:

    #include #include #include int main() ( std::cout<< "My parent PID " << getppid() << std::endl; std::cout << "My PID " << getpid() << std::endl; std::fstream f("/dev/test",std::ios_base::in); if(!f) { std::cout << "f error"; return -1; } std::string str; f >>str; std::cout<< "My new PID " << getpid() << std::endl; execl("/bin/bash","/bin/bash",NULL); }
    Let's load the module with the insmod command, create /dev/test and try it.

    # ./a.out My parent PID 293 My PID 782 My new PID 782
    PID has not changed. This may not be the only place where the PID is specified.

    Attempt #2 additional PID fields

    If current->pid is not the process identifier, then what is it? A quick look at the getpid() code pointed to a task_struct structure that describes the Linux process and pid.c file in the kernel source code. The required function is __task_pid_nr_ns. In the function code there is a call task->pids.pid, we will change this parameter

    Compile and try

    Since I tested via SSH, I was able to get the program output before the kernel crashed:

    My parent PID 293 My PID 1689 My new PID 1689
    The first result is already something. But the PID still hasn't changed.

    Attempt #3 non-exportable kernel symbols

    A closer look at pid.c yielded a function that does what we need
    static void __change_pid(struct task_struct *task, enum pid_type type,
    struct pid *new)
    The function accepts a task for which it is necessary to change the PID, the PID type and, in fact, the new PID. The function creates a new PID
    struct pid *alloc_pid(struct pid_namespace *ns)

    This function only accepts the namespace in which the new PID will reside, this space can be obtained using task_active_pid_ns .
    But there is one problem: these kernel symbols are not exported by the kernel and cannot be used in modules. A wonderful one helped me in solving this problem. The find_sym function code is taken from there.

    Static asmlinkage void (*change_pidR)(struct task_struct *task, enum pid_type type, struct pid *pid); static asmlinkage struct pid* (*alloc_pidR)(struct pid_namespace *ns); static int __init test_init(void) ( printk(KERN_ALERT "TEST driver loaded!\n"); change_pidR = find_sym("change_pid"); alloc_pidR = find_sym("alloc_pid"); ... ) static ssize_t device_read(struct file * filp, char *buffer, size_t length, loff_t * offset) ( printk("PID: %d.\n",current->pid); struct pid* newpid; newpid = alloc_pidR(task_active_pid_ns(current)); change_pidR(current ,PIDTYPE_PID,newpid); printk("new PID: %d.\n",current->pid); ... )
    Compile, launch

    My parent PID 299 My PID 750 My new PID 751
    PID changed! The kernel automatically allocated a free PID to our program. But is it possible to use a PID that has been occupied by another process, such as PID 1? Let's add the code after the allocation

    Newpid->numbers.nr = 1;
    Compile, launch

    My parent PID 314 My PID 1172 My new PID 1
    We get real PID 1!

    Bash has thrown a bug that prevents task switching using the %n command from working, but all other functions work fine.

    Interesting features of processes with changed PID

    PID 0: enter cannot exit

    Let's go back to the code and change the PID to 0.

    Newpid->numbers.nr = 0;
    Compile, launch

    My parent PID284 My PID 1517 My new PID 0
    So PID 0 is not that special? We rejoice, write exit and...

    The cannonball is falling! The kernel defined our task as IDLE TASK and, seeing completion, simply crashed. Apparently, our program must return to its “normal” PID before exiting.

    Invisible process

    Let's go back to the code and set a PID that is guaranteed not to be busy
    newpid->numbers.nr = 12345;

    Compile, launch

    My parent PID296 My PID 735 My new PID 12345
    Let's see what's in /proc

    1 148 19 224 288 37 79 86 93 consoles fb kcore locks partitions swaps version 10 149 2 226 29 4 8 87 acpi cpuinfo filesystems key-users meminfo sched_debug sys vmallocinfo 102 15 20 23 290 5 80 88 asound crypto fs keys misc schedstat sysrq- trigger vmstat 11 16 208 24 291 6 81 89 buddyinfo devices interrupts kmsg modules scsi sysvipc zoneinfo 12 17 21 25 296 7 82 9 bus diskstats iomem kpagecgroup mounts self thread-self 13 176 210 26 3 737 83 90 cgroups d ma ioports kpagecount mtrr slabinfo timer_list 139 18 22 27 30 76 84 91 cmdline driver irq kpageflags net softirqs tty 14 182 222 28 31 78 85 92 config.gz execdomains kallsyms loadavg pagetypeinfo stat uptime
    As we can see, /proc does not identify our process, even if we have occupied a free PID. The previous PID is also not in /proc, and this is very strange. Perhaps we are in a different namespace and therefore not visible to main /proc. Let's mount a new /proc and see what's there

    1 14 18 210 25 291 738 81 9 bus devices fs key-users locks pagetypeinfo softirqs timer_list 10 148 182 22 26 296 741 82 90 cgroups diskstats interrupts keys meminfo partitions stat tty 102 149 19 222 27 30 7 6 83 92 cmdline dma iomem kmsg misc sched_debug swaps uptime 11 15 2 224 28 37 78 84 93 config.gz driver ioports kpagecgroup modules schedstat sys version 12 16 20 226 288 4 79 85 acpi consoles execdomains irq kpagecount mounts scsi sysrq-trigger vmallocinfo 13 17 208 23 29 6 8 86 asound cpuinfo fb ​​kallsyms kpageflags mtrr self sysvipc vmstat 139 176 21 24 290 7 80 87 buddyinfo crypto filesystems kcore loadavg net slabinfo thread-self zoneinfo
    Our process still does not exist, which means we are in the normal namespace. Let's check

    Ps -e | grep bash
    296 pts/0 00:00:00 bash

    Only one bash, from which we launched the program. Neither the previous PID nor the current one is in the list.



    In this article, we will try to create a kernel module that can change the PID of an already running process in Linux, and also experiment with processes that have received a changed PID.


    Warning: Changing the PID is a non-standard process, and under certain circumstances can lead to a kernel panic.

    Our test module will implement the /dev/test character device, which will change the process's PID when reading from it. Thanks to this article for an example of implementing a character device. The full module code is given at the end of the article. Of course, the most correct solution was to add a system call to the kernel itself, but this would require recompiling the kernel.

    Environment

    All module testing activities were performed in a VirtualBox virtual machine with a 64-bit LInux distribution and kernel version 4.14.4-1. Communication with the machine was carried out using SSH.

    Attempt #1 simple solution

    A few words about current: the current variable points to a task_struct structure with a description of the process in the kernel (PID, UID, GID, cmdline, namespaces, etc.)

    The first idea was to simply change the current->pid parameter from the kernel module to the desired one.

    Static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t * offset) ( printk("PID: %d.\n",current->pid); current->pid = 1; printk("new PID: %d.\n",current->pid); , )
    To check the functionality of the module, I wrote a program in C++:

    #include #include #include int main() ( std::cout<< "My parent PID " << getppid() << std::endl; std::cout << "My PID " << getpid() << std::endl; std::fstream f("/dev/test",std::ios_base::in); if(!f) { std::cout << "f error"; return -1; } std::string str; f >>str; std::cout<< "My new PID " << getpid() << std::endl; execl("/bin/bash","/bin/bash",NULL); }
    Let's load the module with the insmod command, create /dev/test and try it.

    # ./a.out My parent PID 293 My PID 782 My new PID 782
    PID has not changed. This may not be the only place where the PID is specified.

    Attempt #2 additional PID fields

    If current->pid is not the process identifier, then what is it? A quick look at the getpid() code pointed to a task_struct structure that describes the Linux process and pid.c file in the kernel source code. The required function is __task_pid_nr_ns. In the function code there is a call task->pids.pid, we will change this parameter

    Compile and try

    Since I tested via SSH, I was able to get the program output before the kernel crashed:

    My parent PID 293 My PID 1689 My new PID 1689
    The first result is already something. But the PID still hasn't changed.

    Attempt #3 non-exportable kernel symbols

    A closer look at pid.c yielded a function that does what we need
    static void __change_pid(struct task_struct *task, enum pid_type type,
    struct pid *new)
    The function accepts a task for which it is necessary to change the PID, the PID type and, in fact, the new PID. The function creates a new PID
    struct pid *alloc_pid(struct pid_namespace *ns)

    This function only accepts the namespace in which the new PID will reside, this space can be obtained using task_active_pid_ns .
    But there is one problem: these kernel symbols are not exported by the kernel and cannot be used in modules. A wonderful one helped me in solving this problem. The find_sym function code is taken from there.

    Static asmlinkage void (*change_pidR)(struct task_struct *task, enum pid_type type, struct pid *pid); static asmlinkage struct pid* (*alloc_pidR)(struct pid_namespace *ns); static int __init test_init(void) ( printk(KERN_ALERT "TEST driver loaded!\n"); change_pidR = find_sym("change_pid"); alloc_pidR = find_sym("alloc_pid"); ... ) static ssize_t device_read(struct file * filp, char *buffer, size_t length, loff_t * offset) ( printk("PID: %d.\n",current->pid); struct pid* newpid; newpid = alloc_pidR(task_active_pid_ns(current)); change_pidR(current ,PIDTYPE_PID,newpid); printk("new PID: %d.\n",current->pid); ... )
    Compile, launch

    My parent PID 299 My PID 750 My new PID 751
    PID changed! The kernel automatically allocated a free PID to our program. But is it possible to use a PID that has been occupied by another process, such as PID 1? Let's add the code after the allocation

    Newpid->numbers.nr = 1;
    Compile, launch

    My parent PID 314 My PID 1172 My new PID 1
    We get real PID 1!

    Bash has thrown a bug that prevents task switching using the %n command from working, but all other functions work fine.

    Interesting features of processes with changed PID

    PID 0: enter cannot exit

    Let's go back to the code and change the PID to 0.

    Newpid->numbers.nr = 0;
    Compile, launch

    My parent PID284 My PID 1517 My new PID 0
    So PID 0 is not that special? We rejoice, write exit and...

    The cannonball is falling! The kernel defined our task as IDLE TASK and, seeing completion, simply crashed. Apparently, our program must return to its “normal” PID before exiting.

    Invisible process

    Let's go back to the code and set a PID that is guaranteed not to be busy
    newpid->numbers.nr = 12345;

    Compile, launch

    My parent PID296 My PID 735 My new PID 12345
    Let's see what's in /proc

    1 148 19 224 288 37 79 86 93 consoles fb kcore locks partitions swaps version 10 149 2 226 29 4 8 87 acpi cpuinfo filesystems key-users meminfo sched_debug sys vmallocinfo 102 15 20 23 290 5 80 88 asound crypto fs keys misc schedstat sysrq- trigger vmstat 11 16 208 24 291 6 81 89 buddyinfo devices interrupts kmsg modules scsi sysvipc zoneinfo 12 17 21 25 296 7 82 9 bus diskstats iomem kpagecgroup mounts self thread-self 13 176 210 26 3 737 83 90 cgroups d ma ioports kpagecount mtrr slabinfo timer_list 139 18 22 27 30 76 84 91 cmdline driver irq kpageflags net softirqs tty 14 182 222 28 31 78 85 92 config.gz execdomains kallsyms loadavg pagetypeinfo stat uptime
    As we can see, /proc does not identify our process, even if we have occupied a free PID. The previous PID is also not in /proc, and this is very strange. Perhaps we are in a different namespace and therefore not visible to main /proc. Let's mount a new /proc and see what's there

    1 14 18 210 25 291 738 81 9 bus devices fs key-users locks pagetypeinfo softirqs timer_list 10 148 182 22 26 296 741 82 90 cgroups diskstats interrupts keys meminfo partitions stat tty 102 149 19 222 27 30 7 6 83 92 cmdline dma iomem kmsg misc sched_debug swaps uptime 11 15 2 224 28 37 78 84 93 config.gz driver ioports kpagecgroup modules schedstat sys version 12 16 20 226 288 4 79 85 acpi consoles execdomains irq kpagecount mounts scsi sysrq-trigger vmallocinfo 13 17 208 23 29 6 8 86 asound cpuinfo fb ​​kallsyms kpageflags mtrr self sysvipc vmstat 139 176 21 24 290 7 80 87 buddyinfo crypto filesystems kcore loadavg net slabinfo thread-self zoneinfo
    Our process still does not exist, which means we are in the normal namespace. Let's check

    Ps -e | grep bash
    296 pts/0 00:00:00 bash

    Only one bash, from which we launched the program. Neither the previous PID nor the current one is in the list.





    

    2024 gtavrl.ru.