On Thu, 2007-03-22 at 20:56 -0400, James Morris wrote: >On Thu, 22 Mar 2007, Joy Latten wrote: >> > Perhaps a better semantic would be to fail the entire flush operation if >> > one of the security checks failed. e.g. loop through for permissions >> > first, then if all ok, loop through for deletion. >> > >> Ok, will code this up and test it if there are no objections. > >I'd suggest making the permission loop a noop if CONFIG_SECURITY=n, via a >static inline function.
Reworked patch with improved semantics as suggested. I used CONFIG_SECURITY_NETWORK_XFRM instead of CONFIG_SECURITY since this can be considered part of the labeled networking semantics. Let me know if my assumption sounds incorrect. Also, I have built and tested with and without CONFIG_SECURITY_NETWORK_XFRM. Regards, Joy Signed-off-by: Joy Latten<[EMAIL PROTECTED]> diff -urpN linux-2.6.20.orig/include/net/xfrm.h linux-2.6.20.patch/include/net/xfrm.h --- linux-2.6.20.orig/include/net/xfrm.h 2007-03-23 11:01:48.000000000 -0500 +++ linux-2.6.20.patch/include/net/xfrm.h 2007-03-25 21:36:05.000000000 -0500 @@ -937,7 +937,7 @@ static inline int xfrm_state_sort(struct #endif extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); extern int xfrm_state_delete(struct xfrm_state *x); -extern void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); +extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq); extern void xfrm_replay_notify(struct xfrm_state *x, int event); @@ -991,13 +991,13 @@ struct xfrm_policy *xfrm_policy_bysel_ct 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); +int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); u32 xfrm_get_acqseq(void); void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi); struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); -extern void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); +extern int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst, struct flowi *fl, int family, int strict); diff -urpN linux-2.6.20.orig/net/key/af_key.c linux-2.6.20.patch/net/key/af_key.c --- linux-2.6.20.orig/net/key/af_key.c 2007-03-23 11:02:49.000000000 -0500 +++ linux-2.6.20.patch/net/key/af_key.c 2007-03-25 21:34:35.000000000 -0500 @@ -1645,6 +1645,7 @@ static int pfkey_flush(struct sock *sk, unsigned proto; struct km_event c; struct xfrm_audit audit_info; + int err; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) @@ -1652,7 +1653,9 @@ static int pfkey_flush(struct sock *sk, audit_info.loginuid = audit_get_loginuid(current->audit_context); audit_info.secid = 0; - xfrm_state_flush(proto, &audit_info); + err = xfrm_state_flush(proto, &audit_info); + if (err) + return err; c.data.proto = proto; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; @@ -2628,10 +2631,13 @@ static int pfkey_spdflush(struct sock *s { struct km_event c; struct xfrm_audit audit_info; + int err; audit_info.loginuid = audit_get_loginuid(current->audit_context); audit_info.secid = 0; - xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); + err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); + if (err) + return err; c.data.type = XFRM_POLICY_TYPE_MAIN; c.event = XFRM_MSG_FLUSHPOLICY; c.pid = hdr->sadb_msg_pid; diff -urpN linux-2.6.20.orig/net/xfrm/xfrm_policy.c linux-2.6.20.patch/net/xfrm/xfrm_policy.c --- linux-2.6.20.orig/net/xfrm/xfrm_policy.c 2007-03-23 11:02:46.000000000 -0500 +++ linux-2.6.20.patch/net/xfrm/xfrm_policy.c 2007-03-25 21:32:51.000000000 -0500 @@ -813,11 +813,65 @@ struct xfrm_policy *xfrm_policy_byid(u8 } EXPORT_SYMBOL(xfrm_policy_byid); -void xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) +#ifdef CONFIG_SECURITY_NETWORK_XFRM +static inline int +xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) { - int dir; + 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; + if ((err = security_xfrm_policy_delete(pol)) != 0) { + xfrm_audit_log(audit_info->loginuid, + audit_info->secid, + AUDIT_MAC_IPSEC_DELSPD, + err ? 0 : 1, pol, NULL); + 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; + if ((err = security_xfrm_policy_delete(pol)) != 0) { + xfrm_audit_log(audit_info->loginuid, + audit_info->secid, + AUDIT_MAC_IPSEC_DELSPD, + err ? 0 : 1, pol, NULL); + return err; + } + } + } + } + return err; +} +#else +static inline int +xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) +{ + return 0; +} +#endif + +int 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; @@ -870,7 +924,9 @@ void xfrm_policy_flush(u8 type, struct x xfrm_policy_count[dir] -= killed; } atomic_inc(&flow_cache_genid); +out: write_unlock_bh(&xfrm_policy_lock); + return err; } EXPORT_SYMBOL(xfrm_policy_flush); @@ -2485,4 +2541,3 @@ restore_state: } EXPORT_SYMBOL(xfrm_migrate); #endif - diff -urpN linux-2.6.20.orig/net/xfrm/xfrm_state.c linux-2.6.20.patch/net/xfrm/xfrm_state.c --- linux-2.6.20.orig/net/xfrm/xfrm_state.c 2007-03-23 11:02:46.000000000 -0500 +++ linux-2.6.20.patch/net/xfrm/xfrm_state.c 2007-03-25 21:33:02.000000000 -0500 @@ -388,12 +388,48 @@ int xfrm_state_delete(struct xfrm_state } EXPORT_SYMBOL(xfrm_state_delete); -void xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) +#ifdef CONFIG_SECURITY_NETWORK_XFRM +static inline int +xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) { - int i; - int err = 0; + int i, err = 0; + + for (i = 0; i <= xfrm_state_hmask; i++) { + struct hlist_node *entry; + struct xfrm_state *x; + + hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { + if (xfrm_id_proto_match(x->id.proto, proto) && + (err = security_xfrm_state_delete(x)) != 0) { + xfrm_audit_log(audit_info->loginuid, + audit_info->secid, + AUDIT_MAC_IPSEC_DELSA, + err ? 0 : 1, NULL, x); + + return err; + } + } + } + + return err; +} +#else +static inline int +xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) +{ + return 0; +} +#endif + +int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) +{ + int i, err = 0; spin_lock_bh(&xfrm_state_lock); + err = xfrm_state_flush_secctx_check(proto, audit_info); + if (err) + goto out; + for (i = 0; i <= xfrm_state_hmask; i++) { struct hlist_node *entry; struct xfrm_state *x; @@ -416,8 +452,12 @@ restart: } } } + err = 0; + +out: spin_unlock_bh(&xfrm_state_lock); wake_up(&km_waitq); + return err; } EXPORT_SYMBOL(xfrm_state_flush); diff -urpN linux-2.6.20.orig/net/xfrm/xfrm_user.c linux-2.6.20.patch/net/xfrm/xfrm_user.c --- linux-2.6.20.orig/net/xfrm/xfrm_user.c 2007-03-23 11:02:46.000000000 -0500 +++ linux-2.6.20.patch/net/xfrm/xfrm_user.c 2007-03-25 21:33:52.000000000 -0500 @@ -1312,10 +1312,13 @@ static int xfrm_flush_sa(struct sk_buff struct km_event c; struct xfrm_usersa_flush *p = NLMSG_DATA(nlh); struct xfrm_audit audit_info; + int err; audit_info.loginuid = NETLINK_CB(skb).loginuid; audit_info.secid = NETLINK_CB(skb).sid; - xfrm_state_flush(p->proto, &audit_info); + err = xfrm_state_flush(p->proto, &audit_info); + if (err) + return err; c.data.proto = p->proto; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; @@ -1476,7 +1479,9 @@ static int xfrm_flush_policy(struct sk_b audit_info.loginuid = NETLINK_CB(skb).loginuid; audit_info.secid = NETLINK_CB(skb).sid; - xfrm_policy_flush(type, &audit_info); + err = xfrm_policy_flush(type, &audit_info); + if (err) + return err; c.data.type = type; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html