Модуль, реализующий поддержку протокола 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 функций.

На диаграмме ниже красные прямоугольники – это интерфейсные функции, которые могут являться поверхностью атаки.

Розовые прямоугольники – это интерфейсные функции, которые могут являться поверхностью атаки при вызовах из пользовательского пространства.

Темно-серые прямоугольники – это интерфейсные функции, которые не оперируют сетевыми данными и не является поверхностью атаки.

Зеленые ромбы на диаграммах - это элемент некоторой структуры, который является указателем на функцию. Если из ромба выходит стрелка, значит элементу соответствующей структуры присвоено имя функции, на которую указывает стрелка. Если стрелка входит в ромб из функции, значит в этой функции имеется вызов функции по соответствующему указателю. Зеленые прямоугольники – это структуры, переопределяющие структуру обозначенную зеленым ромбом.

8021q

Сводная таблица результатов анализа

Имя подмодуля и/или функцийНазначениеПоверхность атаки
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.