Ну что ж, руки дошли по такому поводу.
Демонстрирую "дырищу".в сырцах ядра:
kernel/kmod.c
* __request_module - try to load a kernel module
int __request_module(bool wait, const char *fmt, ...)
Эта функция сама запускает бинарий /sbin/modprobe
include/linux/kmod.h - тут есть удобный макрос на неё:
#define request_module(mod...) __request_module(true, mod)
А потом - просто грепаем по всия сырцам:
$ grep -r request_module |wc -l
534
$ grep -r request_module
net/sctp/probe.c: if (request_module("sctp"))
net/can/af_can.c: err = request_module("can-proto-%d", protocol);
net/can/af_can.c: printk_ratelimited(KERN_ERR "can: request_module "
net/core/dev_ioctl.c: no_module = request_module("netdev-%s", name);
net/core/dev_ioctl.c: request_module("%s", name);
net/core/rtnetlink.c: request_module("rtnl-link-%s", kind);
net/core/sock_diag.c: request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
net/core/sock_diag.c: request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
net/core/sock_diag.c: request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
net/core/sock_diag.c: request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
net/dccp/probe.c: ret = request_module("dccp");
net/ipv6/af_inet6.c: request_module("net-pf-%d-proto-%d-type-%d",
net/ipv6/af_inet6.c: request_module("net-pf-%d-proto-%d",
net/ipv6/netfilter/ip6_tables.c: t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
net/ipv6/netfilter/ip6_tables.c: t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
net/ipv6/netfilter/ip6_tables.c: try_then_request_module(xt_find_revision(AF_INET6, rev.name,
net/netlink/genetlink.c: request_module("net-pf-%d-proto-%d-family-%s",
net/netlink/af_netlink.c: request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol);
.....
Насчёт этого:
net/dccp/probe.c: ret = request_module("dccp");
Это тоже код модуля, зависимого от dccp, запрашивает собственно самого dccp при инициализации.
Ну и реальное доказательство. На примере conntrack:
убунта 16.04
кернель 4.4.0-62
Нет conntrack модуля
# lsmod|head -3
Module Size Used by
uas 24576 0
usb_storage 69632 1 uas
Дёрнули юзерлевелский conntrack
# conntrack -L >/dev/null
conntrack v1.4.3 (conntrack-tools): 346 flow entries have been shown.
И модуль уже загружен
# lsmod|head -3
Module Size Used by
nf_conntrack_netlink 40960 0
uas 24576 0
Ессьно, убеждаемся, что это не сама прога /usr/sbin/conntrack грузит модуль:
Удаляем модуль:
# rmmod nf_conntrack_netlink
# rmmod nf_conntrack_netlink
rmmod: ERROR: Module nf_conntrack_netlink is not currently loaded
Смотрим:
# lsmod|head -3
Module Size Used by
uas 24576 0
usb_storage 69632 1 uas
И пускаем conntrack под strace'ом, отслеживая execve():
# strace -s 300 -f -e execve conntrack -L >/dev/null
execve("/usr/sbin/conntrack", ["conntrack", "-L"], [/* 39 vars */]) = 0
conntrack v1.4.3 (conntrack-tools): 348 flow entries have been shown.
+++ exited with 0 +++
И как видим, сам бинарь ничего стороннего не вызывает.
А модуль - уже снова с нами:
# lsmod|head -3
Module Size Used by
nf_conntrack_netlink 40960 0
uas 24576 0
Да, бинарь мы пускали от рута конечно. Но факт автоматической загрузки модуля ядром - налицо. Кому интересно - в сырцах ядра можно порыться на предмет наличия загрузки при обращении за функциональносью и нерутового юзера.
Добро пожаловать в реальность.