Модуль, реализующий поддержку протокола IEEE 802.1q (net/8021q)
Ниже представлены результаты анализа поверхности атаки для модуля 8021q с точки зрения зависимости от сетевого трафика.
Модуль 8021Q обеспечивает функциональность виртуальных сетей VLAN на основе стандартов 802.1Q/802.1ad, включая протоколы GVRP (GARP VLAN Registration Protocol) и MVRP (Multiple VLAN Registration Protocol).
Модуль 8021q состоит из четырех подсистем (9 файлов: 7 - *.c, 2 - *.h):
- основная функциональность:
vlan.с,vlan_dev.c,vlan_netlink.c,vlan_core.c; - VLAN_8021Q_GVRP:
vlan_gvrp.c; - VLAN_8021Q_MVRP:
vlan_mvrp.c; - PROC_FS:
vlanproc.c.
Основной интерфейс (функции маркированные EXPORT_SYMBOL) находится в vlan_core.c и состоит из 12 функций.
На диаграмме ниже красные прямоугольники – это интерфейсные функции, которые могут являться поверхностью атаки.
Розовые прямоугольники – это интерфейсные функции, которые могут являться поверхностью атаки при вызовах из пользовательского пространства.
Темно-серые прямоугольники – это интерфейсные функции, которые не оперируют сетевыми данными и не является поверхностью атаки.
Зеленые ромбы на диаграммах - это элемент некоторой структуры, который является указателем на функцию. Если из ромба выходит стрелка, значит элементу соответствующей структуры присвоено имя функции, на которую указывает стрелка. Если стрелка входит в ромб из функции, значит в этой функции имеется вызов функции по соответствующему указателю. Зеленые прямоугольники – это структуры, переопределяющие структуру обозначенную зеленым ромбом.

