Linux 2.6.28 and AEAD initialization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

with the Linux 2.6.28 kernel the first time xfrm_user.c:xfrm_add_sa()
is called with either "rfc4106(gcm(aes))" or "rfc4309(ccm(aes))",
an EEXIST error is returned and the installation of the IPsec SA fails.
A detailed analysis of the function calls (see trace added below) shows
that aead.c:crypto_lookup_aead() first loads

name         : rfc4106(gcm(aes))
driver       : rfc4106(gcm_base(ctr(aes-generic)))
module       : kernel
priority     : 100
refcnt       : 1
selftest     : passed
type         : nivaead
async        : yes
blocksize    : 1
ivsize       : 8
maxauthsize  : 16
geniv        : seqiv

Because of type=nivaead

    if (alg->cra_type == &crypto_aead_type)
        return alg;

crypto_lookup_aead() does not return the algorithm and falls through
to the statement

    return ERR_PTR(crypto_nivaead_default(alg, type, mask));

which makes another call to algapi.c;__crypto_register_alg().
Because the driver has already been installed

    ret = -EEXIST;
    ...

	if (crypto_is_larval(q)) {
	    if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
	        goto err;
	    continue;
	}

__crypto_register_alg() exits with the EEXIST error code.

The second time around the type=aead algorithm is additionally loaded

name         : rfc4106(gcm(aes))
driver       : rfc4106(gcm_base(ctr(aes-generic)))
module       : kernel
priority     : 100
refcnt       : 1
selftest     : passed
type         : aead
async        : yes
blocksize    : 1
ivsize       : 8
maxauthsize  : 16
geniv        : seqiv

name         : rfc4106(gcm(aes))
driver       : rfc4106(gcm_base(ctr(aes-generic)))
module       : kernel
priority     : 100
refcnt       : 1
selftest     : passed
type         : nivaead
async        : yes
blocksize    : 1
ivsize       : 8
maxauthsize  : 16
geniv        : seqiv

and the IPsec SAs can be set up successfully.

With the Linux 2.6.27.10 and earlier kernels the aead type is
loaded right at the beginning and no problems occur:

name         : rfc4106(gcm(aes))
driver       : rfc4106(gcm_base(ctr(aes-asm)))
module       : kernel
priority     : 200
refcnt       : 1
type         : aead
async        : yes
blocksize    : 1
ivsize       : 8
maxauthsize  : 16
geniv        : seqiv

name         : rfc4106(gcm(aes))
driver       : rfc4106(gcm_base(ctr(aes-asm)))
module       : kernel
priority     : 200
refcnt       : 1
type         : nivaead
async        : yes
blocksize    : 1
ivsize       : 8
maxauthsize  : 16
geniv        : seqiv

Best regards

Andreas

Trace of function calls returning EEXIST:

-----------------------------------------------------------------------------
net/xfrm/xfrm_user.c:xfrm_add_sa()
{
	x = xfrm_state_construct(p, attrs, &err);
	if (!x)
		return err;
}

-----------------------------------------------------------------------------
net/xfrm/xfrm_user.c:xfrm_state_construct()
{
	err = xfrm_init_state(x);
	if (err)
		goto error;
    ...
error:
	x->km.state = XFRM_STATE_DEAD;
	xfrm_state_put(x);
error_no_put:
	*errp = err;
	return NULL;
}

-----------------------------------------------------------------------------
net/xfrm/xfrm_state.c:xfrm_init_state()
{
	x->type = xfrm_get_type(x->id.proto, family);
	if (x->type == NULL)
		goto error;

	err = x->type->init_state(x);
	if (err)
		goto error;
    ...
error:
	return err;
}

