浏览代码

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [BRIDGE]: adding new device to bridge should enable if up
  [IPV6]: Do not set IF_READY if device is down
  [IPSEC]: xfrm audit hook misplaced in pfkey_delete and xfrm_del_sa
  [IPSEC]: Add xfrm policy change auditing to pfkey_spdget
  [IPSEC]: xfrm_policy delete security check misplaced
  [CONNECTOR]: Bugfix for cn_call_callback()
  [DCCP]: Revert patch which disables bidirectional mode
  [IPV6]: Handle np->opt being NULL in ipv6_getsockopt_sticky().
  [UDP]: Reread uh pointer after pskb_trim
  [NETFILTER]: nfnetlink_log: fix crash on bridged packet
  [NETFILTER]: nfnetlink_log: zero-terminate prefix
  [NETFILTER]: nf_conntrack_ipv6: fix incorrect classification of IPv6 fragments as ESTABLISHED
Linus Torvalds 18 年之前
父节点
当前提交
eee8abe5de

+ 11 - 11
drivers/connector/connector.c

@@ -128,7 +128,7 @@ EXPORT_SYMBOL_GPL(cn_netlink_send);
  */
  */
 static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
 static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), void *data)
 {
 {
-	struct cn_callback_entry *__cbq;
+	struct cn_callback_entry *__cbq, *__new_cbq;
 	struct cn_dev *dev = &cdev;
 	struct cn_dev *dev = &cdev;
 	int err = -ENODEV;
 	int err = -ENODEV;
 
 
@@ -148,27 +148,27 @@ static int cn_call_callback(struct cn_msg *msg, void (*destruct_data)(void *), v
 			} else {
 			} else {
 				struct cn_callback_data *d;
 				struct cn_callback_data *d;
 				
 				
-				__cbq = kzalloc(sizeof(*__cbq), GFP_ATOMIC);
-				if (__cbq) {
-					d = &__cbq->data;
+				err = -ENOMEM;
+				__new_cbq = kzalloc(sizeof(struct cn_callback_entry), GFP_ATOMIC);
+				if (__new_cbq) {
+					d = &__new_cbq->data;
 					d->callback_priv = msg;
 					d->callback_priv = msg;
 					d->callback = __cbq->data.callback;
 					d->callback = __cbq->data.callback;
 					d->ddata = data;
 					d->ddata = data;
 					d->destruct_data = destruct_data;
 					d->destruct_data = destruct_data;
-					d->free = __cbq;
+					d->free = __new_cbq;
 
 
-					INIT_WORK(&__cbq->work,
+					INIT_WORK(&__new_cbq->work,
 							&cn_queue_wrapper);
 							&cn_queue_wrapper);
-					
+
 					if (queue_work(dev->cbdev->cn_queue,
 					if (queue_work(dev->cbdev->cn_queue,
-						    &__cbq->work))
+						    &__new_cbq->work))
 						err = 0;
 						err = 0;
 					else {
 					else {
-						kfree(__cbq);
+						kfree(__new_cbq);
 						err = -EINVAL;
 						err = -EINVAL;
 					}
 					}
-				} else
-					err = -ENOMEM;
+				}
 			}
 			}
 			break;
 			break;
 		}
 		}

+ 3 - 2
include/net/xfrm.h

@@ -988,8 +988,9 @@ extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int,
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 					  struct xfrm_selector *sel,
 					  struct xfrm_selector *sel,
-					  struct xfrm_sec_ctx *ctx, int delete);
-struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete);
+					  struct xfrm_sec_ctx *ctx, int delete,
+					  int *err);
+struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err);
 void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
 void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info);
 u32 xfrm_get_acqseq(void);
 u32 xfrm_get_acqseq(void);
 void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi);
 void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi);

+ 4 - 0
net/bridge/br_if.c

@@ -428,6 +428,10 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
 	spin_lock_bh(&br->lock);
 	spin_lock_bh(&br->lock);
 	br_stp_recalculate_bridge_id(br);
 	br_stp_recalculate_bridge_id(br);
 	br_features_recompute(br);
 	br_features_recompute(br);