Сводная таблица результатов анализа
| Имя подмодуля и/или функций | Назначение | Поверхность атаки |
|---|---|---|
| vlan_gvrp.c | Часть интерфейса протокола GVRP | Нет |
| vlan_mvrp.c | Часть интерфейса протокола MVRP | Нет |
| vlanproc.c | Поддержка специальной файловой системы PROCFS | Нет |
| vlan.c | Регистрация и инициализация vlan устройств, функции IOCTL, вызовы notifier_block | Нет |
| vlan_netlink.c: vlan_validate, vlan_newlink, vlan_changelink | Использование каналов netlink для vlan | Да |
| vlan_dev.c | Управление настройками vlan устройств, поддержка ethtool, инициализация структур header_ops и net_device_ops | |
| vlan_dev_hard_start_xmit | Используется при отправке пакетов | Да |
| vlan_dev_hard_header, vlan_passthru_hard_header | Создание заголовка VLAN для протоколов любого уровня | Да |
| vlan_core.c | Основной интерфейс vlan | |
| vlan_do_receive | Используется для входящего трафика | Да |
| vlan_gro_receive, vlan_gro_complete | Механизм GRO | Да |
Распределение функций, являющихся поверхностью атаки, по направлению трафика
| Имя функции | Направление трафика |
|---|---|
| vlan_netlink.c | |
| vlan_validate | Внутренний между пользователем и ядром |
| vlan_newlink | Внутренний между пользователем и ядром |
| vlan_changelink | Внутренний между пользователем и ядром |
| vlan_dev.c | |
| vlan_dev_hard_start_xmit | Исходящий |
| vlan_dev_hard_header | В обе стороны |
| vlan_passthru_hard_header | В обе стороны |
| vlan_core.c | |
| vlan_do_receive | Входящий |
| vlan_gro_receive | Входящий |
| vlan_gro_complete | Входящий |
Ниже перечислены все файлы и список функций, доступных вне модуля.
vlan_gvrp.c
С сетевыми данными ни одна функция не работает, однако, протокол использует инфраструктуру протокола GARP (net/802/garp.c) с потенциально опасными функциями, в том числе функцию garp_pdu_rcv, которая является обработчиком входящих сообщений.
int vlan_gvrp_request_join(const struct net_device *dev)
void vlan_gvrp_request_leave(const struct net_device *dev)
int vlan_gvrp_init_applicant(struct net_device *dev)
void vlan_gvrp_uninit_applicant(struct net_device *dev)
int __init vlan_gvrp_init(void)
void vlan_gvrp_uninit(void)
vlan_mvrp.c
С сетевыми данными ни одна функция не работает, однако, протокол использует инфраструктуру протокола MRP (net/802/mrp.c) с потенциально опасными функциями, в том числе функцию mrp_rcv, которая является обработчиком входящих сообщений.
int vlan_mvrp_request_join(const struct net_device *dev)
void vlan_mvrp_request_leave(const struct net_device *dev)
int vlan_mvrp_init_applicant(struct net_device *dev)
void vlan_mvrp_uninit_applicant(struct net_device *dev)
int __init vlan_mvrp_init(void)
void vlan_mvrp_uninit(void)
vlanproc.c
С сетевыми данными ни одна функция не работает.
static const struct seq_operations vlan_seq_ops = {
.start = vlan_seq_start,
.next = vlan_seq_next,
.stop = vlan_seq_stop,
.show = vlan_seq_show,
};
int vlan_proc_init(struct net *net);
void vlan_proc_rem_dev(struct net_device *vlandev);
int vlan_proc_add_dev(struct net_device *vlandev);
void vlan_proc_cleanup(struct net *net);
vlan_netlink.c
struct rtnl_link_ops vlan_link_ops __read_mostly = {
.kind = "vlan",
.maxtype = IFLA_VLAN_MAX,
.policy = vlan_policy,
.priv_size = sizeof(struct vlan_dev_priv),
.setup = vlan_setup,
.validate = vlan_validate,
.newlink = vlan_newlink,
.changelink = vlan_changelink,
.dellink = unregister_vlan_dev,
.get_size = vlan_get_size,
.fill_info = vlan_fill_info,
.get_link_net = vlan_get_link_net,
};
int __init vlan_netlink_init(void)
void __exit vlan_netlink_fini(void)
Только одна функция использует структуру skb, но она только добавляет в эту структуру атрибуты netlink:
static int vlan_fill_info(struct sk_buff *skb, const struct net_device *dev).
Интерес представляют только три функции:
static int vlan_validate(struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack),
static int vlan_changelink(struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack),
static int vlan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack),
Эти функции вызываются через функции __rtnl_newlink и rtnl_newlink (net/core/rtnetlink.c).
Они не обрабатывают входящий трафик, но могут использоваться для передачи данных из пользовательского пространства в ядро через структуру struct nlattr, которая кодирует данные в формате TLV ("type-length-value").
Остальные функции с сетевыми данными не работают.
vlan.c
static struct notifier_block vlan_notifier_block __read_mostly = {
.notifier_call = vlan_device_event,
};
static int vlan_ioctl_handler
vlan_ioctl_set(vlan_ioctl_handler);
void unregister_vlan_dev(struct net_device *dev, struct list_head *head)
int register_vlan_dev(struct net_device *dev, struct netlink_ext_ack *extack)
int vlan_check_real_dev(struct net_device *real_dev, __be16 protocol, u16 vlan_id, struct netlink_ext_ack *extack)
static struct pernet_operations vlan_net_ops = {
.init = vlan_init_net,
.exit = vlan_exit_net,
.id = &vlan_net_id,
.size = sizeof(struct vlan_net),
};
С сетевыми данными ни одна функция не работает.
vlan_dev.c
static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
const void *daddr, const void *saddr,
unsigned int len)
static const struct header_ops vlan_header_ops = {
.create = vlan_dev_hard_header,
.parse = eth_header_parse,
};
static int vlan_passthru_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type,
const void *daddr, const void *saddr,
unsigned int len)
static const struct header_ops vlan_passthru_header_ops = {
.create = vlan_passthru_hard_header,
.parse = eth_header_parse,
};
static const struct net_device_ops vlan_netdev_ops = {
.ndo_start_xmit = vlan_dev_hard_start_xmit,
...
};
static const struct ethtool_ops vlan_ethtool_ops = {
.get_link_ksettings = vlan_ethtool_get_link_ksettings,
.get_drvinfo = vlan_ethtool_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_ts_info = vlan_ethtool_get_ts_info,
};
void vlan_dev_set_ingress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio)
int vlan_dev_set_egress_priority(const struct net_device *dev, u32 skb_prio, u16 vlan_prio)
int vlan_dev_change_flags(const struct net_device *dev, u32 flags, u32 mask)
void vlan_dev_get_realdev_name(const struct net_device *dev, char *result)
bool vlan_dev_inherit_address(struct net_device *dev, struct net_device *real_dev)
void vlan_dev_uninit(struct net_device *dev)
void vlan_setup(struct net_device *dev)
Три функции работают с пакетами:
vlan_dev_hard_start_xmitиспользуется при отправке пакетов.vlan_dev_hard_headerсоздает заголовок VLAN для протоколов любого уровня.vlan_passthru_hard_headerсоздает заголовок через функцию dev_hard_header.
Функции vlan_dev_hard_header и vlan_passthru_hard_header вызываются через структуру struct header_ops.create. Как указывалось в обзоре модуля Ethernet, такие функции могут использоваться, как для входящего, так и для исходящего трафика.
vlan_core.c
Содержит основной интерфейс – функции маркированные EXPORT_SYMBOL.
bool vlan_do_receive(struct sk_buff **skbp);
EXPORT_SYMBOL:
__vlan_find_dev_deep_rcu
vlan_dev_real_dev
vlan_dev_vlan_id
vlan_dev_vlan_proto
vlan_for_each
vlan_filter_push_vids
vlan_filter_drop_vids
vlan_vid_add
vlan_vid_del
vlan_vids_add_by_dev
vlan_vids_del_by_dev
vlan_uses_dev
static struct sk_buff *vlan_gro_receive(struct list_head *head, struct sk_buff *skb)
static int vlan_gro_complete(struct sk_buff *skb, int nhoff)
static struct packet_offload vlan_packet_offloads[] __read_mostly = {
{
.type = cpu_to_be16(ETH_P_8021Q),
.priority = 10,
.callbacks = {
.gro_receive = vlan_gro_receive,
.gro_complete = vlan_gro_complete,
},
},
{
.type = cpu_to_be16(ETH_P_8021AD),
.priority = 10,
.callbacks = {
.gro_receive = vlan_gro_receive,
.gro_complete = vlan_gro_complete,
},
},
};
Здесь три функции, которые работают с пакетами входящего трафика:
vlan_do_receive
vlan_gro_receive
vlan_gro_complete
Заключение
Проведенный анализ модуля 8021q (net/8021q) показал, что 6 функций этого модуля представляют поверхность атаки для сетевого трафика. 1 используется для исходящего трафика, 3 – для входящего, 2 могут использоваться в обоих направлениях. Кроме того 3 функции представляют поверхность атаки при использовании каналов netlink.