-----------------------------------------------------------------------------
linux/net/xfrm.h:struct xfrm_type
{
	char			*description;
	struct module		*owner;
	__u8			proto;
	__u8			flags;
#define XFRM_TYPE_NON_FRAGMENT	1
#define XFRM_TYPE_REPLAY_PROT	2
#define XFRM_TYPE_LOCAL_COADDR	4
#define XFRM_TYPE_REMOTE_COADDR	8

	int			(*init_state)(struct xfrm_state *x);
	void			(*destructor)(struct xfrm_state *);
	int			(*input)(struct xfrm_state *, struct sk_buff *skb);
	int			(*output)(struct xfrm_state *, struct sk_buff *pskb);
	int			(*reject)(struct xfrm_state *, struct sk_buff *, struct flowi *);
	int			(*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **);
	/* Estimate maximal size of result of transformation of a dgram */
	u32			(*get_mtu)(struct xfrm_state *, int size);
};

-----------------------------------------------------------------------------
net/ipv4/esp4.c:esp_init_state()
{
	if (x->aead)
		err = esp_init_aead(x);
	}
	else
		err = esp_init_authenc(x);

	if (err)
		goto error;

}

-----------------------------------------------------------------------------
net/ipv4/esp4.c:esp_init_aead()
{
	struct esp_data *esp = x->data;
	struct crypto_aead *aead;
	int err;

	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
	err = PTR_ERR(aead);
	if (IS_ERR(aead))
		goto error;

error:
	return err;
}

-----------------------------------------------------------------------------
crypto/aead.c:crypto_alloc_aead()
{
		alg = crypto_lookup_aead(alg_name, type, mask);
		if (IS_ERR(alg)) {
			err = PTR_ERR(alg);
			goto err;
		}

err:
		if (err != -EAGAIN)
			break;
		if (signal_pending(current)) {
			err = -EINTR;
			break;
		}
	}

	return ERR_PTR(err);
}

-----------------------------------------------------------------------------
crypto/aead.c:crypto_lookup_aead()
{
	struct crypto_alg *alg;

	alg = crypto_alg_mod_lookup(name, type, mask);
	if (IS_ERR(alg))
		return alg;

    /* after the first call alg->cra_type is &crypto_nivaead_type */

	if (alg->cra_type == &crypto_aead_type)
		return alg;

	if (!alg->cra_aead.ivsize)
		return alg;

	return ERR_PTR(crypto_nivaead_default(alg, type, mask));
}

-----------------------------------------------------------------------------
crypto/aead.c:crypto_nivaead_default()
{
	if ((err = crypto_register_instance(tmpl, inst))) {
		tmpl->free(inst);
		goto put_tmpl;
	}

	/* Redo the lookup to use the instance we just registered. */
	err = -EAGAIN;

put_tmpl:
	crypto_tmpl_put(tmpl);
kill_larval:
	crypto_larval_kill(larval);
drop_larval:
	crypto_mod_put(larval);
out:
	crypto_mod_put(alg);
	return err;
}

-----------------------------------------------------------------------------
crypto/algapi.c:crypto_register_instance()
{
	larval = __crypto_register_alg(&inst->alg);
	if (IS_ERR(larval))
		goto unlock;

	hlist_add_head(&inst->list, &tmpl->instances);
	inst->tmpl = tmpl;

unlock:
	up_write(&crypto_alg_sem);

	err = PTR_ERR(larval);
	if (IS_ERR(larval))
		goto err;

	crypto_wait_for_test(larval);
	err = 0;

err:
	return err;
}

-----------------------------------------------------------------------------
crypto/algapi.c:__crypto_register_alg()
{
	ret = -EEXIST;
    ...

		if (crypto_is_larval(q)) {
			if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
				goto err;
			continue;
		}
}

Uff!

======================================================================
Andreas Steffen                         andreas.steffen@xxxxxxxxxxxxxx
strongSwan - the Linux VPN Solution!                www.strongswan.org
              Institute for Internet Technologies and Applications
University of Applied Sciences Rapperswil
CH-8640 Rapperswil (Switzerland)
===========================================================[ITA-HSR]==

--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux