mirror of
https://github.com/cirosantilli/linux-kernel-module-cheat.git
synced 2026-01-28 20:44:26 +01:00
CONFIG_PROC_EVENTS
This commit is contained in:
48
README.adoc
48
README.adoc
@@ -2357,8 +2357,7 @@ This-did not work on `arm` due to <<gdb-step-debug-kernel-module-arm>> so we nee
|
|||||||
* <<gdb-module_init>>
|
* <<gdb-module_init>>
|
||||||
* <<kernel-module-stack-trace-to-source-line>> post-mortem method
|
* <<kernel-module-stack-trace-to-source-line>> post-mortem method
|
||||||
|
|
||||||
[[dump_stack]]
|
==== dump_stack
|
||||||
==== dump_stack kernel module
|
|
||||||
|
|
||||||
The `dump_stack` function produces a stack trace much like panic and oops, but causes no problems and we return to the normal control flow, and can cleanly remove the module afterwards:
|
The `dump_stack` function produces a stack trace much like panic and oops, but causes no problems and we return to the normal control flow, and can cleanly remove the module afterwards:
|
||||||
|
|
||||||
@@ -2366,7 +2365,7 @@ The `dump_stack` function produces a stack trace much like panic and oops, but c
|
|||||||
insmod /dump_stack.ko
|
insmod /dump_stack.ko
|
||||||
....
|
....
|
||||||
|
|
||||||
==== warn_on kernel module
|
==== WARN_ON
|
||||||
|
|
||||||
The `WARN_ON` macro basically just calls <<dump_stack,dump_stack>>.
|
The `WARN_ON` macro basically just calls <<dump_stack,dump_stack>>.
|
||||||
|
|
||||||
@@ -2404,7 +2403,44 @@ TODO: font and keymap. Mentioned at: https://cmcenroe.me/2017/05/05/linux-consol
|
|||||||
* https://unix.stackexchange.com/questions/177024/remap-keyboard-on-the-linux-console
|
* https://unix.stackexchange.com/questions/177024/remap-keyboard-on-the-linux-console
|
||||||
* https://superuser.com/questions/194202/remapping-keys-system-wide-in-linux-not-just-in-x
|
* https://superuser.com/questions/194202/remapping-keys-system-wide-in-linux-not-just-in-x
|
||||||
|
|
||||||
=== ftrace
|
=== Linux kernel tracing
|
||||||
|
|
||||||
|
==== CONFIG_PROC_EVENTS
|
||||||
|
|
||||||
|
Logs proc events such as process creation to a link:https://en.wikipedia.org/wiki/Netlink[netlink socket].
|
||||||
|
|
||||||
|
We then have a userland program that listens to the events and prints them out:
|
||||||
|
|
||||||
|
....
|
||||||
|
# /proc_events.out &
|
||||||
|
# set mcast listen ok
|
||||||
|
# sleep 2 & sleep 1
|
||||||
|
fork: parent tid=48 pid=48 -> child tid=79 pid=79
|
||||||
|
fork: parent tid=48 pid=48 -> child tid=80 pid=80
|
||||||
|
exec: tid=80 pid=80
|
||||||
|
exec: tid=79 pid=79
|
||||||
|
# exit: tid=80 pid=80 exit_code=0
|
||||||
|
exit: tid=79 pid=79 exit_code=0
|
||||||
|
echo a
|
||||||
|
a
|
||||||
|
#
|
||||||
|
....
|
||||||
|
|
||||||
|
TODO: why `exit: tid=79` shows after `exit: tid=80`?
|
||||||
|
|
||||||
|
Note how `echo a` is a Bash built-in, and therefore does not spawn a new process.
|
||||||
|
|
||||||
|
TODO: why does this produce no output?
|
||||||
|
|
||||||
|
....
|
||||||
|
/proc_events.out >f &
|
||||||
|
....
|
||||||
|
|
||||||
|
* https://stackoverflow.com/questions/6075013/detect-launching-of-programs-on-linux-platform/8255487#8255487
|
||||||
|
* https://serverfault.com/questions/199654/does-anyone-know-a-simple-way-to-monitor-root-process-spawn
|
||||||
|
* https://unix.stackexchange.com/questions/260162/how-to-track-newly-created-processes
|
||||||
|
|
||||||
|
==== ftrace
|
||||||
|
|
||||||
Trace a single function:
|
Trace a single function:
|
||||||
|
|
||||||
@@ -2499,7 +2535,7 @@ TODO: what do `+` and `!` mean?
|
|||||||
|
|
||||||
Each `enable` under the `events/` tree enables a certain set of functions, the higher the `enable` more functions are enabled.
|
Each `enable` under the `events/` tree enables a certain set of functions, the higher the `enable` more functions are enabled.
|
||||||
|
|
||||||
=== Count boot instructions
|
==== Count boot instructions
|
||||||
|
|
||||||
* https://www.quora.com/How-many-instructions-does-a-typical-Linux-kernel-boot-take
|
* https://www.quora.com/How-many-instructions-does-a-typical-Linux-kernel-boot-take
|
||||||
* https://github.com/cirosantilli/chat/issues/31
|
* https://github.com/cirosantilli/chat/issues/31
|
||||||
@@ -4290,7 +4326,7 @@ See also:
|
|||||||
* https://en.wikipedia.org/wiki/Time_Stamp_Counter
|
* https://en.wikipedia.org/wiki/Time_Stamp_Counter
|
||||||
* https://stackoverflow.com/questions/9887839/clock-cycle-count-wth-gcc/9887979
|
* https://stackoverflow.com/questions/9887839/clock-cycle-count-wth-gcc/9887979
|
||||||
|
|
||||||
===== pmccntr kernel module
|
===== pmccntr
|
||||||
|
|
||||||
Unfortunately-we didn't manage to find an ARM analogue: link:kernel_module/pmccntr.c[] is oopsing, and even it if weren't, it likely won't give the cycle count since boot since it needs to be activate before it starts counting anything:
|
Unfortunately-we didn't manage to find an ARM analogue: link:kernel_module/pmccntr.c[] is oopsing, and even it if weren't, it likely won't give the cycle count since boot since it needs to be activate before it starts counting anything:
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ CONFIG_SCHED_TRACER=y
|
|||||||
CONFIG_STACK_TRACER=y
|
CONFIG_STACK_TRACER=y
|
||||||
CONFIG_TRACER_SNAPSHOT=y
|
CONFIG_TRACER_SNAPSHOT=y
|
||||||
|
|
||||||
|
# Process tracing.
|
||||||
|
CONFIG_CONNECTOR=y
|
||||||
|
CONFIG_PROC_EVENTS=y
|
||||||
|
|
||||||
# 9P
|
# 9P
|
||||||
CONFIG_9P_FS=y
|
CONFIG_9P_FS=y
|
||||||
CONFIG_9P_FS_POSIX_ACL=y
|
CONFIG_9P_FS_POSIX_ACL=y
|
||||||
|
|||||||
180
kernel_module/user/proc_events.c
Normal file
180
kernel_module/user/proc_events.c
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
/*
|
||||||
|
This file is licensed under the GPL v2 (http://www.gnu.org/licenses/gpl2.txt) (some parts was originally borrowed from proc events example)
|
||||||
|
|
||||||
|
https://stackoverflow.com/questions/6075013/detect-launching-of-programs-on-linux-platform/8255487#8255487
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 700
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
#include <linux/connector.h>
|
||||||
|
#include <linux/cn_proc.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static volatile bool need_exit = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* connect to netlink
|
||||||
|
* returns netlink socket, or -1 on error
|
||||||
|
*/
|
||||||
|
static int nl_connect()
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
int nl_sock;
|
||||||
|
struct sockaddr_nl sa_nl;
|
||||||
|
|
||||||
|
nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
|
||||||
|
if (nl_sock == -1) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
sa_nl.nl_family = AF_NETLINK;
|
||||||
|
sa_nl.nl_groups = CN_IDX_PROC;
|
||||||
|
sa_nl.nl_pid = getpid();
|
||||||
|
rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
|
||||||
|
if (rc == -1) {
|
||||||
|
perror("bind");
|
||||||
|
close(nl_sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return nl_sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* subscribe on proc events (process notifications)
|
||||||
|
*/
|
||||||
|
static int set_proc_ev_listen(int nl_sock, bool enable)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
|
||||||
|
struct nlmsghdr nl_hdr;
|
||||||
|
struct __attribute__ ((__packed__)) {
|
||||||
|
struct cn_msg cn_msg;
|
||||||
|
enum proc_cn_mcast_op cn_mcast;
|
||||||
|
};
|
||||||
|
} nlcn_msg;
|
||||||
|
|
||||||
|
memset(&nlcn_msg, 0, sizeof(nlcn_msg));
|
||||||
|
nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
|
||||||
|
nlcn_msg.nl_hdr.nlmsg_pid = getpid();
|
||||||
|
nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;
|
||||||
|
|
||||||
|
nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
|
||||||
|
nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
|
||||||
|
nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
|
||||||
|
|
||||||
|
nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
|
||||||
|
|
||||||
|
rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
|
||||||
|
if (rc == -1) {
|
||||||
|
perror("netlink send");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handle a single process event
|
||||||
|
*/
|
||||||
|
static int handle_proc_ev(int nl_sock)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
|
||||||
|
struct nlmsghdr nl_hdr;
|
||||||
|
struct __attribute__ ((__packed__)) {
|
||||||
|
struct cn_msg cn_msg;
|
||||||
|
struct proc_event proc_ev;
|
||||||
|
};
|
||||||
|
} nlcn_msg;
|
||||||
|
while (!need_exit) {
|
||||||
|
rc = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
|
||||||
|
if (rc == 0) {
|
||||||
|
/* shutdown? */
|
||||||
|
return 0;
|
||||||
|
} else if (rc == -1) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
perror("netlink recv");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
switch (nlcn_msg.proc_ev.what) {
|
||||||
|
case PROC_EVENT_NONE:
|
||||||
|
printf("set mcast listen ok\n");
|
||||||
|
break;
|
||||||
|
case PROC_EVENT_FORK:
|
||||||
|
printf("fork: parent tid=%d pid=%d -> child tid=%d pid=%d\n",
|
||||||
|
nlcn_msg.proc_ev.event_data.fork.parent_pid,
|
||||||
|
nlcn_msg.proc_ev.event_data.fork.parent_tgid,
|
||||||
|
nlcn_msg.proc_ev.event_data.fork.child_pid,
|
||||||
|
nlcn_msg.proc_ev.event_data.fork.child_tgid);
|
||||||
|
break;
|
||||||
|
case PROC_EVENT_EXEC:
|
||||||
|
printf("exec: tid=%d pid=%d\n",
|
||||||
|
nlcn_msg.proc_ev.event_data.exec.process_pid,
|
||||||
|
nlcn_msg.proc_ev.event_data.exec.process_tgid);
|
||||||
|
break;
|
||||||
|
case PROC_EVENT_UID:
|
||||||
|
printf("uid change: tid=%d pid=%d from %d to %d\n",
|
||||||
|
nlcn_msg.proc_ev.event_data.id.process_pid,
|
||||||
|
nlcn_msg.proc_ev.event_data.id.process_tgid,
|
||||||
|
nlcn_msg.proc_ev.event_data.id.r.ruid,
|
||||||
|
nlcn_msg.proc_ev.event_data.id.e.euid);
|
||||||
|
break;
|
||||||
|
case PROC_EVENT_GID:
|
||||||
|
printf("gid change: tid=%d pid=%d from %d to %d\n",
|
||||||
|
nlcn_msg.proc_ev.event_data.id.process_pid,
|
||||||
|
nlcn_msg.proc_ev.event_data.id.process_tgid,
|
||||||
|
nlcn_msg.proc_ev.event_data.id.r.rgid,
|
||||||
|
nlcn_msg.proc_ev.event_data.id.e.egid);
|
||||||
|
break;
|
||||||
|
case PROC_EVENT_EXIT:
|
||||||
|
printf("exit: tid=%d pid=%d exit_code=%d\n",
|
||||||
|
nlcn_msg.proc_ev.event_data.exit.process_pid,
|
||||||
|
nlcn_msg.proc_ev.event_data.exit.process_tgid,
|
||||||
|
nlcn_msg.proc_ev.event_data.exit.exit_code);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("unhandled proc event\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void on_sigint(__attribute__ ((unused)) int unused)
|
||||||
|
{
|
||||||
|
need_exit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int nl_sock;
|
||||||
|
int rc = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
signal(SIGINT, &on_sigint);
|
||||||
|
siginterrupt(SIGINT, true);
|
||||||
|
nl_sock = nl_connect();
|
||||||
|
if (nl_sock == -1)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
rc = set_proc_ev_listen(nl_sock, true);
|
||||||
|
if (rc == -1) {
|
||||||
|
rc = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = handle_proc_ev(nl_sock);
|
||||||
|
if (rc == -1) {
|
||||||
|
rc = EXIT_FAILURE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
set_proc_ev_listen(nl_sock, false);
|
||||||
|
out:
|
||||||
|
close(nl_sock);
|
||||||
|
exit(rc);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user