summaryrefslogtreecommitdiff
path: root/md/notes/kernel/usermode_helper.md
blob: 5ac75329017cf719b4da0db0468aba83093052a1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
title:User mode helper
keywords:kernel,linux,threads

# User mode helper

## Adding usermode helper

Here is diff of added new usermode helper

```diff
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c6d9dec11..5d0b5b0ea 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -82,6 +82,8 @@
 #include <linux/rtmutex.h>
 #endif
 
+#include <linux/hacks.h>
+
 /* shared constants to be used in various sysctls */
 const int sysctl_vals[] = { 0, 1, 2, 3, 4, 100, 200, 1000, 3000, INT_MAX, 65535, -1 };
 EXPORT_SYMBOL(sysctl_vals);
@@ -2091,6 +2093,13 @@ static struct ctl_table kern_table[] = {
                .extra2         = SYSCTL_INT_MAX,
        },
 #endif
+       {
+               .procname       = "secret_parth",
+                .data           = &sysctl_secret_path,
+                .maxlen         = sizeof(sysctl_secret_path),
+                .mode           = 0644,
+                .proc_handler   = proc_dostring,
+               },
        { }
 };
 ```

create file __hacks.h__ under the __include/linux/hacks.h__

```c
static char sysctl_secret_path[256] = "/usr/bin/utility";
```

Add to kernel and rebuild then run system with new kernel.
After reboot there should be file at __/proc/sys/kernel__
```sh
/proc/sys/kernel/sysctl_secret_path
```

Now we can set values with echo and when kernel module executes the path will be executed

```sh
echo "/usr/bin/utility" > /proc/sys/kernel/sysctl_secret_path
```

Lets write utility that dumps time to file at /tmp. 

Dump time utility
```c
#include <stdio.h>
#include <time.h>
#include <string.h>

int main() {
	FILE *f=NULL;
	time_t t;
	struct tm *tm;
	char str[128];

	f = fopen("/tmp/date","w+");
	if (f == NULL) {
		printf("cannot create file\n");
	}
	printf("Start utility\n");
	printf("Date today\n");

	time(&t);
	tm = localtime(&t);
	strftime(str, sizeof(str), "%A %c\n", tm);
	printf("Date %s\n", str);

	printf("Dump to file /tmp/date\n");
	
	fwrite(str, strlen(str), 1, f);

	

	printf("Stop utility\n");

	fclose(f);

	return 0;
}
```

Compile and copy under the /usr/bin directory

Call usermod helper from kernel module

## Kernel module starting point

__usermod_helper.c__
```c
//http://www.tldp.org/LDP/lkmpg/2.4/html/c147.htm
#include <linux/module.h>  /* Needed by all modules */
#include <linux/kernel.h>

int usermod_helper_init( void )
{
	printk(KERN_DEBUG "Hello World!\n");
	return 0;
}

void usermod_helper_exit( void )
{
	printk(KERN_DEBUG "Exit Hello World!\n");
}

module_init( usermod_helper_init );
module_exit( usermod_helper_exit );

MODULE_LICENSE("GPL");
```


Call usermode helper from a driver

```c
...
#include <linux/hacks.h>
...

void run_usermode_helper(void) {
       char *argv[1];
       char *envp[3];
       int ret;

       //no args
       argv[0] = 0;

       //basic env
       envp[0] = "HOME=/";
       envp[1] = "PATH=/sbin:/usr/sbin:/usr/bin";
       envp[2] = 0;

       ret = call_usermodehelper(argv[0], argv, envp, 0);
}

int usermode_helper_init( void )
{
    printk(KERN_DEBUG "Hello usermode!\n");

    run_usermode_helper();

    return 0;
}
```

Run 
```sh
 sudo insmod usermode_helper.ko
```

Now there should be file /tmp/date that is created with utility called by driver

## Links

https://www.raspberrypi.com/documentation/computers/linux_kernel.html#updating-your-kernel