+
+	if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
+	    (br->dev->flags & IFF_UP))
+		br_stp_enable_port(p);
 	spin_unlock_bh(&br->lock);
 	spin_unlock_bh(&br->lock);
 
 
 	dev_set_mtu(br->dev, br_min_mtu(br));
 	dev_set_mtu(br->dev, br_min_mtu(br));

+ 1 - 6
net/dccp/ccids/ccid3.c

@@ -545,12 +545,7 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
 		/* set idle flag */
 		/* set idle flag */
 		hctx->ccid3hctx_idle = 1;
 		hctx->ccid3hctx_idle = 1;
 		break;
 		break;
-	case TFRC_SSTATE_NO_SENT:
-		/*
-		 * XXX when implementing bidirectional rx/tx check this again
-		 */
-		DCCP_WARN("Illegal ACK received - no packet sent\n");
-		/* fall through */
+	case TFRC_SSTATE_NO_SENT:	/* fall through */
 	case TFRC_SSTATE_TERM:		/* ignore feedback when closing */
 	case TFRC_SSTATE_TERM:		/* ignore feedback when closing */
 		break;
 		break;
 	}
 	}

+ 4 - 17
net/dccp/input.c

@@ -248,18 +248,8 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
 			    DCCP_ACKVEC_STATE_RECEIVED))
 			    DCCP_ACKVEC_STATE_RECEIVED))
 		goto discard;
 		goto discard;
 
 
-	/*
-	 * Deliver to the CCID module in charge.
-	 * FIXME: Currently DCCP operates one-directional only, i.e. a listening
-	 *        server is not at the same time a connecting client. There is
-	 *        not much sense in delivering to both rx/tx sides at the moment
-	 *        (only one is active at a time); when moving to bidirectional
-	 *        service, this needs to be revised.
-	 */
-	if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT)
-		ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
-	else	/* listening or connected server */
-		ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+	ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+	ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
 
 
 	return __dccp_rcv_established(sk, skb, dh, len);
 	return __dccp_rcv_established(sk, skb, dh, len);
 discard:
 discard:
@@ -494,11 +484,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 				    DCCP_ACKVEC_STATE_RECEIVED))
 				    DCCP_ACKVEC_STATE_RECEIVED))
 			goto discard;
 			goto discard;
 
 
