⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cipso_ipv4.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		return -EPERM;	ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);	if (ret_val != 0)		return ret_val;	if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {		ret_val = cipso_v4_map_cat_rng_hton(doi_def,						    secattr,						    &buffer[4],						    buffer_len - 4);		if (ret_val < 0)			return ret_val;		tag_len = 4 + ret_val;	} else		tag_len = 4;	buffer[0] = 0x05;	buffer[1] = tag_len;	buffer[3] = level;	return tag_len;}/** * cipso_v4_parsetag_rng - Parse a CIPSO ranged tag * @doi_def: the DOI definition * @tag: the CIPSO tag * @secattr: the security attributes * * Description: * Parse a CIPSO ranged tag (tag type #5) and return the security attributes * in @secattr.  Return zero on success, negatives values on failure. * */static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,				 const unsigned char *tag,				 struct netlbl_lsm_secattr *secattr){	int ret_val;	u8 tag_len = tag[1];	u32 level;	ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);	if (ret_val != 0)		return ret_val;	secattr->mls_lvl = level;	secattr->flags |= NETLBL_SECATTR_MLS_LVL;	if (tag_len > 4) {		secattr->mls_cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC);		if (secattr->mls_cat == NULL)			return -ENOMEM;		ret_val = cipso_v4_map_cat_rng_ntoh(doi_def,						    &tag[4],						    tag_len - 4,						    secattr);		if (ret_val != 0) {			netlbl_secattr_catmap_free(secattr->mls_cat);			return ret_val;		}		secattr->flags |= NETLBL_SECATTR_MLS_CAT;	}	return 0;}/** * cipso_v4_validate - Validate a CIPSO option * @option: the start of the option, on error it is set to point to the error * * Description: * This routine is called to validate a CIPSO option, it checks all of the * fields to ensure that they are at least valid, see the draft snippet below * for details.  If the option is valid then a zero value is returned and * the value of @option is unchanged.  If the option is invalid then a * non-zero value is returned and @option is adjusted to point to the * offending portion of the option.  From the IETF draft ... * *  "If any field within the CIPSO options, such as the DOI identifier, is not *   recognized the IP datagram is discarded and an ICMP 'parameter problem' *   (type 12) is generated and returned.  The ICMP code field is set to 'bad *   parameter' (code 0) and the pointer is set to the start of the CIPSO field *   that is unrecognized." * */int cipso_v4_validate(unsigned char **option){	unsigned char *opt = *option;	unsigned char *tag;	unsigned char opt_iter;	unsigned char err_offset = 0;	u8 opt_len;	u8 tag_len;	struct cipso_v4_doi *doi_def = NULL;	u32 tag_iter;	/* caller already checks for length values that are too large */	opt_len = opt[1];	if (opt_len < 8) {		err_offset = 1;		goto validate_return;	}	rcu_read_lock();	doi_def = cipso_v4_doi_search(ntohl(get_unaligned((__be32 *)&opt[2])));	if (doi_def == NULL) {		err_offset = 2;		goto validate_return_locked;	}	opt_iter = 6;	tag = opt + opt_iter;	while (opt_iter < opt_len) {		for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)			if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||			    ++tag_iter == CIPSO_V4_TAG_MAXCNT) {				err_offset = opt_iter;				goto validate_return_locked;			}		tag_len = tag[1];		if (tag_len > (opt_len - opt_iter)) {			err_offset = opt_iter + 1;			goto validate_return_locked;		}		switch (tag[0]) {		case CIPSO_V4_TAG_RBITMAP:			if (tag_len < 4) {				err_offset = opt_iter + 1;				goto validate_return_locked;			}			/* We are already going to do all the verification			 * necessary at the socket layer so from our point of			 * view it is safe to turn these checks off (and less			 * work), however, the CIPSO draft says we should do			 * all the CIPSO validations here but it doesn't			 * really specify _exactly_ what we need to validate			 * ... so, just make it a sysctl tunable. */			if (cipso_v4_rbm_strictvalid) {				if (cipso_v4_map_lvl_valid(doi_def,							   tag[3]) < 0) {					err_offset = opt_iter + 3;					goto validate_return_locked;				}				if (tag_len > 4 &&				    cipso_v4_map_cat_rbm_valid(doi_def,							    &tag[4],							    tag_len - 4) < 0) {					err_offset = opt_iter + 4;					goto validate_return_locked;				}			}			break;		case CIPSO_V4_TAG_ENUM:			if (tag_len < 4) {				err_offset = opt_iter + 1;				goto validate_return_locked;			}			if (cipso_v4_map_lvl_valid(doi_def,						   tag[3]) < 0) {				err_offset = opt_iter + 3;				goto validate_return_locked;			}			if (tag_len > 4 &&			    cipso_v4_map_cat_enum_valid(doi_def,							&tag[4],							tag_len - 4) < 0) {				err_offset = opt_iter + 4;				goto validate_return_locked;			}			break;		case CIPSO_V4_TAG_RANGE:			if (tag_len < 4) {				err_offset = opt_iter + 1;				goto validate_return_locked;			}			if (cipso_v4_map_lvl_valid(doi_def,						   tag[3]) < 0) {				err_offset = opt_iter + 3;				goto validate_return_locked;			}			if (tag_len > 4 &&			    cipso_v4_map_cat_rng_valid(doi_def,						       &tag[4],						       tag_len - 4) < 0) {				err_offset = opt_iter + 4;				goto validate_return_locked;			}			break;		default:			err_offset = opt_iter;			goto validate_return_locked;		}		tag += tag_len;		opt_iter += tag_len;	}validate_return_locked:	rcu_read_unlock();validate_return:	*option = opt + err_offset;	return err_offset;}/** * cipso_v4_error - Send the correct reponse for a bad packet * @skb: the packet * @error: the error code * @gateway: CIPSO gateway flag * * Description: * Based on the error code given in @error, send an ICMP error message back to * the originating host.  From the IETF draft ... * *  "If the contents of the CIPSO [option] are valid but the security label is *   outside of the configured host or port label range, the datagram is *   discarded and an ICMP 'destination unreachable' (type 3) is generated and *   returned.  The code field of the ICMP is set to 'communication with *   destination network administratively prohibited' (code 9) or to *   'communication with destination host administratively prohibited' *   (code 10).  The value of the code is dependent on whether the originator *   of the ICMP message is acting as a CIPSO host or a CIPSO gateway.  The *   recipient of the ICMP message MUST be able to handle either value.  The *   same procedure is performed if a CIPSO [option] can not be added to an *   IP packet because it is too large to fit in the IP options area." * *  "If the error is triggered by receipt of an ICMP message, the message is *   discarded and no response is permitted (consistent with general ICMP *   processing rules)." * */void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway){	if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES)		return;	if (gateway)		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);	else		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);}/** * cipso_v4_sock_setattr - Add a CIPSO option to a socket * @sk: the socket * @doi_def: the CIPSO DOI to use * @secattr: the specific security attributes of the socket * * Description: * Set the CIPSO 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 cipso_v4_sock_setattr(struct sock *sk,			  const struct cipso_v4_doi *doi_def,			  const struct netlbl_lsm_secattr *secattr){	int ret_val = -EPERM;	u32 iter;	unsigned char *buf;	u32 buf_len = 0;	u32 opt_len;	struct ip_options *opt = NULL;	struct inet_sock *sk_inet;	struct inet_connection_sock *sk_conn;	/* In the case of sock_create_lite(), the sock->sk field is not	 * defined yet but it is not a problem as the only users of these	 * "lite" PF_INET sockets are functions which do an accept() call	 * afterwards so we will label the socket as part of the accept(). */	if (sk == NULL)		return 0;	/* We allocate the maximum CIPSO option size here so we are probably	 * being a little wasteful, but it makes our life _much_ easier later	 * on and after all we are only talking about 40 bytes. */	buf_len = CIPSO_V4_OPT_LEN_MAX;	buf = kmalloc(buf_len, GFP_ATOMIC);	if (buf == NULL) {		ret_val = -ENOMEM;		goto socket_setattr_failure;	}	/* XXX - This code assumes only one tag per CIPSO option which isn't	 * really a good assumption to make but since we only support the MAC	 * tags right now it is a safe assumption. */	iter = 0;	do {		memset(buf, 0, buf_len);		switch (doi_def->tags[iter]) {		case CIPSO_V4_TAG_RBITMAP:			ret_val = cipso_v4_gentag_rbm(doi_def,						   secattr,						   &buf[CIPSO_V4_HDR_LEN],						   buf_len - CIPSO_V4_HDR_LEN);			break;		case CIPSO_V4_TAG_ENUM:			ret_val = cipso_v4_gentag_enum(doi_def,						   secattr,						   &buf[CIPSO_V4_HDR_LEN],						   buf_len - CIPSO_V4_HDR_LEN);			break;		case CIPSO_V4_TAG_RANGE:			ret_val = cipso_v4_gentag_rng(doi_def,						   secattr,						   &buf[CIPSO_V4_HDR_LEN],						   buf_len - CIPSO_V4_HDR_LEN);			break;		default:			ret_val = -EPERM;			goto socket_setattr_failure;		}		iter++;	} while (ret_val < 0 &&		 iter < CIPSO_V4_TAG_MAXCNT &&		 doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);	if (ret_val < 0)		goto socket_setattr_failure;	cipso_v4_gentag_hdr(doi_def, buf, ret_val);	buf_len = CIPSO_V4_HDR_LEN + ret_val;	/* We can't use ip_options_get() directly because it makes a call to	 * ip_options_get_alloc() which allocates memory with GFP_KERNEL and	 * we won't always have CAP_NET_RAW even though we _always_ want to	 * set the IPOPT_CIPSO option. */	opt_len = (buf_len + 3) & ~3;	opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);	if (opt == NULL) {		ret_val = -ENOMEM;		goto socket_setattr_failure;	}	memcpy(opt->__data, buf, buf_len);	opt->optlen = opt_len;	opt->is_data = 1;	opt->cipso = sizeof(struct iphdr);	kfree(buf);	buf = NULL;	sk_inet = inet_sk(sk);	if (sk_inet->is_icsk) {		sk_conn = inet_csk(sk);		if (sk_inet->opt)			sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;		sk_conn->icsk_ext_hdr_len += opt->optlen;		sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);	}	opt = xchg(&sk_inet->opt, opt);	kfree(opt);	return 0;socket_setattr_failure:	kfree(buf);	kfree(opt);	return ret_val;}/** * cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions * @cipso: the CIPSO v4 option * @secattr: the security attributes * * Description: * Inspect @cipso and return the security attributes in @secattr.  Returns zero * on success and negative values on failure. * */static int cipso_v4_getattr(const unsigned char *cipso,			    struct netlbl_lsm_secattr *secattr){	int ret_val = -ENOMSG;	u32 doi;	struct cipso_v4_doi *doi_def;	if (cipso_v4_cache_check(cipso, cipso[1], secattr) == 0)		return 0;	doi = ntohl(get_unaligned((__be32 *)&cipso[2]));	rcu_read_lock();	doi_def = cipso_v4_doi_search(doi);	if (doi_def == NULL)		goto getattr_return;	/* XXX - This code assumes only one tag per CIPSO option which isn't	 * really a good assumption to make but since we only support the MAC	 * tags right now it is a safe assumption. */	switch (cipso[6]) {	case CIPSO_V4_TAG_RBITMAP:		ret_val = cipso_v4_parsetag_rbm(doi_def, &cipso[6], secattr);		break;	case CIPSO_V4_TAG_ENUM:		ret_val = cipso_v4_parsetag_enum(doi_def, &cipso[6], secattr);		break;	case CIPSO_V4_TAG_RANGE:		ret_val = cipso_v4_parsetag_rng(doi_def, &cipso[6], secattr);		break;	}getattr_return:	rcu_read_unlock();	return ret_val;}/** * cipso_v4_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 CIPSO option attached to the sock and if * there is return the CIPSO 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 cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr){	struct ip_options *opt;	opt = inet_sk(sk)->opt;	if (opt == NULL || opt->cipso == 0)		return -ENOMSG;	return cipso_v4_getattr(opt->__data + opt->cipso - sizeof(struct iphdr),				secattr);}/** * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option * @skb: the packet * @secattr: the security attributes * * Description: * Parse the given packet's CIPSO option and return the security attributes. * Returns zero on success and negative values on failure. * */int cipso_v4_skbuff_getattr(const struct sk_buff *skb,			    struct netlbl_lsm_secattr *secattr){	return cipso_v4_getattr(CIPSO_V4_OPTPTR(skb), secattr);}/* * Setup Functions *//** * cipso_v4_init - Initialize the CIPSO module * * Description: * Initialize the CIPSO module and prepare it for use.  Returns zero on success * and negative values on failure. * */static int __init cipso_v4_init(void){	int ret_val;	ret_val = cipso_v4_cache_init();	if (ret_val != 0)		panic("Failed to initialize the CIPSO/IPv4 cache (%d)\n",		      ret_val);	return 0;}subsys_initcall(cipso_v4_init);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -