// SPDX-License-Identifier: GPL-2.0-or-later1/*2* NetLabel CALIPSO/IPv6 Support3*4* This file defines the CALIPSO/IPv6 functions for the NetLabel system. The5* NetLabel system manages static and dynamic label mappings for network6* protocols such as CIPSO and CALIPSO.7*8* Authors: Paul Moore <[email protected]>9* Huw Davies <[email protected]>10*/1112/* (c) Copyright Hewlett-Packard Development Company, L.P., 200613* (c) Copyright Huw Davies <[email protected]>, 201514*/1516#include <linux/types.h>17#include <linux/socket.h>18#include <linux/string.h>19#include <linux/skbuff.h>20#include <linux/audit.h>21#include <linux/slab.h>22#include <net/sock.h>23#include <net/netlink.h>24#include <net/genetlink.h>25#include <net/netlabel.h>26#include <net/calipso.h>27#include <linux/atomic.h>2829#include "netlabel_user.h"30#include "netlabel_calipso.h"31#include "netlabel_mgmt.h"32#include "netlabel_domainhash.h"3334/* Argument struct for calipso_doi_walk() */35struct netlbl_calipso_doiwalk_arg {36struct netlink_callback *nl_cb;37struct sk_buff *skb;38u32 seq;39};4041/* Argument struct for netlbl_domhsh_walk() */42struct netlbl_domhsh_walk_arg {43struct netlbl_audit *audit_info;44u32 doi;45};4647/* NetLabel Generic NETLINK CALIPSO family */48static struct genl_family netlbl_calipso_gnl_family;4950/* NetLabel Netlink attribute policy */51static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {52[NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 },53[NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },54};5556static const struct netlbl_calipso_ops *calipso_ops;5758/**59* netlbl_calipso_ops_register - Register the CALIPSO operations60* @ops: ops to register61*62* Description:63* Register the CALIPSO packet engine operations.64*65*/66const struct netlbl_calipso_ops *67netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)68{69return xchg(&calipso_ops, ops);70}71EXPORT_SYMBOL(netlbl_calipso_ops_register);7273static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)74{75return READ_ONCE(calipso_ops);76}7778/* NetLabel Command Handlers79*/80/**81* netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition82* @info: the Generic NETLINK info block83* @audit_info: NetLabel audit information84*85* Description:86* Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message87* and add it to the CALIPSO engine. Return zero on success and non-zero on88* error.89*90*/91static int netlbl_calipso_add_pass(struct genl_info *info,92struct netlbl_audit *audit_info)93{94int ret_val;95struct calipso_doi *doi_def = NULL;9697doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);98if (!doi_def)99return -ENOMEM;100doi_def->type = CALIPSO_MAP_PASS;101doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);102ret_val = calipso_doi_add(doi_def, audit_info);103if (ret_val != 0)104calipso_doi_free(doi_def);105106return ret_val;107}108109/**110* netlbl_calipso_add - Handle an ADD message111* @skb: the NETLINK buffer112* @info: the Generic NETLINK info block113*114* Description:115* Create a new DOI definition based on the given ADD message and add it to the116* CALIPSO engine. Returns zero on success, negative values on failure.117*118*/119static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)120{121int ret_val = -EINVAL;122struct netlbl_audit audit_info;123const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();124125if (!info->attrs[NLBL_CALIPSO_A_DOI] ||126!info->attrs[NLBL_CALIPSO_A_MTYPE])127return -EINVAL;128129if (!ops)130return -EOPNOTSUPP;131132netlbl_netlink_auditinfo(&audit_info);133switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {134case CALIPSO_MAP_PASS:135ret_val = netlbl_calipso_add_pass(info, &audit_info);136break;137}138if (ret_val == 0)139atomic_inc(&netlabel_mgmt_protocount);140141return ret_val;142}143144/**145* netlbl_calipso_list - Handle a LIST message146* @skb: the NETLINK buffer147* @info: the Generic NETLINK info block148*149* Description:150* Process a user generated LIST message and respond accordingly.151* Returns zero on success and negative values on error.152*153*/154static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info)155{156int ret_val;157struct sk_buff *ans_skb = NULL;158void *data;159u32 doi;160struct calipso_doi *doi_def;161162if (!info->attrs[NLBL_CALIPSO_A_DOI]) {163ret_val = -EINVAL;164goto list_failure;165}166167doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);168169doi_def = calipso_doi_getdef(doi);170if (!doi_def) {171ret_val = -EINVAL;172goto list_failure;173}174175ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);176if (!ans_skb) {177ret_val = -ENOMEM;178goto list_failure_put;179}180data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family,1810, NLBL_CALIPSO_C_LIST);182if (!data) {183ret_val = -ENOMEM;184goto list_failure_put;185}186187ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type);188if (ret_val != 0)189goto list_failure_put;190191calipso_doi_putdef(doi_def);192193genlmsg_end(ans_skb, data);194return genlmsg_reply(ans_skb, info);195196list_failure_put:197calipso_doi_putdef(doi_def);198list_failure:199kfree_skb(ans_skb);200return ret_val;201}202203/**204* netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL205* @doi_def: the CALIPSO DOI definition206* @arg: the netlbl_calipso_doiwalk_arg structure207*208* Description:209* This function is designed to be used as a callback to the210* calipso_doi_walk() function for use in generating a response for a LISTALL211* message. Returns the size of the message on success, negative values on212* failure.213*214*/215static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg)216{217int ret_val = -ENOMEM;218struct netlbl_calipso_doiwalk_arg *cb_arg = arg;219void *data;220221data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,222cb_arg->seq, &netlbl_calipso_gnl_family,223NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL);224if (!data)225goto listall_cb_failure;226227ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi);228if (ret_val != 0)229goto listall_cb_failure;230ret_val = nla_put_u32(cb_arg->skb,231NLBL_CALIPSO_A_MTYPE,232doi_def->type);233if (ret_val != 0)234goto listall_cb_failure;235236genlmsg_end(cb_arg->skb, data);237return 0;238239listall_cb_failure:240genlmsg_cancel(cb_arg->skb, data);241return ret_val;242}243244/**245* netlbl_calipso_listall - Handle a LISTALL message246* @skb: the NETLINK buffer247* @cb: the NETLINK callback248*249* Description:250* Process a user generated LISTALL message and respond accordingly. Returns251* zero on success and negative values on error.252*253*/254static int netlbl_calipso_listall(struct sk_buff *skb,255struct netlink_callback *cb)256{257struct netlbl_calipso_doiwalk_arg cb_arg;258u32 doi_skip = cb->args[0];259260cb_arg.nl_cb = cb;261cb_arg.skb = skb;262cb_arg.seq = cb->nlh->nlmsg_seq;263264calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg);265266cb->args[0] = doi_skip;267return skb->len;268}269270/**271* netlbl_calipso_remove_cb - netlbl_calipso_remove() callback for REMOVE272* @entry: LSM domain mapping entry273* @arg: the netlbl_domhsh_walk_arg structure274*275* Description:276* This function is intended for use by netlbl_calipso_remove() as the callback277* for the netlbl_domhsh_walk() function; it removes LSM domain map entries278* which are associated with the CALIPSO DOI specified in @arg. Returns zero on279* success, negative values on failure.280*281*/282static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg)283{284struct netlbl_domhsh_walk_arg *cb_arg = arg;285286if (entry->def.type == NETLBL_NLTYPE_CALIPSO &&287entry->def.calipso->doi == cb_arg->doi)288return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);289290return 0;291}292293/**294* netlbl_calipso_remove - Handle a REMOVE message295* @skb: the NETLINK buffer296* @info: the Generic NETLINK info block297*298* Description:299* Process a user generated REMOVE message and respond accordingly. Returns300* zero on success, negative values on failure.301*302*/303static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)304{305int ret_val = -EINVAL;306struct netlbl_domhsh_walk_arg cb_arg;307struct netlbl_audit audit_info;308u32 skip_bkt = 0;309u32 skip_chain = 0;310311if (!info->attrs[NLBL_CALIPSO_A_DOI])312return -EINVAL;313314netlbl_netlink_auditinfo(&audit_info);315cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);316cb_arg.audit_info = &audit_info;317ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,318netlbl_calipso_remove_cb, &cb_arg);319if (ret_val == 0 || ret_val == -ENOENT) {320ret_val = calipso_doi_remove(cb_arg.doi, &audit_info);321if (ret_val == 0)322atomic_dec(&netlabel_mgmt_protocount);323}324325return ret_val;326}327328/* NetLabel Generic NETLINK Command Definitions329*/330331static const struct genl_small_ops netlbl_calipso_ops[] = {332{333.cmd = NLBL_CALIPSO_C_ADD,334.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,335.flags = GENL_ADMIN_PERM,336.doit = netlbl_calipso_add,337.dumpit = NULL,338},339{340.cmd = NLBL_CALIPSO_C_REMOVE,341.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,342.flags = GENL_ADMIN_PERM,343.doit = netlbl_calipso_remove,344.dumpit = NULL,345},346{347.cmd = NLBL_CALIPSO_C_LIST,348.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,349.flags = 0,350.doit = netlbl_calipso_list,351.dumpit = NULL,352},353{354.cmd = NLBL_CALIPSO_C_LISTALL,355.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,356.flags = 0,357.doit = NULL,358.dumpit = netlbl_calipso_listall,359},360};361362static struct genl_family netlbl_calipso_gnl_family __ro_after_init = {363.hdrsize = 0,364.name = NETLBL_NLTYPE_CALIPSO_NAME,365.version = NETLBL_PROTO_VERSION,366.maxattr = NLBL_CALIPSO_A_MAX,367.policy = calipso_genl_policy,368.module = THIS_MODULE,369.small_ops = netlbl_calipso_ops,370.n_small_ops = ARRAY_SIZE(netlbl_calipso_ops),371.resv_start_op = NLBL_CALIPSO_C_LISTALL + 1,372};373374/* NetLabel Generic NETLINK Protocol Functions375*/376377/**378* netlbl_calipso_genl_init - Register the CALIPSO NetLabel component379*380* Description:381* Register the CALIPSO packet NetLabel component with the Generic NETLINK382* mechanism. Returns zero on success, negative values on failure.383*384*/385int __init netlbl_calipso_genl_init(void)386{387return genl_register_family(&netlbl_calipso_gnl_family);388}389390/**391* calipso_doi_add - Add a new DOI to the CALIPSO protocol engine392* @doi_def: the DOI structure393* @audit_info: NetLabel audit information394*395* Description:396* The caller defines a new DOI for use by the CALIPSO engine and calls this397* function to add it to the list of acceptable domains. The caller must398* ensure that the mapping table specified in @doi_def->map meets all of the399* requirements of the mapping type (see calipso.h for details). Returns400* zero on success and non-zero on failure.401*402*/403int calipso_doi_add(struct calipso_doi *doi_def,404struct netlbl_audit *audit_info)405{406int ret_val = -ENOMSG;407const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();408409if (ops)410ret_val = ops->doi_add(doi_def, audit_info);411return ret_val;412}413414/**415* calipso_doi_free - Frees a DOI definition416* @doi_def: the DOI definition417*418* Description:419* This function frees all of the memory associated with a DOI definition.420*421*/422void calipso_doi_free(struct calipso_doi *doi_def)423{424const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();425426if (ops)427ops->doi_free(doi_def);428}429430/**431* calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine432* @doi: the DOI value433* @audit_info: NetLabel audit information434*435* Description:436* Removes a DOI definition from the CALIPSO engine. The NetLabel routines will437* be called to release their own LSM domain mappings as well as our own438* domain list. Returns zero on success and negative values on failure.439*440*/441int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)442{443int ret_val = -ENOMSG;444const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();445446if (ops)447ret_val = ops->doi_remove(doi, audit_info);448return ret_val;449}450451/**452* calipso_doi_getdef - Returns a reference to a valid DOI definition453* @doi: the DOI value454*455* Description:456* Searches for a valid DOI definition and if one is found it is returned to457* the caller. Otherwise NULL is returned. The caller must ensure that458* calipso_doi_putdef() is called when the caller is done.459*460*/461struct calipso_doi *calipso_doi_getdef(u32 doi)462{463struct calipso_doi *ret_val = NULL;464const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();465466if (ops)467ret_val = ops->doi_getdef(doi);468return ret_val;469}470471/**472* calipso_doi_putdef - Releases a reference for the given DOI definition473* @doi_def: the DOI definition474*475* Description:476* Releases a DOI definition reference obtained from calipso_doi_getdef().477*478*/479void calipso_doi_putdef(struct calipso_doi *doi_def)480{481const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();482483if (ops)484ops->doi_putdef(doi_def);485}486487/**488* calipso_doi_walk - Iterate through the DOI definitions489* @skip_cnt: skip past this number of DOI definitions, updated490* @callback: callback for each DOI definition491* @cb_arg: argument for the callback function492*493* Description:494* Iterate over the DOI definition list, skipping the first @skip_cnt entries.495* For each entry call @callback, if @callback returns a negative value stop496* 'walking' through the list and return. Updates the value in @skip_cnt upon497* return. Returns zero on success, negative values on failure.498*499*/500int calipso_doi_walk(u32 *skip_cnt,501int (*callback)(struct calipso_doi *doi_def, void *arg),502void *cb_arg)503{504int ret_val = -ENOMSG;505const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();506507if (ops)508ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);509return ret_val;510}511512/**513* calipso_sock_getattr - Get the security attributes from a sock514* @sk: the sock515* @secattr: the security attributes516*517* Description:518* Query @sk to see if there is a CALIPSO option attached to the sock and if519* there is return the CALIPSO security attributes in @secattr. This function520* requires that @sk be locked, or privately held, but it does not do any521* locking itself. Returns zero on success and negative values on failure.522*523*/524int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)525{526int ret_val = -ENOMSG;527const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();528529if (ops)530ret_val = ops->sock_getattr(sk, secattr);531return ret_val;532}533534/**535* calipso_sock_setattr - Add a CALIPSO option to a socket536* @sk: the socket537* @doi_def: the CALIPSO DOI to use538* @secattr: the specific security attributes of the socket539*540* Description:541* Set the CALIPSO option on the given socket using the DOI definition and542* security attributes passed to the function. This function requires543* exclusive access to @sk, which means it either needs to be in the544* process of being created or locked. Returns zero on success and negative545* values on failure.546*547*/548int calipso_sock_setattr(struct sock *sk,549const struct calipso_doi *doi_def,550const struct netlbl_lsm_secattr *secattr)551{552int ret_val = -ENOMSG;553const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();554555if (ops)556ret_val = ops->sock_setattr(sk, doi_def, secattr);557return ret_val;558}559560/**561* calipso_sock_delattr - Delete the CALIPSO option from a socket562* @sk: the socket563*564* Description:565* Removes the CALIPSO option from a socket, if present.566*567*/568void calipso_sock_delattr(struct sock *sk)569{570const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();571572if (ops)573ops->sock_delattr(sk);574}575576/**577* calipso_req_setattr - Add a CALIPSO option to a connection request socket578* @req: the connection request socket579* @doi_def: the CALIPSO DOI to use580* @secattr: the specific security attributes of the socket581*582* Description:583* Set the CALIPSO option on the given socket using the DOI definition and584* security attributes passed to the function. Returns zero on success and585* negative values on failure.586*587*/588int calipso_req_setattr(struct request_sock *req,589const struct calipso_doi *doi_def,590const struct netlbl_lsm_secattr *secattr)591{592int ret_val = -ENOMSG;593const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();594595if (ops)596ret_val = ops->req_setattr(req, doi_def, secattr);597return ret_val;598}599600/**601* calipso_req_delattr - Delete the CALIPSO option from a request socket602* @req: the request socket603*604* Description:605* Removes the CALIPSO option from a request socket, if present.606*607*/608void calipso_req_delattr(struct request_sock *req)609{610const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();611612if (ops)613ops->req_delattr(req);614}615616/**617* calipso_optptr - Find the CALIPSO option in the packet618* @skb: the packet619*620* Description:621* Parse the packet's IP header looking for a CALIPSO option. Returns a pointer622* to the start of the CALIPSO option on success, NULL if one if not found.623*624*/625unsigned char *calipso_optptr(const struct sk_buff *skb)626{627unsigned char *ret_val = NULL;628const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();629630if (ops)631ret_val = ops->skbuff_optptr(skb);632return ret_val;633}634635/**636* calipso_getattr - Get the security attributes from a memory block.637* @calipso: the CALIPSO option638* @secattr: the security attributes639*640* Description:641* Inspect @calipso and return the security attributes in @secattr.642* Returns zero on success and negative values on failure.643*644*/645int calipso_getattr(const unsigned char *calipso,646struct netlbl_lsm_secattr *secattr)647{648int ret_val = -ENOMSG;649const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();650651if (ops)652ret_val = ops->opt_getattr(calipso, secattr);653return ret_val;654}655656/**657* calipso_skbuff_setattr - Set the CALIPSO option on a packet658* @skb: the packet659* @doi_def: the CALIPSO DOI to use660* @secattr: the security attributes661*662* Description:663* Set the CALIPSO option on the given packet based on the security attributes.664* Returns a pointer to the IP header on success and NULL on failure.665*666*/667int calipso_skbuff_setattr(struct sk_buff *skb,668const struct calipso_doi *doi_def,669const struct netlbl_lsm_secattr *secattr)670{671int ret_val = -ENOMSG;672const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();673674if (ops)675ret_val = ops->skbuff_setattr(skb, doi_def, secattr);676return ret_val;677}678679/**680* calipso_skbuff_delattr - Delete any CALIPSO options from a packet681* @skb: the packet682*683* Description:684* Removes any and all CALIPSO options from the given packet. Returns zero on685* success, negative values on failure.686*687*/688int calipso_skbuff_delattr(struct sk_buff *skb)689{690int ret_val = -ENOMSG;691const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();692693if (ops)694ret_val = ops->skbuff_delattr(skb);695return ret_val;696}697698/**699* calipso_cache_invalidate - Invalidates the current CALIPSO cache700*701* Description:702* Invalidates and frees any entries in the CALIPSO cache. Returns zero on703* success and negative values on failure.704*705*/706void calipso_cache_invalidate(void)707{708const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();709710if (ops)711ops->cache_invalidate();712}713714/**715* calipso_cache_add - Add an entry to the CALIPSO cache716* @calipso_ptr: the CALIPSO option717* @secattr: the packet's security attributes718*719* Description:720* Add a new entry into the CALIPSO label mapping cache.721* Returns zero on success, negative values on failure.722*723*/724int calipso_cache_add(const unsigned char *calipso_ptr,725const struct netlbl_lsm_secattr *secattr)726727{728int ret_val = -ENOMSG;729const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();730731if (ops)732ret_val = ops->cache_add(calipso_ptr, secattr);733return ret_val;734}735736737