-		/* XXX see the comments in dccp_rcv_established about this */
-		if (dccp_sk(sk)->dccps_role == DCCP_ROLE_CLIENT)
-			ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
-		else
-			ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+		ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb);
+		ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb);
 	}
 	}
 
 
 	/*
 	/*

+ 1 - 0
net/ipv4/udp.c

@@ -1215,6 +1215,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
 
 
 		if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen))
 		if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen))
 			goto short_packet;
 			goto short_packet;
+		uh = skb->h.uh;
 
 
 		udp4_csum_init(skb, uh);
 		udp4_csum_init(skb, uh);
 
 

+ 0 - 4
net/ipv6/addrconf.c

@@ -342,10 +342,6 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 	}
 	}
 #endif
 #endif
 
 
-	if (netif_carrier_ok(dev))
-		ndev->if_flags |= IF_READY;
-
-
 	ipv6_mc_init_dev(ndev);
 	ipv6_mc_init_dev(ndev);
 	ndev->tstamp = jiffies;
 	ndev->tstamp = jiffies;
 #ifdef CONFIG_SYSCTL
 #ifdef CONFIG_SYSCTL

+ 7 - 3
net/ipv6/ipv6_sockglue.c

@@ -795,11 +795,15 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
 EXPORT_SYMBOL(compat_ipv6_setsockopt);
 EXPORT_SYMBOL(compat_ipv6_setsockopt);
 #endif
 #endif
 
 
-static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_opt_hdr *hdr,
+static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt,
 				  char __user *optval, int len)
 				  char __user *optval, int len)
 {
 {
-	if (!hdr)
+	struct ipv6_opt_hdr *hdr;
+
+	if (!opt || !opt->hopopt)
 		return 0;
 		return 0;
+	hdr = opt->hopopt;
+
 	len = min_t(int, len, ipv6_optlen(hdr));
 	len = min_t(int, len, ipv6_optlen(hdr));
 	if (copy_to_user(optval, hdr, ipv6_optlen(hdr)))
 	if (copy_to_user(optval, hdr, ipv6_optlen(hdr)))
 		return -EFAULT;
 		return -EFAULT;
@@ -940,7 +944,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
 	{
 	{
 
 
 		lock_sock(sk);
 		lock_sock(sk);
-		len = ipv6_getsockopt_sticky(sk, np->opt->hopopt,
+		len = ipv6_getsockopt_sticky(sk, np->opt,
 					     optval, len);
 					     optval, len);
 		release_sock(sk);
 		release_sock(sk);
 		return put_user(len, optlen);
 		return put_user(len, optlen);

+ 1 - 0
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c

@@ -257,6 +257,7 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
 		}
 		}
 		nf_conntrack_get(reasm->nfct);
 		nf_conntrack_get(reasm->nfct);
 		(*pskb)->nfct = reasm->nfct;
 		(*pskb)->nfct = reasm->nfct;
+		(*pskb)->nfctinfo = reasm->nfctinfo;
 		return NF_ACCEPT;
 		return NF_ACCEPT;
 	}
 	}
 
 

+ 14 - 12
net/key/af_key.c

@@ -1467,9 +1467,6 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
 
 
 	err = xfrm_state_delete(x);
 	err = xfrm_state_delete(x);
 
 
-	xfrm_audit_log(audit_get_loginuid(current->audit_context), 0,
-		       AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x);
-
 	if (err < 0)
 	if (err < 0)
 		goto out;
 		goto out;
 
 
@@ -1478,6 +1475,8 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
 	c.event = XFRM_MSG_DELSA;
 	c.event = XFRM_MSG_DELSA;
 	km_state_notify(x, &c);
 	km_state_notify(x, &c);
 out:
 out:
+	xfrm_audit_log(audit_get_loginuid(current->audit_context), 0,
+		       AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x);
 	xfrm_state_put(x);
 	xfrm_state_put(x);
 
 
 	return err;
 	return err;
@@ -2294,14 +2293,12 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
 	}
 	}
 
 
 	xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1,
 	xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1,
-				   &sel, tmp.security, 1);
+				   &sel, tmp.security, 1, &err);
 	security_xfrm_policy_free(&tmp);
 	security_xfrm_policy_free(&tmp);
 
 
 	if (xp == NULL)
 	if (xp == NULL)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	err = security_xfrm_policy_delete(xp);
-
 	xfrm_audit_log(audit_get_loginuid(current->audit_context), 0,
 	xfrm_audit_log(audit_get_loginuid(current->audit_context), 0,
 		       AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
 		       AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
 
 
@@ -2539,7 +2536,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
 static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
 {
 {
 	unsigned int dir;
 	unsigned int dir;
-	int err;
+	int err = 0, delete;
 	struct sadb_x_policy *pol;
 	struct sadb_x_policy *pol;
 	struct xfrm_policy *xp;
 	struct xfrm_policy *xp;
 	struct km_event c;
 	struct km_event c;
@@ -2551,16 +2548,20 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
 	if (dir >= XFRM_POLICY_MAX)
 	if (dir >= XFRM_POLICY_MAX)
 		return -EINVAL;
 		return -EINVAL;
 
 
+	delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2);
 	xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id,
 	xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id,
-			      hdr->sadb_msg_type == SADB_X_SPDDELETE2);
+			      delete, &err);
 	if (xp == NULL)
 	if (xp == NULL)
 		return -ENOENT;
 		return -ENOENT;
 
 
-	err = 0;
+	if (delete) {
+		xfrm_audit_log(audit_get_loginuid(current->audit_context), 0,
+			       AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
 
 
-	c.seq = hdr->sadb_msg_seq;
-	c.pid = hdr->sadb_msg_pid;
-	if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) {
+		if (err)
+			goto out;
+		c.seq = hdr->sadb_msg_seq;
+		c.pid = hdr->sadb_msg_pid;
 		c.data.byid = 1;
 		c.data.byid = 1;
 		c.event = XFRM_MSG_DELPOLICY;
 		c.event = XFRM_MSG_DELPOLICY;
 		km_policy_notify(xp, dir, &c);
 		km_policy_notify(xp, dir, &c);
@@ -2568,6 +2569,7 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
 		err = key_pol_get_resp(sk, xp, hdr, dir);
 		err = key_pol_get_resp(sk, xp, hdr, dir);
 	}
 	}
 
 
+out:
 	xfrm_pol_put(xp);
 	xfrm_pol_put(xp);
 	return err;
 	return err;
 }
 }

+ 2 - 2
net/netfilter/nfnetlink_log.c

@@ -486,7 +486,7 @@ __build_packet_message(struct nfulnl_instance *inst,
 			 * for physical device (when called from ipv4) */
 			 * for physical device (when called from ipv4) */
 			NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
 			NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
 				sizeof(tmp_uint), &tmp_uint);
 				sizeof(tmp_uint), &tmp_uint);
