linux/include/net/cipso_ipv4.h

309 lines
7.4 KiB
C
Raw Normal View History

treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 13 Based on 2 normalized pattern(s): 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 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 [based] [from] [clk] [highbank] [c] you should have received a copy of the gnu general public license along with this program if not see http www gnu org licenses extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 355 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Reviewed-by: Jilayne Lovejoy <opensource@jilayne.com> Reviewed-by: Steve Winslow <swinslow@gmail.com> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190519154041.837383322@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-05-19 13:51:43 +00:00
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CIPSO - Commercial IP Security Option
*
* This is an implementation of the CIPSO 2.2 protocol as specified in
* draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
* FIPS-188, copies of both documents can be found in the Documentation
* directory. While CIPSO never became a full IETF RFC standard many vendors
* have chosen to adopt the protocol and over the years it has become a
* de-facto standard for labeled networking.
*
* Author: Paul Moore <paul@paul-moore.com>
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
*/
#ifndef _CIPSO_IPV4_H
#define _CIPSO_IPV4_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>
netlabel: Label incoming TCP connections correctly in SELinux The current NetLabel/SELinux behavior for incoming TCP connections works but only through a series of happy coincidences that rely on the limited nature of standard CIPSO (only able to convey MLS attributes) and the write equality imposed by the SELinux MLS constraints. The problem is that network sockets created as the result of an incoming TCP connection were not on-the-wire labeled based on the security attributes of the parent socket but rather based on the wire label of the remote peer. The issue had to do with how IP options were managed as part of the network stack and where the LSM hooks were in relation to the code which set the IP options on these newly created child sockets. While NetLabel/SELinux did correctly set the socket's on-the-wire label it was promptly cleared by the network stack and reset based on the IP options of the remote peer. This patch, in conjunction with a prior patch that adjusted the LSM hook locations, works to set the correct on-the-wire label format for new incoming connections through the security_inet_conn_request() hook. Besides the correct behavior there are many advantages to this change, the most significant is that all of the NetLabel socket labeling code in SELinux now lives in hooks which can return error codes to the core stack which allows us to finally get ride of the selinux_netlbl_inode_permission() logic which greatly simplfies the NetLabel/SELinux glue code. In the process of developing this patch I also ran into a small handful of AF_INET6 cleanliness issues that have been fixed which should make the code safer and easier to extend in the future. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
2009-03-27 21:10:34 +00:00
#include <net/request_sock.h>
#include <linux/atomic.h>
#include <linux/refcount.h>
#include <asm/unaligned.h>
/* known doi values */
#define CIPSO_V4_DOI_UNKNOWN 0x00000000
/* standard tag types */
#define CIPSO_V4_TAG_INVALID 0
#define CIPSO_V4_TAG_RBITMAP 1
#define CIPSO_V4_TAG_ENUM 2
#define CIPSO_V4_TAG_RANGE 5
#define CIPSO_V4_TAG_PBITMAP 6
#define CIPSO_V4_TAG_FREEFORM 7
/* non-standard tag types (tags > 127) */
#define CIPSO_V4_TAG_LOCAL 128
/* doi mapping types */
#define CIPSO_V4_MAP_UNKNOWN 0
#define CIPSO_V4_MAP_TRANS 1
#define CIPSO_V4_MAP_PASS 2
#define CIPSO_V4_MAP_LOCAL 3
/* limits */
#define CIPSO_V4_MAX_REM_LVLS 255
#define CIPSO_V4_INV_LVL 0x80000000
#define CIPSO_V4_MAX_LOC_LVLS (CIPSO_V4_INV_LVL - 1)
#define CIPSO_V4_MAX_REM_CATS 65534
#define CIPSO_V4_INV_CAT 0x80000000
#define CIPSO_V4_MAX_LOC_CATS (CIPSO_V4_INV_CAT - 1)
/*
* CIPSO DOI definitions
*/
/* DOI definition struct */
#define CIPSO_V4_TAG_MAXCNT 5
struct cipso_v4_doi {
u32 doi;
u32 type;
union {
struct cipso_v4_std_map_tbl *std;
} map;
u8 tags[CIPSO_V4_TAG_MAXCNT];
refcount_t refcount;
struct list_head list;
struct rcu_head rcu;
};
/* Standard CIPSO mapping table */
/* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the
* bit is set then consider that value as unspecified, meaning the
* mapping for that particular level/category is invalid */
struct cipso_v4_std_map_tbl {
struct {
u32 *cipso;
u32 *local;
u32 cipso_size;
u32 local_size;
} lvl;
struct {
u32 *cipso;
u32 *local;
u32 cipso_size;
u32 local_size;
} cat;
};
/*
* Sysctl Variables
*/
#ifdef CONFIG_NETLABEL
extern int cipso_v4_cache_enabled;
extern int cipso_v4_cache_bucketsize;
extern int cipso_v4_rbm_optfmt;
extern int cipso_v4_rbm_strictvalid;
#endif
/*
* DOI List Functions
*/
#ifdef CONFIG_NETLABEL
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
struct netlbl_audit *audit_info);
void cipso_v4_doi_free(struct cipso_v4_doi *doi_def);
int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info);
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def);
int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
void *cb_arg);
#else
static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def,
struct netlbl_audit *audit_info)
{
return -ENOSYS;
}
static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def)
{
return;
}
static inline int cipso_v4_doi_remove(u32 doi,
struct netlbl_audit *audit_info)
{
return 0;
}
static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
{
return NULL;
}
static inline int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
void *cb_arg)
{
return 0;
}
#endif /* CONFIG_NETLABEL */
/*
* Label Mapping Cache Functions
*/
#ifdef CONFIG_NETLABEL
void cipso_v4_cache_invalidate(void);
int cipso_v4_cache_add(const unsigned char *cipso_ptr,
const struct netlbl_lsm_secattr *secattr);
#else
static inline void cipso_v4_cache_invalidate(void)
{
return;
}
static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr,
const struct netlbl_lsm_secattr *secattr)
{
return 0;
}
#endif /* CONFIG_NETLABEL */
/*
* Protocol Handling Functions
*/
#ifdef CONFIG_NETLABEL
void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
int cipso_v4_getattr(const unsigned char *cipso,
struct netlbl_lsm_secattr *secattr);
int cipso_v4_sock_setattr(struct sock *sk,
const struct cipso_v4_doi *doi_def,
netlabel: fix RCU annotation for IPv4 options on socket creation Xiumei reports the following splat when netlabel and TCP socket are used: ============================= WARNING: suspicious RCU usage 6.9.0-rc2+ #637 Not tainted ----------------------------- net/ipv4/cipso_ipv4.c:1880 suspicious rcu_dereference_protected() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 1 lock held by ncat/23333: #0: ffffffff906030c0 (rcu_read_lock){....}-{1:2}, at: netlbl_sock_setattr+0x25/0x1b0 stack backtrace: CPU: 11 PID: 23333 Comm: ncat Kdump: loaded Not tainted 6.9.0-rc2+ #637 Hardware name: Supermicro SYS-6027R-72RF/X9DRH-7TF/7F/iTF/iF, BIOS 3.0 07/26/2013 Call Trace: <TASK> dump_stack_lvl+0xa9/0xc0 lockdep_rcu_suspicious+0x117/0x190 cipso_v4_sock_setattr+0x1ab/0x1b0 netlbl_sock_setattr+0x13e/0x1b0 selinux_netlbl_socket_post_create+0x3f/0x80 selinux_socket_post_create+0x1a0/0x460 security_socket_post_create+0x42/0x60 __sock_create+0x342/0x3a0 __sys_socket_create.part.22+0x42/0x70 __sys_socket+0x37/0xb0 __x64_sys_socket+0x16/0x20 do_syscall_64+0x96/0x180 ? do_user_addr_fault+0x68d/0xa30 ? exc_page_fault+0x171/0x280 ? asm_exc_page_fault+0x22/0x30 entry_SYSCALL_64_after_hwframe+0x71/0x79 RIP: 0033:0x7fbc0ca3fc1b Code: 73 01 c3 48 8b 0d 05 f2 1b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa b8 29 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d5 f1 1b 00 f7 d8 64 89 01 48 RSP: 002b:00007fff18635208 EFLAGS: 00000246 ORIG_RAX: 0000000000000029 RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007fbc0ca3fc1b RDX: 0000000000000006 RSI: 0000000000000001 RDI: 0000000000000002 RBP: 000055d24f80f8a0 R08: 0000000000000003 R09: 0000000000000001 R10: 0000000000020000 R11: 0000000000000246 R12: 000055d24f80f8a0 R13: 0000000000000000 R14: 000055d24f80fb88 R15: 0000000000000000 </TASK> The current implementation of cipso_v4_sock_setattr() replaces IP options under the assumption that the caller holds the socket lock; however, such assumption is not true, nor needed, in selinux_socket_post_create() hook. Let all callers of cipso_v4_sock_setattr() specify the "socket lock held" condition, except selinux_socket_post_create() _ where such condition can safely be set as true even without holding the socket lock. Fixes: f6d8bd051c39 ("inet: add RCU protection to inet->opt") Reported-by: Xiumei Mu <xmu@redhat.com> Signed-off-by: Davide Caratti <dcaratti@redhat.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Acked-by: Paul Moore <paul@paul-moore.com> Link: https://lore.kernel.org/r/f4260d000a3a55b9e8b6a3b4e3fffc7da9f82d41.1715359817.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 17:19:12 +00:00
const struct netlbl_lsm_secattr *secattr,
bool sk_locked);
void cipso_v4_sock_delattr(struct sock *sk);
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
netlabel: Label incoming TCP connections correctly in SELinux The current NetLabel/SELinux behavior for incoming TCP connections works but only through a series of happy coincidences that rely on the limited nature of standard CIPSO (only able to convey MLS attributes) and the write equality imposed by the SELinux MLS constraints. The problem is that network sockets created as the result of an incoming TCP connection were not on-the-wire labeled based on the security attributes of the parent socket but rather based on the wire label of the remote peer. The issue had to do with how IP options were managed as part of the network stack and where the LSM hooks were in relation to the code which set the IP options on these newly created child sockets. While NetLabel/SELinux did correctly set the socket's on-the-wire label it was promptly cleared by the network stack and reset based on the IP options of the remote peer. This patch, in conjunction with a prior patch that adjusted the LSM hook locations, works to set the correct on-the-wire label format for new incoming connections through the security_inet_conn_request() hook. Besides the correct behavior there are many advantages to this change, the most significant is that all of the NetLabel socket labeling code in SELinux now lives in hooks which can return error codes to the core stack which allows us to finally get ride of the selinux_netlbl_inode_permission() logic which greatly simplfies the NetLabel/SELinux glue code. In the process of developing this patch I also ran into a small handful of AF_INET6 cleanliness issues that have been fixed which should make the code safer and easier to extend in the future. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
2009-03-27 21:10:34 +00:00
int cipso_v4_req_setattr(struct request_sock *req,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
void cipso_v4_req_delattr(struct request_sock *req);
int cipso_v4_skbuff_setattr(struct sk_buff *skb,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
int cipso_v4_skbuff_delattr(struct sk_buff *skb);
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr);
unsigned char *cipso_v4_optptr(const struct sk_buff *skb);
int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option);
#else
static inline void cipso_v4_error(struct sk_buff *skb,
int error,
u32 gateway)
{
return;
}
static inline int cipso_v4_getattr(const unsigned char *cipso,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int cipso_v4_sock_setattr(struct sock *sk,
const struct cipso_v4_doi *doi_def,
netlabel: fix RCU annotation for IPv4 options on socket creation Xiumei reports the following splat when netlabel and TCP socket are used: ============================= WARNING: suspicious RCU usage 6.9.0-rc2+ #637 Not tainted ----------------------------- net/ipv4/cipso_ipv4.c:1880 suspicious rcu_dereference_protected() usage! other info that might help us debug this: rcu_scheduler_active = 2, debug_locks = 1 1 lock held by ncat/23333: #0: ffffffff906030c0 (rcu_read_lock){....}-{1:2}, at: netlbl_sock_setattr+0x25/0x1b0 stack backtrace: CPU: 11 PID: 23333 Comm: ncat Kdump: loaded Not tainted 6.9.0-rc2+ #637 Hardware name: Supermicro SYS-6027R-72RF/X9DRH-7TF/7F/iTF/iF, BIOS 3.0 07/26/2013 Call Trace: <TASK> dump_stack_lvl+0xa9/0xc0 lockdep_rcu_suspicious+0x117/0x190 cipso_v4_sock_setattr+0x1ab/0x1b0 netlbl_sock_setattr+0x13e/0x1b0 selinux_netlbl_socket_post_create+0x3f/0x80 selinux_socket_post_create+0x1a0/0x460 security_socket_post_create+0x42/0x60 __sock_create+0x342/0x3a0 __sys_socket_create.part.22+0x42/0x70 __sys_socket+0x37/0xb0 __x64_sys_socket+0x16/0x20 do_syscall_64+0x96/0x180 ? do_user_addr_fault+0x68d/0xa30 ? exc_page_fault+0x171/0x280 ? asm_exc_page_fault+0x22/0x30 entry_SYSCALL_64_after_hwframe+0x71/0x79 RIP: 0033:0x7fbc0ca3fc1b Code: 73 01 c3 48 8b 0d 05 f2 1b 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa b8 29 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d d5 f1 1b 00 f7 d8 64 89 01 48 RSP: 002b:00007fff18635208 EFLAGS: 00000246 ORIG_RAX: 0000000000000029 RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007fbc0ca3fc1b RDX: 0000000000000006 RSI: 0000000000000001 RDI: 0000000000000002 RBP: 000055d24f80f8a0 R08: 0000000000000003 R09: 0000000000000001 R10: 0000000000020000 R11: 0000000000000246 R12: 000055d24f80f8a0 R13: 0000000000000000 R14: 000055d24f80fb88 R15: 0000000000000000 </TASK> The current implementation of cipso_v4_sock_setattr() replaces IP options under the assumption that the caller holds the socket lock; however, such assumption is not true, nor needed, in selinux_socket_post_create() hook. Let all callers of cipso_v4_sock_setattr() specify the "socket lock held" condition, except selinux_socket_post_create() _ where such condition can safely be set as true even without holding the socket lock. Fixes: f6d8bd051c39 ("inet: add RCU protection to inet->opt") Reported-by: Xiumei Mu <xmu@redhat.com> Signed-off-by: Davide Caratti <dcaratti@redhat.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Acked-by: Paul Moore <paul@paul-moore.com> Link: https://lore.kernel.org/r/f4260d000a3a55b9e8b6a3b4e3fffc7da9f82d41.1715359817.git.dcaratti@redhat.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2024-05-10 17:19:12 +00:00
const struct netlbl_lsm_secattr *secattr,
bool sk_locked)
{
return -ENOSYS;
}
static inline void cipso_v4_sock_delattr(struct sock *sk)
{
}
static inline int cipso_v4_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
netlabel: Label incoming TCP connections correctly in SELinux The current NetLabel/SELinux behavior for incoming TCP connections works but only through a series of happy coincidences that rely on the limited nature of standard CIPSO (only able to convey MLS attributes) and the write equality imposed by the SELinux MLS constraints. The problem is that network sockets created as the result of an incoming TCP connection were not on-the-wire labeled based on the security attributes of the parent socket but rather based on the wire label of the remote peer. The issue had to do with how IP options were managed as part of the network stack and where the LSM hooks were in relation to the code which set the IP options on these newly created child sockets. While NetLabel/SELinux did correctly set the socket's on-the-wire label it was promptly cleared by the network stack and reset based on the IP options of the remote peer. This patch, in conjunction with a prior patch that adjusted the LSM hook locations, works to set the correct on-the-wire label format for new incoming connections through the security_inet_conn_request() hook. Besides the correct behavior there are many advantages to this change, the most significant is that all of the NetLabel socket labeling code in SELinux now lives in hooks which can return error codes to the core stack which allows us to finally get ride of the selinux_netlbl_inode_permission() logic which greatly simplfies the NetLabel/SELinux glue code. In the process of developing this patch I also ran into a small handful of AF_INET6 cleanliness issues that have been fixed which should make the code safer and easier to extend in the future. Signed-off-by: Paul Moore <paul.moore@hp.com> Acked-by: Casey Schaufler <casey@schaufler-ca.com> Signed-off-by: James Morris <jmorris@namei.org>
2009-03-27 21:10:34 +00:00
static inline int cipso_v4_req_setattr(struct request_sock *req,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline void cipso_v4_req_delattr(struct request_sock *req)
{
return;
}
static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb)
{
return -ENOSYS;
}
static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb)
{
return NULL;
}
static inline int cipso_v4_validate(const struct sk_buff *skb,
unsigned char **option)
{
unsigned char *opt = *option;
unsigned char err_offset = 0;
u8 opt_len = opt[1];
u8 opt_iter;
u8 tag_len;
if (opt_len < 8) {
err_offset = 1;
goto out;
}
if (get_unaligned_be32(&opt[2]) == 0) {
err_offset = 2;
goto out;
}
for (opt_iter = 6; opt_iter < opt_len;) {
if (opt_iter + 1 == opt_len) {
err_offset = opt_iter;
goto out;
}
tag_len = opt[opt_iter + 1];
if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) {
err_offset = opt_iter + 1;
goto out;
}
opt_iter += tag_len;
}
out:
*option = opt + err_offset;
return err_offset;
}
#endif /* CONFIG_NETLABEL */
#endif /* _CIPSO_IPV4_H */