cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

netlabel_addrlist.c (9886B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * NetLabel Network Address Lists
      4 *
      5 * This file contains network address list functions used to manage ordered
      6 * lists of network addresses for use by the NetLabel subsystem.  The NetLabel
      7 * system manages static and dynamic label mappings for network protocols such
      8 * as CIPSO and RIPSO.
      9 *
     10 * Author: Paul Moore <paul@paul-moore.com>
     11 */
     12
     13/*
     14 * (c) Copyright Hewlett-Packard Development Company, L.P., 2008
     15 */
     16
     17#include <linux/types.h>
     18#include <linux/rcupdate.h>
     19#include <linux/list.h>
     20#include <linux/spinlock.h>
     21#include <linux/in.h>
     22#include <linux/in6.h>
     23#include <linux/ip.h>
     24#include <linux/ipv6.h>
     25#include <net/ip.h>
     26#include <net/ipv6.h>
     27#include <linux/audit.h>
     28
     29#include "netlabel_addrlist.h"
     30
     31/*
     32 * Address List Functions
     33 */
     34
     35/**
     36 * netlbl_af4list_search - Search for a matching IPv4 address entry
     37 * @addr: IPv4 address
     38 * @head: the list head
     39 *
     40 * Description:
     41 * Searches the IPv4 address list given by @head.  If a matching address entry
     42 * is found it is returned, otherwise NULL is returned.  The caller is
     43 * responsible for calling the rcu_read_[un]lock() functions.
     44 *
     45 */
     46struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
     47					     struct list_head *head)
     48{
     49	struct netlbl_af4list *iter;
     50
     51	list_for_each_entry_rcu(iter, head, list)
     52		if (iter->valid && (addr & iter->mask) == iter->addr)
     53			return iter;
     54
     55	return NULL;
     56}
     57
     58/**
     59 * netlbl_af4list_search_exact - Search for an exact IPv4 address entry
     60 * @addr: IPv4 address
     61 * @mask: IPv4 address mask
     62 * @head: the list head
     63 *
     64 * Description:
     65 * Searches the IPv4 address list given by @head.  If an exact match if found
     66 * it is returned, otherwise NULL is returned.  The caller is responsible for
     67 * calling the rcu_read_[un]lock() functions.
     68 *
     69 */
     70struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
     71						   __be32 mask,
     72						   struct list_head *head)
     73{
     74	struct netlbl_af4list *iter;
     75
     76	list_for_each_entry_rcu(iter, head, list)
     77		if (iter->valid && iter->addr == addr && iter->mask == mask)
     78			return iter;
     79
     80	return NULL;
     81}
     82
     83
     84#if IS_ENABLED(CONFIG_IPV6)
     85/**
     86 * netlbl_af6list_search - Search for a matching IPv6 address entry
     87 * @addr: IPv6 address
     88 * @head: the list head
     89 *
     90 * Description:
     91 * Searches the IPv6 address list given by @head.  If a matching address entry
     92 * is found it is returned, otherwise NULL is returned.  The caller is
     93 * responsible for calling the rcu_read_[un]lock() functions.
     94 *
     95 */
     96struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
     97					     struct list_head *head)
     98{
     99	struct netlbl_af6list *iter;
    100
    101	list_for_each_entry_rcu(iter, head, list)
    102		if (iter->valid &&
    103		    ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
    104			return iter;
    105
    106	return NULL;
    107}
    108
    109/**
    110 * netlbl_af6list_search_exact - Search for an exact IPv6 address entry
    111 * @addr: IPv6 address
    112 * @mask: IPv6 address mask
    113 * @head: the list head
    114 *
    115 * Description:
    116 * Searches the IPv6 address list given by @head.  If an exact match if found
    117 * it is returned, otherwise NULL is returned.  The caller is responsible for
    118 * calling the rcu_read_[un]lock() functions.
    119 *
    120 */
    121struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
    122						   const struct in6_addr *mask,
    123						   struct list_head *head)
    124{
    125	struct netlbl_af6list *iter;
    126
    127	list_for_each_entry_rcu(iter, head, list)
    128		if (iter->valid &&
    129		    ipv6_addr_equal(&iter->addr, addr) &&
    130		    ipv6_addr_equal(&iter->mask, mask))
    131			return iter;
    132
    133	return NULL;
    134}
    135#endif /* IPv6 */
    136
    137/**
    138 * netlbl_af4list_add - Add a new IPv4 address entry to a list
    139 * @entry: address entry
    140 * @head: the list head
    141 *
    142 * Description:
    143 * Add a new address entry to the list pointed to by @head.  On success zero is
    144 * returned, otherwise a negative value is returned.  The caller is responsible
    145 * for calling the necessary locking functions.
    146 *
    147 */
    148int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
    149{
    150	struct netlbl_af4list *iter;
    151
    152	iter = netlbl_af4list_search(entry->addr, head);
    153	if (iter != NULL &&
    154	    iter->addr == entry->addr && iter->mask == entry->mask)
    155		return -EEXIST;
    156
    157	/* in order to speed up address searches through the list (the common
    158	 * case) we need to keep the list in order based on the size of the
    159	 * address mask such that the entry with the widest mask (smallest
    160	 * numerical value) appears first in the list */
    161	list_for_each_entry_rcu(iter, head, list)
    162		if (iter->valid &&
    163		    ntohl(entry->mask) > ntohl(iter->mask)) {
    164			__list_add_rcu(&entry->list,
    165				       iter->list.prev,
    166				       &iter->list);
    167			return 0;
    168		}
    169	list_add_tail_rcu(&entry->list, head);
    170	return 0;
    171}
    172
    173#if IS_ENABLED(CONFIG_IPV6)
    174/**
    175 * netlbl_af6list_add - Add a new IPv6 address entry to a list
    176 * @entry: address entry
    177 * @head: the list head
    178 *
    179 * Description:
    180 * Add a new address entry to the list pointed to by @head.  On success zero is
    181 * returned, otherwise a negative value is returned.  The caller is responsible
    182 * for calling the necessary locking functions.
    183 *
    184 */
    185int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
    186{
    187	struct netlbl_af6list *iter;
    188
    189	iter = netlbl_af6list_search(&entry->addr, head);
    190	if (iter != NULL &&
    191	    ipv6_addr_equal(&iter->addr, &entry->addr) &&
    192	    ipv6_addr_equal(&iter->mask, &entry->mask))
    193		return -EEXIST;
    194
    195	/* in order to speed up address searches through the list (the common
    196	 * case) we need to keep the list in order based on the size of the
    197	 * address mask such that the entry with the widest mask (smallest
    198	 * numerical value) appears first in the list */
    199	list_for_each_entry_rcu(iter, head, list)
    200		if (iter->valid &&
    201		    ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
    202			__list_add_rcu(&entry->list,
    203				       iter->list.prev,
    204				       &iter->list);
    205			return 0;
    206		}
    207	list_add_tail_rcu(&entry->list, head);
    208	return 0;
    209}
    210#endif /* IPv6 */
    211
    212/**
    213 * netlbl_af4list_remove_entry - Remove an IPv4 address entry
    214 * @entry: address entry
    215 *
    216 * Description:
    217 * Remove the specified IP address entry.  The caller is responsible for
    218 * calling the necessary locking functions.
    219 *
    220 */
    221void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
    222{
    223	entry->valid = 0;
    224	list_del_rcu(&entry->list);
    225}
    226
    227/**
    228 * netlbl_af4list_remove - Remove an IPv4 address entry
    229 * @addr: IP address
    230 * @mask: IP address mask
    231 * @head: the list head
    232 *
    233 * Description:
    234 * Remove an IP address entry from the list pointed to by @head.  Returns the
    235 * entry on success, NULL on failure.  The caller is responsible for calling
    236 * the necessary locking functions.
    237 *
    238 */
    239struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
    240					     struct list_head *head)
    241{
    242	struct netlbl_af4list *entry;
    243
    244	entry = netlbl_af4list_search_exact(addr, mask, head);
    245	if (entry == NULL)
    246		return NULL;
    247	netlbl_af4list_remove_entry(entry);
    248	return entry;
    249}
    250
    251#if IS_ENABLED(CONFIG_IPV6)
    252/**
    253 * netlbl_af6list_remove_entry - Remove an IPv6 address entry
    254 * @entry: address entry
    255 *
    256 * Description:
    257 * Remove the specified IP address entry.  The caller is responsible for
    258 * calling the necessary locking functions.
    259 *
    260 */
    261void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
    262{
    263	entry->valid = 0;
    264	list_del_rcu(&entry->list);
    265}
    266
    267/**
    268 * netlbl_af6list_remove - Remove an IPv6 address entry
    269 * @addr: IP address
    270 * @mask: IP address mask
    271 * @head: the list head
    272 *
    273 * Description:
    274 * Remove an IP address entry from the list pointed to by @head.  Returns the
    275 * entry on success, NULL on failure.  The caller is responsible for calling
    276 * the necessary locking functions.
    277 *
    278 */
    279struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
    280					     const struct in6_addr *mask,
    281					     struct list_head *head)
    282{
    283	struct netlbl_af6list *entry;
    284
    285	entry = netlbl_af6list_search_exact(addr, mask, head);
    286	if (entry == NULL)
    287		return NULL;
    288	netlbl_af6list_remove_entry(entry);
    289	return entry;
    290}
    291#endif /* IPv6 */
    292
    293/*
    294 * Audit Helper Functions
    295 */
    296
    297#ifdef CONFIG_AUDIT
    298/**
    299 * netlbl_af4list_audit_addr - Audit an IPv4 address
    300 * @audit_buf: audit buffer
    301 * @src: true if source address, false if destination
    302 * @dev: network interface
    303 * @addr: IP address
    304 * @mask: IP address mask
    305 *
    306 * Description:
    307 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
    308 *
    309 */
    310void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
    311					int src, const char *dev,
    312					__be32 addr, __be32 mask)
    313{
    314	u32 mask_val = ntohl(mask);
    315	char *dir = (src ? "src" : "dst");
    316
    317	if (dev != NULL)
    318		audit_log_format(audit_buf, " netif=%s", dev);
    319	audit_log_format(audit_buf, " %s=%pI4", dir, &addr);
    320	if (mask_val != 0xffffffff) {
    321		u32 mask_len = 0;
    322		while (mask_val > 0) {
    323			mask_val <<= 1;
    324			mask_len++;
    325		}
    326		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
    327	}
    328}
    329
    330#if IS_ENABLED(CONFIG_IPV6)
    331/**
    332 * netlbl_af6list_audit_addr - Audit an IPv6 address
    333 * @audit_buf: audit buffer
    334 * @src: true if source address, false if destination
    335 * @dev: network interface
    336 * @addr: IP address
    337 * @mask: IP address mask
    338 *
    339 * Description:
    340 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
    341 *
    342 */
    343void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
    344				 int src,
    345				 const char *dev,
    346				 const struct in6_addr *addr,
    347				 const struct in6_addr *mask)
    348{
    349	char *dir = (src ? "src" : "dst");
    350
    351	if (dev != NULL)
    352		audit_log_format(audit_buf, " netif=%s", dev);
    353	audit_log_format(audit_buf, " %s=%pI6", dir, addr);
    354	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
    355		u32 mask_len = 0;
    356		u32 mask_val;
    357		int iter = -1;
    358		while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
    359			mask_len += 32;
    360		mask_val = ntohl(mask->s6_addr32[iter]);
    361		while (mask_val > 0) {
    362			mask_val <<= 1;
    363			mask_len++;
    364		}
    365		audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
    366	}
    367}
    368#endif /* IPv6 */
    369#endif /* CONFIG_AUDIT */