Merge branch 'stable-4.8' of git://git.infradead.org/users/pcmoore/selinux into next
This commit is contained in:
commit
d011a4d861
|
@ -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;
|
||||
union {
|
||||
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,
|
||||
struct ipv6_opt_hdr __user *newopt,
|
||||
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 *opt);
|
||||
|
||||
bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb,
|
||||
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)
|
||||
{
|
||||
|
@ -943,7 +951,7 @@ enum {
|
|||
int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target,
|
||||
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,
|
||||
const struct ipv6_txoptions *opt,
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/atomic.h>
|
||||
|
||||
struct cipso_v4_doi;
|
||||
struct calipso_doi;
|
||||
|
||||
/*
|
||||
* 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_ADDRSELECT 6
|
||||
#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.
|
||||
|
@ -216,6 +219,63 @@ struct netlbl_lsm_secattr {
|
|||
} 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)
|
||||
*/
|
||||
|
@ -385,6 +445,14 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
|
|||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
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
|
||||
*/
|
||||
|
@ -405,6 +473,12 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
|
|||
unsigned long bitmap,
|
||||
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)
|
||||
*/
|
||||
|
@ -427,13 +501,13 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
|||
int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||
u16 family,
|
||||
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
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
|
@ -495,6 +569,24 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
|
|||
{
|
||||
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,
|
||||
u32 offset)
|
||||
{
|
||||
|
@ -586,7 +678,7 @@ static inline void netlbl_cache_invalidate(void)
|
|||
{
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
|
@ -598,4 +690,7 @@ static inline struct audit_buffer *netlbl_audit_start(int type,
|
|||
}
|
||||
#endif /* CONFIG_NETLABEL */
|
||||
|
||||
const struct netlbl_calipso_ops *
|
||||
netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops);
|
||||
|
||||
#endif /* _NETLABEL_H */
|
||||
|
|
|
@ -130,6 +130,8 @@
|
|||
#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_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_LAST_KERN_ANOM_MSG 1799
|
||||
|
|
|
@ -143,6 +143,7 @@ struct in6_flowlabel_req {
|
|||
#define IPV6_TLV_PAD1 0
|
||||
#define IPV6_TLV_PADN 1
|
||||
#define IPV6_TLV_ROUTERALERT 5
|
||||
#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
|
||||
#define IPV6_TLV_JUMBO 194
|
||||
#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);
|
||||
if (skb != NULL) {
|
||||
struct dccp_hdr *dh = dccp_hdr(skb);
|
||||
struct ipv6_txoptions *opt;
|
||||
|
||||
dh->dccph_checksum = dccp_v6_csum_finish(skb,
|
||||
&ireq->ir_v6_loc_addr,
|
||||
&ireq->ir_v6_rmt_addr);
|
||||
fl6.daddr = ireq->ir_v6_rmt_addr;
|
||||
rcu_read_lock();
|
||||
err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
|
||||
np->tclass);
|
||||
opt = ireq->ipv6_opt;
|
||||
if (!opt)
|
||||
opt = rcu_dereference(np->opt);
|
||||
err = ip6_xmit(sk, skb, &fl6, opt, np->tclass);
|
||||
rcu_read_unlock();
|
||||
err = net_xmit_eval(err);
|
||||
}
|
||||
|
@ -236,6 +239,7 @@ done:
|
|||
static void dccp_v6_reqsk_destructor(struct request_sock *req)
|
||||
{
|
||||
dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg);
|
||||
kfree(inet_rsk(req)->ipv6_opt);
|
||||
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
|
||||
* 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) {
|
||||
opt = ipv6_dup_options(newsk, opt);
|
||||
RCU_INIT_POINTER(newnp->opt, opt);
|
||||
|
|
|
@ -134,76 +134,6 @@ int cipso_v4_rbm_strictvalid = 1;
|
|||
* 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
|
||||
* @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_array = doi_def->map.std->cat.cipso;
|
||||
for (;;) {
|
||||
cat = cipso_v4_bitmap_walk(bitmap,
|
||||
bitmap_len_bits,
|
||||
cat + 1,
|
||||
1);
|
||||
cat = netlbl_bitmap_walk(bitmap,
|
||||
bitmap_len_bits,
|
||||
cat + 1,
|
||||
1);
|
||||
if (cat < 0)
|
||||
break;
|
||||
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)
|
||||
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)
|
||||
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 (;;) {
|
||||
net_spot = cipso_v4_bitmap_walk(net_cat,
|
||||
net_clen_bits,
|
||||
net_spot + 1,
|
||||
1);
|
||||
net_spot = netlbl_bitmap_walk(net_cat,
|
||||
net_clen_bits,
|
||||
net_spot + 1,
|
||||
1);
|
||||
if (net_spot < 0) {
|
||||
if (net_spot == -2)
|
||||
return -EFAULT;
|
||||
|
|
|
@ -6114,6 +6114,9 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
|
|||
|
||||
kmemcheck_annotate_bitfield(ireq, flags);
|
||||
ireq->opt = NULL;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
ireq->pktopts = NULL;
|
||||
#endif
|
||||
atomic64_set(&ireq->ir_cookie, 0);
|
||||
ireq->ireq_state = TCP_NEW_SYN_RECV;
|
||||
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_PROC_FS) += proc.o
|
||||
ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o
|
||||
ipv6-$(CONFIG_NETLABEL) += calipso.o
|
||||
|
||||
ipv6-objs += $(ipv6-y)
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
#ifdef CONFIG_IPV6_TUNNEL
|
||||
#include <net/ip6_tunnel.h>
|
||||
#endif
|
||||
#include <net/calipso.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/mroute6.h>
|
||||
|
@ -977,6 +978,10 @@ static int __init inet6_init(void)
|
|||
if (err)
|
||||
goto pingv6_fail;
|
||||
|
||||
err = calipso_init();
|
||||
if (err)
|
||||
goto calipso_fail;
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
err = ipv6_sysctl_register();
|
||||
if (err)
|
||||
|
@ -987,8 +992,10 @@ out:
|
|||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
sysctl_fail:
|
||||
pingv6_exit();
|
||||
calipso_exit();
|
||||
#endif
|
||||
calipso_fail:
|
||||
pingv6_exit();
|
||||
pingv6_fail:
|
||||
ipv6_packet_cleanup();
|
||||
ipv6_packet_fail:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -43,6 +43,7 @@
|
|||
#include <net/ndisc.h>
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/calipso.h>
|
||||
#if IS_ENABLED(CONFIG_IPV6_MIP6)
|
||||
#include <net/xfrm.h>
|
||||
#endif
|
||||
|
@ -603,6 +604,28 @@ drop:
|
|||
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[] = {
|
||||
{
|
||||
.type = IPV6_TLV_ROUTERALERT,
|
||||
|
@ -612,6 +635,10 @@ static const struct tlvtype_proc tlvprochopopt_lst[] = {
|
|||
.type = IPV6_TLV_JUMBO,
|
||||
.func = ipv6_hop_jumbo,
|
||||
},
|
||||
{
|
||||
.type = IPV6_TLV_CALIPSO,
|
||||
.func = ipv6_hop_calipso,
|
||||
},
|
||||
{ -1, }
|
||||
};
|
||||
|
||||
|
@ -758,6 +785,27 @@ static int ipv6_renew_option(void *ohdr,
|
|||
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 *
|
||||
ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
|
||||
int newtype,
|
||||
|
@ -830,6 +878,34 @@ out:
|
|||
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 *opt)
|
||||
{
|
||||
|
|
|
@ -112,7 +112,7 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
|
|||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
static
|
||||
struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
|
||||
struct ipv6_txoptions *opt)
|
||||
{
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include <net/ipv6.h>
|
||||
#include <net/addrconf.h>
|
||||
#include <net/inet_frag.h>
|
||||
#ifdef CONFIG_NETLABEL
|
||||
#include <net/calipso.h>
|
||||
#endif
|
||||
|
||||
static int one = 1;
|
||||
static int auto_flowlabels_min;
|
||||
|
@ -106,6 +109,22 @@ static struct ctl_table ipv6_rotable[] = {
|
|||
.proc_handler = proc_dointvec_minmax,
|
||||
.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 ipv6_pinfo *np = inet6_sk(sk);
|
||||
struct ipv6_txoptions *opt;
|
||||
struct flowi6 *fl6 = &fl->u.ip6;
|
||||
struct sk_buff *skb;
|
||||
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));
|
||||
|
||||
rcu_read_lock();
|
||||
err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
|
||||
np->tclass);
|
||||
opt = ireq->ipv6_opt;
|
||||
if (!opt)
|
||||
opt = rcu_dereference(np->opt);
|
||||
err = ip6_xmit(sk, skb, fl6, opt, np->tclass);
|
||||
rcu_read_unlock();
|
||||
err = net_xmit_eval(err);
|
||||
}
|
||||
|
@ -476,6 +479,7 @@ done:
|
|||
|
||||
static void tcp_v6_reqsk_destructor(struct request_sock *req)
|
||||
{
|
||||
kfree(inet_rsk(req)->ipv6_opt);
|
||||
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
|
||||
to newsk.
|
||||
*/
|
||||
opt = rcu_dereference(np->opt);
|
||||
opt = ireq->ipv6_opt;
|
||||
if (!opt)
|
||||
opt = rcu_dereference(np->opt);
|
||||
if (opt) {
|
||||
opt = ipv6_dup_options(newsk, opt);
|
||||
RCU_INIT_POINTER(newnp->opt, opt);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/security.h>
|
||||
#include <net/sock.h>
|
||||
#include <asm/ebcdic.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)
|
||||
{
|
||||
if (parent)
|
||||
if (parent) {
|
||||
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)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
config NETLABEL
|
||||
bool "NetLabel subsystem support"
|
||||
depends on SECURITY
|
||||
select CRC_CCITT if IPV6
|
||||
default n
|
||||
---help---
|
||||
NetLabel provides support for explicit network packet labeling
|
||||
|
|
|
@ -12,4 +12,4 @@ obj-y += netlabel_mgmt.o
|
|||
# protocol modules
|
||||
obj-y += netlabel_unlabeled.o
|
||||
obj-y += netlabel_cipso_v4.o
|
||||
|
||||
obj-$(subst m,y,$(CONFIG_IPV6)) += netlabel_calipso.o
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <net/calipso.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_addrlist.h"
|
||||
#include "netlabel_calipso.h"
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.h"
|
||||
|
||||
|
@ -55,8 +57,9 @@ struct netlbl_domhsh_tbl {
|
|||
static DEFINE_SPINLOCK(netlbl_domhsh_lock);
|
||||
#define netlbl_domhsh_rcu_deref(p) \
|
||||
rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
|
||||
static struct netlbl_domhsh_tbl *netlbl_domhsh;
|
||||
static struct netlbl_dom_map *netlbl_domhsh_def;
|
||||
static struct netlbl_domhsh_tbl __rcu *netlbl_domhsh;
|
||||
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
|
||||
|
@ -126,18 +129,26 @@ static u32 netlbl_domhsh_hash(const char *key)
|
|||
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
|
||||
* @domain: the domain
|
||||
* @family: the address family
|
||||
*
|
||||
* Description:
|
||||
* 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
|
||||
* 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;
|
||||
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_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -157,28 +170,37 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
|
|||
/**
|
||||
* netlbl_domhsh_search_def - Search for a domain entry
|
||||
* @domain: the domain
|
||||
* @def: return default if no match is found
|
||||
* @family: the address family
|
||||
*
|
||||
* Description:
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
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;
|
||||
|
||||
entry = netlbl_domhsh_search(domain);
|
||||
if (entry == NULL) {
|
||||
entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def);
|
||||
if (entry != NULL && !entry->valid)
|
||||
entry = NULL;
|
||||
entry = netlbl_domhsh_search(domain, family);
|
||||
if (entry != NULL)
|
||||
return entry;
|
||||
if (family == AF_INET || family == AF_UNSPEC) {
|
||||
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 cipso_v4_doi *cipsov4 = NULL;
|
||||
struct calipso_doi *calipso = NULL;
|
||||
u32 type;
|
||||
|
||||
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;
|
||||
map6 = netlbl_domhsh_addr6_entry(addr6);
|
||||
type = map6->def.type;
|
||||
calipso = map6->def.calipso;
|
||||
netlbl_af6list_audit_addr(audit_buf, 0, NULL,
|
||||
&addr6->addr, &addr6->mask);
|
||||
#endif /* IPv6 */
|
||||
} else {
|
||||
type = entry->def.type;
|
||||
cipsov4 = entry->def.cipso;
|
||||
calipso = entry->def.calipso;
|
||||
}
|
||||
switch (type) {
|
||||
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",
|
||||
cipsov4->doi);
|
||||
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_end(audit_buf);
|
||||
|
@ -264,13 +295,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
|
|||
if (entry == NULL)
|
||||
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) {
|
||||
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;
|
||||
break;
|
||||
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;
|
||||
break;
|
||||
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);
|
||||
switch (map6->def.type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
if (map6->def.calipso != NULL)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NETLBL_NLTYPE_CALIPSO:
|
||||
if (map6->def.calipso == NULL)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -358,15 +407,18 @@ int __init netlbl_domhsh_init(u32 size)
|
|||
*
|
||||
* Description:
|
||||
* 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,
|
||||
* negative on failure.
|
||||
* lower level protocol handler (i.e. CIPSO). @entry->family may be set to
|
||||
* %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,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
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 *tmp4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
|
@ -385,9 +437,10 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
|||
rcu_read_lock();
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->domain != NULL)
|
||||
entry_old = netlbl_domhsh_search(entry->domain);
|
||||
entry_old = netlbl_domhsh_search(entry->domain, entry->family);
|
||||
else
|
||||
entry_old = netlbl_domhsh_search_def(entry->domain);
|
||||
entry_old = netlbl_domhsh_search_def(entry->domain,
|
||||
entry->family);
|
||||
if (entry_old == NULL) {
|
||||
entry->valid = 1;
|
||||
|
||||
|
@ -397,7 +450,41 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
|||
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
|
||||
} else {
|
||||
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) {
|
||||
|
@ -513,10 +600,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
if (entry != rcu_dereference(netlbl_domhsh_def))
|
||||
list_del_rcu(&entry->list);
|
||||
if (entry == rcu_dereference(netlbl_domhsh_def_ipv4))
|
||||
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
|
||||
RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
|
||||
list_del_rcu(&entry->list);
|
||||
} else
|
||||
ret_val = -ENOENT;
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
|
@ -533,6 +622,10 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||
if (ret_val == 0) {
|
||||
struct netlbl_af4list *iter4;
|
||||
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) {
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
|
@ -541,12 +634,22 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
|||
map4 = netlbl_domhsh_addr4_entry(iter4);
|
||||
cipso_v4_doi_putdef(map4->def.cipso);
|
||||
}
|
||||
/* no need to check the IPv6 list since we currently
|
||||
* support only unlabeled protocols for IPv6 */
|
||||
#if IS_ENABLED(CONFIG_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;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
cipso_v4_doi_putdef(entry->def.cipso);
|
||||
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);
|
||||
}
|
||||
|
@ -583,9 +686,9 @@ int netlbl_domhsh_remove_af4(const char *domain,
|
|||
rcu_read_lock();
|
||||
|
||||
if (domain)
|
||||
entry_map = netlbl_domhsh_search(domain);
|
||||
entry_map = netlbl_domhsh_search(domain, AF_INET);
|
||||
else
|
||||
entry_map = netlbl_domhsh_search_def(domain);
|
||||
entry_map = netlbl_domhsh_search_def(domain, AF_INET);
|
||||
if (entry_map == NULL ||
|
||||
entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
||||
goto remove_af4_failure;
|
||||
|
@ -622,28 +725,114 @@ remove_af4_failure:
|
|||
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
|
||||
* @domain: the domain to remove
|
||||
* @family: address family
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* 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,
|
||||
* negative on failure.
|
||||
* lower level protocol handler (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(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;
|
||||
|
||||
rcu_read_lock();
|
||||
if (domain)
|
||||
entry = netlbl_domhsh_search(domain);
|
||||
else
|
||||
entry = netlbl_domhsh_search_def(domain);
|
||||
ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
|
||||
|
||||
if (family == AF_INET || family == AF_UNSPEC) {
|
||||
if (domain)
|
||||
entry = netlbl_domhsh_search(domain, AF_INET);
|
||||
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();
|
||||
|
||||
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
|
||||
* @family: address family
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes/resets the default entry for the domain hash table and handles any
|
||||
* updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
|
||||
* success, non-zero on failure.
|
||||
* Removes/resets the default entry corresponding to @family from the domain
|
||||
* hash table and handles any updates to the lower level protocol handler
|
||||
* (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
|
||||
* @domain: the domain name to search for
|
||||
* @family: address family
|
||||
*
|
||||
* Description:
|
||||
* 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
|
||||
* for ensuring that rcu_read_[un]lock() is called.
|
||||
* with address family @family, return a pointer to a copy of the entry or
|
||||
* 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_af4list *addr_iter;
|
||||
|
||||
dom_iter = netlbl_domhsh_search_def(domain);
|
||||
dom_iter = netlbl_domhsh_search_def(domain, AF_INET);
|
||||
if (dom_iter == 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_af6list *addr_iter;
|
||||
|
||||
dom_iter = netlbl_domhsh_search_def(domain);
|
||||
dom_iter = netlbl_domhsh_search_def(domain, AF_INET6);
|
||||
if (dom_iter == NULL)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ struct netlbl_dommap_def {
|
|||
union {
|
||||
struct netlbl_domaddr_map *addrsel;
|
||||
struct cipso_v4_doi *cipso;
|
||||
struct calipso_doi *calipso;
|
||||
};
|
||||
};
|
||||
#define netlbl_domhsh_addr4_entry(iter) \
|
||||
|
@ -70,6 +71,7 @@ struct netlbl_domaddr6_map {
|
|||
|
||||
struct netlbl_dom_map {
|
||||
char *domain;
|
||||
u16 family;
|
||||
struct netlbl_dommap_def def;
|
||||
|
||||
u32 valid;
|
||||
|
@ -91,14 +93,23 @@ int netlbl_domhsh_remove_af4(const char *domain,
|
|||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
|
||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
|
||||
int netlbl_domhsh_remove_af6(const char *domain,
|
||||
const struct in6_addr *addr,
|
||||
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,
|
||||
__be32 addr);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
|
||||
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 */
|
||||
|
||||
int netlbl_domhsh_walk(u32 *skip_bkt,
|
||||
|
|
|
@ -37,12 +37,14 @@
|
|||
#include <net/ipv6.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <net/calipso.h>
|
||||
#include <asm/bug.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_unlabeled.h"
|
||||
#include "netlabel_cipso_v4.h"
|
||||
#include "netlabel_calipso.h"
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_addrlist.h"
|
||||
|
@ -72,12 +74,17 @@ int netlbl_cfg_map_del(const char *domain,
|
|||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
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) {
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return netlbl_domhsh_remove_af4(domain, addr, mask,
|
||||
audit_info);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
return netlbl_domhsh_remove_af6(domain, addr, mask,
|
||||
audit_info);
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
return -EPFNOSUPPORT;
|
||||
}
|
||||
|
@ -119,6 +126,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
|
|||
if (entry->domain == NULL)
|
||||
goto cfg_unlbl_map_add_failure;
|
||||
}
|
||||
entry->family = family;
|
||||
|
||||
if (addr == NULL && mask == NULL)
|
||||
entry->def.type = NETLBL_NLTYPE_UNLABELED;
|
||||
|
@ -345,6 +353,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
|
|||
entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
|
||||
if (entry == NULL)
|
||||
goto out_entry;
|
||||
entry->family = AF_INET;
|
||||
if (domain != NULL) {
|
||||
entry->domain = kstrdup(domain, GFP_ATOMIC);
|
||||
if (entry->domain == NULL)
|
||||
|
@ -399,6 +408,139 @@ out_entry:
|
|||
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
|
||||
*/
|
||||
|
@ -519,6 +661,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
|
|||
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL(netlbl_catmap_walk);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
*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) {
|
||||
*offset = (u32)-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (off < iter->startbit) {
|
||||
off = iter->startbit;
|
||||
*offset = off;
|
||||
*offset = iter->startbit;
|
||||
off = 0;
|
||||
} else
|
||||
off -= iter->startbit;
|
||||
|
||||
idx = off / NETLBL_CATMAP_MAPSIZE;
|
||||
*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_SIZE);
|
||||
*bitmap = iter->bitmap[idx] >> (off % NETLBL_CATMAP_MAPSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -655,6 +797,7 @@ int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(netlbl_catmap_setbit);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
@ -774,7 +987,7 @@ int netlbl_sock_setattr(struct sock *sk,
|
|||
struct netlbl_dom_map *dom_entry;
|
||||
|
||||
rcu_read_lock();
|
||||
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
||||
dom_entry = netlbl_domhsh_getentry(secattr->domain, family);
|
||||
if (dom_entry == NULL) {
|
||||
ret_val = -ENOENT;
|
||||
goto socket_setattr_return;
|
||||
|
@ -799,9 +1012,21 @@ int netlbl_sock_setattr(struct sock *sk,
|
|||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
/* since we don't support any IPv6 labeling protocols right
|
||||
* now we can optimize everything away until we do */
|
||||
ret_val = 0;
|
||||
switch (dom_entry->def.type) {
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
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;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
|
@ -824,7 +1049,16 @@ socket_setattr_return:
|
|||
*/
|
||||
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;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
ret_val = -ENOMSG;
|
||||
ret_val = calipso_sock_getattr(sk, secattr);
|
||||
break;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
|
@ -878,6 +1112,9 @@ int netlbl_conn_setattr(struct sock *sk,
|
|||
{
|
||||
int ret_val;
|
||||
struct sockaddr_in *addr4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct sockaddr_in6 *addr6;
|
||||
#endif
|
||||
struct netlbl_dommap_def *entry;
|
||||
|
||||
rcu_read_lock();
|
||||
|
@ -898,7 +1135,7 @@ int netlbl_conn_setattr(struct sock *sk,
|
|||
case NETLBL_NLTYPE_UNLABELED:
|
||||
/* just delete the protocols we support for right now
|
||||
* but we could remove other protocols if needed */
|
||||
cipso_v4_sock_delattr(sk);
|
||||
netlbl_sock_delattr(sk);
|
||||
ret_val = 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -907,9 +1144,27 @@ int netlbl_conn_setattr(struct sock *sk,
|
|||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
/* since we don't support any IPv6 labeling protocols right
|
||||
* now we can optimize everything away until we do */
|
||||
ret_val = 0;
|
||||
addr6 = (struct sockaddr_in6 *)addr;
|
||||
entry = netlbl_domhsh_getentry_af6(secattr->domain,
|
||||
&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;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
|
@ -936,12 +1191,13 @@ int netlbl_req_setattr(struct request_sock *req,
|
|||
{
|
||||
int ret_val;
|
||||
struct netlbl_dommap_def *entry;
|
||||
struct inet_request_sock *ireq = inet_rsk(req);
|
||||
|
||||
rcu_read_lock();
|
||||
switch (req->rsk_ops->family) {
|
||||
case AF_INET:
|
||||
entry = netlbl_domhsh_getentry_af4(secattr->domain,
|
||||
inet_rsk(req)->ir_rmt_addr);
|
||||
ireq->ir_rmt_addr);
|
||||
if (entry == NULL) {
|
||||
ret_val = -ENOENT;
|
||||
goto req_setattr_return;
|
||||
|
@ -952,9 +1208,7 @@ int netlbl_req_setattr(struct request_sock *req,
|
|||
entry->cipso, secattr);
|
||||
break;
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
/* just delete the protocols we support for right now
|
||||
* but we could remove other protocols if needed */
|
||||
cipso_v4_req_delattr(req);
|
||||
netlbl_req_delattr(req);
|
||||
ret_val = 0;
|
||||
break;
|
||||
default:
|
||||
|
@ -963,9 +1217,24 @@ int netlbl_req_setattr(struct request_sock *req,
|
|||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
/* since we don't support any IPv6 labeling protocols right
|
||||
* now we can optimize everything away until we do */
|
||||
ret_val = 0;
|
||||
entry = netlbl_domhsh_getentry_af6(secattr->domain,
|
||||
&ireq->ir_v6_rmt_addr);
|
||||
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;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
|
@ -987,7 +1256,16 @@ req_setattr_return:
|
|||
*/
|
||||
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;
|
||||
struct iphdr *hdr4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct ipv6hdr *hdr6;
|
||||
#endif
|
||||
struct netlbl_dommap_def *entry;
|
||||
|
||||
rcu_read_lock();
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
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) {
|
||||
ret_val = -ENOENT;
|
||||
goto skbuff_setattr_return;
|
||||
|
@ -1034,9 +1316,26 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
|
|||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
/* since we don't support any IPv6 labeling protocols right
|
||||
* now we can optimize everything away until we do */
|
||||
ret_val = 0;
|
||||
hdr6 = ipv6_hdr(skb);
|
||||
entry = netlbl_domhsh_getentry_af6(secattr->domain,
|
||||
&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;
|
||||
#endif /* IPv6 */
|
||||
default:
|
||||
|
@ -1075,6 +1374,9 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
|||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
ptr = calipso_optptr(skb);
|
||||
if (ptr && calipso_getattr(ptr, secattr) == 0)
|
||||
return 0;
|
||||
break;
|
||||
#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
|
||||
* @skb: the packet
|
||||
* @family: the family
|
||||
* @error: the error code
|
||||
* @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.
|
||||
*
|
||||
*/
|
||||
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))
|
||||
cipso_v4_error(skb, error, gateway);
|
||||
switch (family) {
|
||||
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)
|
||||
{
|
||||
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
|
||||
* @skb: the packet
|
||||
* @family: the family
|
||||
* @secattr: the packet's security attributes
|
||||
*
|
||||
* Description:
|
||||
|
@ -1125,7 +1436,7 @@ void netlbl_cache_invalidate(void)
|
|||
* 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)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
|
@ -1133,10 +1444,20 @@ int netlbl_cache_add(const struct sk_buff *skb,
|
|||
if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
|
||||
return -ENOMSG;
|
||||
|
||||
ptr = cipso_v4_optptr(skb);
|
||||
if (ptr)
|
||||
return cipso_v4_cache_add(ptr, secattr);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1161,6 +1482,7 @@ struct audit_buffer *netlbl_audit_start(int type,
|
|||
{
|
||||
return netlbl_audit_start_common(type, audit_info);
|
||||
}
|
||||
EXPORT_SYMBOL(netlbl_audit_start);
|
||||
|
||||
/*
|
||||
* Setup Functions
|
||||
|
|
|
@ -41,8 +41,10 @@
|
|||
#include <net/ipv6.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <net/calipso.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include "netlabel_calipso.h"
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.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_VERSION] = { .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;
|
||||
struct netlbl_domaddr_map *addrmap = NULL;
|
||||
struct cipso_v4_doi *cipsov4 = NULL;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct calipso_doi *calipso = NULL;
|
||||
#endif
|
||||
u32 tmp_val;
|
||||
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) {
|
||||
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;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
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);
|
||||
if (cipsov4 == NULL)
|
||||
goto add_free_domain;
|
||||
entry->family = AF_INET;
|
||||
entry->def.cipso = cipsov4;
|
||||
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:
|
||||
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]) {
|
||||
struct in_addr *addr;
|
||||
struct in_addr *mask;
|
||||
|
@ -178,6 +208,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||
goto add_free_addrmap;
|
||||
}
|
||||
|
||||
entry->family = AF_INET;
|
||||
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||
entry->def.addrsel = addrmap;
|
||||
#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.valid = 1;
|
||||
map->def.type = entry->def.type;
|
||||
if (calipso)
|
||||
map->def.calipso = calipso;
|
||||
|
||||
ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
|
||||
if (ret_val != 0) {
|
||||
|
@ -227,6 +260,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
|
|||
goto add_free_addrmap;
|
||||
}
|
||||
|
||||
entry->family = AF_INET6;
|
||||
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||
entry->def.addrsel = addrmap;
|
||||
#endif /* IPv6 */
|
||||
|
@ -242,6 +276,9 @@ add_free_addrmap:
|
|||
kfree(addrmap);
|
||||
add_doi_put_def:
|
||||
cipso_v4_doi_putdef(cipsov4);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
calipso_doi_putdef(calipso);
|
||||
#endif
|
||||
add_free_domain:
|
||||
kfree(entry->domain);
|
||||
add_free_entry:
|
||||
|
@ -278,6 +315,10 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
|
|||
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) {
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
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)
|
||||
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);
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
|
@ -347,15 +397,25 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
|
|||
nla_nest_end(skb, nla_a);
|
||||
break;
|
||||
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;
|
||||
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)
|
||||
return ret_val;
|
||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
|
||||
entry->def.cipso->doi);
|
||||
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;
|
||||
|
@ -418,7 +478,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
|
|||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
void *data;
|
||||
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);
|
||||
if (ans_skb == NULL)
|
||||
|
@ -566,7 +632,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
|
|||
goto listdef_failure;
|
||||
|
||||
rcu_read_lock();
|
||||
entry = netlbl_domhsh_getentry(NULL);
|
||||
entry = netlbl_domhsh_getentry(NULL, family);
|
||||
if (entry == NULL) {
|
||||
ret_val = -ENOENT;
|
||||
goto listdef_failure_lock;
|
||||
|
@ -651,6 +717,15 @@ static int netlbl_mgmt_protocols(struct sk_buff *skb,
|
|||
goto protocols_return;
|
||||
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:
|
||||
cb->args[0] = protos_sent;
|
||||
|
|
|
@ -58,7 +58,10 @@
|
|||
*
|
||||
* 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:
|
||||
* Sent by an application to remove a domain mapping from the NetLabel
|
||||
|
@ -77,6 +80,7 @@
|
|||
* Required attributes:
|
||||
*
|
||||
* NLBL_MGMT_A_DOMAIN
|
||||
* NLBL_MGMT_A_FAMILY
|
||||
*
|
||||
* If the IP address selectors are not used the following attribute is
|
||||
* required:
|
||||
|
@ -108,7 +112,10 @@
|
|||
*
|
||||
* 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:
|
||||
* Sent by an application to remove the default domain mapping from the
|
||||
|
@ -117,13 +124,17 @@
|
|||
* o LISTDEF:
|
||||
* 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
|
||||
* application there is no payload. On success the kernel should send a
|
||||
* response using the following format.
|
||||
* application there may be an optional payload.
|
||||
*
|
||||
* 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:
|
||||
*
|
||||
* NLBL_MGMT_A_PROTOCOL
|
||||
* NLBL_MGMT_A_FAMILY
|
||||
*
|
||||
* If the IP address selectors are used then the following attritbute is
|
||||
* required:
|
||||
|
@ -209,6 +220,12 @@ enum {
|
|||
/* (NLA_NESTED)
|
||||
* the selector list, there must be at least one
|
||||
* 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,
|
||||
};
|
||||
#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);
|
||||
#define netlbl_unlhsh_rcu_deref(p) \
|
||||
rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
|
||||
static struct netlbl_unlhsh_tbl *netlbl_unlhsh;
|
||||
static struct netlbl_unlhsh_iface *netlbl_unlhsh_def;
|
||||
static struct netlbl_unlhsh_tbl __rcu *netlbl_unlhsh;
|
||||
static struct netlbl_unlhsh_iface __rcu *netlbl_unlhsh_def;
|
||||
|
||||
/* Accept unlabeled packets flag */
|
||||
static u8 netlabel_unlabel_acceptflg;
|
||||
|
@ -1537,6 +1537,7 @@ int __init netlbl_unlabel_defconf(void)
|
|||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry == NULL)
|
||||
return -ENOMEM;
|
||||
entry->family = AF_UNSPEC;
|
||||
entry->def.type = NETLBL_NLTYPE_UNLABELED;
|
||||
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
|
||||
if (ret_val != 0)
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_unlabeled.h"
|
||||
#include "netlabel_cipso_v4.h"
|
||||
#include "netlabel_calipso.h"
|
||||
#include "netlabel_user.h"
|
||||
|
||||
/*
|
||||
|
@ -71,6 +72,10 @@ int __init netlbl_netlink_init(void)
|
|||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
ret_val = netlbl_calipso_genl_init();
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
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,
|
||||
addrp, family, peer_sid, &ad);
|
||||
if (err) {
|
||||
selinux_netlbl_err(skb, err, 0);
|
||||
selinux_netlbl_err(skb, family, err, 0);
|
||||
return err;
|
||||
}
|
||||
err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
|
||||
PEER__RECV, &ad);
|
||||
if (err) {
|
||||
selinux_netlbl_err(skb, err, 0);
|
||||
selinux_netlbl_err(skb, family, err, 0);
|
||||
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,
|
||||
addrp, family, peer_sid, &ad);
|
||||
if (err) {
|
||||
selinux_netlbl_err(skb, err, 1);
|
||||
selinux_netlbl_err(skb, family, err, 1);
|
||||
return NF_DROP;
|
||||
}
|
||||
}
|
||||
|
@ -5064,6 +5064,15 @@ static unsigned int selinux_ipv4_output(void *priv,
|
|||
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,
|
||||
int ifindex,
|
||||
u16 family)
|
||||
|
@ -6298,6 +6307,12 @@ static struct nf_hook_ops selinux_nf_ops[] = {
|
|||
.hooknum = NF_INET_FORWARD,
|
||||
.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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
#ifdef CONFIG_NETLABEL
|
||||
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_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,
|
||||
u16 family,
|
||||
int error,
|
||||
int gateway)
|
||||
{
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
*
|
||||
*/
|
||||
static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct netlbl_lsm_secattr *secattr,
|
||||
u32 *sid)
|
||||
{
|
||||
|
@ -63,7 +64,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
|
|||
if (rc == 0 &&
|
||||
(secattr->flags & NETLBL_SECATTR_CACHEABLE) &&
|
||||
(secattr->flags & NETLBL_SECATTR_CACHE))
|
||||
netlbl_cache_add(skb, secattr);
|
||||
netlbl_cache_add(skb, family, secattr);
|
||||
|
||||
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.
|
||||
*
|
||||
*/
|
||||
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);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
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
|
||||
*sid = SECSID_NULL;
|
||||
*type = secattr.type;
|
||||
|
@ -284,7 +286,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
|
|||
int rc;
|
||||
struct netlbl_lsm_secattr secattr;
|
||||
|
||||
if (family != PF_INET)
|
||||
if (family != PF_INET && family != PF_INET6)
|
||||
return 0;
|
||||
|
||||
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 netlbl_lsm_secattr *secattr;
|
||||
|
||||
if (family != PF_INET)
|
||||
if (family != PF_INET && family != PF_INET6)
|
||||
return 0;
|
||||
|
||||
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);
|
||||
rc = netlbl_skbuff_getattr(skb, family, &secattr);
|
||||
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
|
||||
nlbl_sid = SECINITSID_UNLABELED;
|
||||
netlbl_secattr_destroy(&secattr);
|
||||
|
@ -405,10 +408,25 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
|
|||
return 0;
|
||||
|
||||
if (nlbl_sid != SECINITSID_UNLABELED)
|
||||
netlbl_skbuff_err(skb, rc, 0);
|
||||
netlbl_skbuff_err(skb, family, rc, 0);
|
||||
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
|
||||
* @sock: the socket
|
||||
|
@ -431,7 +449,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
|||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
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_CONNLABELED)) {
|
||||
netlbl_secattr_init(&secattr);
|
||||
|
|
|
@ -1347,7 +1347,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
|
|||
{
|
||||
char *page;
|
||||
ssize_t ret;
|
||||
int new_value;
|
||||
unsigned int new_value;
|
||||
|
||||
ret = task_has_security(current, SECURITY__SETSECPARAM);
|
||||
if (ret)
|
||||
|
|
|
@ -165,7 +165,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
|
|||
e_iter = kzalloc(sizeof(*e_iter), GFP_ATOMIC);
|
||||
if (e_iter == NULL)
|
||||
goto netlbl_import_failure;
|
||||
e_iter->startbit = offset & ~(EBITMAP_SIZE - 1);
|
||||
e_iter->startbit = offset - (offset % EBITMAP_SIZE);
|
||||
if (e_prev == NULL)
|
||||
ebmap->node = e_iter;
|
||||
else
|
||||
|
|
|
@ -543,7 +543,7 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|||
struct av_decision *avd)
|
||||
{
|
||||
struct context lo_scontext;
|
||||
struct context lo_tcontext;
|
||||
struct context lo_tcontext, *tcontextp = tcontext;
|
||||
struct av_decision lo_avd;
|
||||
struct type_datum *source;
|
||||
struct type_datum *target;
|
||||
|
@ -553,67 +553,41 @@ static void type_attribute_bounds_av(struct context *scontext,
|
|||
scontext->type - 1);
|
||||
BUG_ON(!source);
|
||||
|
||||
if (!source->bounds)
|
||||
return;
|
||||
|
||||
target = flex_array_get_ptr(policydb.type_val_to_struct_array,
|
||||
tcontext->type - 1);
|
||||
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));
|
||||
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;
|
||||
}
|
||||
memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
|
||||
lo_scontext.type = source->bounds;
|
||||
|
||||
if (target->bounds) {
|
||||
memset(&lo_avd, 0, sizeof(lo_avd));
|
||||
|
||||
memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
|
||||
lo_tcontext.type = target->bounds;
|
||||
|
||||
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;
|
||||
tcontextp = &lo_tcontext;
|
||||
}
|
||||
|
||||
if (source->bounds && target->bounds) {
|
||||
memset(&lo_avd, 0, sizeof(lo_avd));
|
||||
/*
|
||||
* lo_scontext and lo_tcontext are already
|
||||
* set up.
|
||||
*/
|
||||
context_struct_compute_av(&lo_scontext,
|
||||
tcontextp,
|
||||
tclass,
|
||||
&lo_avd,
|
||||
NULL);
|
||||
|
||||
context_struct_compute_av(&lo_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;
|
||||
}
|
||||
masked = ~lo_avd.allowed & avd->allowed;
|
||||
|
||||
if (masked) {
|
||||
/* mask violated permissions */
|
||||
avd->allowed &= ~masked;
|
||||
if (likely(!masked))
|
||||
return; /* no masked permission */
|
||||
|
||||
/* audit masked permissions */
|
||||
security_dump_masked_av(scontext, tcontext,
|
||||
tclass, masked, "bounds");
|
||||
}
|
||||
/* mask violated permissions */
|
||||
avd->allowed &= ~masked;
|
||||
|
||||
/* 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,
|
||||
MAY_WRITE, rc);
|
||||
if (rc != 0)
|
||||
netlbl_skbuff_err(skb, rc, 0);
|
||||
netlbl_skbuff_err(skb, sk->sk_family, rc, 0);
|
||||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case PF_INET6:
|
||||
|
|
Loading…
Reference in New Issue