Re: [PATCH 2/2] auth_gss: unregister gss_domain when unloadingmodule

From: Trond Myklebust
Date: Sun Oct 29 2006 - 15:17:15 EST


On Sun, 2006-10-29 at 22:38 +0900, Akinobu Mita wrote:
> Reloading rpcsec_gss_krb5 or rpcsec_gss_spkm3 hit duplicate
> registration in svcauth_gss_register_pseudoflavor().
> (If DEBUG_PAGEALLOC is enabled, oops will happen at
> auth_domain_put() --> hlist_del() with uninitialized hlist_node)
>
> svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
> {
> ...
>
> test = auth_domain_lookup(name, &new->h);
> if (test != &new->h) { /* XXX Duplicate registration? */
> auth_domain_put(&new->h);
> /* dangling ref-count... */
> ...
> }
>
> This patch unregisters gss_domain and free it when unloading
> modules.
>
> - Define svcauth_gss_unregister_pseudoflavor()
> (doing the opposite of svcauth_gss_register_pseudoflavor())
>
> - Call svcauth_gss_unregister_pseudoflavor() in gss_mech_free()
>
> Cc: Andy Adamson <andros@xxxxxxxxxxxxxx>
> Cc: J. Bruce Fields <bfields@xxxxxxxxxxxxxx>
> Cc: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx>
> Signed-off-by: Akinobu Mita <akinobu.mita@xxxxxxxxx>
>
> net/sunrpc/auth_gss/gss_mech_switch.c | 4 ++++
> net/sunrpc/auth_gss/svcauth_gss.c | 6 +++---
> 2 files changed, 7 insertions(+), 3 deletions(-)
>
> Index: work-fault-inject/net/sunrpc/auth_gss/gss_mech_switch.c
> ===================================================================
> --- work-fault-inject.orig/net/sunrpc/auth_gss/gss_mech_switch.c
> +++ work-fault-inject/net/sunrpc/auth_gss/gss_mech_switch.c
> @@ -60,6 +60,9 @@ gss_mech_free(struct gss_api_mech *gm)
>
> for (i = 0; i < gm->gm_pf_num; i++) {
> pf = &gm->gm_pfs[i];
> + if (!pf->auth_domain_name)
> + continue;
> + svcauth_gss_unregister_pseudoflavor(pf->auth_domain_name);
> kfree(pf->auth_domain_name);
> pf->auth_domain_name = NULL;
> }
> @@ -93,8 +96,11 @@ gss_mech_svc_setup(struct gss_api_mech *
> goto out;
> status = svcauth_gss_register_pseudoflavor(pf->pseudoflavor,
> pf->auth_domain_name);
> - if (status)
> + if (status) {
> + kfree(pf->auth_domain_name);
> + pf->auth_domain_name = NULL;
> goto out;
> + }
> }
> return 0;
> out:
> Index: work-fault-inject/net/sunrpc/auth_gss/svcauth_gss.c
> ===================================================================
> --- work-fault-inject.orig/net/sunrpc/auth_gss/svcauth_gss.c
> +++ work-fault-inject/net/sunrpc/auth_gss/svcauth_gss.c
> @@ -765,10 +765,12 @@ svcauth_gss_register_pseudoflavor(u32 ps
>
> test = auth_domain_lookup(name, &new->h);
> if (test != &new->h) { /* XXX Duplicate registration? */
> - auth_domain_put(&new->h);
> - /* dangling ref-count... */
> - goto out;
> + WARN_ON(1);
> + stat = -EBUSY;
> + kfree(new->h.name);
> + goto out_free_dom;
> }
> + auth_domain_put(&new->h);
> return 0;
>
> out_free_dom:
> @@ -779,6 +781,19 @@ out:
>
> EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor);
>
> +void svcauth_gss_unregister_pseudoflavor(char *name)
> +{
> + struct auth_domain *dom;
> +
> + dom = auth_domain_find(name);
> + if (dom) {
> + auth_domain_put(dom);
> + auth_domain_put(dom);
> + }
> +}

Strictly speaking, if you want to be smp-safe, you probably need
something like the following:

dom = auth_domain_find(name);
if (dom) {
spin_lock(&auth_domain_lock);
if (!hlist_unhashed(dom->hash)) {
hlist_del_init(dom->hash);
spin_unlock(&auth_domain_lock);
auth_domain_put(dom);
} else
spin_unlock(&auth_domain_lock);
auth_domain_put(dom);
}

and then add a test for hlist_unhashed into auth_domain_put(). If not,
some other processor could race you inside
svcauth_gss_unregister_pseudoflavor.

However since all this is being done under the BKL, then your
alternative above might be sufficient. The only question then would be
why we need auth_domain_lock?

> +EXPORT_SYMBOL(svcauth_gss_unregister_pseudoflavor);
> +
> static inline int
> read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
> {
> Index: work-fault-inject/include/linux/sunrpc/svcauth_gss.h
> ===================================================================
> --- work-fault-inject.orig/include/linux/sunrpc/svcauth_gss.h
> +++ work-fault-inject/include/linux/sunrpc/svcauth_gss.h
> @@ -22,6 +22,7 @@
> int gss_svc_init(void);
> void gss_svc_shutdown(void);
> int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
> +void svcauth_gss_unregister_pseudoflavor(char *name);
>
> #endif /* __KERNEL__ */
> #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */

Cheers,
Trond
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/