-			if (skb->nf_bridge) {
+			if (skb->nf_bridge && skb->nf_bridge->physoutdev) {
 				tmp_uint =
 				tmp_uint =
 				    htonl(skb->nf_bridge->physoutdev->ifindex);
 				    htonl(skb->nf_bridge->physoutdev->ifindex);
 				NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
 				NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
@@ -615,7 +615,7 @@ nfulnl_log_packet(unsigned int pf,
 
 
 	plen = 0;
 	plen = 0;
 	if (prefix)
 	if (prefix)
-		plen = strlen(prefix);
+		plen = strlen(prefix) + 1;
 
 
 	/* all macros expand to constant values at compile time */
 	/* all macros expand to constant values at compile time */
 	/* FIXME: do we want to make the size calculation conditional based on
 	/* FIXME: do we want to make the size calculation conditional based on

+ 16 - 2
net/xfrm/xfrm_policy.c

@@ -735,12 +735,14 @@ EXPORT_SYMBOL(xfrm_policy_insert);
 
 
 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 					  struct xfrm_selector *sel,
 					  struct xfrm_selector *sel,
-					  struct xfrm_sec_ctx *ctx, int delete)
+					  struct xfrm_sec_ctx *ctx, int delete,
+					  int *err)
 {
 {
 	struct xfrm_policy *pol, *ret;
 	struct xfrm_policy *pol, *ret;
 	struct hlist_head *chain;
 	struct hlist_head *chain;
 	struct hlist_node *entry;
 	struct hlist_node *entry;
 
 
+	*err = 0;
 	write_lock_bh(&xfrm_policy_lock);
 	write_lock_bh(&xfrm_policy_lock);
 	chain = policy_hash_bysel(sel, sel->family, dir);
 	chain = policy_hash_bysel(sel, sel->family, dir);
 	ret = NULL;
 	ret = NULL;
@@ -750,6 +752,11 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 		    xfrm_sec_ctx_match(ctx, pol->security)) {
 		    xfrm_sec_ctx_match(ctx, pol->security)) {
 			xfrm_pol_hold(pol);
 			xfrm_pol_hold(pol);
 			if (delete) {
 			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->bydst);
 				hlist_del(&pol->byidx);
 				hlist_del(&pol->byidx);
 				xfrm_policy_count[dir]--;
 				xfrm_policy_count[dir]--;
@@ -768,12 +775,14 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
 }
 }
 EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
 EXPORT_SYMBOL(xfrm_policy_bysel_ctx);
 
 
-struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete)
+struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete,
+				     int *err)
 {
 {
 	struct xfrm_policy *pol, *ret;
 	struct xfrm_policy *pol, *ret;
 	struct hlist_head *chain;
 	struct hlist_head *chain;
 	struct hlist_node *entry;
 	struct hlist_node *entry;
 
 
+	*err = 0;
 	write_lock_bh(&xfrm_policy_lock);
 	write_lock_bh(&xfrm_policy_lock);
 	chain = xfrm_policy_byidx + idx_hash(id);
 	chain = xfrm_policy_byidx + idx_hash(id);
 	ret = NULL;
 	ret = NULL;
@@ -781,6 +790,11 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete)
 		if (pol->type == type && pol->index == id) {
 		if (pol->type == type && pol->index == id) {
 			xfrm_pol_hold(pol);
 			xfrm_pol_hold(pol);
 			if (delete) {
 			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->bydst);
 				hlist_del(&pol->byidx);
 				hlist_del(&pol->byidx);
 				xfrm_policy_count[dir]--;
 				xfrm_policy_count[dir]--;

+ 11 - 13
net/xfrm/xfrm_user.c

@@ -530,9 +530,6 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 
 
 	err = xfrm_state_delete(x);
 	err = xfrm_state_delete(x);
 
 
-	xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
-		       AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x);
-
 	if (err < 0)
 	if (err < 0)
 		goto out;
 		goto out;
 
 
@@ -542,6 +539,8 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh,
 	km_state_notify(x, &c);
 	km_state_notify(x, &c);
 
 
 out:
 out:
+	xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
+		       AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x);
 	xfrm_state_put(x);
 	xfrm_state_put(x);
 	return err;
 	return err;
 }
 }
@@ -1254,7 +1253,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return err;
 		return err;
 
 
 	if (p->index)
 	if (p->index)
-		xp = xfrm_policy_byid(type, p->dir, p->index, delete);
+		xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err);
 	else {
 	else {
 		struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
 		struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
 		struct xfrm_policy tmp;
 		struct xfrm_policy tmp;
@@ -1270,7 +1269,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 			if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
 			if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
 				return err;
 				return err;
 		}
 		}
-		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, delete);
+		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security,
+					   delete, &err);
 		security_xfrm_policy_free(&tmp);
 		security_xfrm_policy_free(&tmp);
 	}
 	}
 	if (xp == NULL)
 	if (xp == NULL)
@@ -1288,8 +1288,6 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 					      MSG_DONTWAIT);
 					      MSG_DONTWAIT);
 		}
 		}
 	} else {
 	} else {
-		err = security_xfrm_policy_delete(xp);
-
 		xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
 		xfrm_audit_log(NETLINK_CB(skb).loginuid, NETLINK_CB(skb).sid,
 			       AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
 			       AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL);
 
 
@@ -1303,9 +1301,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
 		km_policy_notify(xp, p->dir, &c);
 		km_policy_notify(xp, p->dir, &c);
 	}
 	}
 
 
-	xfrm_pol_put(xp);
-
 out:
 out:
+	xfrm_pol_put(xp);
 	return err;
 	return err;
 }
 }
 
 
@@ -1502,7 +1499,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 		return err;
 		return err;
 
 
 	if (p->index)
 	if (p->index)
-		xp = xfrm_policy_byid(type, p->dir, p->index, 0);
+		xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err);
 	else {
 	else {
 		struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
 		struct rtattr *rt = xfrma[XFRMA_SEC_CTX-1];
 		struct xfrm_policy tmp;
 		struct xfrm_policy tmp;
@@ -1518,13 +1515,14 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh,
 			if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
 			if ((err = security_xfrm_policy_alloc(&tmp, uctx)))
 				return err;
 				return err;
 		}
 		}
-		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 0);
+		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security,
+					   0, &err);
 		security_xfrm_policy_free(&tmp);
 		security_xfrm_policy_free(&tmp);
 	}
 	}
 
 
 	if (xp == NULL)
 	if (xp == NULL)
-		return err;
-											read_lock(&xp->lock);
+		return -ENOENT;
+	read_lock(&xp->lock);
 	if (xp->dead) {
 	if (xp->dead) {
 		read_unlock(&xp->lock);
 		read_unlock(&xp->lock);
 		goto out;
 		goto out;