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

📄 xfrm_user.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	       + nla_total_size(sizeof(struct xfrmu_spdhinfo));}static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags){	struct xfrmk_spdinfo si;	struct xfrmu_spdinfo spc;	struct xfrmu_spdhinfo sph;	struct nlmsghdr *nlh;	u32 *f;	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0);	if (nlh == NULL) /* shouldnt really happen ... */		return -EMSGSIZE;	f = nlmsg_data(nlh);	*f = flags;	xfrm_spd_getinfo(&si);	spc.incnt = si.incnt;	spc.outcnt = si.outcnt;	spc.fwdcnt = si.fwdcnt;	spc.inscnt = si.inscnt;	spc.outscnt = si.outscnt;	spc.fwdscnt = si.fwdscnt;	sph.spdhcnt = si.spdhcnt;	sph.spdhmcnt = si.spdhmcnt;	NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc);	NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph);	return nlmsg_end(skb, nlh);nla_put_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh,		struct nlattr **attrs){	struct sk_buff *r_skb;	u32 *flags = nlmsg_data(nlh);	u32 spid = NETLINK_CB(skb).pid;	u32 seq = nlh->nlmsg_seq;	r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC);	if (r_skb == NULL)		return -ENOMEM;	if (build_spdinfo(r_skb, spid, seq, *flags) < 0)		BUG();	return nlmsg_unicast(xfrm_nl, r_skb, spid);}static inline size_t xfrm_sadinfo_msgsize(void){	return NLMSG_ALIGN(4)	       + nla_total_size(sizeof(struct xfrmu_sadhinfo))	       + nla_total_size(4); /* XFRMA_SAD_CNT */}static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags){	struct xfrmk_sadinfo si;	struct xfrmu_sadhinfo sh;	struct nlmsghdr *nlh;	u32 *f;	nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0);	if (nlh == NULL) /* shouldnt really happen ... */		return -EMSGSIZE;	f = nlmsg_data(nlh);	*f = flags;	xfrm_sad_getinfo(&si);	sh.sadhmcnt = si.sadhmcnt;	sh.sadhcnt = si.sadhcnt;	NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt);	NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh);	return nlmsg_end(skb, nlh);nla_put_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh,		struct nlattr **attrs){	struct sk_buff *r_skb;	u32 *flags = nlmsg_data(nlh);	u32 spid = NETLINK_CB(skb).pid;	u32 seq = nlh->nlmsg_seq;	r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC);	if (r_skb == NULL)		return -ENOMEM;	if (build_sadinfo(r_skb, spid, seq, *flags) < 0)		BUG();	return nlmsg_unicast(xfrm_nl, r_skb, spid);}static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh,		struct nlattr **attrs){	struct xfrm_usersa_id *p = nlmsg_data(nlh);	struct xfrm_state *x;	struct sk_buff *resp_skb;	int err = -ESRCH;	x = xfrm_user_state_lookup(p, attrs, &err);	if (x == NULL)		goto out_noput;	resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);	if (IS_ERR(resp_skb)) {		err = PTR_ERR(resp_skb);	} else {		err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid);	}	xfrm_state_put(x);out_noput:	return err;}static int verify_userspi_info(struct xfrm_userspi_info *p){	switch (p->info.id.proto) {	case IPPROTO_AH:	case IPPROTO_ESP:		break;	case IPPROTO_COMP:		/* IPCOMP spi is 16-bits. */		if (p->max >= 0x10000)			return -EINVAL;		break;	default:		return -EINVAL;	}	if (p->min > p->max)		return -EINVAL;	return 0;}static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh,		struct nlattr **attrs){	struct xfrm_state *x;	struct xfrm_userspi_info *p;	struct sk_buff *resp_skb;	xfrm_address_t *daddr;	int family;	int err;	p = nlmsg_data(nlh);	err = verify_userspi_info(p);	if (err)		goto out_noput;	family = p->info.family;	daddr = &p->info.id.daddr;	x = NULL;	if (p->info.seq) {		x = xfrm_find_acq_byseq(p->info.seq);		if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) {			xfrm_state_put(x);			x = NULL;		}	}	if (!x)		x = xfrm_find_acq(p->info.mode, p->info.reqid,				  p->info.id.proto, daddr,				  &p->info.saddr, 1,				  family);	err = -ENOENT;	if (x == NULL)		goto out_noput;	err = xfrm_alloc_spi(x, p->min, p->max);	if (err)		goto out;	resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);	if (IS_ERR(resp_skb)) {		err = PTR_ERR(resp_skb);		goto out;	}	err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid);out:	xfrm_state_put(x);out_noput:	return err;}static int verify_policy_dir(u8 dir){	switch (dir) {	case XFRM_POLICY_IN:	case XFRM_POLICY_OUT:	case XFRM_POLICY_FWD:		break;	default:		return -EINVAL;	}	return 0;}static int verify_policy_type(u8 type){	switch (type) {	case XFRM_POLICY_TYPE_MAIN:#ifdef CONFIG_XFRM_SUB_POLICY	case XFRM_POLICY_TYPE_SUB:#endif		break;	default:		return -EINVAL;	}	return 0;}static int verify_newpolicy_info(struct xfrm_userpolicy_info *p){	switch (p->share) {	case XFRM_SHARE_ANY:	case XFRM_SHARE_SESSION:	case XFRM_SHARE_USER:	case XFRM_SHARE_UNIQUE:		break;	default:		return -EINVAL;	}	switch (p->action) {	case XFRM_POLICY_ALLOW:	case XFRM_POLICY_BLOCK:		break;	default:		return -EINVAL;	}	switch (p->sel.family) {	case AF_INET:		break;	case AF_INET6:#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)		break;#else		return  -EAFNOSUPPORT;#endif	default:		return -EINVAL;	}	return verify_policy_dir(p->dir);}static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs){	struct nlattr *rt = attrs[XFRMA_SEC_CTX];	struct xfrm_user_sec_ctx *uctx;	if (!rt)		return 0;	uctx = nla_data(rt);	return security_xfrm_policy_alloc(pol, uctx);}static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,			   int nr){	int i;	xp->xfrm_nr = nr;	for (i = 0; i < nr; i++, ut++) {		struct xfrm_tmpl *t = &xp->xfrm_vec[i];		memcpy(&t->id, &ut->id, sizeof(struct xfrm_id));		memcpy(&t->saddr, &ut->saddr,		       sizeof(xfrm_address_t));		t->reqid = ut->reqid;		t->mode = ut->mode;		t->share = ut->share;		t->optional = ut->optional;		t->aalgos = ut->aalgos;		t->ealgos = ut->ealgos;		t->calgos = ut->calgos;		t->encap_family = ut->family;	}}static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family){	int i;	if (nr > XFRM_MAX_DEPTH)		return -EINVAL;	for (i = 0; i < nr; i++) {		/* We never validated the ut->family value, so many		 * applications simply leave it at zero.  The check was		 * never made and ut->family was ignored because all		 * templates could be assumed to have the same family as		 * the policy itself.  Now that we will have ipv4-in-ipv6		 * and ipv6-in-ipv4 tunnels, this is no longer true.		 */		if (!ut[i].family)			ut[i].family = family;		switch (ut[i].family) {		case AF_INET:			break;#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)		case AF_INET6:			break;#endif		default:			return -EINVAL;		}	}	return 0;}static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs){	struct nlattr *rt = attrs[XFRMA_TMPL];	if (!rt) {		pol->xfrm_nr = 0;	} else {		struct xfrm_user_tmpl *utmpl = nla_data(rt);		int nr = nla_len(rt) / sizeof(*utmpl);		int err;		err = validate_tmpl(nr, utmpl, pol->family);		if (err)			return err;		copy_templates(pol, utmpl, nr);	}	return 0;}static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs){	struct nlattr *rt = attrs[XFRMA_POLICY_TYPE];	struct xfrm_userpolicy_type *upt;	u8 type = XFRM_POLICY_TYPE_MAIN;	int err;	if (rt) {		upt = nla_data(rt);		type = upt->type;	}	err = verify_policy_type(type);	if (err)		return err;	*tp = type;	return 0;}static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p){	xp->priority = p->priority;	xp->index = p->index;	memcpy(&xp->selector, &p->sel, sizeof(xp->selector));	memcpy(&xp->lft, &p->lft, sizeof(xp->lft));	xp->action = p->action;	xp->flags = p->flags;	xp->family = p->sel.family;	/* XXX xp->share = p->share; */}static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir){	memcpy(&p->sel, &xp->selector, sizeof(p->sel));	memcpy(&p->lft, &xp->lft, sizeof(p->lft));	memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));	p->priority = xp->priority;	p->index = xp->index;	p->sel.family = xp->family;	p->dir = dir;	p->action = xp->action;	p->flags = xp->flags;	p->share = XFRM_SHARE_ANY; /* XXX xp->share */}static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp){	struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL);	int err;	if (!xp) {		*errp = -ENOMEM;		return NULL;	}	copy_from_user_policy(xp, p);	err = copy_from_user_policy_type(&xp->type, attrs);	if (err)		goto error;	if (!(err = copy_from_user_tmpl(xp, attrs)))		err = copy_from_user_sec_ctx(xp, attrs);	if (err)		goto error;	return xp; error:	*errp = err;	kfree(xp);	return NULL;}static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh,		struct nlattr **attrs){	struct xfrm_userpolicy_info *p = nlmsg_data(nlh);	struct xfrm_policy *xp;	struct km_event c;	int err;	int excl;	err = verify_newpolicy_info(p);	if (err)		return err;	err = verify_sec_ctx_len(attrs);	if (err)		return err;	xp = xfrm_policy_construct(p, attrs, &err);	if (!xp)		return err;	/* shouldnt excl be based on nlh flags??	 * Aha! this is anti-netlink really i.e  more pfkey derived	 * in netlink excl is a flag and you wouldnt need	 * a type XFRM_MSG_UPDPOLICY - JHS */	excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;	err = xfrm_policy_insert(p->dir, xp, excl);	xfrm_audit_policy_add(xp, err ? 0 : 1, NETLINK_CB(skb).loginuid,			      NETLINK_CB(skb).sid);	if (err) {		security_xfrm_policy_free(xp);		kfree(xp);		return err;	}	c.event = nlh->nlmsg_type;	c.seq = nlh->nlmsg_seq;	c.pid = nlh->nlmsg_pid;	km_policy_notify(xp, p->dir, &c);	xfrm_pol_put(xp);	return 0;}static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb){	struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH];	int i;	if (xp->xfrm_nr == 0)		return 0;	for (i = 0; i < xp->xfrm_nr; i++) {		struct xfrm_user_tmpl *up = &vec[i];		struct xfrm_tmpl *kp = &xp->xfrm_vec[i];		memcpy(&up->id, &kp->id, sizeof(up->id));		up->family = kp->encap_family;		memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));		up->reqid = kp->reqid;		up->mode = kp->mode;		up->share = kp->share;		up->optional = kp->optional;		up->aalgos = kp->aalgos;		up->ealgos = kp->ealgos;		up->calgos = kp->calgos;	}	return nla_put(skb, XFRMA_TMPL,		       sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec);}static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb){	if (x->security) {		return copy_sec_ctx(x->security, skb);	}	return 0;}static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb){	if (xp->security) {		return copy_sec_ctx(xp->security, skb);	}	return 0;}static inline size_t userpolicy_type_attrsize(void){#ifdef CONFIG_XFRM_SUB_POLICY	return nla_total_size(sizeof(struct xfrm_userpolicy_type));#else	return 0;#endif}#ifdef CONFIG_XFRM_SUB_POLICYstatic int copy_to_user_policy_type(u8 type, struct sk_buff *skb){	struct xfrm_userpolicy_type upt = {		.type = type,	};	return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt);}#elsestatic inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb){	return 0;}#endifstatic int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr){	struct xfrm_dump_info *sp = ptr;	struct xfrm_userpolicy_info *p;	struct sk_buff *in_skb = sp->in_skb;	struct sk_buff *skb = sp->out_skb;	struct nlmsghdr *nlh;	if (sp->this_idx < sp->start_idx)		goto out;	nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq,			XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags);	if (nlh == NULL)		return -EMSGSIZE;	p = nlmsg_data(nlh);	copy_to_user_policy(xp, p, dir);	if (copy_to_user_tmpl(xp, skb) < 0)		goto nlmsg_failure;	if (copy_to_user_sec_ctx(xp, skb))		goto nlmsg_failure;	if (copy_to_user_policy_type(xp->type, skb) < 0)		goto nlmsg_failure;	nlmsg_end(skb, nlh);out:	sp->this_idx++;	return 0;nlmsg_failure:	nlmsg_cancel(skb, nlh);	return -EMSGSIZE;}static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb){	struct xfrm_dump_info info;	info.in_skb = cb->skb;	info.out_skb = skb;	info.nlmsg_seq = cb->nlh->nlmsg_seq;	info.nlmsg_flags = NLM_F_MULTI;	info.this_idx = 0;	info.start_idx = cb->args[0];	(void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info);#ifdef CONFIG_XFRM_SUB_POLICY	(void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info);#endif	cb->args[0] = info.this_idx;	return skb->len;}

⌨️ 快捷键说明

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