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

📄 xfrm_policy.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	ret = NULL;	hlist_for_each_entry(pol, entry, chain, bydst) {		if (pol->type == type &&		    !selector_cmp(sel, &pol->selector) &&		    xfrm_sec_ctx_match(ctx, pol->security)) {			xfrm_pol_hold(pol);			if (delete) {				*err = security_xfrm_policy_delete(pol);				if (*err) {					write_unlock_bh(&xfrm_policy_lock);					return pol;				}				hlist_del(&pol->bydst);				hlist_del(&pol->byidx);				xfrm_policy_count[dir]--;			}			ret = pol;			break;		}	}	write_unlock_bh(&xfrm_policy_lock);	if (ret && delete) {		atomic_inc(&flow_cache_genid);		xfrm_policy_kill(ret);	}	return ret;}EXPORT_SYMBOL(xfrm_policy_bysel_ctx);struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,				     int *err){	struct xfrm_policy *pol, *ret;	struct hlist_head *chain;	struct hlist_node *entry;	*err = -ENOENT;	if (xfrm_policy_id2dir(id) != dir)		return NULL;	*err = 0;	write_lock_bh(&xfrm_policy_lock);	chain = xfrm_policy_byidx + idx_hash(id);	ret = NULL;	hlist_for_each_entry(pol, entry, chain, byidx) {		if (pol->type == type && pol->index == id) {			xfrm_pol_hold(pol);			if (delete) {				*err = security_xfrm_policy_delete(pol);				if (*err) {					write_unlock_bh(&xfrm_policy_lock);					return pol;				}				hlist_del(&pol->bydst);				hlist_del(&pol->byidx);				xfrm_policy_count[dir]--;			}			ret = pol;			break;		}	}	write_unlock_bh(&xfrm_policy_lock);	if (ret && delete) {		atomic_inc(&flow_cache_genid);		xfrm_policy_kill(ret);	}	return ret;}EXPORT_SYMBOL(xfrm_policy_byid);#ifdef CONFIG_SECURITY_NETWORK_XFRMstatic inline intxfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info){	int dir, err = 0;	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {		struct xfrm_policy *pol;		struct hlist_node *entry;		int i;		hlist_for_each_entry(pol, entry,				     &xfrm_policy_inexact[dir], bydst) {			if (pol->type != type)				continue;			err = security_xfrm_policy_delete(pol);			if (err) {				xfrm_audit_policy_delete(pol, 0,							 audit_info->loginuid,							 audit_info->secid);				return err;			}		}		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {			hlist_for_each_entry(pol, entry,					     xfrm_policy_bydst[dir].table + i,					     bydst) {				if (pol->type != type)					continue;				err = security_xfrm_policy_delete(pol);				if (err) {					xfrm_audit_policy_delete(pol, 0,							audit_info->loginuid,							audit_info->secid);					return err;				}			}		}	}	return err;}#elsestatic inline intxfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info){	return 0;}#endifint xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info){	int dir, err = 0;	write_lock_bh(&xfrm_policy_lock);	err = xfrm_policy_flush_secctx_check(type, audit_info);	if (err)		goto out;	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {		struct xfrm_policy *pol;		struct hlist_node *entry;		int i, killed;		killed = 0;	again1:		hlist_for_each_entry(pol, entry,				     &xfrm_policy_inexact[dir], bydst) {			if (pol->type != type)				continue;			hlist_del(&pol->bydst);			hlist_del(&pol->byidx);			write_unlock_bh(&xfrm_policy_lock);			xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,						 audit_info->secid);			xfrm_policy_kill(pol);			killed++;			write_lock_bh(&xfrm_policy_lock);			goto again1;		}		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {	again2:			hlist_for_each_entry(pol, entry,					     xfrm_policy_bydst[dir].table + i,					     bydst) {				if (pol->type != type)					continue;				hlist_del(&pol->bydst);				hlist_del(&pol->byidx);				write_unlock_bh(&xfrm_policy_lock);				xfrm_audit_policy_delete(pol, 1,							 audit_info->loginuid,							 audit_info->secid);				xfrm_policy_kill(pol);				killed++;				write_lock_bh(&xfrm_policy_lock);				goto again2;			}		}		xfrm_policy_count[dir] -= killed;	}	atomic_inc(&flow_cache_genid);out:	write_unlock_bh(&xfrm_policy_lock);	return err;}EXPORT_SYMBOL(xfrm_policy_flush);int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*),		     void *data){	struct xfrm_policy *pol, *last = NULL;	struct hlist_node *entry;	int dir, last_dir = 0, count, error;	read_lock_bh(&xfrm_policy_lock);	count = 0;	for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) {		struct hlist_head *table = xfrm_policy_bydst[dir].table;		int i;		hlist_for_each_entry(pol, entry,				     &xfrm_policy_inexact[dir], bydst) {			if (pol->type != type)				continue;			if (last) {				error = func(last, last_dir % XFRM_POLICY_MAX,					     count, data);				if (error)					goto out;			}			last = pol;			last_dir = dir;			count++;		}		for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) {			hlist_for_each_entry(pol, entry, table + i, bydst) {				if (pol->type != type)					continue;				if (last) {					error = func(last, last_dir % XFRM_POLICY_MAX,						     count, data);					if (error)						goto out;				}				last = pol;				last_dir = dir;				count++;			}		}	}	if (count == 0) {		error = -ENOENT;		goto out;	}	error = func(last, last_dir % XFRM_POLICY_MAX, 0, data);out:	read_unlock_bh(&xfrm_policy_lock);	return error;}EXPORT_SYMBOL(xfrm_policy_walk);/* * Find policy to apply to this flow. * * Returns 0 if policy found, else an -errno. */static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,			     u8 type, u16 family, int dir){	struct xfrm_selector *sel = &pol->selector;	int match, ret = -ESRCH;	if (pol->family != family ||	    pol->type != type)		return ret;	match = xfrm_selector_match(sel, fl, family);	if (match)		ret = security_xfrm_policy_lookup(pol, fl->secid, dir);	return ret;}static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,						     u16 family, u8 dir){	int err;	struct xfrm_policy *pol, *ret;	xfrm_address_t *daddr, *saddr;	struct hlist_node *entry;	struct hlist_head *chain;	u32 priority = ~0U;	daddr = xfrm_flowi_daddr(fl, family);	saddr = xfrm_flowi_saddr(fl, family);	if (unlikely(!daddr || !saddr))		return NULL;	read_lock_bh(&xfrm_policy_lock);	chain = policy_hash_direct(daddr, saddr, family, dir);	ret = NULL;	hlist_for_each_entry(pol, entry, chain, bydst) {		err = xfrm_policy_match(pol, fl, type, family, dir);		if (err) {			if (err == -ESRCH)				continue;			else {				ret = ERR_PTR(err);				goto fail;			}		} else {			ret = pol;			priority = ret->priority;			break;		}	}	chain = &xfrm_policy_inexact[dir];	hlist_for_each_entry(pol, entry, chain, bydst) {		err = xfrm_policy_match(pol, fl, type, family, dir);		if (err) {			if (err == -ESRCH)				continue;			else {				ret = ERR_PTR(err);				goto fail;			}		} else if (pol->priority < priority) {			ret = pol;			break;		}	}	if (ret)		xfrm_pol_hold(ret);fail:	read_unlock_bh(&xfrm_policy_lock);	return ret;}static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,			       void **objp, atomic_t **obj_refp){	struct xfrm_policy *pol;	int err = 0;#ifdef CONFIG_XFRM_SUB_POLICY	pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir);	if (IS_ERR(pol)) {		err = PTR_ERR(pol);		pol = NULL;	}	if (pol || err)		goto end;#endif	pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir);	if (IS_ERR(pol)) {		err = PTR_ERR(pol);		pol = NULL;	}#ifdef CONFIG_XFRM_SUB_POLICYend:#endif	if ((*objp = (void *) pol) != NULL)		*obj_refp = &pol->refcnt;	return err;}static inline int policy_to_flow_dir(int dir){	if (XFRM_POLICY_IN == FLOW_DIR_IN &&	    XFRM_POLICY_OUT == FLOW_DIR_OUT &&	    XFRM_POLICY_FWD == FLOW_DIR_FWD)		return dir;	switch (dir) {	default:	case XFRM_POLICY_IN:		return FLOW_DIR_IN;	case XFRM_POLICY_OUT:		return FLOW_DIR_OUT;	case XFRM_POLICY_FWD:		return FLOW_DIR_FWD;	}}static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl){	struct xfrm_policy *pol;	read_lock_bh(&xfrm_policy_lock);	if ((pol = sk->sk_policy[dir]) != NULL) {		int match = xfrm_selector_match(&pol->selector, fl,						sk->sk_family);		int err = 0;		if (match) {			err = security_xfrm_policy_lookup(pol, fl->secid,					policy_to_flow_dir(dir));			if (!err)				xfrm_pol_hold(pol);			else if (err == -ESRCH)				pol = NULL;			else				pol = ERR_PTR(err);		} else			pol = NULL;	}	read_unlock_bh(&xfrm_policy_lock);	return pol;}static void __xfrm_policy_link(struct xfrm_policy *pol, int dir){	struct hlist_head *chain = policy_hash_bysel(&pol->selector,						     pol->family, dir);	hlist_add_head(&pol->bydst, chain);	hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index));	xfrm_policy_count[dir]++;	xfrm_pol_hold(pol);	if (xfrm_bydst_should_resize(dir, NULL))		schedule_work(&xfrm_hash_work);}static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,						int dir){	if (hlist_unhashed(&pol->bydst))		return NULL;	hlist_del(&pol->bydst);	hlist_del(&pol->byidx);	xfrm_policy_count[dir]--;	return pol;}int xfrm_policy_delete(struct xfrm_policy *pol, int dir){	write_lock_bh(&xfrm_policy_lock);	pol = __xfrm_policy_unlink(pol, dir);	write_unlock_bh(&xfrm_policy_lock);	if (pol) {		if (dir < XFRM_POLICY_MAX)			atomic_inc(&flow_cache_genid);		xfrm_policy_kill(pol);		return 0;	}	return -ENOENT;}EXPORT_SYMBOL(xfrm_policy_delete);int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol){	struct xfrm_policy *old_pol;#ifdef CONFIG_XFRM_SUB_POLICY	if (pol && pol->type != XFRM_POLICY_TYPE_MAIN)		return -EINVAL;#endif	write_lock_bh(&xfrm_policy_lock);	old_pol = sk->sk_policy[dir];	sk->sk_policy[dir] = pol;	if (pol) {		pol->curlft.add_time = get_seconds();		pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir);		__xfrm_policy_link(pol, XFRM_POLICY_MAX+dir);	}	if (old_pol)		__xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir);	write_unlock_bh(&xfrm_policy_lock);	if (old_pol) {		xfrm_policy_kill(old_pol);	}	return 0;}static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir){	struct xfrm_policy *newp = xfrm_policy_alloc(GFP_ATOMIC);	if (newp) {		newp->selector = old->selector;		if (security_xfrm_policy_clone(old, newp)) {			kfree(newp);			return NULL;  /* ENOMEM */		}		newp->lft = old->lft;		newp->curlft = old->curlft;		newp->action = old->action;		newp->flags = old->flags;		newp->xfrm_nr = old->xfrm_nr;		newp->index = old->index;		newp->type = old->type;		memcpy(newp->xfrm_vec, old->xfrm_vec,		       newp->xfrm_nr*sizeof(struct xfrm_tmpl));		write_lock_bh(&xfrm_policy_lock);		__xfrm_policy_link(newp, XFRM_POLICY_MAX+dir);		write_unlock_bh(&xfrm_policy_lock);		xfrm_pol_put(newp);	}	return newp;}int __xfrm_sk_clone_policy(struct sock *sk){	struct xfrm_policy *p0 = sk->sk_policy[0],			   *p1 = sk->sk_policy[1];	sk->sk_policy[0] = sk->sk_policy[1] = NULL;	if (p0 && (sk->sk_policy[0] = clone_policy(p0, 0)) == NULL)		return -ENOMEM;	if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL)		return -ENOMEM;	return 0;}static intxfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote,	       unsigned short family){	int err;	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);	if (unlikely(afinfo == NULL))		return -EINVAL;	err = afinfo->get_saddr(local, remote);	xfrm_policy_put_afinfo(afinfo);	return err;}/* Resolve list of templates for the flow, given policy. */static intxfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl,		      struct xfrm_state **xfrm,		      unsigned short family){	int nx;	int i, error;	xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family);	xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family);	xfrm_address_t tmp;	for (nx=0, i = 0; i < policy->xfrm_nr; i++) {		struct xfrm_state *x;		xfrm_address_t *remote = daddr;		xfrm_address_t *local  = saddr;		struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];		if (tmpl->mode == XFRM_MODE_TUNNEL ||		    tmpl->mode == XFRM_MODE_BEET) {			remote = &tmpl->id.daddr;			local = &tmpl->saddr;			family = tmpl->encap_family;			if (xfrm_addr_any(local, family)) {				error = xfrm_get_saddr(&tmp, remote, family);				if (error)					goto fail;				local = &tmp;			}		}		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);		if (x && x->km.state == XFRM_STATE_VALID) {			xfrm[nx++] = x;			daddr = remote;			saddr = local;			continue;		}		if (x) {			error = (x->km.state == XFRM_STATE_ERROR ?				 -EINVAL : -EAGAIN);			xfrm_state_put(x);		}		if (!tmpl->optional)			goto fail;	}	return nx;fail:	for (nx--; nx>=0; nx--)		xfrm_state_put(xfrm[nx]);	return error;}static intxfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, struct flowi *fl,		  struct xfrm_state **xfrm,		  unsigned short family){	struct xfrm_state *tp[XFRM_MAX_DEPTH];	struct xfrm_state **tpp = (npols > 1) ? tp : xfrm;	int cnx = 0;	int error;	int ret;	int i;	for (i = 0; i < npols; i++) {		if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) {			error = -ENOBUFS;			goto fail;		}		ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family);		if (ret < 0) {			error = ret;			goto fail;		} else			cnx += ret;	}	/* found states are sorted for outbound processing */	if (npols > 1)		xfrm_state_sort(xfrm, tpp, cnx, family);	return cnx; fail:	for (cnx--; cnx>=0; cnx--)		xfrm_state_put(tpp[cnx]);

⌨️ 快捷键说明

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