Merge branch 'stable-4.8' of git://git.infradead.org/users/pcmoore/selinux into next
This commit is contained in:
commit
d011a4d861
91
include/net/calipso.h
Normal file
91
include/net/calipso.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* CALIPSO - Common Architecture Label IPv6 Security Option
|
||||||
|
*
|
||||||
|
* This is an implementation of the CALIPSO protocol as specified in
|
||||||
|
* RFC 5570.
|
||||||
|
*
|
||||||
|
* Authors: Paul Moore <paul@paul-moore.com>
|
||||||
|
* Huw Davies <huw@codeweavers.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||||
|
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CALIPSO_H
|
||||||
|
#define _CALIPSO_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/rcupdate.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/net.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <net/netlabel.h>
|
||||||
|
#include <net/request_sock.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
|
/* known doi values */
|
||||||
|
#define CALIPSO_DOI_UNKNOWN 0x00000000
|
||||||
|
|
||||||
|
/* doi mapping types */
|
||||||
|
#define CALIPSO_MAP_UNKNOWN 0
|
||||||
|
#define CALIPSO_MAP_PASS 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CALIPSO DOI definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* DOI definition struct */
|
||||||
|
struct calipso_doi {
|
||||||
|
u32 doi;
|
||||||
|
u32 type;
|
||||||
|
|
||||||
|
atomic_t refcount;
|
||||||
|
struct list_head list;
|
||||||
|
struct rcu_head rcu;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sysctl Variables
|
||||||
|
*/
|
||||||
|
extern int calipso_cache_enabled;
|
||||||
|
extern int calipso_cache_bucketsize;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NETLABEL
|
||||||
|
int __init calipso_init(void);
|
||||||
|
void calipso_exit(void);
|
||||||
|
bool calipso_validate(const struct sk_buff *skb, const unsigned char *option);
|
||||||
|
#else
|
||||||
|
static inline int __init calipso_init(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void calipso_exit(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static inline bool calipso_validate(const struct sk_buff *skb,
|
||||||
|
const unsigned char *option)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_NETLABEL */
|
||||||
|
|
||||||
|
#endif /* _CALIPSO_H */
|
@ -97,7 +97,12 @@ struct inet_request_sock {
|
|||||||
u32 ir_mark;
|
u32 ir_mark;
|
||||||
union {
|
union {
|
||||||
struct ip_options_rcu *opt;
|
struct ip_options_rcu *opt;
|
||||||
struct sk_buff *pktopts;
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
struct {
|
||||||
|
struct ipv6_txoptions *ipv6_opt;
|
||||||
|
struct sk_buff *pktopts;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -313,11 +313,19 @@ struct ipv6_txoptions *ipv6_renew_options(struct sock *sk,
|
|||||||
int newtype,
|
int newtype,
|
||||||
struct ipv6_opt_hdr __user *newopt,
|
struct ipv6_opt_hdr __user *newopt,
|
||||||
int newoptlen);
|
int newoptlen);
|
||||||
|
struct ipv6_txoptions *
|
||||||
|
ipv6_renew_options_kern(struct sock *sk,
|
||||||
|
struct ipv6_txoptions *opt,
|
||||||
|
int newtype,
|
||||||
|
struct ipv6_opt_hdr *newopt,
|
||||||
|
int newoptlen);
|
||||||
struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
|
struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
|
||||||
struct ipv6_txoptions *opt);
|
struct ipv6_txoptions *opt);
|
||||||
|
|
||||||
bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb,
|
bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb,
|
||||||
const struct inet6_skb_parm *opt);
|
const struct inet6_skb_parm *opt);
|
||||||
|
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
||||||
|
struct ipv6_txoptions *opt);
|
||||||
|
|
||||||
static inline bool ipv6_accept_ra(struct inet6_dev *idev)
|
static inline bool ipv6_accept_ra(struct inet6_dev *idev)
|
||||||
{
|
{
|
||||||
@ -943,7 +951,7 @@ enum {
|
|||||||
int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target,
|
int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target,
|
||||||
unsigned short *fragoff, int *fragflg);
|
unsigned short *fragoff, int *fragflg);
|
||||||
|
|
||||||
int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);
|
int ipv6_find_tlv(const struct sk_buff *skb, int offset, int type);
|
||||||
|
|
||||||
struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
|
struct in6_addr *fl6_update_dst(struct flowi6 *fl6,
|
||||||
const struct ipv6_txoptions *opt,
|
const struct ipv6_txoptions *opt,
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
struct cipso_v4_doi;
|
struct cipso_v4_doi;
|
||||||
|
struct calipso_doi;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NetLabel - A management interface for maintaining network packet label
|
* NetLabel - A management interface for maintaining network packet label
|
||||||
@ -94,6 +95,8 @@ struct cipso_v4_doi;
|
|||||||
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
|
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
|
||||||
#define NETLBL_NLTYPE_ADDRSELECT 6
|
#define NETLBL_NLTYPE_ADDRSELECT 6
|
||||||
#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
|
#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
|
||||||
|
#define NETLBL_NLTYPE_CALIPSO 7
|
||||||
|
#define NETLBL_NLTYPE_CALIPSO_NAME "NLBL_CALIPSO"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* NetLabel - Kernel API for accessing the network packet label mappings.
|
* NetLabel - Kernel API for accessing the network packet label mappings.
|
||||||
@ -216,6 +219,63 @@ struct netlbl_lsm_secattr {
|
|||||||
} attr;
|
} attr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct netlbl_calipso_ops - NetLabel CALIPSO operations
|
||||||
|
* @doi_add: add a CALIPSO DOI
|
||||||
|
* @doi_free: free a CALIPSO DOI
|
||||||
|
* @doi_getdef: returns a reference to a DOI
|
||||||
|
* @doi_putdef: releases a reference of a DOI
|
||||||
|
* @doi_walk: enumerate the DOI list
|
||||||
|
* @sock_getattr: retrieve the socket's attr
|
||||||
|
* @sock_setattr: set the socket's attr
|
||||||
|
* @sock_delattr: remove the socket's attr
|
||||||
|
* @req_setattr: set the req socket's attr
|
||||||
|
* @req_delattr: remove the req socket's attr
|
||||||
|
* @opt_getattr: retrieve attr from memory block
|
||||||
|
* @skbuff_optptr: find option in packet
|
||||||
|
* @skbuff_setattr: set the skbuff's attr
|
||||||
|
* @skbuff_delattr: remove the skbuff's attr
|
||||||
|
* @cache_invalidate: invalidate cache
|
||||||
|
* @cache_add: add cache entry
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This structure is filled out by the CALIPSO engine and passed
|
||||||
|
* to the NetLabel core via a call to netlbl_calipso_ops_register().
|
||||||
|
* It enables the CALIPSO engine (and hence IPv6) to be compiled
|
||||||
|
* as a module.
|
||||||
|
*/
|
||||||
|
struct netlbl_calipso_ops {
|
||||||
|
int (*doi_add)(struct calipso_doi *doi_def,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
|
void (*doi_free)(struct calipso_doi *doi_def);
|
||||||
|
int (*doi_remove)(u32 doi, struct netlbl_audit *audit_info);
|
||||||
|
struct calipso_doi *(*doi_getdef)(u32 doi);
|
||||||
|
void (*doi_putdef)(struct calipso_doi *doi_def);
|
||||||
|
int (*doi_walk)(u32 *skip_cnt,
|
||||||
|
int (*callback)(struct calipso_doi *doi_def, void *arg),
|
||||||
|
void *cb_arg);
|
||||||
|
int (*sock_getattr)(struct sock *sk,
|
||||||
|
struct netlbl_lsm_secattr *secattr);
|
||||||
|
int (*sock_setattr)(struct sock *sk,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
void (*sock_delattr)(struct sock *sk);
|
||||||
|
int (*req_setattr)(struct request_sock *req,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
void (*req_delattr)(struct request_sock *req);
|
||||||
|
int (*opt_getattr)(const unsigned char *calipso,
|
||||||
|
struct netlbl_lsm_secattr *secattr);
|
||||||
|
unsigned char *(*skbuff_optptr)(const struct sk_buff *skb);
|
||||||
|
int (*skbuff_setattr)(struct sk_buff *skb,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
int (*skbuff_delattr)(struct sk_buff *skb);
|
||||||
|
void (*cache_invalidate)(void);
|
||||||
|
int (*cache_add)(const unsigned char *calipso_ptr,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LSM security attribute operations (inline)
|
* LSM security attribute operations (inline)
|
||||||
*/
|
*/
|
||||||
@ -385,6 +445,14 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
|
|||||||
const struct in_addr *addr,
|
const struct in_addr *addr,
|
||||||
const struct in_addr *mask,
|
const struct in_addr *mask,
|
||||||
struct netlbl_audit *audit_info);
|
struct netlbl_audit *audit_info);
|
||||||
|
int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
|
void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info);
|
||||||
|
int netlbl_cfg_calipso_map_add(u32 doi,
|
||||||
|
const char *domain,
|
||||||
|
const struct in6_addr *addr,
|
||||||
|
const struct in6_addr *mask,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
/*
|
/*
|
||||||
* LSM security attribute operations
|
* LSM security attribute operations
|
||||||
*/
|
*/
|
||||||
@ -405,6 +473,12 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
|
|||||||
unsigned long bitmap,
|
unsigned long bitmap,
|
||||||
gfp_t flags);
|
gfp_t flags);
|
||||||
|
|
||||||
|
/* Bitmap functions
|
||||||
|
*/
|
||||||
|
int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len,
|
||||||
|
u32 offset, u8 state);
|
||||||
|
void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LSM protocol operations (NetLabel LSM/kernel API)
|
* LSM protocol operations (NetLabel LSM/kernel API)
|
||||||
*/
|
*/
|
||||||
@ -427,13 +501,13 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
|||||||
int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||||
u16 family,
|
u16 family,
|
||||||
struct netlbl_lsm_secattr *secattr);
|
struct netlbl_lsm_secattr *secattr);
|
||||||
void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway);
|
void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LSM label mapping cache operations
|
* LSM label mapping cache operations
|
||||||
*/
|
*/
|
||||||
void netlbl_cache_invalidate(void);
|
void netlbl_cache_invalidate(void);
|
||||||
int netlbl_cache_add(const struct sk_buff *skb,
|
int netlbl_cache_add(const struct sk_buff *skb, u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr);
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -495,6 +569,24 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
|
|||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
static inline int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
static inline void netlbl_cfg_calipso_del(u32 doi,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
static inline int netlbl_cfg_calipso_map_add(u32 doi,
|
||||||
|
const char *domain,
|
||||||
|
const struct in6_addr *addr,
|
||||||
|
const struct in6_addr *mask,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap,
|
static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap,
|
||||||
u32 offset)
|
u32 offset)
|
||||||
{
|
{
|
||||||
@ -586,7 +678,7 @@ static inline void netlbl_cache_invalidate(void)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static inline int netlbl_cache_add(const struct sk_buff *skb,
|
static inline int netlbl_cache_add(const struct sk_buff *skb, u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
@ -598,4 +690,7 @@ static inline struct audit_buffer *netlbl_audit_start(int type,
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_NETLABEL */
|
#endif /* CONFIG_NETLABEL */
|
||||||
|
|
||||||
|
const struct netlbl_calipso_ops *
|
||||||
|
netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops);
|
||||||
|
|
||||||
#endif /* _NETLABEL_H */
|
#endif /* _NETLABEL_H */
|
||||||
|
@ -130,6 +130,8 @@
|
|||||||
#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */
|
#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */
|
||||||
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
|
#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */
|
||||||
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
|
#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */
|
||||||
|
#define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */
|
||||||
|
#define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */
|
||||||
|
|
||||||
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
|
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
|
||||||
#define AUDIT_LAST_KERN_ANOM_MSG 1799
|
#define AUDIT_LAST_KERN_ANOM_MSG 1799
|
||||||
|
@ -143,6 +143,7 @@ struct in6_flowlabel_req {
|
|||||||
#define IPV6_TLV_PAD1 0
|
#define IPV6_TLV_PAD1 0
|
||||||
#define IPV6_TLV_PADN 1
|
#define IPV6_TLV_PADN 1
|
||||||
#define IPV6_TLV_ROUTERALERT 5
|
#define IPV6_TLV_ROUTERALERT 5
|
||||||
|
#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
|
||||||
#define IPV6_TLV_JUMBO 194
|
#define IPV6_TLV_JUMBO 194
|
||||||
#define IPV6_TLV_HAO 201 /* home address option */
|
#define IPV6_TLV_HAO 201 /* home address option */
|
||||||
|
|
||||||
|
@ -216,14 +216,17 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
|
|||||||
skb = dccp_make_response(sk, dst, req);
|
skb = dccp_make_response(sk, dst, req);
|
||||||
if (skb != NULL) {
|
if (skb != NULL) {
|
||||||
struct dccp_hdr *dh = dccp_hdr(skb);
|
struct dccp_hdr *dh = dccp_hdr(skb);
|
||||||
|
struct ipv6_txoptions *opt;
|
||||||
|
|
||||||
dh->dccph_checksum = dccp_v6_csum_finish(skb,
|
dh->dccph_checksum = dccp_v6_csum_finish(skb,
|
||||||
&ireq->ir_v6_loc_addr,
|
&ireq->ir_v6_loc_addr,
|
||||||
&ireq->ir_v6_rmt_addr);
|
&ireq->ir_v6_rmt_addr);
|
||||||
fl6.daddr = ireq->ir_v6_rmt_addr;
|
fl6.daddr = ireq->ir_v6_rmt_addr;
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
|
opt = ireq->ipv6_opt;
|
||||||
np->tclass);
|
if (!opt)
|
||||||
|
opt = rcu_dereference(np->opt);
|
||||||
|
err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
err = net_xmit_eval(err);
|
err = net_xmit_eval(err);
|
||||||
}
|
}
|
||||||
@ -236,6 +239,7 @@ done:
|
|||||||
static void dccp_v6_reqsk_destructor(struct request_sock *req)
|
static void dccp_v6_reqsk_destructor(struct request_sock *req)
|
||||||
{
|
{
|
||||||
dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
|
dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
|
||||||
|
kfree(inet_rsk(req)->ipv6_opt);
|
||||||
kfree_skb(inet_rsk(req)->pktopts);
|
kfree_skb(inet_rsk(req)->pktopts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +498,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
|
|||||||
* Yes, keeping reference count would be much more clever, but we make
|
* Yes, keeping reference count would be much more clever, but we make
|
||||||
* one more one thing there: reattach optmem to newsk.
|
* one more one thing there: reattach optmem to newsk.
|
||||||
*/
|
*/
|
||||||
opt = rcu_dereference(np->opt);
|
opt = ireq->ipv6_opt;
|
||||||
|
if (!opt)
|
||||||
|
opt = rcu_dereference(np->opt);
|
||||||
if (opt) {
|
if (opt) {
|
||||||
opt = ipv6_dup_options(newsk, opt);
|
opt = ipv6_dup_options(newsk, opt);
|
||||||
RCU_INIT_POINTER(newnp->opt, opt);
|
RCU_INIT_POINTER(newnp->opt, opt);
|
||||||
|
@ -134,76 +134,6 @@ int cipso_v4_rbm_strictvalid = 1;
|
|||||||
* Helper Functions
|
* Helper Functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
|
|
||||||
* @bitmap: the bitmap
|
|
||||||
* @bitmap_len: length in bits
|
|
||||||
* @offset: starting offset
|
|
||||||
* @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Starting at @offset, walk the bitmap from left to right until either the
|
|
||||||
* desired bit is found or we reach the end. Return the bit offset, -1 if
|
|
||||||
* not found, or -2 if error.
|
|
||||||
*/
|
|
||||||
static int cipso_v4_bitmap_walk(const unsigned char *bitmap,
|
|
||||||
u32 bitmap_len,
|
|
||||||
u32 offset,
|
|
||||||
u8 state)
|
|
||||||
{
|
|
||||||
u32 bit_spot;
|
|
||||||
u32 byte_offset;
|
|
||||||
unsigned char bitmask;
|
|
||||||
unsigned char byte;
|
|
||||||
|
|
||||||
/* gcc always rounds to zero when doing integer division */
|
|
||||||
byte_offset = offset / 8;
|
|
||||||
byte = bitmap[byte_offset];
|
|
||||||
bit_spot = offset;
|
|
||||||
bitmask = 0x80 >> (offset % 8);
|
|
||||||
|
|
||||||
while (bit_spot < bitmap_len) {
|
|
||||||
if ((state && (byte & bitmask) == bitmask) ||
|
|
||||||
(state == 0 && (byte & bitmask) == 0))
|
|
||||||
return bit_spot;
|
|
||||||
|
|
||||||
bit_spot++;
|
|
||||||
bitmask >>= 1;
|
|
||||||
if (bitmask == 0) {
|
|
||||||
byte = bitmap[++byte_offset];
|
|
||||||
bitmask = 0x80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
|
|
||||||
* @bitmap: the bitmap
|
|
||||||
* @bit: the bit
|
|
||||||
* @state: if non-zero, set the bit (1) else clear the bit (0)
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Set a single bit in the bitmask. Returns zero on success, negative values
|
|
||||||
* on error.
|
|
||||||
*/
|
|
||||||
static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
|
|
||||||
u32 bit,
|
|
||||||
u8 state)
|
|
||||||
{
|
|
||||||
u32 byte_spot;
|
|
||||||
u8 bitmask;
|
|
||||||
|
|
||||||
/* gcc always rounds to zero when doing integer division */
|
|
||||||
byte_spot = bit / 8;
|
|
||||||
bitmask = 0x80 >> (bit % 8);
|
|
||||||
if (state)
|
|
||||||
bitmap[byte_spot] |= bitmask;
|
|
||||||
else
|
|
||||||
bitmap[byte_spot] &= ~bitmask;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cipso_v4_cache_entry_free - Frees a cache entry
|
* cipso_v4_cache_entry_free - Frees a cache entry
|
||||||
* @entry: the entry to free
|
* @entry: the entry to free
|
||||||
@ -840,10 +770,10 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
|
|||||||
cipso_cat_size = doi_def->map.std->cat.cipso_size;
|
cipso_cat_size = doi_def->map.std->cat.cipso_size;
|
||||||
cipso_array = doi_def->map.std->cat.cipso;
|
cipso_array = doi_def->map.std->cat.cipso;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
cat = cipso_v4_bitmap_walk(bitmap,
|
cat = netlbl_bitmap_walk(bitmap,
|
||||||
bitmap_len_bits,
|
bitmap_len_bits,
|
||||||
cat + 1,
|
cat + 1,
|
||||||
1);
|
1);
|
||||||
if (cat < 0)
|
if (cat < 0)
|
||||||
break;
|
break;
|
||||||
if (cat >= cipso_cat_size ||
|
if (cat >= cipso_cat_size ||
|
||||||
@ -909,7 +839,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
|
|||||||
}
|
}
|
||||||
if (net_spot >= net_clen_bits)
|
if (net_spot >= net_clen_bits)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
|
netlbl_bitmap_setbit(net_cat, net_spot, 1);
|
||||||
|
|
||||||
if (net_spot > net_spot_max)
|
if (net_spot > net_spot_max)
|
||||||
net_spot_max = net_spot;
|
net_spot_max = net_spot;
|
||||||
@ -951,10 +881,10 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
net_spot = cipso_v4_bitmap_walk(net_cat,
|
net_spot = netlbl_bitmap_walk(net_cat,
|
||||||
net_clen_bits,
|
net_clen_bits,
|
||||||
net_spot + 1,
|
net_spot + 1,
|
||||||
1);
|
1);
|
||||||
if (net_spot < 0) {
|
if (net_spot < 0) {
|
||||||
if (net_spot == -2)
|
if (net_spot == -2)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -6114,6 +6114,9 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
|
|||||||
|
|
||||||
kmemcheck_annotate_bitfield(ireq, flags);
|
kmemcheck_annotate_bitfield(ireq, flags);
|
||||||
ireq->opt = NULL;
|
ireq->opt = NULL;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
ireq->pktopts = NULL;
|
||||||
|
#endif
|
||||||
atomic64_set(&ireq->ir_cookie, 0);
|
atomic64_set(&ireq->ir_cookie, 0);
|
||||||
ireq->ireq_state = TCP_NEW_SYN_RECV;
|
ireq->ireq_state = TCP_NEW_SYN_RECV;
|
||||||
write_pnet(&ireq->ireq_net, sock_net(sk_listener));
|
write_pnet(&ireq->ireq_net, sock_net(sk_listener));
|
||||||
|
@ -22,6 +22,7 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o
|
|||||||
ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
|
ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o
|
||||||
ipv6-$(CONFIG_PROC_FS) += proc.o
|
ipv6-$(CONFIG_PROC_FS) += proc.o
|
||||||
ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
|
ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
|
||||||
|
ipv6-$(CONFIG_NETLABEL) += calipso.o
|
||||||
|
|
||||||
ipv6-objs += $(ipv6-y)
|
ipv6-objs += $(ipv6-y)
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@
|
|||||||
#ifdef CONFIG_IPV6_TUNNEL
|
#ifdef CONFIG_IPV6_TUNNEL
|
||||||
#include <net/ip6_tunnel.h>
|
#include <net/ip6_tunnel.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <net/calipso.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <linux/mroute6.h>
|
#include <linux/mroute6.h>
|
||||||
@ -977,6 +978,10 @@ static int __init inet6_init(void)
|
|||||||
if (err)
|
if (err)
|
||||||
goto pingv6_fail;
|
goto pingv6_fail;
|
||||||
|
|
||||||
|
err = calipso_init();
|
||||||
|
if (err)
|
||||||
|
goto calipso_fail;
|
||||||
|
|
||||||
#ifdef CONFIG_SYSCTL
|
#ifdef CONFIG_SYSCTL
|
||||||
err = ipv6_sysctl_register();
|
err = ipv6_sysctl_register();
|
||||||
if (err)
|
if (err)
|
||||||
@ -987,8 +992,10 @@ out:
|
|||||||
|
|
||||||
#ifdef CONFIG_SYSCTL
|
#ifdef CONFIG_SYSCTL
|
||||||
sysctl_fail:
|
sysctl_fail:
|
||||||
pingv6_exit();
|
calipso_exit();
|
||||||
#endif
|
#endif
|
||||||
|
calipso_fail:
|
||||||
|
pingv6_exit();
|
||||||
pingv6_fail:
|
pingv6_fail:
|
||||||
ipv6_packet_cleanup();
|
ipv6_packet_cleanup();
|
||||||
ipv6_packet_fail:
|
ipv6_packet_fail:
|
||||||
|
1473
net/ipv6/calipso.c
Normal file
1473
net/ipv6/calipso.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,7 @@
|
|||||||
#include <net/ndisc.h>
|
#include <net/ndisc.h>
|
||||||
#include <net/ip6_route.h>
|
#include <net/ip6_route.h>
|
||||||
#include <net/addrconf.h>
|
#include <net/addrconf.h>
|
||||||
|
#include <net/calipso.h>
|
||||||
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
#endif
|
#endif
|
||||||
@ -603,6 +604,28 @@ drop:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* CALIPSO RFC 5570 */
|
||||||
|
|
||||||
|
static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
|
||||||
|
{
|
||||||
|
const unsigned char *nh = skb_network_header(skb);
|
||||||
|
|
||||||
|
if (nh[optoff + 1] < 8)
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1])
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
if (!calipso_validate(skb, nh + optoff))
|
||||||
|
goto drop;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
drop:
|
||||||
|
kfree_skb(skb);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct tlvtype_proc tlvprochopopt_lst[] = {
|
static const struct tlvtype_proc tlvprochopopt_lst[] = {
|
||||||
{
|
{
|
||||||
.type = IPV6_TLV_ROUTERALERT,
|
.type = IPV6_TLV_ROUTERALERT,
|
||||||
@ -612,6 +635,10 @@ static const struct tlvtype_proc tlvprochopopt_lst[] = {
|
|||||||
.type = IPV6_TLV_JUMBO,
|
.type = IPV6_TLV_JUMBO,
|
||||||
.func = ipv6_hop_jumbo,
|
.func = ipv6_hop_jumbo,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.type = IPV6_TLV_CALIPSO,
|
||||||
|
.func = ipv6_hop_calipso,
|
||||||
|
},
|
||||||
{ -1, }
|
{ -1, }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -758,6 +785,27 @@ static int ipv6_renew_option(void *ohdr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipv6_renew_options - replace a specific ext hdr with a new one.
|
||||||
|
*
|
||||||
|
* @sk: sock from which to allocate memory
|
||||||
|
* @opt: original options
|
||||||
|
* @newtype: option type to replace in @opt
|
||||||
|
* @newopt: new option of type @newtype to replace (user-mem)
|
||||||
|
* @newoptlen: length of @newopt
|
||||||
|
*
|
||||||
|
* Returns a new set of options which is a copy of @opt with the
|
||||||
|
* option type @newtype replaced with @newopt.
|
||||||
|
*
|
||||||
|
* @opt may be NULL, in which case a new set of options is returned
|
||||||
|
* containing just @newopt.
|
||||||
|
*
|
||||||
|
* @newopt may be NULL, in which case the specified option type is
|
||||||
|
* not copied into the new set of options.
|
||||||
|
*
|
||||||
|
* The new set of options is allocated from the socket option memory
|
||||||
|
* buffer of @sk.
|
||||||
|
*/
|
||||||
struct ipv6_txoptions *
|
struct ipv6_txoptions *
|
||||||
ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
|
ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
|
||||||
int newtype,
|
int newtype,
|
||||||
@ -830,6 +878,34 @@ out:
|
|||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ipv6_renew_options_kern - replace a specific ext hdr with a new one.
|
||||||
|
*
|
||||||
|
* @sk: sock from which to allocate memory
|
||||||
|
* @opt: original options
|
||||||
|
* @newtype: option type to replace in @opt
|
||||||
|
* @newopt: new option of type @newtype to replace (kernel-mem)
|
||||||
|
* @newoptlen: length of @newopt
|
||||||
|
*
|
||||||
|
* See ipv6_renew_options(). The difference is that @newopt is
|
||||||
|
* kernel memory, rather than user memory.
|
||||||
|
*/
|
||||||
|
struct ipv6_txoptions *
|
||||||
|
ipv6_renew_options_kern(struct sock *sk, struct ipv6_txoptions *opt,
|
||||||
|
int newtype, struct ipv6_opt_hdr *newopt,
|
||||||
|
int newoptlen)
|
||||||
|
{
|
||||||
|
struct ipv6_txoptions *ret_val;
|
||||||
|
const mm_segment_t old_fs = get_fs();
|
||||||
|
|
||||||
|
set_fs(KERNEL_DS);
|
||||||
|
ret_val = ipv6_renew_options(sk, opt, newtype,
|
||||||
|
(struct ipv6_opt_hdr __user *)newopt,
|
||||||
|
newoptlen);
|
||||||
|
set_fs(old_fs);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
|
struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
|
||||||
struct ipv6_txoptions *opt)
|
struct ipv6_txoptions *opt)
|
||||||
{
|
{
|
||||||
|
@ -112,7 +112,7 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ipv6_skip_exthdr);
|
EXPORT_SYMBOL(ipv6_skip_exthdr);
|
||||||
|
|
||||||
int ipv6_find_tlv(struct sk_buff *skb, int offset, int type)
|
int ipv6_find_tlv(const struct sk_buff *skb, int offset, int type)
|
||||||
{
|
{
|
||||||
const unsigned char *nh = skb_network_header(skb);
|
const unsigned char *nh = skb_network_header(skb);
|
||||||
int packet_len = skb_tail_pointer(skb) - skb_network_header(skb);
|
int packet_len = skb_tail_pointer(skb) - skb_network_header(skb);
|
||||||
|
@ -98,7 +98,6 @@ int ip6_ra_control(struct sock *sk, int sel)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
||||||
struct ipv6_txoptions *opt)
|
struct ipv6_txoptions *opt)
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/addrconf.h>
|
#include <net/addrconf.h>
|
||||||
#include <net/inet_frag.h>
|
#include <net/inet_frag.h>
|
||||||
|
#ifdef CONFIG_NETLABEL
|
||||||
|
#include <net/calipso.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
static int one = 1;
|
static int one = 1;
|
||||||
static int auto_flowlabels_min;
|
static int auto_flowlabels_min;
|
||||||
@ -106,6 +109,22 @@ static struct ctl_table ipv6_rotable[] = {
|
|||||||
.proc_handler = proc_dointvec_minmax,
|
.proc_handler = proc_dointvec_minmax,
|
||||||
.extra1 = &one
|
.extra1 = &one
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_NETLABEL
|
||||||
|
{
|
||||||
|
.procname = "calipso_cache_enable",
|
||||||
|
.data = &calipso_cache_enabled,
|
||||||
|
.maxlen = sizeof(int),
|
||||||
|
.mode = 0644,
|
||||||
|
.proc_handler = proc_dointvec,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.procname = "calipso_cache_bucket_size",
|
||||||
|
.data = &calipso_cache_bucketsize,
|
||||||
|
.maxlen = sizeof(int),
|
||||||
|
.mode = 0644,
|
||||||
|
.proc_handler = proc_dointvec,
|
||||||
|
},
|
||||||
|
#endif /* CONFIG_NETLABEL */
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -443,6 +443,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
|
|||||||
{
|
{
|
||||||
struct inet_request_sock *ireq = inet_rsk(req);
|
struct inet_request_sock *ireq = inet_rsk(req);
|
||||||
struct ipv6_pinfo *np = inet6_sk(sk);
|
struct ipv6_pinfo *np = inet6_sk(sk);
|
||||||
|
struct ipv6_txoptions *opt;
|
||||||
struct flowi6 *fl6 = &fl->u.ip6;
|
struct flowi6 *fl6 = &fl->u.ip6;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
@ -463,8 +464,10 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
|
|||||||
fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
|
fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
|
opt = ireq->ipv6_opt;
|
||||||
np->tclass);
|
if (!opt)
|
||||||
|
opt = rcu_dereference(np->opt);
|
||||||
|
err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
err = net_xmit_eval(err);
|
err = net_xmit_eval(err);
|
||||||
}
|
}
|
||||||
@ -476,6 +479,7 @@ done:
|
|||||||
|
|
||||||
static void tcp_v6_reqsk_destructor(struct request_sock *req)
|
static void tcp_v6_reqsk_destructor(struct request_sock *req)
|
||||||
{
|
{
|
||||||
|
kfree(inet_rsk(req)->ipv6_opt);
|
||||||
kfree_skb(inet_rsk(req)->pktopts);
|
kfree_skb(inet_rsk(req)->pktopts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1109,7 +1113,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
|
|||||||
but we make one more one thing there: reattach optmem
|
but we make one more one thing there: reattach optmem
|
||||||
to newsk.
|
to newsk.
|
||||||
*/
|
*/
|
||||||
opt = rcu_dereference(np->opt);
|
opt = ireq->ipv6_opt;
|
||||||
|
if (!opt)
|
||||||
|
opt = rcu_dereference(np->opt);
|
||||||
if (opt) {
|
if (opt) {
|
||||||
opt = ipv6_dup_options(newsk, opt);
|
opt = ipv6_dup_options(newsk, opt);
|
||||||
RCU_INIT_POINTER(newnp->opt, opt);
|
RCU_INIT_POINTER(newnp->opt, opt);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
|
#include <linux/security.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/cpcmd.h>
|
#include <asm/cpcmd.h>
|
||||||
@ -530,8 +531,10 @@ static void iucv_sock_close(struct sock *sk)
|
|||||||
|
|
||||||
static void iucv_sock_init(struct sock *sk, struct sock *parent)
|
static void iucv_sock_init(struct sock *sk, struct sock *parent)
|
||||||
{
|
{
|
||||||
if (parent)
|
if (parent) {
|
||||||
sk->sk_type = parent->sk_type;
|
sk->sk_type = parent->sk_type;
|
||||||
|
security_sk_clone(parent, sk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio, int kern)
|
static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio, int kern)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
config NETLABEL
|
config NETLABEL
|
||||||
bool "NetLabel subsystem support"
|
bool "NetLabel subsystem support"
|
||||||
depends on SECURITY
|
depends on SECURITY
|
||||||
|
select CRC_CCITT if IPV6
|
||||||
default n
|
default n
|
||||||
---help---
|
---help---
|
||||||
NetLabel provides support for explicit network packet labeling
|
NetLabel provides support for explicit network packet labeling
|
||||||
|
@ -12,4 +12,4 @@ obj-y += netlabel_mgmt.o
|
|||||||
# protocol modules
|
# protocol modules
|
||||||
obj-y += netlabel_unlabeled.o
|
obj-y += netlabel_unlabeled.o
|
||||||
obj-y += netlabel_cipso_v4.o
|
obj-y += netlabel_cipso_v4.o
|
||||||
|
obj-$(subst m,y,$(CONFIG_IPV6)) += netlabel_calipso.o
|
||||||
|
740
net/netlabel/netlabel_calipso.c
Normal file
740
net/netlabel/netlabel_calipso.c
Normal file
@ -0,0 +1,740 @@
|
|||||||
|
/*
|
||||||
|
* NetLabel CALIPSO/IPv6 Support
|
||||||
|
*
|
||||||
|
* This file defines the CALIPSO/IPv6 functions for the NetLabel system. The
|
||||||
|
* NetLabel system manages static and dynamic label mappings for network
|
||||||
|
* protocols such as CIPSO and CALIPSO.
|
||||||
|
*
|
||||||
|
* Authors: Paul Moore <paul@paul-moore.com>
|
||||||
|
* Huw Davies <huw@codeweavers.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||||
|
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/socket.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/audit.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <net/sock.h>
|
||||||
|
#include <net/netlink.h>
|
||||||
|
#include <net/genetlink.h>
|
||||||
|
#include <net/netlabel.h>
|
||||||
|
#include <net/calipso.h>
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
|
#include "netlabel_user.h"
|
||||||
|
#include "netlabel_calipso.h"
|
||||||
|
#include "netlabel_mgmt.h"
|
||||||
|
#include "netlabel_domainhash.h"
|
||||||
|
|
||||||
|
/* Argument struct for calipso_doi_walk() */
|
||||||
|
struct netlbl_calipso_doiwalk_arg {
|
||||||
|
struct netlink_callback *nl_cb;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
u32 seq;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Argument struct for netlbl_domhsh_walk() */
|
||||||
|
struct netlbl_domhsh_walk_arg {
|
||||||
|
struct netlbl_audit *audit_info;
|
||||||
|
u32 doi;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NetLabel Generic NETLINK CALIPSO family */
|
||||||
|
static struct genl_family netlbl_calipso_gnl_family = {
|
||||||
|
.id = GENL_ID_GENERATE,
|
||||||
|
.hdrsize = 0,
|
||||||
|
.name = NETLBL_NLTYPE_CALIPSO_NAME,
|
||||||
|
.version = NETLBL_PROTO_VERSION,
|
||||||
|
.maxattr = NLBL_CALIPSO_A_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NetLabel Netlink attribute policy */
|
||||||
|
static const struct nla_policy calipso_genl_policy[NLBL_CALIPSO_A_MAX + 1] = {
|
||||||
|
[NLBL_CALIPSO_A_DOI] = { .type = NLA_U32 },
|
||||||
|
[NLBL_CALIPSO_A_MTYPE] = { .type = NLA_U32 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NetLabel Command Handlers
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition
|
||||||
|
* @info: the Generic NETLINK info block
|
||||||
|
* @audit_info: NetLabel audit information
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message
|
||||||
|
* and add it to the CALIPSO engine. Return zero on success and non-zero on
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_add_pass(struct genl_info *info,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
int ret_val;
|
||||||
|
struct calipso_doi *doi_def = NULL;
|
||||||
|
|
||||||
|
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
|
||||||
|
if (!doi_def)
|
||||||
|
return -ENOMEM;
|
||||||
|
doi_def->type = CALIPSO_MAP_PASS;
|
||||||
|
doi_def->doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
|
||||||
|
ret_val = calipso_doi_add(doi_def, audit_info);
|
||||||
|
if (ret_val != 0)
|
||||||
|
calipso_doi_free(doi_def);
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_add - Handle an ADD message
|
||||||
|
* @skb: the NETLINK buffer
|
||||||
|
* @info: the Generic NETLINK info block
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Create a new DOI definition based on the given ADD message and add it to the
|
||||||
|
* CALIPSO engine. Returns zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_add(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
||||||
|
{
|
||||||
|
int ret_val = -EINVAL;
|
||||||
|
struct netlbl_audit audit_info;
|
||||||
|
|
||||||
|
if (!info->attrs[NLBL_CALIPSO_A_DOI] ||
|
||||||
|
!info->attrs[NLBL_CALIPSO_A_MTYPE])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||||
|
switch (nla_get_u32(info->attrs[NLBL_CALIPSO_A_MTYPE])) {
|
||||||
|
case CALIPSO_MAP_PASS:
|
||||||
|
ret_val = netlbl_calipso_add_pass(info, &audit_info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ret_val == 0)
|
||||||
|
atomic_inc(&netlabel_mgmt_protocount);
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_list - Handle a LIST message
|
||||||
|
* @skb: the NETLINK buffer
|
||||||
|
* @info: the Generic NETLINK info block
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Process a user generated LIST message and respond accordingly.
|
||||||
|
* Returns zero on success and negative values on error.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_list(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
{
|
||||||
|
int ret_val;
|
||||||
|
struct sk_buff *ans_skb = NULL;
|
||||||
|
void *data;
|
||||||
|
u32 doi;
|
||||||
|
struct calipso_doi *doi_def;
|
||||||
|
|
||||||
|
if (!info->attrs[NLBL_CALIPSO_A_DOI]) {
|
||||||
|
ret_val = -EINVAL;
|
||||||
|
goto list_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
|
||||||
|
|
||||||
|
doi_def = calipso_doi_getdef(doi);
|
||||||
|
if (!doi_def) {
|
||||||
|
ret_val = -EINVAL;
|
||||||
|
goto list_failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||||
|
if (!ans_skb) {
|
||||||
|
ret_val = -ENOMEM;
|
||||||
|
goto list_failure_put;
|
||||||
|
}
|
||||||
|
data = genlmsg_put_reply(ans_skb, info, &netlbl_calipso_gnl_family,
|
||||||
|
0, NLBL_CALIPSO_C_LIST);
|
||||||
|
if (!data) {
|
||||||
|
ret_val = -ENOMEM;
|
||||||
|
goto list_failure_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_val = nla_put_u32(ans_skb, NLBL_CALIPSO_A_MTYPE, doi_def->type);
|
||||||
|
if (ret_val != 0)
|
||||||
|
goto list_failure_put;
|
||||||
|
|
||||||
|
calipso_doi_putdef(doi_def);
|
||||||
|
|
||||||
|
genlmsg_end(ans_skb, data);
|
||||||
|
return genlmsg_reply(ans_skb, info);
|
||||||
|
|
||||||
|
list_failure_put:
|
||||||
|
calipso_doi_putdef(doi_def);
|
||||||
|
list_failure:
|
||||||
|
kfree_skb(ans_skb);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL
|
||||||
|
* @doi_def: the CALIPSO DOI definition
|
||||||
|
* @arg: the netlbl_calipso_doiwalk_arg structure
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is designed to be used as a callback to the
|
||||||
|
* calipso_doi_walk() function for use in generating a response for a LISTALL
|
||||||
|
* message. Returns the size of the message on success, negative values on
|
||||||
|
* failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_listall_cb(struct calipso_doi *doi_def, void *arg)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMEM;
|
||||||
|
struct netlbl_calipso_doiwalk_arg *cb_arg = arg;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
|
||||||
|
cb_arg->seq, &netlbl_calipso_gnl_family,
|
||||||
|
NLM_F_MULTI, NLBL_CALIPSO_C_LISTALL);
|
||||||
|
if (!data)
|
||||||
|
goto listall_cb_failure;
|
||||||
|
|
||||||
|
ret_val = nla_put_u32(cb_arg->skb, NLBL_CALIPSO_A_DOI, doi_def->doi);
|
||||||
|
if (ret_val != 0)
|
||||||
|
goto listall_cb_failure;
|
||||||
|
ret_val = nla_put_u32(cb_arg->skb,
|
||||||
|
NLBL_CALIPSO_A_MTYPE,
|
||||||
|
doi_def->type);
|
||||||
|
if (ret_val != 0)
|
||||||
|
goto listall_cb_failure;
|
||||||
|
|
||||||
|
genlmsg_end(cb_arg->skb, data);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
listall_cb_failure:
|
||||||
|
genlmsg_cancel(cb_arg->skb, data);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_listall - Handle a LISTALL message
|
||||||
|
* @skb: the NETLINK buffer
|
||||||
|
* @cb: the NETLINK callback
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Process a user generated LISTALL message and respond accordingly. Returns
|
||||||
|
* zero on success and negative values on error.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_listall(struct sk_buff *skb,
|
||||||
|
struct netlink_callback *cb)
|
||||||
|
{
|
||||||
|
struct netlbl_calipso_doiwalk_arg cb_arg;
|
||||||
|
u32 doi_skip = cb->args[0];
|
||||||
|
|
||||||
|
cb_arg.nl_cb = cb;
|
||||||
|
cb_arg.skb = skb;
|
||||||
|
cb_arg.seq = cb->nlh->nlmsg_seq;
|
||||||
|
|
||||||
|
calipso_doi_walk(&doi_skip, netlbl_calipso_listall_cb, &cb_arg);
|
||||||
|
|
||||||
|
cb->args[0] = doi_skip;
|
||||||
|
return skb->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_remove_cb - netlbl_calipso_remove() callback for REMOVE
|
||||||
|
* @entry: LSM domain mapping entry
|
||||||
|
* @arg: the netlbl_domhsh_walk_arg structure
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function is intended for use by netlbl_calipso_remove() as the callback
|
||||||
|
* for the netlbl_domhsh_walk() function; it removes LSM domain map entries
|
||||||
|
* which are associated with the CALIPSO DOI specified in @arg. Returns zero on
|
||||||
|
* success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_remove_cb(struct netlbl_dom_map *entry, void *arg)
|
||||||
|
{
|
||||||
|
struct netlbl_domhsh_walk_arg *cb_arg = arg;
|
||||||
|
|
||||||
|
if (entry->def.type == NETLBL_NLTYPE_CALIPSO &&
|
||||||
|
entry->def.calipso->doi == cb_arg->doi)
|
||||||
|
return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_remove - Handle a REMOVE message
|
||||||
|
* @skb: the NETLINK buffer
|
||||||
|
* @info: the Generic NETLINK info block
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Process a user generated REMOVE message and respond accordingly. Returns
|
||||||
|
* zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static int netlbl_calipso_remove(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
{
|
||||||
|
int ret_val = -EINVAL;
|
||||||
|
struct netlbl_domhsh_walk_arg cb_arg;
|
||||||
|
struct netlbl_audit audit_info;
|
||||||
|
u32 skip_bkt = 0;
|
||||||
|
u32 skip_chain = 0;
|
||||||
|
|
||||||
|
if (!info->attrs[NLBL_CALIPSO_A_DOI])
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||||
|
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CALIPSO_A_DOI]);
|
||||||
|
cb_arg.audit_info = &audit_info;
|
||||||
|
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
|
||||||
|
netlbl_calipso_remove_cb, &cb_arg);
|
||||||
|
if (ret_val == 0 || ret_val == -ENOENT) {
|
||||||
|
ret_val = calipso_doi_remove(cb_arg.doi, &audit_info);
|
||||||
|
if (ret_val == 0)
|
||||||
|
atomic_dec(&netlabel_mgmt_protocount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NetLabel Generic NETLINK Command Definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const struct genl_ops netlbl_calipso_ops[] = {
|
||||||
|
{
|
||||||
|
.cmd = NLBL_CALIPSO_C_ADD,
|
||||||
|
.flags = GENL_ADMIN_PERM,
|
||||||
|
.policy = calipso_genl_policy,
|
||||||
|
.doit = netlbl_calipso_add,
|
||||||
|
.dumpit = NULL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = NLBL_CALIPSO_C_REMOVE,
|
||||||
|
.flags = GENL_ADMIN_PERM,
|
||||||
|
.policy = calipso_genl_policy,
|
||||||
|
.doit = netlbl_calipso_remove,
|
||||||
|
.dumpit = NULL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = NLBL_CALIPSO_C_LIST,
|
||||||
|
.flags = 0,
|
||||||
|
.policy = calipso_genl_policy,
|
||||||
|
.doit = netlbl_calipso_list,
|
||||||
|
.dumpit = NULL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = NLBL_CALIPSO_C_LISTALL,
|
||||||
|
.flags = 0,
|
||||||
|
.policy = calipso_genl_policy,
|
||||||
|
.doit = NULL,
|
||||||
|
.dumpit = netlbl_calipso_listall,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NetLabel Generic NETLINK Protocol Functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_genl_init - Register the CALIPSO NetLabel component
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Register the CALIPSO packet NetLabel component with the Generic NETLINK
|
||||||
|
* mechanism. Returns zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int __init netlbl_calipso_genl_init(void)
|
||||||
|
{
|
||||||
|
return genl_register_family_with_ops(&netlbl_calipso_gnl_family,
|
||||||
|
netlbl_calipso_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct netlbl_calipso_ops *calipso_ops;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_calipso_ops_register - Register the CALIPSO operations
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Register the CALIPSO packet engine operations.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const struct netlbl_calipso_ops *
|
||||||
|
netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops)
|
||||||
|
{
|
||||||
|
return xchg(&calipso_ops, ops);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(netlbl_calipso_ops_register);
|
||||||
|
|
||||||
|
static const struct netlbl_calipso_ops *netlbl_calipso_ops_get(void)
|
||||||
|
{
|
||||||
|
return ACCESS_ONCE(calipso_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
|
||||||
|
* @doi_def: the DOI structure
|
||||||
|
* @audit_info: NetLabel audit information
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* The caller defines a new DOI for use by the CALIPSO engine and calls this
|
||||||
|
* function to add it to the list of acceptable domains. The caller must
|
||||||
|
* ensure that the mapping table specified in @doi_def->map meets all of the
|
||||||
|
* requirements of the mapping type (see calipso.h for details). Returns
|
||||||
|
* zero on success and non-zero on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_doi_add(struct calipso_doi *doi_def,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->doi_add(doi_def, audit_info);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_doi_free - Frees a DOI definition
|
||||||
|
* @doi_def: the DOI definition
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* This function frees all of the memory associated with a DOI definition.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void calipso_doi_free(struct calipso_doi *doi_def)
|
||||||
|
{
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ops->doi_free(doi_def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
|
||||||
|
* @doi: the DOI value
|
||||||
|
* @audit_secid: the LSM secid to use in the audit message
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes a DOI definition from the CALIPSO engine. The NetLabel routines will
|
||||||
|
* be called to release their own LSM domain mappings as well as our own
|
||||||
|
* domain list. Returns zero on success and negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->doi_remove(doi, audit_info);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_doi_getdef - Returns a reference to a valid DOI definition
|
||||||
|
* @doi: the DOI value
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Searches for a valid DOI definition and if one is found it is returned to
|
||||||
|
* the caller. Otherwise NULL is returned. The caller must ensure that
|
||||||
|
* calipso_doi_putdef() is called when the caller is done.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct calipso_doi *calipso_doi_getdef(u32 doi)
|
||||||
|
{
|
||||||
|
struct calipso_doi *ret_val = NULL;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->doi_getdef(doi);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_doi_putdef - Releases a reference for the given DOI definition
|
||||||
|
* @doi_def: the DOI definition
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Releases a DOI definition reference obtained from calipso_doi_getdef().
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void calipso_doi_putdef(struct calipso_doi *doi_def)
|
||||||
|
{
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ops->doi_putdef(doi_def);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_doi_walk - Iterate through the DOI definitions
|
||||||
|
* @skip_cnt: skip past this number of DOI definitions, updated
|
||||||
|
* @callback: callback for each DOI definition
|
||||||
|
* @cb_arg: argument for the callback function
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Iterate over the DOI definition list, skipping the first @skip_cnt entries.
|
||||||
|
* For each entry call @callback, if @callback returns a negative value stop
|
||||||
|
* 'walking' through the list and return. Updates the value in @skip_cnt upon
|
||||||
|
* return. Returns zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_doi_walk(u32 *skip_cnt,
|
||||||
|
int (*callback)(struct calipso_doi *doi_def, void *arg),
|
||||||
|
void *cb_arg)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->doi_walk(skip_cnt, callback, cb_arg);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_sock_getattr - Get the security attributes from a sock
|
||||||
|
* @sk: the sock
|
||||||
|
* @secattr: the security attributes
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Query @sk to see if there is a CALIPSO option attached to the sock and if
|
||||||
|
* there is return the CALIPSO security attributes in @secattr. This function
|
||||||
|
* requires that @sk be locked, or privately held, but it does not do any
|
||||||
|
* locking itself. Returns zero on success and negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->sock_getattr(sk, secattr);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_sock_setattr - Add a CALIPSO option to a socket
|
||||||
|
* @sk: the socket
|
||||||
|
* @doi_def: the CALIPSO DOI to use
|
||||||
|
* @secattr: the specific security attributes of the socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set the CALIPSO option on the given socket using the DOI definition and
|
||||||
|
* security attributes passed to the function. This function requires
|
||||||
|
* exclusive access to @sk, which means it either needs to be in the
|
||||||
|
* process of being created or locked. Returns zero on success and negative
|
||||||
|
* values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_sock_setattr(struct sock *sk,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->sock_setattr(sk, doi_def, secattr);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_sock_delattr - Delete the CALIPSO option from a socket
|
||||||
|
* @sk: the socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes the CALIPSO option from a socket, if present.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void calipso_sock_delattr(struct sock *sk)
|
||||||
|
{
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ops->sock_delattr(sk);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_req_setattr - Add a CALIPSO option to a connection request socket
|
||||||
|
* @req: the connection request socket
|
||||||
|
* @doi_def: the CALIPSO DOI to use
|
||||||
|
* @secattr: the specific security attributes of the socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set the CALIPSO option on the given socket using the DOI definition and
|
||||||
|
* security attributes passed to the function. Returns zero on success and
|
||||||
|
* negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_req_setattr(struct request_sock *req,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->req_setattr(req, doi_def, secattr);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_req_delattr - Delete the CALIPSO option from a request socket
|
||||||
|
* @reg: the request socket
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes the CALIPSO option from a request socket, if present.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void calipso_req_delattr(struct request_sock *req)
|
||||||
|
{
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ops->req_delattr(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_optptr - Find the CALIPSO option in the packet
|
||||||
|
* @skb: the packet
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
|
||||||
|
* to the start of the CALIPSO option on success, NULL if one if not found.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
unsigned char *calipso_optptr(const struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
unsigned char *ret_val = NULL;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->skbuff_optptr(skb);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_getattr - Get the security attributes from a memory block.
|
||||||
|
* @calipso: the CALIPSO option
|
||||||
|
* @secattr: the security attributes
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Inspect @calipso and return the security attributes in @secattr.
|
||||||
|
* Returns zero on success and negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_getattr(const unsigned char *calipso,
|
||||||
|
struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->opt_getattr(calipso, secattr);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_skbuff_setattr - Set the CALIPSO option on a packet
|
||||||
|
* @skb: the packet
|
||||||
|
* @doi_def: the CALIPSO DOI to use
|
||||||
|
* @secattr: the security attributes
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set the CALIPSO option on the given packet based on the security attributes.
|
||||||
|
* Returns a pointer to the IP header on success and NULL on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_skbuff_setattr(struct sk_buff *skb,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->skbuff_setattr(skb, doi_def, secattr);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_skbuff_delattr - Delete any CALIPSO options from a packet
|
||||||
|
* @skb: the packet
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes any and all CALIPSO options from the given packet. Returns zero on
|
||||||
|
* success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_skbuff_delattr(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->skbuff_delattr(skb);
|
||||||
|
return ret_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_cache_invalidate - Invalidates the current CALIPSO cache
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Invalidates and frees any entries in the CALIPSO cache. Returns zero on
|
||||||
|
* success and negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void calipso_cache_invalidate(void)
|
||||||
|
{
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ops->cache_invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calipso_cache_add - Add an entry to the CALIPSO cache
|
||||||
|
* @calipso_ptr: the CALIPSO option
|
||||||
|
* @secattr: the packet's security attributes
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Add a new entry into the CALIPSO label mapping cache.
|
||||||
|
* Returns zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int calipso_cache_add(const unsigned char *calipso_ptr,
|
||||||
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
|
|
||||||
|
{
|
||||||
|
int ret_val = -ENOMSG;
|
||||||
|
const struct netlbl_calipso_ops *ops = netlbl_calipso_ops_get();
|
||||||
|
|
||||||
|
if (ops)
|
||||||
|
ret_val = ops->cache_add(calipso_ptr, secattr);
|
||||||
|
return ret_val;
|
||||||
|
}
|
151
net/netlabel/netlabel_calipso.h
Normal file
151
net/netlabel/netlabel_calipso.h
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* NetLabel CALIPSO Support
|
||||||
|
*
|
||||||
|
* This file defines the CALIPSO functions for the NetLabel system. The
|
||||||
|
* NetLabel system manages static and dynamic label mappings for network
|
||||||
|
* protocols such as CIPSO and RIPSO.
|
||||||
|
*
|
||||||
|
* Authors: Paul Moore <paul@paul-moore.com>
|
||||||
|
* Huw Davies <huw@codeweavers.com>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||||
|
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||||
|
* the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _NETLABEL_CALIPSO
|
||||||
|
#define _NETLABEL_CALIPSO
|
||||||
|
|
||||||
|
#include <net/netlabel.h>
|
||||||
|
#include <net/calipso.h>
|
||||||
|
|
||||||
|
/* The following NetLabel payloads are supported by the CALIPSO subsystem.
|
||||||
|
*
|
||||||
|
* o ADD:
|
||||||
|
* Sent by an application to add a new DOI mapping table.
|
||||||
|
*
|
||||||
|
* Required attributes:
|
||||||
|
*
|
||||||
|
* NLBL_CALIPSO_A_DOI
|
||||||
|
* NLBL_CALIPSO_A_MTYPE
|
||||||
|
*
|
||||||
|
* If using CALIPSO_MAP_PASS no additional attributes are required.
|
||||||
|
*
|
||||||
|
* o REMOVE:
|
||||||
|
* Sent by an application to remove a specific DOI mapping table from the
|
||||||
|
* CALIPSO system.
|
||||||
|
*
|
||||||
|
* Required attributes:
|
||||||
|
*
|
||||||
|
* NLBL_CALIPSO_A_DOI
|
||||||
|
*
|
||||||
|
* o LIST:
|
||||||
|
* Sent by an application to list the details of a DOI definition. On
|
||||||
|
* success the kernel should send a response using the following format.
|
||||||
|
*
|
||||||
|
* Required attributes:
|
||||||
|
*
|
||||||
|
* NLBL_CALIPSO_A_DOI
|
||||||
|
*
|
||||||
|
* The valid response message format depends on the type of the DOI mapping,
|
||||||
|
* the defined formats are shown below.
|
||||||
|
*
|
||||||
|
* Required attributes:
|
||||||
|
*
|
||||||
|
* NLBL_CALIPSO_A_MTYPE
|
||||||
|
*
|
||||||
|
* If using CALIPSO_MAP_PASS no additional attributes are required.
|
||||||
|
*
|
||||||
|
* o LISTALL:
|
||||||
|
* This message is sent by an application to list the valid DOIs on the
|
||||||
|
* system. When sent by an application there is no payload and the
|
||||||
|
* NLM_F_DUMP flag should be set. The kernel should respond with a series of
|
||||||
|
* the following messages.
|
||||||
|
*
|
||||||
|
* Required attributes:
|
||||||
|
*
|
||||||
|
* NLBL_CALIPSO_A_DOI
|
||||||
|
* NLBL_CALIPSO_A_MTYPE
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NetLabel CALIPSO commands */
|
||||||
|
enum {
|
||||||
|
NLBL_CALIPSO_C_UNSPEC,
|
||||||
|
NLBL_CALIPSO_C_ADD,
|
||||||
|
NLBL_CALIPSO_C_REMOVE,
|
||||||
|
NLBL_CALIPSO_C_LIST,
|
||||||
|
NLBL_CALIPSO_C_LISTALL,
|
||||||
|
__NLBL_CALIPSO_C_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* NetLabel CALIPSO attributes */
|
||||||
|
enum {
|
||||||
|
NLBL_CALIPSO_A_UNSPEC,
|
||||||
|
NLBL_CALIPSO_A_DOI,
|
||||||
|
/* (NLA_U32)
|
||||||
|
* the DOI value */
|
||||||
|
NLBL_CALIPSO_A_MTYPE,
|
||||||
|
/* (NLA_U32)
|
||||||
|
* the mapping table type (defined in the calipso.h header as
|
||||||
|
* CALIPSO_MAP_*) */
|
||||||
|
__NLBL_CALIPSO_A_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NLBL_CALIPSO_A_MAX (__NLBL_CALIPSO_A_MAX - 1)
|
||||||
|
|
||||||
|
/* NetLabel protocol functions */
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
int netlbl_calipso_genl_init(void);
|
||||||
|
#else
|
||||||
|
static inline int netlbl_calipso_genl_init(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int calipso_doi_add(struct calipso_doi *doi_def,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
|
void calipso_doi_free(struct calipso_doi *doi_def);
|
||||||
|
int calipso_doi_remove(u32 doi, struct netlbl_audit *audit_info);
|
||||||
|
struct calipso_doi *calipso_doi_getdef(u32 doi);
|
||||||
|
void calipso_doi_putdef(struct calipso_doi *doi_def);
|
||||||
|
int calipso_doi_walk(u32 *skip_cnt,
|
||||||
|
int (*callback)(struct calipso_doi *doi_def, void *arg),
|
||||||
|
void *cb_arg);
|
||||||
|
int calipso_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
|
||||||
|
int calipso_sock_setattr(struct sock *sk,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
void calipso_sock_delattr(struct sock *sk);
|
||||||
|
int calipso_req_setattr(struct request_sock *req,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
void calipso_req_delattr(struct request_sock *req);
|
||||||
|
unsigned char *calipso_optptr(const struct sk_buff *skb);
|
||||||
|
int calipso_getattr(const unsigned char *calipso,
|
||||||
|
struct netlbl_lsm_secattr *secattr);
|
||||||
|
int calipso_skbuff_setattr(struct sk_buff *skb,
|
||||||
|
const struct calipso_doi *doi_def,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
int calipso_skbuff_delattr(struct sk_buff *skb);
|
||||||
|
void calipso_cache_invalidate(void);
|
||||||
|
int calipso_cache_add(const unsigned char *calipso_ptr,
|
||||||
|
const struct netlbl_lsm_secattr *secattr);
|
||||||
|
|
||||||
|
#endif
|
@ -37,10 +37,12 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <net/netlabel.h>
|
#include <net/netlabel.h>
|
||||||
#include <net/cipso_ipv4.h>
|
#include <net/cipso_ipv4.h>
|
||||||
|
#include <net/calipso.h>
|
||||||
#include <asm/bug.h>
|
#include <asm/bug.h>
|
||||||
|
|
||||||
#include "netlabel_mgmt.h"
|
#include "netlabel_mgmt.h"
|
||||||
#include "netlabel_addrlist.h"
|
#include "netlabel_addrlist.h"
|
||||||
|
#include "netlabel_calipso.h"
|
||||||
#include "netlabel_domainhash.h"
|
#include "netlabel_domainhash.h"
|
||||||
#include "netlabel_user.h"
|
#include "netlabel_user.h"
|
||||||
|
|
||||||
@ -55,8 +57,9 @@ struct netlbl_domhsh_tbl {
|
|||||||
static DEFINE_SPINLOCK(netlbl_domhsh_lock);
|
static DEFINE_SPINLOCK(netlbl_domhsh_lock);
|
||||||
#define netlbl_domhsh_rcu_deref(p) \
|
#define netlbl_domhsh_rcu_deref(p) \
|
||||||
rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
|
rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
|
||||||
static struct netlbl_domhsh_tbl *netlbl_domhsh;
|
static struct netlbl_domhsh_tbl __rcu *netlbl_domhsh;
|
||||||
static struct netlbl_dom_map *netlbl_domhsh_def;
|
static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv4;
|
||||||
|
static struct netlbl_dom_map __rcu *netlbl_domhsh_def_ipv6;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Domain Hash Table Helper Functions
|
* Domain Hash Table Helper Functions
|
||||||
@ -126,18 +129,26 @@ static u32 netlbl_domhsh_hash(const char *key)
|
|||||||
return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
|
return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool netlbl_family_match(u16 f1, u16 f2)
|
||||||
|
{
|
||||||
|
return (f1 == f2) || (f1 == AF_UNSPEC) || (f2 == AF_UNSPEC);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_domhsh_search - Search for a domain entry
|
* netlbl_domhsh_search - Search for a domain entry
|
||||||
* @domain: the domain
|
* @domain: the domain
|
||||||
|
* @family: the address family
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Searches the domain hash table and returns a pointer to the hash table
|
* Searches the domain hash table and returns a pointer to the hash table
|
||||||
* entry if found, otherwise NULL is returned. The caller is responsible for
|
* entry if found, otherwise NULL is returned. @family may be %AF_UNSPEC
|
||||||
|
* which matches any address family entries. The caller is responsible for
|
||||||
* ensuring that the hash table is protected with either a RCU read lock or the
|
* ensuring that the hash table is protected with either a RCU read lock or the
|
||||||
* hash table lock.
|
* hash table lock.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
|
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain,
|
||||||
|
u16 family)
|
||||||
{
|
{
|
||||||
u32 bkt;
|
u32 bkt;
|
||||||
struct list_head *bkt_list;
|
struct list_head *bkt_list;
|
||||||
@ -147,7 +158,9 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
|
|||||||
bkt = netlbl_domhsh_hash(domain);
|
bkt = netlbl_domhsh_hash(domain);
|
||||||
bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
|
bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
|
||||||
list_for_each_entry_rcu(iter, bkt_list, list)
|
list_for_each_entry_rcu(iter, bkt_list, list)
|
||||||
if (iter->valid && strcmp(iter->domain, domain) == 0)
|
if (iter->valid &&
|
||||||
|
netlbl_family_match(iter->family, family) &&
|
||||||
|
strcmp(iter->domain, domain) == 0)
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,28 +170,37 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
|
|||||||
/**
|
/**
|
||||||
* netlbl_domhsh_search_def - Search for a domain entry
|
* netlbl_domhsh_search_def - Search for a domain entry
|
||||||
* @domain: the domain
|
* @domain: the domain
|
||||||
* @def: return default if no match is found
|
* @family: the address family
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Searches the domain hash table and returns a pointer to the hash table
|
* Searches the domain hash table and returns a pointer to the hash table
|
||||||
* entry if an exact match is found, if an exact match is not present in the
|
* entry if an exact match is found, if an exact match is not present in the
|
||||||
* hash table then the default entry is returned if valid otherwise NULL is
|
* hash table then the default entry is returned if valid otherwise NULL is
|
||||||
* returned. The caller is responsible ensuring that the hash table is
|
* returned. @family may be %AF_UNSPEC which matches any address family
|
||||||
|
* entries. The caller is responsible ensuring that the hash table is
|
||||||
* protected with either a RCU read lock or the hash table lock.
|
* protected with either a RCU read lock or the hash table lock.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
|
static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain,
|
||||||
|
u16 family)
|
||||||
{
|
{
|
||||||
struct netlbl_dom_map *entry;
|
struct netlbl_dom_map *entry;
|
||||||
|
|
||||||
entry = netlbl_domhsh_search(domain);
|
entry = netlbl_domhsh_search(domain, family);
|
||||||
if (entry == NULL) {
|
if (entry != NULL)
|
||||||
entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def);
|
return entry;
|
||||||
if (entry != NULL && !entry->valid)
|
if (family == AF_INET || family == AF_UNSPEC) {
|
||||||
entry = NULL;
|
entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv4);
|
||||||
|
if (entry != NULL && entry->valid)
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
if (family == AF_INET6 || family == AF_UNSPEC) {
|
||||||
|
entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def_ipv6);
|
||||||
|
if (entry != NULL && entry->valid)
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -203,6 +225,7 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
|
|||||||
{
|
{
|
||||||
struct audit_buffer *audit_buf;
|
struct audit_buffer *audit_buf;
|
||||||
struct cipso_v4_doi *cipsov4 = NULL;
|
struct cipso_v4_doi *cipsov4 = NULL;
|
||||||
|
struct calipso_doi *calipso = NULL;
|
||||||
u32 type;
|
u32 type;
|
||||||
|
|
||||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
|
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
|
||||||
@ -221,12 +244,14 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
|
|||||||
struct netlbl_domaddr6_map *map6;
|
struct netlbl_domaddr6_map *map6;
|
||||||
map6 = netlbl_domhsh_addr6_entry(addr6);
|
map6 = netlbl_domhsh_addr6_entry(addr6);
|
||||||
type = map6->def.type;
|
type = map6->def.type;
|
||||||
|
calipso = map6->def.calipso;
|
||||||
netlbl_af6list_audit_addr(audit_buf, 0, NULL,
|
netlbl_af6list_audit_addr(audit_buf, 0, NULL,
|
||||||
&addr6->addr, &addr6->mask);
|
&addr6->addr, &addr6->mask);
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
} else {
|
} else {
|
||||||
type = entry->def.type;
|
type = entry->def.type;
|
||||||
cipsov4 = entry->def.cipso;
|
cipsov4 = entry->def.cipso;
|
||||||
|
calipso = entry->def.calipso;
|
||||||
}
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
@ -238,6 +263,12 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
|
|||||||
" nlbl_protocol=cipsov4 cipso_doi=%u",
|
" nlbl_protocol=cipsov4 cipso_doi=%u",
|
||||||
cipsov4->doi);
|
cipsov4->doi);
|
||||||
break;
|
break;
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
BUG_ON(calipso == NULL);
|
||||||
|
audit_log_format(audit_buf,
|
||||||
|
" nlbl_protocol=calipso calipso_doi=%u",
|
||||||
|
calipso->doi);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
|
audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
|
||||||
audit_log_end(audit_buf);
|
audit_log_end(audit_buf);
|
||||||
@ -264,13 +295,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
|
|||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (entry->family != AF_INET && entry->family != AF_INET6 &&
|
||||||
|
(entry->family != AF_UNSPEC ||
|
||||||
|
entry->def.type != NETLBL_NLTYPE_UNLABELED))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
switch (entry->def.type) {
|
switch (entry->def.type) {
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
if (entry->def.cipso != NULL || entry->def.addrsel != NULL)
|
if (entry->def.cipso != NULL || entry->def.calipso != NULL ||
|
||||||
|
entry->def.addrsel != NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_CIPSOV4:
|
case NETLBL_NLTYPE_CIPSOV4:
|
||||||
if (entry->def.cipso == NULL)
|
if (entry->family != AF_INET ||
|
||||||
|
entry->def.cipso == NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
if (entry->family != AF_INET6 ||
|
||||||
|
entry->def.calipso == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_ADDRSELECT:
|
case NETLBL_NLTYPE_ADDRSELECT:
|
||||||
@ -294,6 +337,12 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
|
|||||||
map6 = netlbl_domhsh_addr6_entry(iter6);
|
map6 = netlbl_domhsh_addr6_entry(iter6);
|
||||||
switch (map6->def.type) {
|
switch (map6->def.type) {
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
if (map6->def.calipso != NULL)
|
||||||
|
return -EINVAL;
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
if (map6->def.calipso == NULL)
|
||||||
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -358,15 +407,18 @@ int __init netlbl_domhsh_init(u32 size)
|
|||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Adds a new entry to the domain hash table and handles any updates to the
|
* Adds a new entry to the domain hash table and handles any updates to the
|
||||||
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
|
* lower level protocol handler (i.e. CIPSO). @entry->family may be set to
|
||||||
* negative on failure.
|
* %AF_UNSPEC which will add an entry that matches all address families. This
|
||||||
|
* is only useful for the unlabelled type and will only succeed if there is no
|
||||||
|
* existing entry for any address family with the same domain. Returns zero
|
||||||
|
* on success, negative on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
||||||
struct netlbl_audit *audit_info)
|
struct netlbl_audit *audit_info)
|
||||||
{
|
{
|
||||||
int ret_val = 0;
|
int ret_val = 0;
|
||||||
struct netlbl_dom_map *entry_old;
|
struct netlbl_dom_map *entry_old, *entry_b;
|
||||||
struct netlbl_af4list *iter4;
|
struct netlbl_af4list *iter4;
|
||||||
struct netlbl_af4list *tmp4;
|
struct netlbl_af4list *tmp4;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
@ -385,9 +437,10 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
|||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
spin_lock(&netlbl_domhsh_lock);
|
spin_lock(&netlbl_domhsh_lock);
|
||||||
if (entry->domain != NULL)
|
if (entry->domain != NULL)
|
||||||
entry_old = netlbl_domhsh_search(entry->domain);
|
entry_old = netlbl_domhsh_search(entry->domain, entry->family);
|
||||||
else
|
else
|
||||||
entry_old = netlbl_domhsh_search_def(entry->domain);
|
entry_old = netlbl_domhsh_search_def(entry->domain,
|
||||||
|
entry->family);
|
||||||
if (entry_old == NULL) {
|
if (entry_old == NULL) {
|
||||||
entry->valid = 1;
|
entry->valid = 1;
|
||||||
|
|
||||||
@ -397,7 +450,41 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
|||||||
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
|
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
|
||||||
} else {
|
} else {
|
||||||
INIT_LIST_HEAD(&entry->list);
|
INIT_LIST_HEAD(&entry->list);
|
||||||
rcu_assign_pointer(netlbl_domhsh_def, entry);
|
switch (entry->family) {
|
||||||
|
case AF_INET:
|
||||||
|
rcu_assign_pointer(netlbl_domhsh_def_ipv4,
|
||||||
|
entry);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
rcu_assign_pointer(netlbl_domhsh_def_ipv6,
|
||||||
|
entry);
|
||||||
|
break;
|
||||||
|
case AF_UNSPEC:
|
||||||
|
if (entry->def.type !=
|
||||||
|
NETLBL_NLTYPE_UNLABELED) {
|
||||||
|
ret_val = -EINVAL;
|
||||||
|
goto add_return;
|
||||||
|
}
|
||||||
|
entry_b = kzalloc(sizeof(*entry_b), GFP_ATOMIC);
|
||||||
|
if (entry_b == NULL) {
|
||||||
|
ret_val = -ENOMEM;
|
||||||
|
goto add_return;
|
||||||
|
}
|
||||||
|
entry_b->family = AF_INET6;
|
||||||
|
entry_b->def.type = NETLBL_NLTYPE_UNLABELED;
|
||||||
|
entry_b->valid = 1;
|
||||||
|
entry->family = AF_INET;
|
||||||
|
rcu_assign_pointer(netlbl_domhsh_def_ipv4,
|
||||||
|
entry);
|
||||||
|
rcu_assign_pointer(netlbl_domhsh_def_ipv6,
|
||||||
|
entry_b);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Already checked in
|
||||||
|
* netlbl_domhsh_validate(). */
|
||||||
|
ret_val = -EINVAL;
|
||||||
|
goto add_return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
|
if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
|
||||||
@ -513,10 +600,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||||||
spin_lock(&netlbl_domhsh_lock);
|
spin_lock(&netlbl_domhsh_lock);
|
||||||
if (entry->valid) {
|
if (entry->valid) {
|
||||||
entry->valid = 0;
|
entry->valid = 0;
|
||||||
if (entry != rcu_dereference(netlbl_domhsh_def))
|
if (entry == rcu_dereference(netlbl_domhsh_def_ipv4))
|
||||||
list_del_rcu(&entry->list);
|
RCU_INIT_POINTER(netlbl_domhsh_def_ipv4, NULL);
|
||||||
|
else if (entry == rcu_dereference(netlbl_domhsh_def_ipv6))
|
||||||
|
RCU_INIT_POINTER(netlbl_domhsh_def_ipv6, NULL);
|
||||||
else
|
else
|
||||||
RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
|
list_del_rcu(&entry->list);
|
||||||
} else
|
} else
|
||||||
ret_val = -ENOENT;
|
ret_val = -ENOENT;
|
||||||
spin_unlock(&netlbl_domhsh_lock);
|
spin_unlock(&netlbl_domhsh_lock);
|
||||||
@ -533,6 +622,10 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||||||
if (ret_val == 0) {
|
if (ret_val == 0) {
|
||||||
struct netlbl_af4list *iter4;
|
struct netlbl_af4list *iter4;
|
||||||
struct netlbl_domaddr4_map *map4;
|
struct netlbl_domaddr4_map *map4;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
struct netlbl_af6list *iter6;
|
||||||
|
struct netlbl_domaddr6_map *map6;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
|
||||||
switch (entry->def.type) {
|
switch (entry->def.type) {
|
||||||
case NETLBL_NLTYPE_ADDRSELECT:
|
case NETLBL_NLTYPE_ADDRSELECT:
|
||||||
@ -541,12 +634,22 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||||||
map4 = netlbl_domhsh_addr4_entry(iter4);
|
map4 = netlbl_domhsh_addr4_entry(iter4);
|
||||||
cipso_v4_doi_putdef(map4->def.cipso);
|
cipso_v4_doi_putdef(map4->def.cipso);
|
||||||
}
|
}
|
||||||
/* no need to check the IPv6 list since we currently
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
* support only unlabeled protocols for IPv6 */
|
netlbl_af6list_foreach_rcu(iter6,
|
||||||
|
&entry->def.addrsel->list6) {
|
||||||
|
map6 = netlbl_domhsh_addr6_entry(iter6);
|
||||||
|
calipso_doi_putdef(map6->def.calipso);
|
||||||
|
}
|
||||||
|
#endif /* IPv6 */
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_CIPSOV4:
|
case NETLBL_NLTYPE_CIPSOV4:
|
||||||
cipso_v4_doi_putdef(entry->def.cipso);
|
cipso_v4_doi_putdef(entry->def.cipso);
|
||||||
break;
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
calipso_doi_putdef(entry->def.calipso);
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
}
|
}
|
||||||
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
|
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
|
||||||
}
|
}
|
||||||
@ -583,9 +686,9 @@ int netlbl_domhsh_remove_af4(const char *domain,
|
|||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
if (domain)
|
if (domain)
|
||||||
entry_map = netlbl_domhsh_search(domain);
|
entry_map = netlbl_domhsh_search(domain, AF_INET);
|
||||||
else
|
else
|
||||||
entry_map = netlbl_domhsh_search_def(domain);
|
entry_map = netlbl_domhsh_search_def(domain, AF_INET);
|
||||||
if (entry_map == NULL ||
|
if (entry_map == NULL ||
|
||||||
entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
||||||
goto remove_af4_failure;
|
goto remove_af4_failure;
|
||||||
@ -622,28 +725,114 @@ remove_af4_failure:
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
/**
|
||||||
|
* netlbl_domhsh_remove_af6 - Removes an address selector entry
|
||||||
|
* @domain: the domain
|
||||||
|
* @addr: IPv6 address
|
||||||
|
* @mask: IPv6 address mask
|
||||||
|
* @audit_info: NetLabel audit information
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Removes an individual address selector from a domain mapping and potentially
|
||||||
|
* the entire mapping if it is empty. Returns zero on success, negative values
|
||||||
|
* on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int netlbl_domhsh_remove_af6(const char *domain,
|
||||||
|
const struct in6_addr *addr,
|
||||||
|
const struct in6_addr *mask,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
struct netlbl_dom_map *entry_map;
|
||||||
|
struct netlbl_af6list *entry_addr;
|
||||||
|
struct netlbl_af4list *iter4;
|
||||||
|
struct netlbl_af6list *iter6;
|
||||||
|
struct netlbl_domaddr6_map *entry;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
if (domain)
|
||||||
|
entry_map = netlbl_domhsh_search(domain, AF_INET6);
|
||||||
|
else
|
||||||
|
entry_map = netlbl_domhsh_search_def(domain, AF_INET6);
|
||||||
|
if (entry_map == NULL ||
|
||||||
|
entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
||||||
|
goto remove_af6_failure;
|
||||||
|
|
||||||
|
spin_lock(&netlbl_domhsh_lock);
|
||||||
|
entry_addr = netlbl_af6list_remove(addr, mask,
|
||||||
|
&entry_map->def.addrsel->list6);
|
||||||
|
spin_unlock(&netlbl_domhsh_lock);
|
||||||
|
|
||||||
|
if (entry_addr == NULL)
|
||||||
|
goto remove_af6_failure;
|
||||||
|
netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
|
||||||
|
goto remove_af6_single_addr;
|
||||||
|
netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
|
||||||
|
goto remove_af6_single_addr;
|
||||||
|
/* the domain mapping is empty so remove it from the mapping table */
|
||||||
|
netlbl_domhsh_remove_entry(entry_map, audit_info);
|
||||||
|
|
||||||
|
remove_af6_single_addr:
|
||||||
|
rcu_read_unlock();
|
||||||
|
/* yick, we can't use call_rcu here because we don't have a rcu head
|
||||||
|
* pointer but hopefully this should be a rare case so the pause
|
||||||
|
* shouldn't be a problem */
|
||||||
|
synchronize_rcu();
|
||||||
|
entry = netlbl_domhsh_addr6_entry(entry_addr);
|
||||||
|
calipso_doi_putdef(entry->def.calipso);
|
||||||
|
kfree(entry);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
remove_af6_failure:
|
||||||
|
rcu_read_unlock();
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
#endif /* IPv6 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_domhsh_remove - Removes an entry from the domain hash table
|
* netlbl_domhsh_remove - Removes an entry from the domain hash table
|
||||||
* @domain: the domain to remove
|
* @domain: the domain to remove
|
||||||
|
* @family: address family
|
||||||
* @audit_info: NetLabel audit information
|
* @audit_info: NetLabel audit information
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Removes an entry from the domain hash table and handles any updates to the
|
* Removes an entry from the domain hash table and handles any updates to the
|
||||||
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
|
* lower level protocol handler (i.e. CIPSO). @family may be %AF_UNSPEC which
|
||||||
* negative on failure.
|
* removes all address family entries. Returns zero on success, negative on
|
||||||
|
* failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
|
int netlbl_domhsh_remove(const char *domain, u16 family,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
{
|
{
|
||||||
int ret_val;
|
int ret_val = -EINVAL;
|
||||||
struct netlbl_dom_map *entry;
|
struct netlbl_dom_map *entry;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
if (domain)
|
|
||||||
entry = netlbl_domhsh_search(domain);
|
if (family == AF_INET || family == AF_UNSPEC) {
|
||||||
else
|
if (domain)
|
||||||
entry = netlbl_domhsh_search_def(domain);
|
entry = netlbl_domhsh_search(domain, AF_INET);
|
||||||
ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
|
else
|
||||||
|
entry = netlbl_domhsh_search_def(domain, AF_INET);
|
||||||
|
ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
|
||||||
|
if (ret_val && ret_val != -ENOENT)
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (family == AF_INET6 || family == AF_UNSPEC) {
|
||||||
|
int ret_val2;
|
||||||
|
|
||||||
|
if (domain)
|
||||||
|
entry = netlbl_domhsh_search(domain, AF_INET6);
|
||||||
|
else
|
||||||
|
entry = netlbl_domhsh_search_def(domain, AF_INET6);
|
||||||
|
ret_val2 = netlbl_domhsh_remove_entry(entry, audit_info);
|
||||||
|
if (ret_val2 != -ENOENT)
|
||||||
|
ret_val = ret_val2;
|
||||||
|
}
|
||||||
|
done:
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
@ -651,32 +840,38 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_domhsh_remove_default - Removes the default entry from the table
|
* netlbl_domhsh_remove_default - Removes the default entry from the table
|
||||||
|
* @family: address family
|
||||||
* @audit_info: NetLabel audit information
|
* @audit_info: NetLabel audit information
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Removes/resets the default entry for the domain hash table and handles any
|
* Removes/resets the default entry corresponding to @family from the domain
|
||||||
* updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
|
* hash table and handles any updates to the lower level protocol handler
|
||||||
* success, non-zero on failure.
|
* (i.e. CIPSO). @family may be %AF_UNSPEC which removes all address family
|
||||||
|
* entries. Returns zero on success, negative on failure.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
|
int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info)
|
||||||
{
|
{
|
||||||
return netlbl_domhsh_remove(NULL, audit_info);
|
return netlbl_domhsh_remove(NULL, family, audit_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_domhsh_getentry - Get an entry from the domain hash table
|
* netlbl_domhsh_getentry - Get an entry from the domain hash table
|
||||||
* @domain: the domain name to search for
|
* @domain: the domain name to search for
|
||||||
|
* @family: address family
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Look through the domain hash table searching for an entry to match @domain,
|
* Look through the domain hash table searching for an entry to match @domain,
|
||||||
* return a pointer to a copy of the entry or NULL. The caller is responsible
|
* with address family @family, return a pointer to a copy of the entry or
|
||||||
* for ensuring that rcu_read_[un]lock() is called.
|
* NULL. The caller is responsible for ensuring that rcu_read_[un]lock() is
|
||||||
|
* called.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
|
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family)
|
||||||
{
|
{
|
||||||
return netlbl_domhsh_search_def(domain);
|
if (family == AF_UNSPEC)
|
||||||
|
return NULL;
|
||||||
|
return netlbl_domhsh_search_def(domain, family);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -696,7 +891,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
|
|||||||
struct netlbl_dom_map *dom_iter;
|
struct netlbl_dom_map *dom_iter;
|
||||||
struct netlbl_af4list *addr_iter;
|
struct netlbl_af4list *addr_iter;
|
||||||
|
|
||||||
dom_iter = netlbl_domhsh_search_def(domain);
|
dom_iter = netlbl_domhsh_search_def(domain, AF_INET);
|
||||||
if (dom_iter == NULL)
|
if (dom_iter == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -726,7 +921,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
|
|||||||
struct netlbl_dom_map *dom_iter;
|
struct netlbl_dom_map *dom_iter;
|
||||||
struct netlbl_af6list *addr_iter;
|
struct netlbl_af6list *addr_iter;
|
||||||
|
|
||||||
dom_iter = netlbl_domhsh_search_def(domain);
|
dom_iter = netlbl_domhsh_search_def(domain, AF_INET6);
|
||||||
if (dom_iter == NULL)
|
if (dom_iter == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -51,6 +51,7 @@ struct netlbl_dommap_def {
|
|||||||
union {
|
union {
|
||||||
struct netlbl_domaddr_map *addrsel;
|
struct netlbl_domaddr_map *addrsel;
|
||||||
struct cipso_v4_doi *cipso;
|
struct cipso_v4_doi *cipso;
|
||||||
|
struct calipso_doi *calipso;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
#define netlbl_domhsh_addr4_entry(iter) \
|
#define netlbl_domhsh_addr4_entry(iter) \
|
||||||
@ -70,6 +71,7 @@ struct netlbl_domaddr6_map {
|
|||||||
|
|
||||||
struct netlbl_dom_map {
|
struct netlbl_dom_map {
|
||||||
char *domain;
|
char *domain;
|
||||||
|
u16 family;
|
||||||
struct netlbl_dommap_def def;
|
struct netlbl_dommap_def def;
|
||||||
|
|
||||||
u32 valid;
|
u32 valid;
|
||||||
@ -91,14 +93,23 @@ int netlbl_domhsh_remove_af4(const char *domain,
|
|||||||
const struct in_addr *addr,
|
const struct in_addr *addr,
|
||||||
const struct in_addr *mask,
|
const struct in_addr *mask,
|
||||||
struct netlbl_audit *audit_info);
|
struct netlbl_audit *audit_info);
|
||||||
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
|
int netlbl_domhsh_remove_af6(const char *domain,
|
||||||
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
|
const struct in6_addr *addr,
|
||||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
|
const struct in6_addr *mask,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
|
int netlbl_domhsh_remove(const char *domain, u16 family,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
|
int netlbl_domhsh_remove_default(u16 family, struct netlbl_audit *audit_info);
|
||||||
|
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain, u16 family);
|
||||||
struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
|
struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
|
||||||
__be32 addr);
|
__be32 addr);
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
|
struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
|
||||||
const struct in6_addr *addr);
|
const struct in6_addr *addr);
|
||||||
|
int netlbl_domhsh_remove_af6(const char *domain,
|
||||||
|
const struct in6_addr *addr,
|
||||||
|
const struct in6_addr *mask,
|
||||||
|
struct netlbl_audit *audit_info);
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
|
|
||||||
int netlbl_domhsh_walk(u32 *skip_bkt,
|
int netlbl_domhsh_walk(u32 *skip_bkt,
|
||||||
|
@ -37,12 +37,14 @@
|
|||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/netlabel.h>
|
#include <net/netlabel.h>
|
||||||
#include <net/cipso_ipv4.h>
|
#include <net/cipso_ipv4.h>
|
||||||
|
#include <net/calipso.h>
|
||||||
#include <asm/bug.h>
|
#include <asm/bug.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
#include "netlabel_domainhash.h"
|
#include "netlabel_domainhash.h"
|
||||||
#include "netlabel_unlabeled.h"
|
#include "netlabel_unlabeled.h"
|
||||||
#include "netlabel_cipso_v4.h"
|
#include "netlabel_cipso_v4.h"
|
||||||
|
#include "netlabel_calipso.h"
|
||||||
#include "netlabel_user.h"
|
#include "netlabel_user.h"
|
||||||
#include "netlabel_mgmt.h"
|
#include "netlabel_mgmt.h"
|
||||||
#include "netlabel_addrlist.h"
|
#include "netlabel_addrlist.h"
|
||||||
@ -72,12 +74,17 @@ int netlbl_cfg_map_del(const char *domain,
|
|||||||
struct netlbl_audit *audit_info)
|
struct netlbl_audit *audit_info)
|
||||||
{
|
{
|
||||||
if (addr == NULL && mask == NULL) {
|
if (addr == NULL && mask == NULL) {
|
||||||
return netlbl_domhsh_remove(domain, audit_info);
|
return netlbl_domhsh_remove(domain, family, audit_info);
|
||||||
} else if (addr != NULL && mask != NULL) {
|
} else if (addr != NULL && mask != NULL) {
|
||||||
switch (family) {
|
switch (family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
return netlbl_domhsh_remove_af4(domain, addr, mask,
|
return netlbl_domhsh_remove_af4(domain, addr, mask,
|
||||||
audit_info);
|
audit_info);
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case AF_INET6:
|
||||||
|
return netlbl_domhsh_remove_af6(domain, addr, mask,
|
||||||
|
audit_info);
|
||||||
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
return -EPFNOSUPPORT;
|
return -EPFNOSUPPORT;
|
||||||
}
|
}
|
||||||
@ -119,6 +126,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
|
|||||||
if (entry->domain == NULL)
|
if (entry->domain == NULL)
|
||||||
goto cfg_unlbl_map_add_failure;
|
goto cfg_unlbl_map_add_failure;
|
||||||
}
|
}
|
||||||
|
entry->family = family;
|
||||||
|
|
||||||
if (addr == NULL && mask == NULL)
|
if (addr == NULL && mask == NULL)
|
||||||
entry->def.type = NETLBL_NLTYPE_UNLABELED;
|
entry->def.type = NETLBL_NLTYPE_UNLABELED;
|
||||||
@ -345,6 +353,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
|
|||||||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
goto out_entry;
|
goto out_entry;
|
||||||
|
entry->family = AF_INET;
|
||||||
if (domain != NULL) {
|
if (domain != NULL) {
|
||||||
entry->domain = kstrdup(domain, GFP_ATOMIC);
|
entry->domain = kstrdup(domain, GFP_ATOMIC);
|
||||||
if (entry->domain == NULL)
|
if (entry->domain == NULL)
|
||||||
@ -399,6 +408,139 @@ out_entry:
|
|||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
|
||||||
|
* @doi_def: CALIPSO DOI definition
|
||||||
|
* @audit_info: NetLabel audit information
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on
|
||||||
|
* success and negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int netlbl_cfg_calipso_add(struct calipso_doi *doi_def,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
return calipso_doi_add(doi_def, audit_info);
|
||||||
|
#else /* IPv6 */
|
||||||
|
return -ENOSYS;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
|
||||||
|
* @doi: CALIPSO DOI
|
||||||
|
* @audit_info: NetLabel audit information
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Remove an existing CALIPSO DOI definition matching @doi. Returns zero on
|
||||||
|
* success and negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
calipso_doi_remove(doi, audit_info);
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
|
||||||
|
* @doi: the CALIPSO DOI
|
||||||
|
* @domain: the domain mapping to add
|
||||||
|
* @addr: IP address
|
||||||
|
* @mask: IP address mask
|
||||||
|
* @audit_info: NetLabel audit information
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
|
||||||
|
* NetLabel subsystem. A @domain value of NULL adds a new default domain
|
||||||
|
* mapping. Returns zero on success, negative values on failure.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int netlbl_cfg_calipso_map_add(u32 doi,
|
||||||
|
const char *domain,
|
||||||
|
const struct in6_addr *addr,
|
||||||
|
const struct in6_addr *mask,
|
||||||
|
struct netlbl_audit *audit_info)
|
||||||
|
{
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
int ret_val = -ENOMEM;
|
||||||
|
struct calipso_doi *doi_def;
|
||||||
|
struct netlbl_dom_map *entry;
|
||||||
|
struct netlbl_domaddr_map *addrmap = NULL;
|
||||||
|
struct netlbl_domaddr6_map *addrinfo = NULL;
|
||||||
|
|
||||||
|
doi_def = calipso_doi_getdef(doi);
|
||||||
|
if (doi_def == NULL)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
|
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||||
|
if (entry == NULL)
|
||||||
|
goto out_entry;
|
||||||
|
entry->family = AF_INET6;
|
||||||
|
if (domain != NULL) {
|
||||||
|
entry->domain = kstrdup(domain, GFP_ATOMIC);
|
||||||
|
if (entry->domain == NULL)
|
||||||
|
goto out_domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr == NULL && mask == NULL) {
|
||||||
|
entry->def.calipso = doi_def;
|
||||||
|
entry->def.type = NETLBL_NLTYPE_CALIPSO;
|
||||||
|
} else if (addr != NULL && mask != NULL) {
|
||||||
|
addrmap = kzalloc(sizeof(*addrmap), GFP_ATOMIC);
|
||||||
|
if (addrmap == NULL)
|
||||||
|
goto out_addrmap;
|
||||||
|
INIT_LIST_HEAD(&addrmap->list4);
|
||||||
|
INIT_LIST_HEAD(&addrmap->list6);
|
||||||
|
|
||||||
|
addrinfo = kzalloc(sizeof(*addrinfo), GFP_ATOMIC);
|
||||||
|
if (addrinfo == NULL)
|
||||||
|
goto out_addrinfo;
|
||||||
|
addrinfo->def.calipso = doi_def;
|
||||||
|
addrinfo->def.type = NETLBL_NLTYPE_CALIPSO;
|
||||||
|
addrinfo->list.addr = *addr;
|
||||||
|
addrinfo->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
|
||||||
|
addrinfo->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
|
||||||
|
addrinfo->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
|
||||||
|
addrinfo->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
|
||||||
|
addrinfo->list.mask = *mask;
|
||||||
|
addrinfo->list.valid = 1;
|
||||||
|
ret_val = netlbl_af6list_add(&addrinfo->list, &addrmap->list6);
|
||||||
|
if (ret_val != 0)
|
||||||
|
goto cfg_calipso_map_add_failure;
|
||||||
|
|
||||||
|
entry->def.addrsel = addrmap;
|
||||||
|
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||||
|
} else {
|
||||||
|
ret_val = -EINVAL;
|
||||||
|
goto out_addrmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret_val = netlbl_domhsh_add(entry, audit_info);
|
||||||
|
if (ret_val != 0)
|
||||||
|
goto cfg_calipso_map_add_failure;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cfg_calipso_map_add_failure:
|
||||||
|
kfree(addrinfo);
|
||||||
|
out_addrinfo:
|
||||||
|
kfree(addrmap);
|
||||||
|
out_addrmap:
|
||||||
|
kfree(entry->domain);
|
||||||
|
out_domain:
|
||||||
|
kfree(entry);
|
||||||
|
out_entry:
|
||||||
|
calipso_doi_putdef(doi_def);
|
||||||
|
return ret_val;
|
||||||
|
#else /* IPv6 */
|
||||||
|
return -ENOSYS;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Security Attribute Functions
|
* Security Attribute Functions
|
||||||
*/
|
*/
|
||||||
@ -519,6 +661,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
|
|||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(netlbl_catmap_walk);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_catmap_walkrng - Find the end of a string of set bits
|
* netlbl_catmap_walkrng - Find the end of a string of set bits
|
||||||
@ -609,20 +752,19 @@ int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
|
|||||||
off = catmap->startbit;
|
off = catmap->startbit;
|
||||||
*offset = off;
|
*offset = off;
|
||||||
}
|
}
|
||||||
iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_NONE, 0);
|
iter = _netlbl_catmap_getnode(&catmap, off, _CM_F_WALK, 0);
|
||||||
if (iter == NULL) {
|
if (iter == NULL) {
|
||||||
*offset = (u32)-1;
|
*offset = (u32)-1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (off < iter->startbit) {
|
if (off < iter->startbit) {
|
||||||
off = iter->startbit;
|
*offset = iter->startbit;
|
||||||
*offset = off;
|
off = 0;
|
||||||
} else
|
} else
|
||||||
off -= iter->startbit;
|
off -= iter->startbit;
|
||||||
|
|
||||||
idx = off / NETLBL_CATMAP_MAPSIZE;
|
idx = off / NETLBL_CATMAP_MAPSIZE;
|
||||||
*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE);
|
*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -655,6 +797,7 @@ int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(netlbl_catmap_setbit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
|
* netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
|
||||||
@ -727,6 +870,76 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Bitmap functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_bitmap_walk - Walk a bitmap looking for a bit
|
||||||
|
* @bitmap: the bitmap
|
||||||
|
* @bitmap_len: length in bits
|
||||||
|
* @offset: starting offset
|
||||||
|
* @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Starting at @offset, walk the bitmap from left to right until either the
|
||||||
|
* desired bit is found or we reach the end. Return the bit offset, -1 if
|
||||||
|
* not found, or -2 if error.
|
||||||
|
*/
|
||||||
|
int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len,
|
||||||
|
u32 offset, u8 state)
|
||||||
|
{
|
||||||
|
u32 bit_spot;
|
||||||
|
u32 byte_offset;
|
||||||
|
unsigned char bitmask;
|
||||||
|
unsigned char byte;
|
||||||
|
|
||||||
|
byte_offset = offset / 8;
|
||||||
|
byte = bitmap[byte_offset];
|
||||||
|
bit_spot = offset;
|
||||||
|
bitmask = 0x80 >> (offset % 8);
|
||||||
|
|
||||||
|
while (bit_spot < bitmap_len) {
|
||||||
|
if ((state && (byte & bitmask) == bitmask) ||
|
||||||
|
(state == 0 && (byte & bitmask) == 0))
|
||||||
|
return bit_spot;
|
||||||
|
|
||||||
|
bit_spot++;
|
||||||
|
bitmask >>= 1;
|
||||||
|
if (bitmask == 0) {
|
||||||
|
byte = bitmap[++byte_offset];
|
||||||
|
bitmask = 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(netlbl_bitmap_walk);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* netlbl_bitmap_setbit - Sets a single bit in a bitmap
|
||||||
|
* @bitmap: the bitmap
|
||||||
|
* @bit: the bit
|
||||||
|
* @state: if non-zero, set the bit (1) else clear the bit (0)
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Set a single bit in the bitmask. Returns zero on success, negative values
|
||||||
|
* on error.
|
||||||
|
*/
|
||||||
|
void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state)
|
||||||
|
{
|
||||||
|
u32 byte_spot;
|
||||||
|
u8 bitmask;
|
||||||
|
|
||||||
|
/* gcc always rounds to zero when doing integer division */
|
||||||
|
byte_spot = bit / 8;
|
||||||
|
bitmask = 0x80 >> (bit % 8);
|
||||||
|
if (state)
|
||||||
|
bitmap[byte_spot] |= bitmask;
|
||||||
|
else
|
||||||
|
bitmap[byte_spot] &= ~bitmask;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(netlbl_bitmap_setbit);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LSM Functions
|
* LSM Functions
|
||||||
*/
|
*/
|
||||||
@ -774,7 +987,7 @@ int netlbl_sock_setattr(struct sock *sk,
|
|||||||
struct netlbl_dom_map *dom_entry;
|
struct netlbl_dom_map *dom_entry;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
dom_entry = netlbl_domhsh_getentry(secattr->domain, family);
|
||||||
if (dom_entry == NULL) {
|
if (dom_entry == NULL) {
|
||||||
ret_val = -ENOENT;
|
ret_val = -ENOENT;
|
||||||
goto socket_setattr_return;
|
goto socket_setattr_return;
|
||||||
@ -799,9 +1012,21 @@ int netlbl_sock_setattr(struct sock *sk,
|
|||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
/* since we don't support any IPv6 labeling protocols right
|
switch (dom_entry->def.type) {
|
||||||
* now we can optimize everything away until we do */
|
case NETLBL_NLTYPE_ADDRSELECT:
|
||||||
ret_val = 0;
|
ret_val = -EDESTADDRREQ;
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
ret_val = calipso_sock_setattr(sk,
|
||||||
|
dom_entry->def.calipso,
|
||||||
|
secattr);
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
ret_val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
@ -824,7 +1049,16 @@ socket_setattr_return:
|
|||||||
*/
|
*/
|
||||||
void netlbl_sock_delattr(struct sock *sk)
|
void netlbl_sock_delattr(struct sock *sk)
|
||||||
{
|
{
|
||||||
cipso_v4_sock_delattr(sk);
|
switch (sk->sk_family) {
|
||||||
|
case AF_INET:
|
||||||
|
cipso_v4_sock_delattr(sk);
|
||||||
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case AF_INET6:
|
||||||
|
calipso_sock_delattr(sk);
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -850,7 +1084,7 @@ int netlbl_sock_getattr(struct sock *sk,
|
|||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
ret_val = -ENOMSG;
|
ret_val = calipso_sock_getattr(sk, secattr);
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
@ -878,6 +1112,9 @@ int netlbl_conn_setattr(struct sock *sk,
|
|||||||
{
|
{
|
||||||
int ret_val;
|
int ret_val;
|
||||||
struct sockaddr_in *addr4;
|
struct sockaddr_in *addr4;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
struct sockaddr_in6 *addr6;
|
||||||
|
#endif
|
||||||
struct netlbl_dommap_def *entry;
|
struct netlbl_dommap_def *entry;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
@ -898,7 +1135,7 @@ int netlbl_conn_setattr(struct sock *sk,
|
|||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
/* just delete the protocols we support for right now
|
/* just delete the protocols we support for right now
|
||||||
* but we could remove other protocols if needed */
|
* but we could remove other protocols if needed */
|
||||||
cipso_v4_sock_delattr(sk);
|
netlbl_sock_delattr(sk);
|
||||||
ret_val = 0;
|
ret_val = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -907,9 +1144,27 @@ int netlbl_conn_setattr(struct sock *sk,
|
|||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
/* since we don't support any IPv6 labeling protocols right
|
addr6 = (struct sockaddr_in6 *)addr;
|
||||||
* now we can optimize everything away until we do */
|
entry = netlbl_domhsh_getentry_af6(secattr->domain,
|
||||||
ret_val = 0;
|
&addr6->sin6_addr);
|
||||||
|
if (entry == NULL) {
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
goto conn_setattr_return;
|
||||||
|
}
|
||||||
|
switch (entry->type) {
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
ret_val = calipso_sock_setattr(sk,
|
||||||
|
entry->calipso, secattr);
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
/* just delete the protocols we support for right now
|
||||||
|
* but we could remove other protocols if needed */
|
||||||
|
netlbl_sock_delattr(sk);
|
||||||
|
ret_val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
@ -936,12 +1191,13 @@ int netlbl_req_setattr(struct request_sock *req,
|
|||||||
{
|
{
|
||||||
int ret_val;
|
int ret_val;
|
||||||
struct netlbl_dommap_def *entry;
|
struct netlbl_dommap_def *entry;
|
||||||
|
struct inet_request_sock *ireq = inet_rsk(req);
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
switch (req->rsk_ops->family) {
|
switch (req->rsk_ops->family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
entry = netlbl_domhsh_getentry_af4(secattr->domain,
|
entry = netlbl_domhsh_getentry_af4(secattr->domain,
|
||||||
inet_rsk(req)->ir_rmt_addr);
|
ireq->ir_rmt_addr);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
ret_val = -ENOENT;
|
ret_val = -ENOENT;
|
||||||
goto req_setattr_return;
|
goto req_setattr_return;
|
||||||
@ -952,9 +1208,7 @@ int netlbl_req_setattr(struct request_sock *req,
|
|||||||
entry->cipso, secattr);
|
entry->cipso, secattr);
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
/* just delete the protocols we support for right now
|
netlbl_req_delattr(req);
|
||||||
* but we could remove other protocols if needed */
|
|
||||||
cipso_v4_req_delattr(req);
|
|
||||||
ret_val = 0;
|
ret_val = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -963,9 +1217,24 @@ int netlbl_req_setattr(struct request_sock *req,
|
|||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
/* since we don't support any IPv6 labeling protocols right
|
entry = netlbl_domhsh_getentry_af6(secattr->domain,
|
||||||
* now we can optimize everything away until we do */
|
&ireq->ir_v6_rmt_addr);
|
||||||
ret_val = 0;
|
if (entry == NULL) {
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
goto req_setattr_return;
|
||||||
|
}
|
||||||
|
switch (entry->type) {
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
ret_val = calipso_req_setattr(req,
|
||||||
|
entry->calipso, secattr);
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
netlbl_req_delattr(req);
|
||||||
|
ret_val = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
@ -987,7 +1256,16 @@ req_setattr_return:
|
|||||||
*/
|
*/
|
||||||
void netlbl_req_delattr(struct request_sock *req)
|
void netlbl_req_delattr(struct request_sock *req)
|
||||||
{
|
{
|
||||||
cipso_v4_req_delattr(req);
|
switch (req->rsk_ops->family) {
|
||||||
|
case AF_INET:
|
||||||
|
cipso_v4_req_delattr(req);
|
||||||
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case AF_INET6:
|
||||||
|
calipso_req_delattr(req);
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1007,13 +1285,17 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
|||||||
{
|
{
|
||||||
int ret_val;
|
int ret_val;
|
||||||
struct iphdr *hdr4;
|
struct iphdr *hdr4;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
struct ipv6hdr *hdr6;
|
||||||
|
#endif
|
||||||
struct netlbl_dommap_def *entry;
|
struct netlbl_dommap_def *entry;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
switch (family) {
|
switch (family) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
hdr4 = ip_hdr(skb);
|
hdr4 = ip_hdr(skb);
|
||||||
entry = netlbl_domhsh_getentry_af4(secattr->domain,hdr4->daddr);
|
entry = netlbl_domhsh_getentry_af4(secattr->domain,
|
||||||
|
hdr4->daddr);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
ret_val = -ENOENT;
|
ret_val = -ENOENT;
|
||||||
goto skbuff_setattr_return;
|
goto skbuff_setattr_return;
|
||||||
@ -1034,9 +1316,26 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
|||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
/* since we don't support any IPv6 labeling protocols right
|
hdr6 = ipv6_hdr(skb);
|
||||||
* now we can optimize everything away until we do */
|
entry = netlbl_domhsh_getentry_af6(secattr->domain,
|
||||||
ret_val = 0;
|
&hdr6->daddr);
|
||||||
|
if (entry == NULL) {
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
goto skbuff_setattr_return;
|
||||||
|
}
|
||||||
|
switch (entry->type) {
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
ret_val = calipso_skbuff_setattr(skb, entry->calipso,
|
||||||
|
secattr);
|
||||||
|
break;
|
||||||
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
/* just delete the protocols we support for right now
|
||||||
|
* but we could remove other protocols if needed */
|
||||||
|
ret_val = calipso_skbuff_delattr(skb);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret_val = -ENOENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
@ -1075,6 +1374,9 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
|||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
|
ptr = calipso_optptr(skb);
|
||||||
|
if (ptr && calipso_getattr(ptr, secattr) == 0)
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
}
|
}
|
||||||
@ -1085,6 +1387,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
|||||||
/**
|
/**
|
||||||
* netlbl_skbuff_err - Handle a LSM error on a sk_buff
|
* netlbl_skbuff_err - Handle a LSM error on a sk_buff
|
||||||
* @skb: the packet
|
* @skb: the packet
|
||||||
|
* @family: the family
|
||||||
* @error: the error code
|
* @error: the error code
|
||||||
* @gateway: true if host is acting as a gateway, false otherwise
|
* @gateway: true if host is acting as a gateway, false otherwise
|
||||||
*
|
*
|
||||||
@ -1094,10 +1397,14 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
|||||||
* according to the packet's labeling protocol.
|
* according to the packet's labeling protocol.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
|
void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway)
|
||||||
{
|
{
|
||||||
if (cipso_v4_optptr(skb))
|
switch (family) {
|
||||||
cipso_v4_error(skb, error, gateway);
|
case AF_INET:
|
||||||
|
if (cipso_v4_optptr(skb))
|
||||||
|
cipso_v4_error(skb, error, gateway);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1112,11 +1419,15 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
|
|||||||
void netlbl_cache_invalidate(void)
|
void netlbl_cache_invalidate(void)
|
||||||
{
|
{
|
||||||
cipso_v4_cache_invalidate();
|
cipso_v4_cache_invalidate();
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
calipso_cache_invalidate();
|
||||||
|
#endif /* IPv6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* netlbl_cache_add - Add an entry to a NetLabel protocol cache
|
* netlbl_cache_add - Add an entry to a NetLabel protocol cache
|
||||||
* @skb: the packet
|
* @skb: the packet
|
||||||
|
* @family: the family
|
||||||
* @secattr: the packet's security attributes
|
* @secattr: the packet's security attributes
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
@ -1125,7 +1436,7 @@ void netlbl_cache_invalidate(void)
|
|||||||
* values on error.
|
* values on error.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
int netlbl_cache_add(const struct sk_buff *skb,
|
int netlbl_cache_add(const struct sk_buff *skb, u16 family,
|
||||||
const struct netlbl_lsm_secattr *secattr)
|
const struct netlbl_lsm_secattr *secattr)
|
||||||
{
|
{
|
||||||
unsigned char *ptr;
|
unsigned char *ptr;
|
||||||
@ -1133,10 +1444,20 @@ int netlbl_cache_add(const struct sk_buff *skb,
|
|||||||
if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
|
if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
|
||||||
ptr = cipso_v4_optptr(skb);
|
switch (family) {
|
||||||
if (ptr)
|
case AF_INET:
|
||||||
return cipso_v4_cache_add(ptr, secattr);
|
ptr = cipso_v4_optptr(skb);
|
||||||
|
if (ptr)
|
||||||
|
return cipso_v4_cache_add(ptr, secattr);
|
||||||
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case AF_INET6:
|
||||||
|
ptr = calipso_optptr(skb);
|
||||||
|
if (ptr)
|
||||||
|
return calipso_cache_add(ptr, secattr);
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
|
}
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1161,6 +1482,7 @@ struct audit_buffer *netlbl_audit_start(int type,
|
|||||||
{
|
{
|
||||||
return netlbl_audit_start_common(type, audit_info);
|
return netlbl_audit_start_common(type, audit_info);
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(netlbl_audit_start);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup Functions
|
* Setup Functions
|
||||||
|
@ -41,8 +41,10 @@
|
|||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/netlabel.h>
|
#include <net/netlabel.h>
|
||||||
#include <net/cipso_ipv4.h>
|
#include <net/cipso_ipv4.h>
|
||||||
|
#include <net/calipso.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
|
|
||||||
|
#include "netlabel_calipso.h"
|
||||||
#include "netlabel_domainhash.h"
|
#include "netlabel_domainhash.h"
|
||||||
#include "netlabel_user.h"
|
#include "netlabel_user.h"
|
||||||
#include "netlabel_mgmt.h"
|
#include "netlabel_mgmt.h"
|
||||||
@ -72,6 +74,8 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
|
|||||||
[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
|
[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
|
||||||
[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
|
[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
|
||||||
[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
|
[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
|
||||||
|
[NLBL_MGMT_A_FAMILY] = { .type = NLA_U16 },
|
||||||
|
[NLBL_MGMT_A_CLPDOI] = { .type = NLA_U32 },
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -95,6 +99,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||||||
int ret_val = -EINVAL;
|
int ret_val = -EINVAL;
|
||||||
struct netlbl_domaddr_map *addrmap = NULL;
|
struct netlbl_domaddr_map *addrmap = NULL;
|
||||||
struct cipso_v4_doi *cipsov4 = NULL;
|
struct cipso_v4_doi *cipsov4 = NULL;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
struct calipso_doi *calipso = NULL;
|
||||||
|
#endif
|
||||||
u32 tmp_val;
|
u32 tmp_val;
|
||||||
struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
struct netlbl_dom_map *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||||
|
|
||||||
@ -119,6 +126,11 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||||||
|
|
||||||
switch (entry->def.type) {
|
switch (entry->def.type) {
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
|
if (info->attrs[NLBL_MGMT_A_FAMILY])
|
||||||
|
entry->family =
|
||||||
|
nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
|
||||||
|
else
|
||||||
|
entry->family = AF_UNSPEC;
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_CIPSOV4:
|
case NETLBL_NLTYPE_CIPSOV4:
|
||||||
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
|
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
|
||||||
@ -128,12 +140,30 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||||||
cipsov4 = cipso_v4_doi_getdef(tmp_val);
|
cipsov4 = cipso_v4_doi_getdef(tmp_val);
|
||||||
if (cipsov4 == NULL)
|
if (cipsov4 == NULL)
|
||||||
goto add_free_domain;
|
goto add_free_domain;
|
||||||
|
entry->family = AF_INET;
|
||||||
entry->def.cipso = cipsov4;
|
entry->def.cipso = cipsov4;
|
||||||
break;
|
break;
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
if (!info->attrs[NLBL_MGMT_A_CLPDOI])
|
||||||
|
goto add_free_domain;
|
||||||
|
|
||||||
|
tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CLPDOI]);
|
||||||
|
calipso = calipso_doi_getdef(tmp_val);
|
||||||
|
if (calipso == NULL)
|
||||||
|
goto add_free_domain;
|
||||||
|
entry->family = AF_INET6;
|
||||||
|
entry->def.calipso = calipso;
|
||||||
|
break;
|
||||||
|
#endif /* IPv6 */
|
||||||
default:
|
default:
|
||||||
goto add_free_domain;
|
goto add_free_domain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((entry->family == AF_INET && info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
|
||||||
|
(entry->family == AF_INET6 && info->attrs[NLBL_MGMT_A_IPV4ADDR]))
|
||||||
|
goto add_doi_put_def;
|
||||||
|
|
||||||
if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
|
if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
|
||||||
struct in_addr *addr;
|
struct in_addr *addr;
|
||||||
struct in_addr *mask;
|
struct in_addr *mask;
|
||||||
@ -178,6 +208,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||||||
goto add_free_addrmap;
|
goto add_free_addrmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry->family = AF_INET;
|
||||||
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||||
entry->def.addrsel = addrmap;
|
entry->def.addrsel = addrmap;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
@ -220,6 +251,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||||||
map->list.mask = *mask;
|
map->list.mask = *mask;
|
||||||
map->list.valid = 1;
|
map->list.valid = 1;
|
||||||
map->def.type = entry->def.type;
|
map->def.type = entry->def.type;
|
||||||
|
if (calipso)
|
||||||
|
map->def.calipso = calipso;
|
||||||
|
|
||||||
ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
|
ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
|
||||||
if (ret_val != 0) {
|
if (ret_val != 0) {
|
||||||
@ -227,6 +260,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||||||
goto add_free_addrmap;
|
goto add_free_addrmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entry->family = AF_INET6;
|
||||||
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||||
entry->def.addrsel = addrmap;
|
entry->def.addrsel = addrmap;
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
@ -242,6 +276,9 @@ add_free_addrmap:
|
|||||||
kfree(addrmap);
|
kfree(addrmap);
|
||||||
add_doi_put_def:
|
add_doi_put_def:
|
||||||
cipso_v4_doi_putdef(cipsov4);
|
cipso_v4_doi_putdef(cipsov4);
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
calipso_doi_putdef(calipso);
|
||||||
|
#endif
|
||||||
add_free_domain:
|
add_free_domain:
|
||||||
kfree(entry->domain);
|
kfree(entry->domain);
|
||||||
add_free_entry:
|
add_free_entry:
|
||||||
@ -278,6 +315,10 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
|
|||||||
return ret_val;
|
return ret_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret_val = nla_put_u16(skb, NLBL_MGMT_A_FAMILY, entry->family);
|
||||||
|
if (ret_val != 0)
|
||||||
|
return ret_val;
|
||||||
|
|
||||||
switch (entry->def.type) {
|
switch (entry->def.type) {
|
||||||
case NETLBL_NLTYPE_ADDRSELECT:
|
case NETLBL_NLTYPE_ADDRSELECT:
|
||||||
nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
|
nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
|
||||||
@ -340,6 +381,15 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
|
|||||||
if (ret_val != 0)
|
if (ret_val != 0)
|
||||||
return ret_val;
|
return ret_val;
|
||||||
|
|
||||||
|
switch (map6->def.type) {
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
|
||||||
|
map6->def.calipso->doi);
|
||||||
|
if (ret_val != 0)
|
||||||
|
return ret_val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
nla_nest_end(skb, nla_b);
|
nla_nest_end(skb, nla_b);
|
||||||
}
|
}
|
||||||
#endif /* IPv6 */
|
#endif /* IPv6 */
|
||||||
@ -347,15 +397,25 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
|
|||||||
nla_nest_end(skb, nla_a);
|
nla_nest_end(skb, nla_a);
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_UNLABELED:
|
case NETLBL_NLTYPE_UNLABELED:
|
||||||
ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
|
ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
|
||||||
|
entry->def.type);
|
||||||
break;
|
break;
|
||||||
case NETLBL_NLTYPE_CIPSOV4:
|
case NETLBL_NLTYPE_CIPSOV4:
|
||||||
ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
|
ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
|
||||||
|
entry->def.type);
|
||||||
if (ret_val != 0)
|
if (ret_val != 0)
|
||||||
return ret_val;
|
return ret_val;
|
||||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
|
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
|
||||||
entry->def.cipso->doi);
|
entry->def.cipso->doi);
|
||||||
break;
|
break;
|
||||||
|
case NETLBL_NLTYPE_CALIPSO:
|
||||||
|
ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
|
||||||
|
entry->def.type);
|
||||||
|
if (ret_val != 0)
|
||||||
|
return ret_val;
|
||||||
|
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CLPDOI,
|
||||||
|
entry->def.calipso->doi);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret_val;
|
return ret_val;
|
||||||
@ -418,7 +478,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
|
|||||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||||
|
|
||||||
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
|
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
|
||||||
return netlbl_domhsh_remove(domain, &audit_info);
|
return netlbl_domhsh_remove(domain, AF_UNSPEC, &audit_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -536,7 +596,7 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
|
|||||||
|
|
||||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||||
|
|
||||||
return netlbl_domhsh_remove_default(&audit_info);
|
return netlbl_domhsh_remove_default(AF_UNSPEC, &audit_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -556,6 +616,12 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
|
|||||||
struct sk_buff *ans_skb = NULL;
|
struct sk_buff *ans_skb = NULL;
|
||||||
void *data;
|
void *data;
|
||||||
struct netlbl_dom_map *entry;
|
struct netlbl_dom_map *entry;
|
||||||
|
u16 family;
|
||||||
|
|
||||||
|
if (info->attrs[NLBL_MGMT_A_FAMILY])
|
||||||
|
family = nla_get_u16(info->attrs[NLBL_MGMT_A_FAMILY]);
|
||||||
|
else
|
||||||
|
family = AF_INET;
|
||||||
|
|
||||||
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||||
if (ans_skb == NULL)
|
if (ans_skb == NULL)
|
||||||
@ -566,7 +632,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
|
|||||||
goto listdef_failure;
|
goto listdef_failure;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
entry = netlbl_domhsh_getentry(NULL);
|
entry = netlbl_domhsh_getentry(NULL, family);
|
||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
ret_val = -ENOENT;
|
ret_val = -ENOENT;
|
||||||
goto listdef_failure_lock;
|
goto listdef_failure_lock;
|
||||||
@ -651,6 +717,15 @@ static int netlbl_mgmt_protocols(struct sk_buff *skb,
|
|||||||
goto protocols_return;
|
goto protocols_return;
|
||||||
protos_sent++;
|
protos_sent++;
|
||||||
}
|
}
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
if (protos_sent == 2) {
|
||||||
|
if (netlbl_mgmt_protocols_cb(skb,
|
||||||
|
cb,
|
||||||
|
NETLBL_NLTYPE_CALIPSO) < 0)
|
||||||
|
goto protocols_return;
|
||||||
|
protos_sent++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
protocols_return:
|
protocols_return:
|
||||||
cb->args[0] = protos_sent;
|
cb->args[0] = protos_sent;
|
||||||
|
@ -58,7 +58,10 @@
|
|||||||
*
|
*
|
||||||
* NLBL_MGMT_A_CV4DOI
|
* NLBL_MGMT_A_CV4DOI
|
||||||
*
|
*
|
||||||
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
|
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required,
|
||||||
|
* however the following attribute may optionally be sent:
|
||||||
|
*
|
||||||
|
* NLBL_MGMT_A_FAMILY
|
||||||
*
|
*
|
||||||
* o REMOVE:
|
* o REMOVE:
|
||||||
* Sent by an application to remove a domain mapping from the NetLabel
|
* Sent by an application to remove a domain mapping from the NetLabel
|
||||||
@ -77,6 +80,7 @@
|
|||||||
* Required attributes:
|
* Required attributes:
|
||||||
*
|
*
|
||||||
* NLBL_MGMT_A_DOMAIN
|
* NLBL_MGMT_A_DOMAIN
|
||||||
|
* NLBL_MGMT_A_FAMILY
|
||||||
*
|
*
|
||||||
* If the IP address selectors are not used the following attribute is
|
* If the IP address selectors are not used the following attribute is
|
||||||
* required:
|
* required:
|
||||||
@ -108,7 +112,10 @@
|
|||||||
*
|
*
|
||||||
* NLBL_MGMT_A_CV4DOI
|
* NLBL_MGMT_A_CV4DOI
|
||||||
*
|
*
|
||||||
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
|
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required,
|
||||||
|
* however the following attribute may optionally be sent:
|
||||||
|
*
|
||||||
|
* NLBL_MGMT_A_FAMILY
|
||||||
*
|
*
|
||||||
* o REMOVEDEF:
|
* o REMOVEDEF:
|
||||||
* Sent by an application to remove the default domain mapping from the
|
* Sent by an application to remove the default domain mapping from the
|
||||||
@ -117,13 +124,17 @@
|
|||||||
* o LISTDEF:
|
* o LISTDEF:
|
||||||
* This message can be sent either from an application or by the kernel in
|
* This message can be sent either from an application or by the kernel in
|
||||||
* response to an application generated LISTDEF message. When sent by an
|
* response to an application generated LISTDEF message. When sent by an
|
||||||
* application there is no payload. On success the kernel should send a
|
* application there may be an optional payload.
|
||||||
* response using the following format.
|
|
||||||
*
|
*
|
||||||
* If the IP address selectors are not used the following attribute is
|
* NLBL_MGMT_A_FAMILY
|
||||||
|
*
|
||||||
|
* On success the kernel should send a response using the following format:
|
||||||
|
*
|
||||||
|
* If the IP address selectors are not used the following attributes are
|
||||||
* required:
|
* required:
|
||||||
*
|
*
|
||||||
* NLBL_MGMT_A_PROTOCOL
|
* NLBL_MGMT_A_PROTOCOL
|
||||||
|
* NLBL_MGMT_A_FAMILY
|
||||||
*
|
*
|
||||||
* If the IP address selectors are used then the following attritbute is
|
* If the IP address selectors are used then the following attritbute is
|
||||||
* required:
|
* required:
|
||||||
@ -209,6 +220,12 @@ enum {
|
|||||||
/* (NLA_NESTED)
|
/* (NLA_NESTED)
|
||||||
* the selector list, there must be at least one
|
* the selector list, there must be at least one
|
||||||
* NLBL_MGMT_A_ADDRSELECTOR attribute */
|
* NLBL_MGMT_A_ADDRSELECTOR attribute */
|
||||||
|
NLBL_MGMT_A_FAMILY,
|
||||||
|
/* (NLA_U16)
|
||||||
|
* The address family */
|
||||||
|
NLBL_MGMT_A_CLPDOI,
|
||||||
|
/* (NLA_U32)
|
||||||
|
* the CALIPSO DOI value */
|
||||||
__NLBL_MGMT_A_MAX,
|
__NLBL_MGMT_A_MAX,
|
||||||
};
|
};
|
||||||
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
|
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
|
||||||
|
@ -116,8 +116,8 @@ struct netlbl_unlhsh_walk_arg {
|
|||||||
static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
|
static DEFINE_SPINLOCK(netlbl_unlhsh_lock);
|
||||||
#define netlbl_unlhsh_rcu_deref(p) \
|
#define netlbl_unlhsh_rcu_deref(p) \
|
||||||
rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
|
rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
|
||||||
static struct netlbl_unlhsh_tbl *netlbl_unlhsh;
|
static struct netlbl_unlhsh_tbl __rcu *netlbl_unlhsh;
|
||||||
static struct netlbl_unlhsh_iface *netlbl_unlhsh_def;
|
static struct netlbl_unlhsh_iface __rcu *netlbl_unlhsh_def;
|
||||||
|
|
||||||
/* Accept unlabeled packets flag */
|
/* Accept unlabeled packets flag */
|
||||||
static u8 netlabel_unlabel_acceptflg;
|
static u8 netlabel_unlabel_acceptflg;
|
||||||
@ -1537,6 +1537,7 @@ int __init netlbl_unlabel_defconf(void)
|
|||||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
entry->family = AF_UNSPEC;
|
||||||
entry->def.type = NETLBL_NLTYPE_UNLABELED;
|
entry->def.type = NETLBL_NLTYPE_UNLABELED;
|
||||||
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
|
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
|
||||||
if (ret_val != 0)
|
if (ret_val != 0)
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
#include "netlabel_mgmt.h"
|
#include "netlabel_mgmt.h"
|
||||||
#include "netlabel_unlabeled.h"
|
#include "netlabel_unlabeled.h"
|
||||||
#include "netlabel_cipso_v4.h"
|
#include "netlabel_cipso_v4.h"
|
||||||
|
#include "netlabel_calipso.h"
|
||||||
#include "netlabel_user.h"
|
#include "netlabel_user.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -71,6 +72,10 @@ int __init netlbl_netlink_init(void)
|
|||||||
if (ret_val != 0)
|
if (ret_val != 0)
|
||||||
return ret_val;
|
return ret_val;
|
||||||
|
|
||||||
|
ret_val = netlbl_calipso_genl_init();
|
||||||
|
if (ret_val != 0)
|
||||||
|
return ret_val;
|
||||||
|
|
||||||
return netlbl_unlabel_genl_init();
|
return netlbl_unlabel_genl_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4604,13 +4604,13 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
|
|||||||
err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
|
err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
|
||||||
addrp, family, peer_sid, &ad);
|
addrp, family, peer_sid, &ad);
|
||||||
if (err) {
|
if (err) {
|
||||||
selinux_netlbl_err(skb, err, 0);
|
selinux_netlbl_err(skb, family, err, 0);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
|
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
|
||||||
PEER__RECV, &ad);
|
PEER__RECV, &ad);
|
||||||
if (err) {
|
if (err) {
|
||||||
selinux_netlbl_err(skb, err, 0);
|
selinux_netlbl_err(skb, family, err, 0);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4978,7 +4978,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
|
|||||||
err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
|
err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
|
||||||
addrp, family, peer_sid, &ad);
|
addrp, family, peer_sid, &ad);
|
||||||
if (err) {
|
if (err) {
|
||||||
selinux_netlbl_err(skb, err, 1);
|
selinux_netlbl_err(skb, family, err, 1);
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5064,6 +5064,15 @@ static unsigned int selinux_ipv4_output(void *priv,
|
|||||||
return selinux_ip_output(skb, PF_INET);
|
return selinux_ip_output(skb, PF_INET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
|
||||||
|
static unsigned int selinux_ipv6_output(void *priv,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
const struct nf_hook_state *state)
|
||||||
|
{
|
||||||
|
return selinux_ip_output(skb, PF_INET6);
|
||||||
|
}
|
||||||
|
#endif /* IPV6 */
|
||||||
|
|
||||||
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
u16 family)
|
u16 family)
|
||||||
@ -6298,6 +6307,12 @@ static struct nf_hook_ops selinux_nf_ops[] = {
|
|||||||
.hooknum = NF_INET_FORWARD,
|
.hooknum = NF_INET_FORWARD,
|
||||||
.priority = NF_IP6_PRI_SELINUX_FIRST,
|
.priority = NF_IP6_PRI_SELINUX_FIRST,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.hook = selinux_ipv6_output,
|
||||||
|
.pf = NFPROTO_IPV6,
|
||||||
|
.hooknum = NF_INET_LOCAL_OUT,
|
||||||
|
.priority = NF_IP6_PRI_SELINUX_FIRST,
|
||||||
|
},
|
||||||
#endif /* IPV6 */
|
#endif /* IPV6 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@
|
|||||||
#ifdef CONFIG_NETLABEL
|
#ifdef CONFIG_NETLABEL
|
||||||
void selinux_netlbl_cache_invalidate(void);
|
void selinux_netlbl_cache_invalidate(void);
|
||||||
|
|
||||||
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway);
|
void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error,
|
||||||
|
int gateway);
|
||||||
|
|
||||||
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec);
|
void selinux_netlbl_sk_security_free(struct sk_security_struct *sksec);
|
||||||
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec);
|
void selinux_netlbl_sk_security_reset(struct sk_security_struct *sksec);
|
||||||
@ -72,6 +73,7 @@ static inline void selinux_netlbl_cache_invalidate(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void selinux_netlbl_err(struct sk_buff *skb,
|
static inline void selinux_netlbl_err(struct sk_buff *skb,
|
||||||
|
u16 family,
|
||||||
int error,
|
int error,
|
||||||
int gateway)
|
int gateway)
|
||||||
{
|
{
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
|
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
|
||||||
|
u16 family,
|
||||||
struct netlbl_lsm_secattr *secattr,
|
struct netlbl_lsm_secattr *secattr,
|
||||||
u32 *sid)
|
u32 *sid)
|
||||||
{
|
{
|
||||||
@ -63,7 +64,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
|
|||||||
if (rc == 0 &&
|
if (rc == 0 &&
|
||||||
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
|
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
|
||||||
(secattr->flags & NETLBL_SECATTR_CACHE))
|
(secattr->flags & NETLBL_SECATTR_CACHE))
|
||||||
netlbl_cache_add(skb, secattr);
|
netlbl_cache_add(skb, family, secattr);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -151,9 +152,9 @@ void selinux_netlbl_cache_invalidate(void)
|
|||||||
* present on the packet, NetLabel is smart enough to only act when it should.
|
* present on the packet, NetLabel is smart enough to only act when it should.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)
|
void selinux_netlbl_err(struct sk_buff *skb, u16 family, int error, int gateway)
|
||||||
{
|
{
|
||||||
netlbl_skbuff_err(skb, error, gateway);
|
netlbl_skbuff_err(skb, family, error, gateway);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -214,7 +215,8 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
|
|||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||||
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
||||||
rc = selinux_netlbl_sidlookup_cached(skb, &secattr, sid);
|
rc = selinux_netlbl_sidlookup_cached(skb, family,
|
||||||
|
&secattr, sid);
|
||||||
else
|
else
|
||||||
*sid = SECSID_NULL;
|
*sid = SECSID_NULL;
|
||||||
*type = secattr.type;
|
*type = secattr.type;
|
||||||
@ -284,7 +286,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
|
|||||||
int rc;
|
int rc;
|
||||||
struct netlbl_lsm_secattr secattr;
|
struct netlbl_lsm_secattr secattr;
|
||||||
|
|
||||||
if (family != PF_INET)
|
if (family != PF_INET && family != PF_INET6)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
@ -333,7 +335,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
|
|||||||
struct sk_security_struct *sksec = sk->sk_security;
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
struct netlbl_lsm_secattr *secattr;
|
struct netlbl_lsm_secattr *secattr;
|
||||||
|
|
||||||
if (family != PF_INET)
|
if (family != PF_INET && family != PF_INET6)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
secattr = selinux_netlbl_sock_genattr(sk);
|
secattr = selinux_netlbl_sock_genattr(sk);
|
||||||
@ -382,7 +384,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
|||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||||
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
|
||||||
rc = selinux_netlbl_sidlookup_cached(skb, &secattr, &nlbl_sid);
|
rc = selinux_netlbl_sidlookup_cached(skb, family,
|
||||||
|
&secattr, &nlbl_sid);
|
||||||
else
|
else
|
||||||
nlbl_sid = SECINITSID_UNLABELED;
|
nlbl_sid = SECINITSID_UNLABELED;
|
||||||
netlbl_secattr_destroy(&secattr);
|
netlbl_secattr_destroy(&secattr);
|
||||||
@ -405,10 +408,25 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (nlbl_sid != SECINITSID_UNLABELED)
|
if (nlbl_sid != SECINITSID_UNLABELED)
|
||||||
netlbl_skbuff_err(skb, rc, 0);
|
netlbl_skbuff_err(skb, family, rc, 0);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* selinux_netlbl_option - Is this a NetLabel option
|
||||||
|
* @level: the socket level or protocol
|
||||||
|
* @optname: the socket option name
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Returns true if @level and @optname refer to a NetLabel option.
|
||||||
|
* Helper for selinux_netlbl_socket_setsockopt().
|
||||||
|
*/
|
||||||
|
static inline int selinux_netlbl_option(int level, int optname)
|
||||||
|
{
|
||||||
|
return (level == IPPROTO_IP && optname == IP_OPTIONS) ||
|
||||||
|
(level == IPPROTO_IPV6 && optname == IPV6_HOPOPTS);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
|
* selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
|
||||||
* @sock: the socket
|
* @sock: the socket
|
||||||
@ -431,7 +449,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
|||||||
struct sk_security_struct *sksec = sk->sk_security;
|
struct sk_security_struct *sksec = sk->sk_security;
|
||||||
struct netlbl_lsm_secattr secattr;
|
struct netlbl_lsm_secattr secattr;
|
||||||
|
|
||||||
if (level == IPPROTO_IP && optname == IP_OPTIONS &&
|
if (selinux_netlbl_option(level, optname) &&
|
||||||
(sksec->nlbl_state == NLBL_LABELED ||
|
(sksec->nlbl_state == NLBL_LABELED ||
|
||||||
sksec->nlbl_state == NLBL_CONNLABELED)) {
|
sksec->nlbl_state == NLBL_CONNLABELED)) {
|
||||||
netlbl_secattr_init(&secattr);
|
netlbl_secattr_init(&secattr);
|
||||||
|
@ -1347,7 +1347,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
|
|||||||
{
|
{
|
||||||
char *page;
|
char *page;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
int new_value;
|
unsigned int new_value;
|
||||||
|
|
||||||
ret = task_has_security(current, SECURITY__SETSECPARAM);
|
ret = task_has_security(current, SECURITY__SETSECPARAM);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
@ -165,7 +165,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
|
|||||||
e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
|
e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
|
||||||
if (e_iter == NULL)
|
if (e_iter == NULL)
|
||||||
goto netlbl_import_failure;
|
goto netlbl_import_failure;
|
||||||
e_iter->startbit = offset & ~(EBITMAP_SIZE - 1);
|
e_iter->startbit = offset - (offset % EBITMAP_SIZE);
|
||||||
if (e_prev == NULL)
|
if (e_prev == NULL)
|
||||||
ebmap->node = e_iter;
|
ebmap->node = e_iter;
|
||||||
else
|
else
|
||||||
|
@ -543,7 +543,7 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|||||||
struct av_decision *avd)
|
struct av_decision *avd)
|
||||||
{
|
{
|
||||||
struct context lo_scontext;
|
struct context lo_scontext;
|
||||||
struct context lo_tcontext;
|
struct context lo_tcontext, *tcontextp = tcontext;
|
||||||
struct av_decision lo_avd;
|
struct av_decision lo_avd;
|
||||||
struct type_datum *source;
|
struct type_datum *source;
|
||||||
struct type_datum *target;
|
struct type_datum *target;
|
||||||
@ -553,67 +553,41 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|||||||
scontext->type - 1);
|
scontext->type - 1);
|
||||||
BUG_ON(!source);
|
BUG_ON(!source);
|
||||||
|
|
||||||
|
if (!source->bounds)
|
||||||
|
return;
|
||||||
|
|
||||||
target = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
target = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
||||||
tcontext->type - 1);
|
tcontext->type - 1);
|
||||||
BUG_ON(!target);
|
BUG_ON(!target);
|
||||||
|
|
||||||
if (source->bounds) {
|
memset(&lo_avd, 0, sizeof(lo_avd));
|
||||||
memset(&lo_avd, 0, sizeof(lo_avd));
|
|
||||||
|
|
||||||
memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
|
memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
|
||||||
lo_scontext.type = source->bounds;
|
lo_scontext.type = source->bounds;
|
||||||
|
|
||||||
context_struct_compute_av(&lo_scontext,
|
|
||||||
tcontext,
|
|
||||||
tclass,
|
|
||||||
&lo_avd,
|
|
||||||
NULL);
|
|
||||||
if ((lo_avd.allowed & avd->allowed) == avd->allowed)
|
|
||||||
return; /* no masked permission */
|
|
||||||
masked = ~lo_avd.allowed & avd->allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target->bounds) {
|
if (target->bounds) {
|
||||||
memset(&lo_avd, 0, sizeof(lo_avd));
|
|
||||||
|
|
||||||
memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
|
memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
|
||||||
lo_tcontext.type = target->bounds;
|
lo_tcontext.type = target->bounds;
|
||||||
|
tcontextp = &lo_tcontext;
|
||||||
context_struct_compute_av(scontext,
|
|
||||||
&lo_tcontext,
|
|
||||||
tclass,
|
|
||||||
&lo_avd,
|
|
||||||
NULL);
|
|
||||||
if ((lo_avd.allowed & avd->allowed) == avd->allowed)
|
|
||||||
return; /* no masked permission */
|
|
||||||
masked = ~lo_avd.allowed & avd->allowed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source->bounds && target->bounds) {
|
context_struct_compute_av(&lo_scontext,
|
||||||
memset(&lo_avd, 0, sizeof(lo_avd));
|
tcontextp,
|
||||||
/*
|
tclass,
|
||||||
* lo_scontext and lo_tcontext are already
|
&lo_avd,
|
||||||
* set up.
|
NULL);
|
||||||
*/
|
|
||||||
|
|
||||||
context_struct_compute_av(&lo_scontext,
|
masked = ~lo_avd.allowed & avd->allowed;
|
||||||
&lo_tcontext,
|
|
||||||
tclass,
|
|
||||||
&lo_avd,
|
|
||||||
NULL);
|
|
||||||
if ((lo_avd.allowed & avd->allowed) == avd->allowed)
|
|
||||||
return; /* no masked permission */
|
|
||||||
masked = ~lo_avd.allowed & avd->allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masked) {
|
if (likely(!masked))
|
||||||
/* mask violated permissions */
|
return; /* no masked permission */
|
||||||
avd->allowed &= ~masked;
|
|
||||||
|
|
||||||
/* audit masked permissions */
|
/* mask violated permissions */
|
||||||
security_dump_masked_av(scontext, tcontext,
|
avd->allowed &= ~masked;
|
||||||
tclass, masked, "bounds");
|
|
||||||
}
|
/* audit masked permissions */
|
||||||
|
security_dump_masked_av(scontext, tcontext,
|
||||||
|
tclass, masked, "bounds");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -3992,7 +3992,7 @@ access_check:
|
|||||||
rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
|
rc = smk_bu_note("IPv4 delivery", skp, ssp->smk_in,
|
||||||
MAY_WRITE, rc);
|
MAY_WRITE, rc);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
netlbl_skbuff_err(skb, rc, 0);
|
netlbl_skbuff_err(skb, sk->sk_family, rc, 0);
|
||||||
break;
|
break;
|
||||||
#if IS_ENABLED(CONFIG_IPV6)
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
case PF_INET6:
|
case PF_INET6:
|
||||||
|
Loading…
Reference in New Issue
Block a user