Path: blob/master/net/netlabel/netlabel_unlabeled.c
15109 views
/*1* NetLabel Unlabeled Support2*3* This file defines functions for dealing with unlabeled packets for the4* NetLabel system. The NetLabel system manages static and dynamic label5* mappings for network protocols such as CIPSO and RIPSO.6*7* Author: Paul Moore <[email protected]>8*9*/1011/*12* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 200813*14* This program is free software; you can redistribute it and/or modify15* it under the terms of the GNU General Public License as published by16* the Free Software Foundation; either version 2 of the License, or17* (at your option) any later version.18*19* This program is distributed in the hope that it will be useful,20* but WITHOUT ANY WARRANTY; without even the implied warranty of21* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See22* the GNU General Public License for more details.23*24* You should have received a copy of the GNU General Public License25* along with this program; if not, write to the Free Software26* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA27*28*/2930#include <linux/types.h>31#include <linux/rcupdate.h>32#include <linux/list.h>33#include <linux/spinlock.h>34#include <linux/socket.h>35#include <linux/string.h>36#include <linux/skbuff.h>37#include <linux/audit.h>38#include <linux/in.h>39#include <linux/in6.h>40#include <linux/ip.h>41#include <linux/ipv6.h>42#include <linux/notifier.h>43#include <linux/netdevice.h>44#include <linux/security.h>45#include <linux/slab.h>46#include <net/sock.h>47#include <net/netlink.h>48#include <net/genetlink.h>49#include <net/ip.h>50#include <net/ipv6.h>51#include <net/net_namespace.h>52#include <net/netlabel.h>53#include <asm/bug.h>54#include <asm/atomic.h>5556#include "netlabel_user.h"57#include "netlabel_addrlist.h"58#include "netlabel_domainhash.h"59#include "netlabel_unlabeled.h"60#include "netlabel_mgmt.h"6162/* NOTE: at present we always use init's network namespace since we don't63* presently support different namespaces even though the majority of64* the functions in this file are "namespace safe" */6566/* The unlabeled connection hash table which we use to map network interfaces67* and addresses of unlabeled packets to a user specified secid value for the68* LSM. The hash table is used to lookup the network interface entry69* (struct netlbl_unlhsh_iface) and then the interface entry is used to70* lookup an IP address match from an ordered list. If a network interface71* match can not be found in the hash table then the default entry72* (netlbl_unlhsh_def) is used. The IP address entry list73* (struct netlbl_unlhsh_addr) is ordered such that the entries with a74* larger netmask come first.75*/76struct netlbl_unlhsh_tbl {77struct list_head *tbl;78u32 size;79};80#define netlbl_unlhsh_addr4_entry(iter) \81container_of(iter, struct netlbl_unlhsh_addr4, list)82struct netlbl_unlhsh_addr4 {83u32 secid;8485struct netlbl_af4list list;86struct rcu_head rcu;87};88#define netlbl_unlhsh_addr6_entry(iter) \89container_of(iter, struct netlbl_unlhsh_addr6, list)90struct netlbl_unlhsh_addr6 {91u32 secid;9293struct netlbl_af6list list;94struct rcu_head rcu;95};96struct netlbl_unlhsh_iface {97int ifindex;98struct list_head addr4_list;99struct list_head addr6_list;100101u32 valid;102struct list_head list;103struct rcu_head rcu;104};105106/* Argument struct for netlbl_unlhsh_walk() */107struct netlbl_unlhsh_walk_arg {108struct netlink_callback *nl_cb;109struct sk_buff *skb;110u32 seq;111};112113/* Unlabeled connection hash table */114/* updates should be so rare that having one spinlock for the entire115* hash table should be okay */116static DEFINE_SPINLOCK(netlbl_unlhsh_lock);117#define netlbl_unlhsh_rcu_deref(p) \118rcu_dereference_check(p, rcu_read_lock_held() || \119lockdep_is_held(&netlbl_unlhsh_lock))120static struct netlbl_unlhsh_tbl *netlbl_unlhsh = NULL;121static struct netlbl_unlhsh_iface *netlbl_unlhsh_def = NULL;122123/* Accept unlabeled packets flag */124static u8 netlabel_unlabel_acceptflg = 0;125126/* NetLabel Generic NETLINK unlabeled family */127static struct genl_family netlbl_unlabel_gnl_family = {128.id = GENL_ID_GENERATE,129.hdrsize = 0,130.name = NETLBL_NLTYPE_UNLABELED_NAME,131.version = NETLBL_PROTO_VERSION,132.maxattr = NLBL_UNLABEL_A_MAX,133};134135/* NetLabel Netlink attribute policy */136static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {137[NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },138[NLBL_UNLABEL_A_IPV6ADDR] = { .type = NLA_BINARY,139.len = sizeof(struct in6_addr) },140[NLBL_UNLABEL_A_IPV6MASK] = { .type = NLA_BINARY,141.len = sizeof(struct in6_addr) },142[NLBL_UNLABEL_A_IPV4ADDR] = { .type = NLA_BINARY,143.len = sizeof(struct in_addr) },144[NLBL_UNLABEL_A_IPV4MASK] = { .type = NLA_BINARY,145.len = sizeof(struct in_addr) },146[NLBL_UNLABEL_A_IFACE] = { .type = NLA_NUL_STRING,147.len = IFNAMSIZ - 1 },148[NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }149};150151/*152* Unlabeled Connection Hash Table Functions153*/154155/**156* netlbl_unlhsh_free_iface - Frees an interface entry from the hash table157* @entry: the entry's RCU field158*159* Description:160* This function is designed to be used as a callback to the call_rcu()161* function so that memory allocated to a hash table interface entry can be162* released safely. It is important to note that this function does not free163* the IPv4 and IPv6 address lists contained as part of an interface entry. It164* is up to the rest of the code to make sure an interface entry is only freed165* once it's address lists are empty.166*167*/168static void netlbl_unlhsh_free_iface(struct rcu_head *entry)169{170struct netlbl_unlhsh_iface *iface;171struct netlbl_af4list *iter4;172struct netlbl_af4list *tmp4;173#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)174struct netlbl_af6list *iter6;175struct netlbl_af6list *tmp6;176#endif /* IPv6 */177178iface = container_of(entry, struct netlbl_unlhsh_iface, rcu);179180/* no need for locks here since we are the only one with access to this181* structure */182183netlbl_af4list_foreach_safe(iter4, tmp4, &iface->addr4_list) {184netlbl_af4list_remove_entry(iter4);185kfree(netlbl_unlhsh_addr4_entry(iter4));186}187#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)188netlbl_af6list_foreach_safe(iter6, tmp6, &iface->addr6_list) {189netlbl_af6list_remove_entry(iter6);190kfree(netlbl_unlhsh_addr6_entry(iter6));191}192#endif /* IPv6 */193kfree(iface);194}195196/**197* netlbl_unlhsh_hash - Hashing function for the hash table198* @ifindex: the network interface/device to hash199*200* Description:201* This is the hashing function for the unlabeled hash table, it returns the202* bucket number for the given device/interface. The caller is responsible for203* ensuring that the hash table is protected with either a RCU read lock or204* the hash table lock.205*206*/207static u32 netlbl_unlhsh_hash(int ifindex)208{209return ifindex & (netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->size - 1);210}211212/**213* netlbl_unlhsh_search_iface - Search for a matching interface entry214* @ifindex: the network interface215*216* Description:217* Searches the unlabeled connection hash table and returns a pointer to the218* interface entry which matches @ifindex, otherwise NULL is returned. The219* caller is responsible for ensuring that the hash table is protected with220* either a RCU read lock or the hash table lock.221*222*/223static struct netlbl_unlhsh_iface *netlbl_unlhsh_search_iface(int ifindex)224{225u32 bkt;226struct list_head *bkt_list;227struct netlbl_unlhsh_iface *iter;228229bkt = netlbl_unlhsh_hash(ifindex);230bkt_list = &netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt];231list_for_each_entry_rcu(iter, bkt_list, list)232if (iter->valid && iter->ifindex == ifindex)233return iter;234235return NULL;236}237238/**239* netlbl_unlhsh_add_addr4 - Add a new IPv4 address entry to the hash table240* @iface: the associated interface entry241* @addr: IPv4 address in network byte order242* @mask: IPv4 address mask in network byte order243* @secid: LSM secid value for entry244*245* Description:246* Add a new address entry into the unlabeled connection hash table using the247* interface entry specified by @iface. On success zero is returned, otherwise248* a negative value is returned.249*250*/251static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,252const struct in_addr *addr,253const struct in_addr *mask,254u32 secid)255{256int ret_val;257struct netlbl_unlhsh_addr4 *entry;258259entry = kzalloc(sizeof(*entry), GFP_ATOMIC);260if (entry == NULL)261return -ENOMEM;262263entry->list.addr = addr->s_addr & mask->s_addr;264entry->list.mask = mask->s_addr;265entry->list.valid = 1;266entry->secid = secid;267268spin_lock(&netlbl_unlhsh_lock);269ret_val = netlbl_af4list_add(&entry->list, &iface->addr4_list);270spin_unlock(&netlbl_unlhsh_lock);271272if (ret_val != 0)273kfree(entry);274return ret_val;275}276277#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)278/**279* netlbl_unlhsh_add_addr6 - Add a new IPv6 address entry to the hash table280* @iface: the associated interface entry281* @addr: IPv6 address in network byte order282* @mask: IPv6 address mask in network byte order283* @secid: LSM secid value for entry284*285* Description:286* Add a new address entry into the unlabeled connection hash table using the287* interface entry specified by @iface. On success zero is returned, otherwise288* a negative value is returned.289*290*/291static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,292const struct in6_addr *addr,293const struct in6_addr *mask,294u32 secid)295{296int ret_val;297struct netlbl_unlhsh_addr6 *entry;298299entry = kzalloc(sizeof(*entry), GFP_ATOMIC);300if (entry == NULL)301return -ENOMEM;302303ipv6_addr_copy(&entry->list.addr, addr);304entry->list.addr.s6_addr32[0] &= mask->s6_addr32[0];305entry->list.addr.s6_addr32[1] &= mask->s6_addr32[1];306entry->list.addr.s6_addr32[2] &= mask->s6_addr32[2];307entry->list.addr.s6_addr32[3] &= mask->s6_addr32[3];308ipv6_addr_copy(&entry->list.mask, mask);309entry->list.valid = 1;310entry->secid = secid;311312spin_lock(&netlbl_unlhsh_lock);313ret_val = netlbl_af6list_add(&entry->list, &iface->addr6_list);314spin_unlock(&netlbl_unlhsh_lock);315316if (ret_val != 0)317kfree(entry);318return 0;319}320#endif /* IPv6 */321322/**323* netlbl_unlhsh_add_iface - Adds a new interface entry to the hash table324* @ifindex: network interface325*326* Description:327* Add a new, empty, interface entry into the unlabeled connection hash table.328* On success a pointer to the new interface entry is returned, on failure NULL329* is returned.330*331*/332static struct netlbl_unlhsh_iface *netlbl_unlhsh_add_iface(int ifindex)333{334u32 bkt;335struct netlbl_unlhsh_iface *iface;336337iface = kzalloc(sizeof(*iface), GFP_ATOMIC);338if (iface == NULL)339return NULL;340341iface->ifindex = ifindex;342INIT_LIST_HEAD(&iface->addr4_list);343INIT_LIST_HEAD(&iface->addr6_list);344iface->valid = 1;345346spin_lock(&netlbl_unlhsh_lock);347if (ifindex > 0) {348bkt = netlbl_unlhsh_hash(ifindex);349if (netlbl_unlhsh_search_iface(ifindex) != NULL)350goto add_iface_failure;351list_add_tail_rcu(&iface->list,352&netlbl_unlhsh_rcu_deref(netlbl_unlhsh)->tbl[bkt]);353} else {354INIT_LIST_HEAD(&iface->list);355if (netlbl_unlhsh_rcu_deref(netlbl_unlhsh_def) != NULL)356goto add_iface_failure;357rcu_assign_pointer(netlbl_unlhsh_def, iface);358}359spin_unlock(&netlbl_unlhsh_lock);360361return iface;362363add_iface_failure:364spin_unlock(&netlbl_unlhsh_lock);365kfree(iface);366return NULL;367}368369/**370* netlbl_unlhsh_add - Adds a new entry to the unlabeled connection hash table371* @net: network namespace372* @dev_name: interface name373* @addr: IP address in network byte order374* @mask: address mask in network byte order375* @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)376* @secid: LSM secid value for the entry377* @audit_info: NetLabel audit information378*379* Description:380* Adds a new entry to the unlabeled connection hash table. Returns zero on381* success, negative values on failure.382*383*/384int netlbl_unlhsh_add(struct net *net,385const char *dev_name,386const void *addr,387const void *mask,388u32 addr_len,389u32 secid,390struct netlbl_audit *audit_info)391{392int ret_val;393int ifindex;394struct net_device *dev;395struct netlbl_unlhsh_iface *iface;396struct audit_buffer *audit_buf = NULL;397char *secctx = NULL;398u32 secctx_len;399400if (addr_len != sizeof(struct in_addr) &&401addr_len != sizeof(struct in6_addr))402return -EINVAL;403404rcu_read_lock();405if (dev_name != NULL) {406dev = dev_get_by_name_rcu(net, dev_name);407if (dev == NULL) {408ret_val = -ENODEV;409goto unlhsh_add_return;410}411ifindex = dev->ifindex;412iface = netlbl_unlhsh_search_iface(ifindex);413} else {414ifindex = 0;415iface = rcu_dereference(netlbl_unlhsh_def);416}417if (iface == NULL) {418iface = netlbl_unlhsh_add_iface(ifindex);419if (iface == NULL) {420ret_val = -ENOMEM;421goto unlhsh_add_return;422}423}424audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,425audit_info);426switch (addr_len) {427case sizeof(struct in_addr): {428struct in_addr *addr4, *mask4;429430addr4 = (struct in_addr *)addr;431mask4 = (struct in_addr *)mask;432ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);433if (audit_buf != NULL)434netlbl_af4list_audit_addr(audit_buf, 1,435dev_name,436addr4->s_addr,437mask4->s_addr);438break;439}440#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)441case sizeof(struct in6_addr): {442struct in6_addr *addr6, *mask6;443444addr6 = (struct in6_addr *)addr;445mask6 = (struct in6_addr *)mask;446ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);447if (audit_buf != NULL)448netlbl_af6list_audit_addr(audit_buf, 1,449dev_name,450addr6, mask6);451break;452}453#endif /* IPv6 */454default:455ret_val = -EINVAL;456}457if (ret_val == 0)458atomic_inc(&netlabel_mgmt_protocount);459460unlhsh_add_return:461rcu_read_unlock();462if (audit_buf != NULL) {463if (security_secid_to_secctx(secid,464&secctx,465&secctx_len) == 0) {466audit_log_format(audit_buf, " sec_obj=%s", secctx);467security_release_secctx(secctx, secctx_len);468}469audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);470audit_log_end(audit_buf);471}472return ret_val;473}474475/**476* netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry477* @net: network namespace478* @iface: interface entry479* @addr: IP address480* @mask: IP address mask481* @audit_info: NetLabel audit information482*483* Description:484* Remove an IP address entry from the unlabeled connection hash table.485* Returns zero on success, negative values on failure.486*487*/488static int netlbl_unlhsh_remove_addr4(struct net *net,489struct netlbl_unlhsh_iface *iface,490const struct in_addr *addr,491const struct in_addr *mask,492struct netlbl_audit *audit_info)493{494struct netlbl_af4list *list_entry;495struct netlbl_unlhsh_addr4 *entry;496struct audit_buffer *audit_buf;497struct net_device *dev;498char *secctx;499u32 secctx_len;500501spin_lock(&netlbl_unlhsh_lock);502list_entry = netlbl_af4list_remove(addr->s_addr, mask->s_addr,503&iface->addr4_list);504spin_unlock(&netlbl_unlhsh_lock);505if (list_entry != NULL)506entry = netlbl_unlhsh_addr4_entry(list_entry);507else508entry = NULL;509510audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,511audit_info);512if (audit_buf != NULL) {513dev = dev_get_by_index(net, iface->ifindex);514netlbl_af4list_audit_addr(audit_buf, 1,515(dev != NULL ? dev->name : NULL),516addr->s_addr, mask->s_addr);517if (dev != NULL)518dev_put(dev);519if (entry != NULL &&520security_secid_to_secctx(entry->secid,521&secctx, &secctx_len) == 0) {522audit_log_format(audit_buf, " sec_obj=%s", secctx);523security_release_secctx(secctx, secctx_len);524}525audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);526audit_log_end(audit_buf);527}528529if (entry == NULL)530return -ENOENT;531532kfree_rcu(entry, rcu);533return 0;534}535536#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)537/**538* netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry539* @net: network namespace540* @iface: interface entry541* @addr: IP address542* @mask: IP address mask543* @audit_info: NetLabel audit information544*545* Description:546* Remove an IP address entry from the unlabeled connection hash table.547* Returns zero on success, negative values on failure.548*549*/550static int netlbl_unlhsh_remove_addr6(struct net *net,551struct netlbl_unlhsh_iface *iface,552const struct in6_addr *addr,553const struct in6_addr *mask,554struct netlbl_audit *audit_info)555{556struct netlbl_af6list *list_entry;557struct netlbl_unlhsh_addr6 *entry;558struct audit_buffer *audit_buf;559struct net_device *dev;560char *secctx;561u32 secctx_len;562563spin_lock(&netlbl_unlhsh_lock);564list_entry = netlbl_af6list_remove(addr, mask, &iface->addr6_list);565spin_unlock(&netlbl_unlhsh_lock);566if (list_entry != NULL)567entry = netlbl_unlhsh_addr6_entry(list_entry);568else569entry = NULL;570571audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,572audit_info);573if (audit_buf != NULL) {574dev = dev_get_by_index(net, iface->ifindex);575netlbl_af6list_audit_addr(audit_buf, 1,576(dev != NULL ? dev->name : NULL),577addr, mask);578if (dev != NULL)579dev_put(dev);580if (entry != NULL &&581security_secid_to_secctx(entry->secid,582&secctx, &secctx_len) == 0) {583audit_log_format(audit_buf, " sec_obj=%s", secctx);584security_release_secctx(secctx, secctx_len);585}586audit_log_format(audit_buf, " res=%u", entry != NULL ? 1 : 0);587audit_log_end(audit_buf);588}589590if (entry == NULL)591return -ENOENT;592593kfree_rcu(entry, rcu);594return 0;595}596#endif /* IPv6 */597598/**599* netlbl_unlhsh_condremove_iface - Remove an interface entry600* @iface: the interface entry601*602* Description:603* Remove an interface entry from the unlabeled connection hash table if it is604* empty. An interface entry is considered to be empty if there are no605* address entries assigned to it.606*607*/608static void netlbl_unlhsh_condremove_iface(struct netlbl_unlhsh_iface *iface)609{610struct netlbl_af4list *iter4;611#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)612struct netlbl_af6list *iter6;613#endif /* IPv6 */614615spin_lock(&netlbl_unlhsh_lock);616netlbl_af4list_foreach_rcu(iter4, &iface->addr4_list)617goto unlhsh_condremove_failure;618#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)619netlbl_af6list_foreach_rcu(iter6, &iface->addr6_list)620goto unlhsh_condremove_failure;621#endif /* IPv6 */622iface->valid = 0;623if (iface->ifindex > 0)624list_del_rcu(&iface->list);625else626rcu_assign_pointer(netlbl_unlhsh_def, NULL);627spin_unlock(&netlbl_unlhsh_lock);628629call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);630return;631632unlhsh_condremove_failure:633spin_unlock(&netlbl_unlhsh_lock);634}635636/**637* netlbl_unlhsh_remove - Remove an entry from the unlabeled hash table638* @net: network namespace639* @dev_name: interface name640* @addr: IP address in network byte order641* @mask: address mask in network byte order642* @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)643* @audit_info: NetLabel audit information644*645* Description:646* Removes and existing entry from the unlabeled connection hash table.647* Returns zero on success, negative values on failure.648*649*/650int netlbl_unlhsh_remove(struct net *net,651const char *dev_name,652const void *addr,653const void *mask,654u32 addr_len,655struct netlbl_audit *audit_info)656{657int ret_val;658struct net_device *dev;659struct netlbl_unlhsh_iface *iface;660661if (addr_len != sizeof(struct in_addr) &&662addr_len != sizeof(struct in6_addr))663return -EINVAL;664665rcu_read_lock();666if (dev_name != NULL) {667dev = dev_get_by_name_rcu(net, dev_name);668if (dev == NULL) {669ret_val = -ENODEV;670goto unlhsh_remove_return;671}672iface = netlbl_unlhsh_search_iface(dev->ifindex);673} else674iface = rcu_dereference(netlbl_unlhsh_def);675if (iface == NULL) {676ret_val = -ENOENT;677goto unlhsh_remove_return;678}679switch (addr_len) {680case sizeof(struct in_addr):681ret_val = netlbl_unlhsh_remove_addr4(net,682iface, addr, mask,683audit_info);684break;685#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)686case sizeof(struct in6_addr):687ret_val = netlbl_unlhsh_remove_addr6(net,688iface, addr, mask,689audit_info);690break;691#endif /* IPv6 */692default:693ret_val = -EINVAL;694}695if (ret_val == 0) {696netlbl_unlhsh_condremove_iface(iface);697atomic_dec(&netlabel_mgmt_protocount);698}699700unlhsh_remove_return:701rcu_read_unlock();702return ret_val;703}704705/*706* General Helper Functions707*/708709/**710* netlbl_unlhsh_netdev_handler - Network device notification handler711* @this: notifier block712* @event: the event713* @ptr: the network device (cast to void)714*715* Description:716* Handle network device events, although at present all we care about is a717* network device going away. In the case of a device going away we clear any718* related entries from the unlabeled connection hash table.719*720*/721static int netlbl_unlhsh_netdev_handler(struct notifier_block *this,722unsigned long event,723void *ptr)724{725struct net_device *dev = ptr;726struct netlbl_unlhsh_iface *iface = NULL;727728if (!net_eq(dev_net(dev), &init_net))729return NOTIFY_DONE;730731/* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */732if (event == NETDEV_DOWN) {733spin_lock(&netlbl_unlhsh_lock);734iface = netlbl_unlhsh_search_iface(dev->ifindex);735if (iface != NULL && iface->valid) {736iface->valid = 0;737list_del_rcu(&iface->list);738} else739iface = NULL;740spin_unlock(&netlbl_unlhsh_lock);741}742743if (iface != NULL)744call_rcu(&iface->rcu, netlbl_unlhsh_free_iface);745746return NOTIFY_DONE;747}748749/**750* netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag751* @value: desired value752* @audit_info: NetLabel audit information753*754* Description:755* Set the value of the unlabeled accept flag to @value.756*757*/758static void netlbl_unlabel_acceptflg_set(u8 value,759struct netlbl_audit *audit_info)760{761struct audit_buffer *audit_buf;762u8 old_val;763764old_val = netlabel_unlabel_acceptflg;765netlabel_unlabel_acceptflg = value;766audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,767audit_info);768if (audit_buf != NULL) {769audit_log_format(audit_buf,770" unlbl_accept=%u old=%u", value, old_val);771audit_log_end(audit_buf);772}773}774775/**776* netlbl_unlabel_addrinfo_get - Get the IPv4/6 address information777* @info: the Generic NETLINK info block778* @addr: the IP address779* @mask: the IP address mask780* @len: the address length781*782* Description:783* Examine the Generic NETLINK message and extract the IP address information.784* Returns zero on success, negative values on failure.785*786*/787static int netlbl_unlabel_addrinfo_get(struct genl_info *info,788void **addr,789void **mask,790u32 *len)791{792u32 addr_len;793794if (info->attrs[NLBL_UNLABEL_A_IPV4ADDR]) {795addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);796if (addr_len != sizeof(struct in_addr) &&797addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV4MASK]))798return -EINVAL;799*len = addr_len;800*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4ADDR]);801*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV4MASK]);802return 0;803} else if (info->attrs[NLBL_UNLABEL_A_IPV6ADDR]) {804addr_len = nla_len(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);805if (addr_len != sizeof(struct in6_addr) &&806addr_len != nla_len(info->attrs[NLBL_UNLABEL_A_IPV6MASK]))807return -EINVAL;808*len = addr_len;809*addr = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6ADDR]);810*mask = nla_data(info->attrs[NLBL_UNLABEL_A_IPV6MASK]);811return 0;812}813814return -EINVAL;815}816817/*818* NetLabel Command Handlers819*/820821/**822* netlbl_unlabel_accept - Handle an ACCEPT message823* @skb: the NETLINK buffer824* @info: the Generic NETLINK info block825*826* Description:827* Process a user generated ACCEPT message and set the accept flag accordingly.828* Returns zero on success, negative values on failure.829*830*/831static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)832{833u8 value;834struct netlbl_audit audit_info;835836if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {837value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);838if (value == 1 || value == 0) {839netlbl_netlink_auditinfo(skb, &audit_info);840netlbl_unlabel_acceptflg_set(value, &audit_info);841return 0;842}843}844845return -EINVAL;846}847848/**849* netlbl_unlabel_list - Handle a LIST message850* @skb: the NETLINK buffer851* @info: the Generic NETLINK info block852*853* Description:854* Process a user generated LIST message and respond with the current status.855* Returns zero on success, negative values on failure.856*857*/858static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)859{860int ret_val = -EINVAL;861struct sk_buff *ans_skb;862void *data;863864ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);865if (ans_skb == NULL)866goto list_failure;867data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family,8680, NLBL_UNLABEL_C_LIST);869if (data == NULL) {870ret_val = -ENOMEM;871goto list_failure;872}873874ret_val = nla_put_u8(ans_skb,875NLBL_UNLABEL_A_ACPTFLG,876netlabel_unlabel_acceptflg);877if (ret_val != 0)878goto list_failure;879880genlmsg_end(ans_skb, data);881return genlmsg_reply(ans_skb, info);882883list_failure:884kfree_skb(ans_skb);885return ret_val;886}887888/**889* netlbl_unlabel_staticadd - Handle a STATICADD message890* @skb: the NETLINK buffer891* @info: the Generic NETLINK info block892*893* Description:894* Process a user generated STATICADD message and add a new unlabeled895* connection entry to the hash table. Returns zero on success, negative896* values on failure.897*898*/899static int netlbl_unlabel_staticadd(struct sk_buff *skb,900struct genl_info *info)901{902int ret_val;903char *dev_name;904void *addr;905void *mask;906u32 addr_len;907u32 secid;908struct netlbl_audit audit_info;909910/* Don't allow users to add both IPv4 and IPv6 addresses for a911* single entry. However, allow users to create two entries, one each912* for IPv4 and IPv4, with the same LSM security context which should913* achieve the same result. */914if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||915!info->attrs[NLBL_UNLABEL_A_IFACE] ||916!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||917!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^918(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||919!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))920return -EINVAL;921922netlbl_netlink_auditinfo(skb, &audit_info);923924ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);925if (ret_val != 0)926return ret_val;927dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);928ret_val = security_secctx_to_secid(929nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),930nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),931&secid);932if (ret_val != 0)933return ret_val;934935return netlbl_unlhsh_add(&init_net,936dev_name, addr, mask, addr_len, secid,937&audit_info);938}939940/**941* netlbl_unlabel_staticadddef - Handle a STATICADDDEF message942* @skb: the NETLINK buffer943* @info: the Generic NETLINK info block944*945* Description:946* Process a user generated STATICADDDEF message and add a new default947* unlabeled connection entry. Returns zero on success, negative values on948* failure.949*950*/951static int netlbl_unlabel_staticadddef(struct sk_buff *skb,952struct genl_info *info)953{954int ret_val;955void *addr;956void *mask;957u32 addr_len;958u32 secid;959struct netlbl_audit audit_info;960961/* Don't allow users to add both IPv4 and IPv6 addresses for a962* single entry. However, allow users to create two entries, one each963* for IPv4 and IPv6, with the same LSM security context which should964* achieve the same result. */965if (!info->attrs[NLBL_UNLABEL_A_SECCTX] ||966!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||967!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^968(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||969!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))970return -EINVAL;971972netlbl_netlink_auditinfo(skb, &audit_info);973974ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);975if (ret_val != 0)976return ret_val;977ret_val = security_secctx_to_secid(978nla_data(info->attrs[NLBL_UNLABEL_A_SECCTX]),979nla_len(info->attrs[NLBL_UNLABEL_A_SECCTX]),980&secid);981if (ret_val != 0)982return ret_val;983984return netlbl_unlhsh_add(&init_net,985NULL, addr, mask, addr_len, secid,986&audit_info);987}988989/**990* netlbl_unlabel_staticremove - Handle a STATICREMOVE message991* @skb: the NETLINK buffer992* @info: the Generic NETLINK info block993*994* Description:995* Process a user generated STATICREMOVE message and remove the specified996* unlabeled connection entry. Returns zero on success, negative values on997* failure.998*999*/1000static int netlbl_unlabel_staticremove(struct sk_buff *skb,1001struct genl_info *info)1002{1003int ret_val;1004char *dev_name;1005void *addr;1006void *mask;1007u32 addr_len;1008struct netlbl_audit audit_info;10091010/* See the note in netlbl_unlabel_staticadd() about not allowing both1011* IPv4 and IPv6 in the same entry. */1012if (!info->attrs[NLBL_UNLABEL_A_IFACE] ||1013!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||1014!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^1015(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||1016!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))1017return -EINVAL;10181019netlbl_netlink_auditinfo(skb, &audit_info);10201021ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);1022if (ret_val != 0)1023return ret_val;1024dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);10251026return netlbl_unlhsh_remove(&init_net,1027dev_name, addr, mask, addr_len,1028&audit_info);1029}10301031/**1032* netlbl_unlabel_staticremovedef - Handle a STATICREMOVEDEF message1033* @skb: the NETLINK buffer1034* @info: the Generic NETLINK info block1035*1036* Description:1037* Process a user generated STATICREMOVEDEF message and remove the default1038* unlabeled connection entry. Returns zero on success, negative values on1039* failure.1040*1041*/1042static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,1043struct genl_info *info)1044{1045int ret_val;1046void *addr;1047void *mask;1048u32 addr_len;1049struct netlbl_audit audit_info;10501051/* See the note in netlbl_unlabel_staticadd() about not allowing both1052* IPv4 and IPv6 in the same entry. */1053if (!((!info->attrs[NLBL_UNLABEL_A_IPV4ADDR] ||1054!info->attrs[NLBL_UNLABEL_A_IPV4MASK]) ^1055(!info->attrs[NLBL_UNLABEL_A_IPV6ADDR] ||1056!info->attrs[NLBL_UNLABEL_A_IPV6MASK])))1057return -EINVAL;10581059netlbl_netlink_auditinfo(skb, &audit_info);10601061ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);1062if (ret_val != 0)1063return ret_val;10641065return netlbl_unlhsh_remove(&init_net,1066NULL, addr, mask, addr_len,1067&audit_info);1068}106910701071/**1072* netlbl_unlabel_staticlist_gen - Generate messages for STATICLIST[DEF]1073* @cmd: command/message1074* @iface: the interface entry1075* @addr4: the IPv4 address entry1076* @addr6: the IPv6 address entry1077* @arg: the netlbl_unlhsh_walk_arg structure1078*1079* Description:1080* This function is designed to be used to generate a response for a1081* STATICLIST or STATICLISTDEF message. When called either @addr4 or @addr61082* can be specified, not both, the other unspecified entry should be set to1083* NULL by the caller. Returns the size of the message on success, negative1084* values on failure.1085*1086*/1087static int netlbl_unlabel_staticlist_gen(u32 cmd,1088const struct netlbl_unlhsh_iface *iface,1089const struct netlbl_unlhsh_addr4 *addr4,1090const struct netlbl_unlhsh_addr6 *addr6,1091void *arg)1092{1093int ret_val = -ENOMEM;1094struct netlbl_unlhsh_walk_arg *cb_arg = arg;1095struct net_device *dev;1096void *data;1097u32 secid;1098char *secctx;1099u32 secctx_len;11001101data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).pid,1102cb_arg->seq, &netlbl_unlabel_gnl_family,1103NLM_F_MULTI, cmd);1104if (data == NULL)1105goto list_cb_failure;11061107if (iface->ifindex > 0) {1108dev = dev_get_by_index(&init_net, iface->ifindex);1109if (!dev) {1110ret_val = -ENODEV;1111goto list_cb_failure;1112}1113ret_val = nla_put_string(cb_arg->skb,1114NLBL_UNLABEL_A_IFACE, dev->name);1115dev_put(dev);1116if (ret_val != 0)1117goto list_cb_failure;1118}11191120if (addr4) {1121struct in_addr addr_struct;11221123addr_struct.s_addr = addr4->list.addr;1124ret_val = nla_put(cb_arg->skb,1125NLBL_UNLABEL_A_IPV4ADDR,1126sizeof(struct in_addr),1127&addr_struct);1128if (ret_val != 0)1129goto list_cb_failure;11301131addr_struct.s_addr = addr4->list.mask;1132ret_val = nla_put(cb_arg->skb,1133NLBL_UNLABEL_A_IPV4MASK,1134sizeof(struct in_addr),1135&addr_struct);1136if (ret_val != 0)1137goto list_cb_failure;11381139secid = addr4->secid;1140} else {1141ret_val = nla_put(cb_arg->skb,1142NLBL_UNLABEL_A_IPV6ADDR,1143sizeof(struct in6_addr),1144&addr6->list.addr);1145if (ret_val != 0)1146goto list_cb_failure;11471148ret_val = nla_put(cb_arg->skb,1149NLBL_UNLABEL_A_IPV6MASK,1150sizeof(struct in6_addr),1151&addr6->list.mask);1152if (ret_val != 0)1153goto list_cb_failure;11541155secid = addr6->secid;1156}11571158ret_val = security_secid_to_secctx(secid, &secctx, &secctx_len);1159if (ret_val != 0)1160goto list_cb_failure;1161ret_val = nla_put(cb_arg->skb,1162NLBL_UNLABEL_A_SECCTX,1163secctx_len,1164secctx);1165security_release_secctx(secctx, secctx_len);1166if (ret_val != 0)1167goto list_cb_failure;11681169cb_arg->seq++;1170return genlmsg_end(cb_arg->skb, data);11711172list_cb_failure:1173genlmsg_cancel(cb_arg->skb, data);1174return ret_val;1175}11761177/**1178* netlbl_unlabel_staticlist - Handle a STATICLIST message1179* @skb: the NETLINK buffer1180* @cb: the NETLINK callback1181*1182* Description:1183* Process a user generated STATICLIST message and dump the unlabeled1184* connection hash table in a form suitable for use in a kernel generated1185* STATICLIST message. Returns the length of @skb.1186*1187*/1188static int netlbl_unlabel_staticlist(struct sk_buff *skb,1189struct netlink_callback *cb)1190{1191struct netlbl_unlhsh_walk_arg cb_arg;1192u32 skip_bkt = cb->args[0];1193u32 skip_chain = cb->args[1];1194u32 skip_addr4 = cb->args[2];1195u32 skip_addr6 = cb->args[3];1196u32 iter_bkt;1197u32 iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0;1198struct netlbl_unlhsh_iface *iface;1199struct list_head *iter_list;1200struct netlbl_af4list *addr4;1201#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)1202struct netlbl_af6list *addr6;1203#endif12041205cb_arg.nl_cb = cb;1206cb_arg.skb = skb;1207cb_arg.seq = cb->nlh->nlmsg_seq;12081209rcu_read_lock();1210for (iter_bkt = skip_bkt;1211iter_bkt < rcu_dereference(netlbl_unlhsh)->size;1212iter_bkt++, iter_chain = 0, iter_addr4 = 0, iter_addr6 = 0) {1213iter_list = &rcu_dereference(netlbl_unlhsh)->tbl[iter_bkt];1214list_for_each_entry_rcu(iface, iter_list, list) {1215if (!iface->valid ||1216iter_chain++ < skip_chain)1217continue;1218netlbl_af4list_foreach_rcu(addr4,1219&iface->addr4_list) {1220if (iter_addr4++ < skip_addr4)1221continue;1222if (netlbl_unlabel_staticlist_gen(1223NLBL_UNLABEL_C_STATICLIST,1224iface,1225netlbl_unlhsh_addr4_entry(addr4),1226NULL,1227&cb_arg) < 0) {1228iter_addr4--;1229iter_chain--;1230goto unlabel_staticlist_return;1231}1232}1233#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)1234netlbl_af6list_foreach_rcu(addr6,1235&iface->addr6_list) {1236if (iter_addr6++ < skip_addr6)1237continue;1238if (netlbl_unlabel_staticlist_gen(1239NLBL_UNLABEL_C_STATICLIST,1240iface,1241NULL,1242netlbl_unlhsh_addr6_entry(addr6),1243&cb_arg) < 0) {1244iter_addr6--;1245iter_chain--;1246goto unlabel_staticlist_return;1247}1248}1249#endif /* IPv6 */1250}1251}12521253unlabel_staticlist_return:1254rcu_read_unlock();1255cb->args[0] = skip_bkt;1256cb->args[1] = skip_chain;1257cb->args[2] = skip_addr4;1258cb->args[3] = skip_addr6;1259return skb->len;1260}12611262/**1263* netlbl_unlabel_staticlistdef - Handle a STATICLISTDEF message1264* @skb: the NETLINK buffer1265* @cb: the NETLINK callback1266*1267* Description:1268* Process a user generated STATICLISTDEF message and dump the default1269* unlabeled connection entry in a form suitable for use in a kernel generated1270* STATICLISTDEF message. Returns the length of @skb.1271*1272*/1273static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,1274struct netlink_callback *cb)1275{1276struct netlbl_unlhsh_walk_arg cb_arg;1277struct netlbl_unlhsh_iface *iface;1278u32 skip_addr4 = cb->args[0];1279u32 skip_addr6 = cb->args[1];1280u32 iter_addr4 = 0;1281struct netlbl_af4list *addr4;1282#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)1283u32 iter_addr6 = 0;1284struct netlbl_af6list *addr6;1285#endif12861287cb_arg.nl_cb = cb;1288cb_arg.skb = skb;1289cb_arg.seq = cb->nlh->nlmsg_seq;12901291rcu_read_lock();1292iface = rcu_dereference(netlbl_unlhsh_def);1293if (iface == NULL || !iface->valid)1294goto unlabel_staticlistdef_return;12951296netlbl_af4list_foreach_rcu(addr4, &iface->addr4_list) {1297if (iter_addr4++ < skip_addr4)1298continue;1299if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,1300iface,1301netlbl_unlhsh_addr4_entry(addr4),1302NULL,1303&cb_arg) < 0) {1304iter_addr4--;1305goto unlabel_staticlistdef_return;1306}1307}1308#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)1309netlbl_af6list_foreach_rcu(addr6, &iface->addr6_list) {1310if (iter_addr6++ < skip_addr6)1311continue;1312if (netlbl_unlabel_staticlist_gen(NLBL_UNLABEL_C_STATICLISTDEF,1313iface,1314NULL,1315netlbl_unlhsh_addr6_entry(addr6),1316&cb_arg) < 0) {1317iter_addr6--;1318goto unlabel_staticlistdef_return;1319}1320}1321#endif /* IPv6 */13221323unlabel_staticlistdef_return:1324rcu_read_unlock();1325cb->args[0] = skip_addr4;1326cb->args[1] = skip_addr6;1327return skb->len;1328}13291330/*1331* NetLabel Generic NETLINK Command Definitions1332*/13331334static struct genl_ops netlbl_unlabel_genl_ops[] = {1335{1336.cmd = NLBL_UNLABEL_C_STATICADD,1337.flags = GENL_ADMIN_PERM,1338.policy = netlbl_unlabel_genl_policy,1339.doit = netlbl_unlabel_staticadd,1340.dumpit = NULL,1341},1342{1343.cmd = NLBL_UNLABEL_C_STATICREMOVE,1344.flags = GENL_ADMIN_PERM,1345.policy = netlbl_unlabel_genl_policy,1346.doit = netlbl_unlabel_staticremove,1347.dumpit = NULL,1348},1349{1350.cmd = NLBL_UNLABEL_C_STATICLIST,1351.flags = 0,1352.policy = netlbl_unlabel_genl_policy,1353.doit = NULL,1354.dumpit = netlbl_unlabel_staticlist,1355},1356{1357.cmd = NLBL_UNLABEL_C_STATICADDDEF,1358.flags = GENL_ADMIN_PERM,1359.policy = netlbl_unlabel_genl_policy,1360.doit = netlbl_unlabel_staticadddef,1361.dumpit = NULL,1362},1363{1364.cmd = NLBL_UNLABEL_C_STATICREMOVEDEF,1365.flags = GENL_ADMIN_PERM,1366.policy = netlbl_unlabel_genl_policy,1367.doit = netlbl_unlabel_staticremovedef,1368.dumpit = NULL,1369},1370{1371.cmd = NLBL_UNLABEL_C_STATICLISTDEF,1372.flags = 0,1373.policy = netlbl_unlabel_genl_policy,1374.doit = NULL,1375.dumpit = netlbl_unlabel_staticlistdef,1376},1377{1378.cmd = NLBL_UNLABEL_C_ACCEPT,1379.flags = GENL_ADMIN_PERM,1380.policy = netlbl_unlabel_genl_policy,1381.doit = netlbl_unlabel_accept,1382.dumpit = NULL,1383},1384{1385.cmd = NLBL_UNLABEL_C_LIST,1386.flags = 0,1387.policy = netlbl_unlabel_genl_policy,1388.doit = netlbl_unlabel_list,1389.dumpit = NULL,1390},1391};13921393/*1394* NetLabel Generic NETLINK Protocol Functions1395*/13961397/**1398* netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component1399*1400* Description:1401* Register the unlabeled packet NetLabel component with the Generic NETLINK1402* mechanism. Returns zero on success, negative values on failure.1403*1404*/1405int __init netlbl_unlabel_genl_init(void)1406{1407return genl_register_family_with_ops(&netlbl_unlabel_gnl_family,1408netlbl_unlabel_genl_ops, ARRAY_SIZE(netlbl_unlabel_genl_ops));1409}14101411/*1412* NetLabel KAPI Hooks1413*/14141415static struct notifier_block netlbl_unlhsh_netdev_notifier = {1416.notifier_call = netlbl_unlhsh_netdev_handler,1417};14181419/**1420* netlbl_unlabel_init - Initialize the unlabeled connection hash table1421* @size: the number of bits to use for the hash buckets1422*1423* Description:1424* Initializes the unlabeled connection hash table and registers a network1425* device notification handler. This function should only be called by the1426* NetLabel subsystem itself during initialization. Returns zero on success,1427* non-zero values on error.1428*1429*/1430int __init netlbl_unlabel_init(u32 size)1431{1432u32 iter;1433struct netlbl_unlhsh_tbl *hsh_tbl;14341435if (size == 0)1436return -EINVAL;14371438hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);1439if (hsh_tbl == NULL)1440return -ENOMEM;1441hsh_tbl->size = 1 << size;1442hsh_tbl->tbl = kcalloc(hsh_tbl->size,1443sizeof(struct list_head),1444GFP_KERNEL);1445if (hsh_tbl->tbl == NULL) {1446kfree(hsh_tbl);1447return -ENOMEM;1448}1449for (iter = 0; iter < hsh_tbl->size; iter++)1450INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);14511452rcu_read_lock();1453spin_lock(&netlbl_unlhsh_lock);1454rcu_assign_pointer(netlbl_unlhsh, hsh_tbl);1455spin_unlock(&netlbl_unlhsh_lock);1456rcu_read_unlock();14571458register_netdevice_notifier(&netlbl_unlhsh_netdev_notifier);14591460return 0;1461}14621463/**1464* netlbl_unlabel_getattr - Get the security attributes for an unlabled packet1465* @skb: the packet1466* @family: protocol family1467* @secattr: the security attributes1468*1469* Description:1470* Determine the security attributes, if any, for an unlabled packet and return1471* them in @secattr. Returns zero on success and negative values on failure.1472*1473*/1474int netlbl_unlabel_getattr(const struct sk_buff *skb,1475u16 family,1476struct netlbl_lsm_secattr *secattr)1477{1478struct netlbl_unlhsh_iface *iface;14791480rcu_read_lock();1481iface = netlbl_unlhsh_search_iface(skb->skb_iif);1482if (iface == NULL)1483iface = rcu_dereference(netlbl_unlhsh_def);1484if (iface == NULL || !iface->valid)1485goto unlabel_getattr_nolabel;1486switch (family) {1487case PF_INET: {1488struct iphdr *hdr4;1489struct netlbl_af4list *addr4;14901491hdr4 = ip_hdr(skb);1492addr4 = netlbl_af4list_search(hdr4->saddr,1493&iface->addr4_list);1494if (addr4 == NULL)1495goto unlabel_getattr_nolabel;1496secattr->attr.secid = netlbl_unlhsh_addr4_entry(addr4)->secid;1497break;1498}1499#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)1500case PF_INET6: {1501struct ipv6hdr *hdr6;1502struct netlbl_af6list *addr6;15031504hdr6 = ipv6_hdr(skb);1505addr6 = netlbl_af6list_search(&hdr6->saddr,1506&iface->addr6_list);1507if (addr6 == NULL)1508goto unlabel_getattr_nolabel;1509secattr->attr.secid = netlbl_unlhsh_addr6_entry(addr6)->secid;1510break;1511}1512#endif /* IPv6 */1513default:1514goto unlabel_getattr_nolabel;1515}1516rcu_read_unlock();15171518secattr->flags |= NETLBL_SECATTR_SECID;1519secattr->type = NETLBL_NLTYPE_UNLABELED;1520return 0;15211522unlabel_getattr_nolabel:1523rcu_read_unlock();1524if (netlabel_unlabel_acceptflg == 0)1525return -ENOMSG;1526secattr->type = NETLBL_NLTYPE_UNLABELED;1527return 0;1528}15291530/**1531* netlbl_unlabel_defconf - Set the default config to allow unlabeled packets1532*1533* Description:1534* Set the default NetLabel configuration to allow incoming unlabeled packets1535* and to send unlabeled network traffic by default.1536*1537*/1538int __init netlbl_unlabel_defconf(void)1539{1540int ret_val;1541struct netlbl_dom_map *entry;1542struct netlbl_audit audit_info;15431544/* Only the kernel is allowed to call this function and the only time1545* it is called is at bootup before the audit subsystem is reporting1546* messages so don't worry to much about these values. */1547security_task_getsecid(current, &audit_info.secid);1548audit_info.loginuid = 0;1549audit_info.sessionid = 0;15501551entry = kzalloc(sizeof(*entry), GFP_KERNEL);1552if (entry == NULL)1553return -ENOMEM;1554entry->type = NETLBL_NLTYPE_UNLABELED;1555ret_val = netlbl_domhsh_add_default(entry, &audit_info);1556if (ret_val != 0)1557return ret_val;15581559netlbl_unlabel_acceptflg_set(1, &audit_info);15601561return 0;1562}156315641565