proc_events.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. This file is licensed under the GPL v2 (http://www.gnu.org/licenses/gpl2.txt) (some parts was originally borrowed from proc events example)
  3. https://stackoverflow.com/questions/6075013/detect-launching-of-programs-on-linux-platform/8255487#8255487
  4. */
  5. #if defined(__aarch64__)
  6. int main() {}
  7. #else
  8. #define _XOPEN_SOURCE 700
  9. #include <sys/socket.h>
  10. #include <linux/netlink.h>
  11. #include <linux/connector.h>
  12. #include <linux/cn_proc.h>
  13. #include <signal.h>
  14. #include <errno.h>
  15. #include <stdbool.h>
  16. #include <unistd.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <stdio.h>
  20. static volatile bool need_exit = false;
  21. /*
  22. * connect to netlink
  23. * returns netlink socket, or -1 on error
  24. */
  25. static int nl_connect()
  26. {
  27. int rc;
  28. int nl_sock;
  29. struct sockaddr_nl sa_nl;
  30. nl_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
  31. if (nl_sock == -1) {
  32. perror("socket");
  33. return -1;
  34. }
  35. sa_nl.nl_family = AF_NETLINK;
  36. sa_nl.nl_groups = CN_IDX_PROC;
  37. sa_nl.nl_pid = getpid();
  38. rc = bind(nl_sock, (struct sockaddr *)&sa_nl, sizeof(sa_nl));
  39. if (rc == -1) {
  40. perror("bind");
  41. close(nl_sock);
  42. return -1;
  43. }
  44. return nl_sock;
  45. }
  46. /*
  47. * subscribe on proc events (process notifications)
  48. */
  49. static int set_proc_ev_listen(int nl_sock, bool enable)
  50. {
  51. int rc;
  52. struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
  53. struct nlmsghdr nl_hdr;
  54. struct __attribute__ ((__packed__)) {
  55. struct cn_msg cn_msg;
  56. enum proc_cn_mcast_op cn_mcast;
  57. };
  58. } nlcn_msg;
  59. memset(&nlcn_msg, 0, sizeof(nlcn_msg));
  60. nlcn_msg.nl_hdr.nlmsg_len = sizeof(nlcn_msg);
  61. nlcn_msg.nl_hdr.nlmsg_pid = getpid();
  62. nlcn_msg.nl_hdr.nlmsg_type = NLMSG_DONE;
  63. nlcn_msg.cn_msg.id.idx = CN_IDX_PROC;
  64. nlcn_msg.cn_msg.id.val = CN_VAL_PROC;
  65. nlcn_msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
  66. nlcn_msg.cn_mcast = enable ? PROC_CN_MCAST_LISTEN : PROC_CN_MCAST_IGNORE;
  67. rc = send(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
  68. if (rc == -1) {
  69. perror("netlink send");
  70. return -1;
  71. }
  72. return 0;
  73. }
  74. /*
  75. * handle a single process event
  76. */
  77. static int handle_proc_ev(int nl_sock)
  78. {
  79. int rc;
  80. struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
  81. struct nlmsghdr nl_hdr;
  82. struct __attribute__ ((__packed__)) {
  83. struct cn_msg cn_msg;
  84. struct proc_event proc_ev;
  85. };
  86. } nlcn_msg;
  87. while (!need_exit) {
  88. rc = recv(nl_sock, &nlcn_msg, sizeof(nlcn_msg), 0);
  89. if (rc == 0) {
  90. /* shutdown? */
  91. return 0;
  92. } else if (rc == -1) {
  93. if (errno == EINTR) continue;
  94. perror("netlink recv");
  95. return -1;
  96. }
  97. switch (nlcn_msg.proc_ev.what) {
  98. case PROC_EVENT_NONE:
  99. printf("set mcast listen ok\n");
  100. break;
  101. case PROC_EVENT_FORK:
  102. printf("fork: parent tid=%d pid=%d -> child tid=%d pid=%d\n",
  103. nlcn_msg.proc_ev.event_data.fork.parent_pid,
  104. nlcn_msg.proc_ev.event_data.fork.parent_tgid,
  105. nlcn_msg.proc_ev.event_data.fork.child_pid,
  106. nlcn_msg.proc_ev.event_data.fork.child_tgid);
  107. break;
  108. case PROC_EVENT_EXEC:
  109. printf("exec: tid=%d pid=%d\n",
  110. nlcn_msg.proc_ev.event_data.exec.process_pid,
  111. nlcn_msg.proc_ev.event_data.exec.process_tgid);
  112. break;
  113. case PROC_EVENT_UID:
  114. printf("uid change: tid=%d pid=%d from %d to %d\n",
  115. nlcn_msg.proc_ev.event_data.id.process_pid,
  116. nlcn_msg.proc_ev.event_data.id.process_tgid,
  117. nlcn_msg.proc_ev.event_data.id.r.ruid,
  118. nlcn_msg.proc_ev.event_data.id.e.euid);
  119. break;
  120. case PROC_EVENT_GID:
  121. printf("gid change: tid=%d pid=%d from %d to %d\n",
  122. nlcn_msg.proc_ev.event_data.id.process_pid,
  123. nlcn_msg.proc_ev.event_data.id.process_tgid,
  124. nlcn_msg.proc_ev.event_data.id.r.rgid,
  125. nlcn_msg.proc_ev.event_data.id.e.egid);
  126. break;
  127. case PROC_EVENT_EXIT:
  128. printf("exit: tid=%d pid=%d exit_code=%d\n",
  129. nlcn_msg.proc_ev.event_data.exit.process_pid,
  130. nlcn_msg.proc_ev.event_data.exit.process_tgid,
  131. nlcn_msg.proc_ev.event_data.exit.exit_code);
  132. break;
  133. default:
  134. printf("unhandled proc event\n");
  135. break;
  136. }
  137. }
  138. return 0;
  139. }
  140. static void on_sigint(__attribute__ ((unused)) int unused)
  141. {
  142. need_exit = true;
  143. }
  144. int main()
  145. {
  146. int nl_sock;
  147. int rc = EXIT_SUCCESS;
  148. signal(SIGINT, &on_sigint);
  149. siginterrupt(SIGINT, true);
  150. nl_sock = nl_connect();
  151. if (nl_sock == -1)
  152. exit(EXIT_FAILURE);
  153. rc = set_proc_ev_listen(nl_sock, true);
  154. if (rc == -1) {
  155. rc = EXIT_FAILURE;
  156. goto out;
  157. }
  158. rc = handle_proc_ev(nl_sock);
  159. if (rc == -1) {
  160. rc = EXIT_FAILURE;
  161. goto out;
  162. }
  163. set_proc_ev_listen(nl_sock, false);
  164. out:
  165. close(nl_sock);
  166. exit(rc);
  167. }
  168. #endif