On 4/6/2016 2:51 AM, Paolo Abeni wrote:
> This patch leverage the netlbl_changed() hook to perform on demand
> registration and deregistration of the netfilter hooks and the
> socket_sock_rcv_skb hook.
>
> With default policy and empty netfilter/netlabel configuration, the
> above hooks are not registered and this allows avoiding nf_hook_slow
> in the xmit path and socket_sock_rcv_skb() in the rx path.

There is no reason to assume that there is a relationship between
a netlabel configuration and a netfilter configuration. Smack always
has a netlabel configuration. Security modules (e.g. AppArmor) may
well use netfilter without netlabel.

Please stop assuming that security == SELinux. 

>
> This gives measurable network performance improvement in both
> directions.

In the case where SELinux is enabled and netfilter is not.

> Signed-off-by: Paolo Abeni <pab...@redhat.com>
> ---
>  security/selinux/hooks.c            | 72 
> +++++++++++++++++++++++++++++++------
>  security/selinux/include/security.h |  1 +
>  security/selinux/ss/services.c      |  1 +
>  security/selinux/xfrm.c             |  4 +++
>  4 files changed, 68 insertions(+), 10 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 912deee..a3baa69 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -4745,11 +4745,13 @@ static int selinux_secmark_relabel_packet(u32 sid)
>  static void selinux_secmark_refcount_inc(void)
>  {
>       atomic_inc(&selinux_secmark_refcount);
> +     selinux_net_update();
>  }
>  
>  static void selinux_secmark_refcount_dec(void)
>  {
>       atomic_dec(&selinux_secmark_refcount);
> +     selinux_net_update();
>  }
>  
>  static void selinux_req_classify_flow(const struct request_sock *req,
> @@ -4836,6 +4838,11 @@ static int selinux_tun_dev_open(void *security)
>       return 0;
>  }
>  
> +static void selinux_netlbl_changed(void)
> +{
> +     selinux_net_update();
> +}
> +
>  static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
>  {
>       int err = 0;
> @@ -6091,7 +6098,6 @@ static struct security_hook_list selinux_hooks[] = {
>       LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
>       LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
>       LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
> -     LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
>       LSM_HOOK_INIT(socket_getpeersec_stream,
>                       selinux_socket_getpeersec_stream),
>       LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
> @@ -6113,6 +6119,7 @@ static struct security_hook_list selinux_hooks[] = {
>       LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
>       LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
>       LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
> +     LSM_HOOK_INIT(netlbl_changed, selinux_netlbl_changed),
>  
>  #ifdef CONFIG_SECURITY_NETWORK_XFRM
>       LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
> @@ -6145,6 +6152,11 @@ static struct security_hook_list selinux_hooks[] = {
>  #endif
>  };
>  
> +/* dynamically registered/unregisterd */
> +static struct security_hook_list selinux_sock_hooks[] = {
> +     LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
> +};
> +
>  static __init int selinux_init(void)
>  {
>       if (!security_module_enable("selinux")) {
> @@ -6240,7 +6252,9 @@ static struct nf_hook_ops selinux_nf_ops[] = {
>  #endif       /* IPV6 */
>  };
>  
> -static int __init selinux_nf_ip_init(void)
> +static bool nf_hooks_registered;
> +
> +static int selinux_nf_ip_init(void)
>  {
>       int err;
>  
> @@ -6253,25 +6267,21 @@ static int __init selinux_nf_ip_init(void)
>       if (err)
>               panic("SELinux: nf_register_hooks: error %d\n", err);
>  
> +     nf_hooks_registered = true;
>       return 0;
>  }
>  
> -__initcall(selinux_nf_ip_init);
> -
> -#ifdef CONFIG_SECURITY_SELINUX_DISABLE
>  static void selinux_nf_ip_exit(void)
>  {
>       printk(KERN_DEBUG "SELinux:  Unregistering netfilter hooks\n");
>  
>       nf_unregister_hooks(selinux_nf_ops, ARRAY_SIZE(selinux_nf_ops));
> +     nf_hooks_registered = false;
>  }
> -#endif
>  
>  #else /* CONFIG_NETFILTER */
>  
> -#ifdef CONFIG_SECURITY_SELINUX_DISABLE
>  #define selinux_nf_ip_exit()
> -#endif
>  
>  #endif /* CONFIG_NETFILTER */
>  
> @@ -6300,8 +6310,8 @@ int selinux_disable(void)
>       /* Try to destroy the avc node cache */
>       avc_disable();
>  
> -     /* Unregister netfilter hooks. */
> -     selinux_nf_ip_exit();
> +     /* Unregister net hooks. */
> +     selinux_net_update();
>  
>       /* Unregister selinuxfs. */
>       exit_sel_fs();
> @@ -6309,3 +6319,45 @@ int selinux_disable(void)
>       return 0;
>  }
>  #endif
> +
> +DEFINE_MUTEX(selinux_net_mutex);
> +
> +static bool nf_hooks_required(void)
> +{
> +     return (selinux_secmark_enabled() || selinux_peerlbl_enabled() ||
> +             !selinux_policycap_netpeer) && selinux_enabled;
> +}
> +
> +static bool sock_hooks_required(void)
> +{
> +     return (!selinux_policycap_netpeer || selinux_secmark_enabled() ||
> +             selinux_peerlbl_enabled()) && selinux_enabled;
> +}
> +
> +static bool sock_hooks_registered;
> +
> +void selinux_net_update(void)
> +{
> +     if ((nf_hooks_required() == nf_hooks_registered) &&
> +         (sock_hooks_required() == sock_hooks_registered))
> +             return;
> +
> +     mutex_lock(&selinux_net_mutex);
> +     if (nf_hooks_required() != nf_hooks_registered) {
> +             if (!nf_hooks_registered)
> +                     selinux_nf_ip_init();
> +             else
> +                     selinux_nf_ip_exit();
> +     }
> +
> +     if (sock_hooks_required() != sock_hooks_registered) {
> +             if (!sock_hooks_registered)
> +                     security_add_hooks(selinux_sock_hooks,
> +                                        ARRAY_SIZE(selinux_sock_hooks));
> +             else
> +                     security_delete_hooks(selinux_sock_hooks,
> +                                           ARRAY_SIZE(selinux_sock_hooks));
> +             sock_hooks_registered = !sock_hooks_registered;
> +     }
> +     mutex_unlock(&selinux_net_mutex);
> +}
> diff --git a/security/selinux/include/security.h 
> b/security/selinux/include/security.h
> index 38feb55..0428ab4 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -261,6 +261,7 @@ extern void selinux_status_update_setenforce(int 
> enforcing);
>  extern void selinux_status_update_policyload(int seqno);
>  extern void selinux_complete_init(void);
>  extern int selinux_disable(void);
> +extern void selinux_net_update(void);
>  extern void exit_sel_fs(void);
>  extern struct path selinux_null;
>  extern struct vfsmount *selinuxfs_mount;
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index ebda973..c509018 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -2016,6 +2016,7 @@ static void security_load_policycaps(void)
>                                                 POLICYDB_CAPABILITY_OPENPERM);
>       selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps,
>                                                 
> POLICYDB_CAPABILITY_ALWAYSNETWORK);
> +     selinux_net_update();
>  }
>  
>  static int security_preserve_bools(struct policydb *p);
> diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
> index 56e354f..cc2b0d4 100644
> --- a/security/selinux/xfrm.c
> +++ b/security/selinux/xfrm.c
> @@ -112,6 +112,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx 
> **ctxp,
>  
>       *ctxp = ctx;
>       atomic_inc(&selinux_xfrm_refcount);
> +     selinux_net_update();
>       return 0;
>  
>  err:
> @@ -128,6 +129,7 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
>               return;
>  
>       atomic_dec(&selinux_xfrm_refcount);
> +     selinux_net_update();
>       kfree(ctx);
>  }
>  
> @@ -303,6 +305,7 @@ int selinux_xfrm_policy_clone(struct xfrm_sec_ctx 
> *old_ctx,
>       if (!new_ctx)
>               return -ENOMEM;
>       atomic_inc(&selinux_xfrm_refcount);
> +     selinux_net_update();
>       *new_ctxp = new_ctx;
>  
>       return 0;
> @@ -370,6 +373,7 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
>  
>       x->security = ctx;
>       atomic_inc(&selinux_xfrm_refcount);
> +     selinux_net_update();
>  out:
>       kfree(ctx_str);
>       return rc;

Reply via email to