RE: [PATCH] crypto: testmgr - Improve randomization of params for AEAD fuzz testing

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

 



Hi Eric,

Thanks for your feedback!

> -----Original Message-----
> From: Eric Biggers <ebiggers@xxxxxxxxxx>
> Sent: Sunday, July 28, 2019 7:31 PM
> To: Pascal van Leeuwen <pascalvanl@xxxxxxxxx>
> Cc: linux-crypto@xxxxxxxxxxxxxxx; herbert@xxxxxxxxxxxxxxxxxxx; davem@xxxxxxxxxxxxx; Pascal Van Leeuwen
> <pvanleeuwen@xxxxxxxxxxxxxx>
> Subject: Re: [PATCH] crypto: testmgr - Improve randomization of params for AEAD fuzz testing
> 
> Hi Pascal, thanks for the patch!
> 
> On Wed, Jul 24, 2019 at 11:35:17AM +0200, Pascal van Leeuwen wrote:
> > The probability of hitting specific input length corner cases relevant
> > for certain hardware driver(s) (specifically: inside-secure) was found
> > to be too low. Additionally, for authenc AEADs, the probability of
> > generating a *legal* key blob approached zero, i.e. most vectors
> > generated would only test the proper generation of a key blob error.
> >
> > This patch address both of these issues by improving the random
> > generation of data lengths (for the key, but also for the ICV output
> > and the AAD and plaintext inputs), making the random generation
> > individually tweakable on a per-ciphersuite basis.
> >
> > Finally, this patch enables fuzz testing for AEAD ciphersuites that do
> > not have a regular testsuite defined as it no longer depends on that
> > regular testsuite for figuring out the key size.
> >
> > Signed-off-by: Pascal van Leeuwen <pvanleeuwen@xxxxxxxxxxxxxx>
> 
> More comments below, but first I see some test failures and warnings with this
> patch applied:
> 
> alg: aead: authenc(hmac(sha1-generic),cbc-aes-aesni) decryption failed on test vector "random: alen=26 plen=594 authsize=20 klen=60";
> expected_error=-22, actual_error=-74, cfg="random: may_sleep use_digest src_divs=[33.6%@+12, 18.23%@+2452, 13.7%@+3761,
> 35.64%@+4019] iv_offset=43"
>
Interesting as the inside-secure driver also advertises this ciphersuite and does not generate such 
an error.  My guess is you get an error here because plen is not a multiple of 16 and this is CBC
(note to self: for block ciphers, emphasize legal lengths in the randomization ...), but the generic
implementation returns -EINVAL while this ciphersuite returns -EBADMSG.
Don't ask me what the actual correct error is in this case, I'm following generic with my driver.

> alg: aead: empty test suite for authenc(hmac(sha1-ni),rfc3686(ctr(aes-generic)))
> alg: aead: empty test suite for authenc(hmac(sha1-generic),rfc3686(ctr(aes-generic)))
> alg: aead: authenc(hmac(sha256-generic),cbc-aes-aesni) decryption failed on test vector "random: alen=14 plen=6237 authsize=32
> klen=72"; expected_error=-22, actual_error=-74, cfg="random: may_sleep use_digest src_divs=[93.90%@+2019, 4.74%@alignmask+4094,
> 1.36%@+21] dst_divs=[100.0%@+4000]"
>
Idem

> alg: aead: empty test suite for authenc(hmac(sha256-ni),rfc3686(ctr-aes-aesni))
> alg: aead: empty test suite for authenc(hmac(sha256-generic),rfc3686(ctr(aes-generic)))
> alg: aead: empty test suite for authenc(hmac(sha384-avx2),rfc3686(ctr-aes-aesni))
> alg: aead: empty test suite for authenc(hmac(sha384-generic),rfc3686(ctr(aes-generic)))

> alg: aead: authenc(hmac(sha512-generic),cbc-aes-aesni) decryption failed on test vector "random: alen=14 plen=406 authsize=12
> klen=104"; expected_error=-22, actual_error=-74, cfg="random: may_sleep use_digest src_divs=[41.41%@+852, 58.59%@+4011]
> dst_divs=[100.0%@alignmask+4017]"
>
Idem

> alg: aead: empty test suite for authenc(hmac(sha512-avx2),rfc3686(ctr-aes-aesni))
> alg: aead: empty test suite for authenc(hmac(sha512-generic),rfc3686(ctr(aes-generic)))
> 
> 
> Note that the "empty test suite" message shouldn't be printed (especially not at
> KERN_ERR level!) if it's working as intended.
> 
That's not my code, that was already there. I already got these messages before my 
modifications, for some ciphersuites. Of course if we don't want that, we can make
it a pr_warn pr_dbg?

> > ---
> >  crypto/testmgr.c | 269 +++++++++++++++++++++++++++++++++++++++++++------
> >  crypto/testmgr.h | 298 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 535 insertions(+), 32 deletions(-)
> >
> > diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> > index 2ba0c48..9c856d3 100644
> > --- a/crypto/testmgr.c
> > +++ b/crypto/testmgr.c
> > @@ -84,11 +84,24 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
> >  #define ENCRYPT 1
> >  #define DECRYPT 0
> >
> > +struct len_range_set {
> > +	const struct len_range_sel *lensel;
> > +	unsigned int count;
> > +};
> > +
> >  struct aead_test_suite {
> >  	const struct aead_testvec *vecs;
> >  	unsigned int count;
> >  };
> >
> > +struct aead_test_params {
> > +	struct len_range_set ckeylensel;
> > +	struct len_range_set akeylensel;
> > +	struct len_range_set authsizesel;
> > +	struct len_range_set aadlensel;
> > +	struct len_range_set ptxtlensel;
> > +};
> > +
> >  struct cipher_test_suite {
> >  	const struct cipher_testvec *vecs;
> >  	unsigned int count;
> > @@ -143,6 +156,10 @@ struct alg_test_desc {
> >  		struct akcipher_test_suite akcipher;
> >  		struct kpp_test_suite kpp;
> >  	} suite;
> > +
> > +	union {
> > +		struct aead_test_params aead;
> > +	} params;
> >  };
> 
> Why not put these new fields in the existing 'struct aead_test_suite'?
> 
> I don't see the point of the separate 'params' struct.  It just confuses things.
> 
Mostly because I'm not that familiar with C datastructures (I'm not a programmer
and this is pretty much my first serious experience with C), so I didn't know how
to do that / didn't want to break anything else :-)

So if you can provide some example on how to do that ...

> >
> >  static void hexdump(unsigned char *buf, unsigned int len)
> > @@ -189,9 +206,6 @@ static void testmgr_free_buf(char *buf[XBUFSIZE])
> >  	__testmgr_free_buf(buf, 0);
> >  }
> >
> > -#define TESTMGR_POISON_BYTE	0xfe
> > -#define TESTMGR_POISON_LEN	16
> > -
> >  static inline void testmgr_poison(void *addr, size_t len)
> >  {
> >  	memset(addr, TESTMGR_POISON_BYTE, len);
> > @@ -2035,6 +2049,19 @@ static int test_aead_vec(const char *driver, int enc,
> >  }
> >
> >  #ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
> > +/* Select a random length value from a list of range specs */
> 
> Perhaps mention the meaning of the -1 return value in this comment?
> 
Ok

> > +int random_lensel(const struct len_range_set *lens)
> 
> static
> 
Yes

> > +{
> > +	u32 i, sel = prandom_u32() % 1000;
> > +
> > +	for (i = 0; i < lens->count; i++)
> > +		if (sel < lens->lensel[i].threshold)
> > +			return (prandom_u32() % (lens->lensel[i].len_hi  -
> > +						 lens->lensel[i].len_lo + 1)) +
> > +				lens->lensel[i].len_lo;
> > +	return -1;
> > +}
> 
> This function isn't really AEAD-specific, so it seems it should be moved to near
> the other common fuzz test helpers like generate_random_length(), rather than be
> here where the AEAD-specific code is.
> 
It's currently only used for AEAD, but good point.

> > +
> >  /*
> >   * Generate an AEAD test vector from the given implementation.
> >   * Assumes the buffers in 'vec' were already allocated.
> > @@ -2043,44 +2070,83 @@ static void generate_random_aead_testvec(struct aead_request *req,
> >  					 struct aead_testvec *vec,
> >  					 unsigned int maxkeysize,
> >  					 unsigned int maxdatasize,
> > +					 const struct aead_test_params *lengths,
> >  					 char *name, size_t max_namelen)
> >  {
> >  	struct crypto_aead *tfm = crypto_aead_reqtfm(req);
> >  	const unsigned int ivsize = crypto_aead_ivsize(tfm);
> >  	unsigned int maxauthsize = crypto_aead_alg(tfm)->maxauthsize;
> > -	unsigned int authsize;
> > +	int authsize, clen, alen;
> >  	unsigned int total_len;
> >  	int i;
> >  	struct scatterlist src[2], dst;
> >  	u8 iv[MAX_IVLEN];
> >  	DECLARE_CRYPTO_WAIT(wait);
> >
> > -	/* Key: length in [0, maxkeysize], but usually choose maxkeysize */
> > -	vec->klen = maxkeysize;
> > -	if (prandom_u32() % 4 == 0)
> > -		vec->klen = prandom_u32() % (maxkeysize + 1);
> > -	generate_random_bytes((u8 *)vec->key, vec->klen);
> > +	alen = random_lensel(&lengths->akeylensel);
> > +	clen = random_lensel(&lengths->ckeylensel);
> > +	if ((alen >= 0) && (clen >= 0)) {
> > +		/* Corect blob header. TBD: Do we care about corrupting this? */
> > +#ifdef __LITTLE_ENDIAN
> > +		memcpy((void *)vec->key, "\x08\x00\x01\x00\x00\x00\x00\x10", 8);
> > +#else
> > +		memcpy((void *)vec->key, "\x00\x08\x00\x01\x00\x00\x00\x10", 8);
> > +#endif
> 
> Isn't this specific to "authenc" AEADs?  There needs to be something in the test
> suite that says an authenc formatted key is needed.
> 
It's under the condition of seperate authentication (alen) and cipher (clen) keys,
true AEAD's only have a single key. Because if they hadn't, they would also need
this kind of key blob thing (at least for consistency) and need this code.

> > +
> > +		/* Generate keys based on length templates */
> > +		generate_random_bytes((u8 *)(vec->key + 8), alen);
> > +		generate_random_bytes((u8 *)(vec->key + 8 + alen),
> > +				      clen);
> > +
> > +		vec->klen = 8 + alen + clen;
> > +	} else {
> > +		if (clen >= 0)
> > +			maxkeysize = clen;
> > +
> > +		vec->klen = maxkeysize;
> > +
> > +		/*
> > +		 * Key: length in [0, maxkeysize],
> > +		 * but usually choose maxkeysize
> > +		 */
> > +		if (prandom_u32() % 4 == 0)
> > +			vec->klen = prandom_u32() % (maxkeysize + 1);
> > +		generate_random_bytes((u8 *)vec->key, vec->klen);
> > +	}
> >  	vec->setkey_error = crypto_aead_setkey(tfm, vec->key, vec->klen);
> 
> The generate_random_aead_testvec() function is getting too long and complicated.
>
I'll ignore that comment to avoid starting some flame war ;-)

> It doesn't help that now the 'clen' variable is used for multiple different
> purposes (encryption key length and ciphertext length).  
>
Ah yeah, actually I had seperate variables for that which I at some point merged to
save some stack space. Blame it on me being oldschool ;-)

> Could you maybe factor out the key generation into a separate function?
> 
I could, if that would make people happy ...

> >
> >  	/* IV */
> >  	generate_random_bytes((u8 *)vec->iv, ivsize);
> >
> > -	/* Tag length: in [0, maxauthsize], but usually choose maxauthsize */
> > -	authsize = maxauthsize;
> > -	if (prandom_u32() % 4 == 0)
> > -		authsize = prandom_u32() % (maxauthsize + 1);
> > +	authsize = random_lensel(&lengths->authsizesel);
> > +	if (authsize < 0) {
> > +		/*
> > +		 * Tag length: in [0, maxauthsize],
> > +		 * but usually choose maxauthsize
> > +		 */
> > +		authsize = maxauthsize;
> > +		if (prandom_u32() % 4 == 0)
> > +			authsize = prandom_u32() % (maxauthsize + 1);
> > +	}
> >  	if (WARN_ON(authsize > maxdatasize))
> >  		authsize = maxdatasize;
> > -	maxdatasize -= authsize;
> >  	vec->setauthsize_error = crypto_aead_setauthsize(tfm, authsize);
> 
> Updating the comments to better match the code changes would be helpful too.
> E.g. here comments like the following would be helpful:
> 
>         /* Authentication tag size */
>         authsize = random_lensel(&lengths->authsizesel);
>         if (authsize < 0) {
>                 /*
>                  * No length hints for this algorithm.  Fall back to a random
>                  * value in [0, maxauthsize], but usually choose maxauthsize.
>                  */
>                 authsize = maxauthsize;
>                 if (prandom_u32() % 4 == 0)
>                         authsize = prandom_u32() % (maxauthsize + 1);
>         }
> 
Agree

> >
> >  	/* Plaintext and associated data */
> > -	total_len = generate_random_length(maxdatasize);
> > -	if (prandom_u32() % 4 == 0)
> > -		vec->alen = 0;
> > -	else
> > -		vec->alen = generate_random_length(total_len);
> > -	vec->plen = total_len - vec->alen;
> > +	alen = random_lensel(&lengths->aadlensel);
> > +	clen = random_lensel(&lengths->ptxtlensel);
> > +	maxdatasize -= authsize;
> > +	if ((alen < 0) || (clen < 0) || ((alen + clen) > maxdatasize)) {
> > +		total_len = generate_random_length(maxdatasize);
> > +		if (prandom_u32() % 4 == 0)
> > +			vec->alen = 0;
> > +		else
> > +			vec->alen = generate_random_length(total_len);
> > +		vec->plen = total_len - vec->alen;
> > +	} else {
> > +		vec->alen = alen;
> > +		vec->plen = clen;
> > +	}
> >  	generate_random_bytes((u8 *)vec->assoc, vec->alen);
> >  	generate_random_bytes((u8 *)vec->ptext, vec->plen);
> >
> > @@ -2133,7 +2199,7 @@ static int test_aead_vs_generic_impl(const char *driver,
> >  	char _generic_driver[CRYPTO_MAX_ALG_NAME];
> >  	struct crypto_aead *generic_tfm = NULL;
> >  	struct aead_request *generic_req = NULL;
> > -	unsigned int maxkeysize;
> > +	unsigned int maxkeysize, maxakeysize;
> >  	unsigned int i;
> >  	struct aead_testvec vec = { 0 };
> >  	char vec_name[64];
> > @@ -2203,9 +2269,27 @@ static int test_aead_vs_generic_impl(const char *driver,
> >  	 */
> >
> >  	maxkeysize = 0;
> > -	for (i = 0; i < test_desc->suite.aead.count; i++)
> > +	for (i = 0; i < test_desc->params.aead.ckeylensel.count; i++)
> >  		maxkeysize = max_t(unsigned int, maxkeysize,
> > -				   test_desc->suite.aead.vecs[i].klen);
> > +			test_desc->params.aead.ckeylensel.lensel[i].len_hi);
> > +
> > +	if (maxkeysize && test_desc->params.aead.akeylensel.count) {
> > +		/* authenc, explicit keylen ranges defined, use them */
> > +		maxakeysize = 0;
> > +		for (i = 0; i < test_desc->params.aead.akeylensel.count; i++)
> > +			maxakeysize = max_t(unsigned int, maxakeysize,
> > +			   test_desc->params.aead.akeylensel.lensel[i].len_hi);
> > +		maxkeysize = 8 + maxkeysize + maxakeysize;
> > +	} else if (!maxkeysize && test_desc->suite.aead.count) {
> > +		/* attempt to derive from test vectors */
> > +		for (i = 0; i < test_desc->suite.aead.count; i++)
> > +			maxkeysize = max_t(unsigned int, maxkeysize,
> > +					test_desc->suite.aead.vecs[i].klen);
> > +	} else {
> > +		pr_err("alg: aead: no key length templates or test vectors for %s - unable to fuzz\n",
> > +		       driver);
> > +		err = -EINVAL;
> > +	}
> 
> Can you put the "find the maxkeysize" logic in its own function, so it doesn't
> make test_aead_vs_generic_impl() longer and harder to understand?
> 
I could ... :-)

> >
> >  	vec.key = kmalloc(maxkeysize, GFP_KERNEL);
> >  	vec.iv = kmalloc(ivsize, GFP_KERNEL);
> > @@ -2220,6 +2304,7 @@ static int test_aead_vs_generic_impl(const char *driver,
> >  	for (i = 0; i < fuzz_iterations * 8; i++) {
> >  		generate_random_aead_testvec(generic_req, &vec,
> >  					     maxkeysize, maxdatasize,
> > +					     &test_desc->params.aead,
> >  					     vec_name, sizeof(vec_name));
> >  		generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
> >
> > @@ -2280,11 +2365,6 @@ static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
> >  	struct cipher_test_sglists *tsgls = NULL;
> >  	int err;
> >
> > -	if (suite->count <= 0) {
> > -		pr_err("alg: aead: empty test suite for %s\n", driver);
> > -		return -EINVAL;
> > -	}
> > -
> >  	tfm = crypto_alloc_aead(driver, type, mask);
> >  	if (IS_ERR(tfm)) {
> >  		pr_err("alg: aead: failed to allocate transform for %s: %ld\n",
> > @@ -2308,6 +2388,11 @@ static int alg_test_aead(const struct alg_test_desc *desc, const char *driver,
> >  		goto out;
> >  	}
> >
> > +	if (suite->count <= 0) {
> > +		pr_err("alg: aead: empty test suite for %s\n", driver);
> > +		goto aead_skip_testsuite;
> > +	}
> > +
> 
> This should be at most pr_warn(), and maybe not printed at all.  We already know
> that some authenc compositions don't have their own test vectors; kernel users
> can't do anything about it.
> 
See comment above, not my code but if everyone agrees I'm fine with the change.

> > diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> > index 6b459a6..105f2ce 100644
> > --- a/crypto/testmgr.h
> > +++ b/crypto/testmgr.h
> > @@ -28,6 +28,8 @@
> >  #include <linux/oid_registry.h>
> >
> >  #define MAX_IVLEN		32
> > +#define TESTMGR_POISON_BYTE	0xfe
> > +#define TESTMGR_POISON_LEN	16
> >
> >  /*
> >   * hash_testvec:	structure to describe a hash (message digest) test
> > @@ -176,6 +178,302 @@ struct kpp_testvec {
> >  static const char zeroed_string[48];
> >
> >  /*
> > + * length range declaration lo-hi plus selection threshold 0 - 1000
> > + */
> > +struct len_range_sel {
> > +	unsigned int len_lo;
> > +	unsigned int len_hi;
> > +	unsigned int threshold;
> > +};
> > +
> > +/*
> > + * List of length ranges sorted on increasing threshold
> > + *
> > + * 25% of each of the legal key sizes (128, 192, 256 bits)
> > + * plus 25% of illegal sizes in between 0 and 1024 bits.
> > + */
> > +static const struct len_range_sel aes_klen_template[] = {
> > +	{
> > +	.len_lo = 0,
> > +	.len_hi = 15,
> > +	.threshold = 25,
> > +	}, {
> > +	.len_lo = 16,
> > +	.len_hi = 16,
> > +	.threshold = 325,
> > +	}, {
> > +	.len_lo = 17,
> > +	.len_hi = 23,
> > +	.threshold = 350,
> > +	}, {
> > +	.len_lo = 24,
> > +	.len_hi = 24,
> > +	.threshold = 650,
> > +	}, {
> > +	.len_lo = 25,
> > +	.len_hi = 31,
> > +	.threshold = 675,
> > +	}, {
> > +	.len_lo = 32,
> > +	.len_hi = 32,
> > +	.threshold = 975,
> > +	}, {
> > +	.len_lo = 33,
> > +	.len_hi = 128,
> > +	.threshold = 1000,
> > +	}
> > +};
> 
> Can you please move these to be next to the test vectors for each algorithm, so
> things are kept in one place for each algorithm?
> 
Actually, these are supposed to be generic, to be shared across multiple
test vectors. So what do you think would be the best place for them?

> Also, perhaps these should use the convention '.proportion_of_total', like
> 'struct testvec_config' already does, rather than '.threshold'?  That would be
> more consistent with the existing test code, and would also make it slightly
> easier to change the probabilities later.
> 
I'm not quite sure if its the same thing. If someone can acknowledge that it is,
I could give it the same name. But otherwise, that would just be confusing ...

> E.g. if someone wanted to increase the probability of the first case and
> decrease the probability of the last case, then with the '.threshold' convention
> they'd have to change for every entry, but with the '.proportion_of_total'
> convention they'd only have to change the first and last entries.
> 
Oh, you are suggesting to change the whole mechanism, not just the name.
Honestly, I didn't like the proportion_of_total mechanism because it 
requires you to parse the data twice. Again, I'm oldschool so I try to provide
my data in such a form that it requires the least amount of actual processing.

> > +
> > +/* 90% legal keys of size 8, rest illegal between 0 and 32 */
> > +static const struct len_range_sel des_klen_template[] = {
> > +	{
> > +	.len_lo = 0,
> > +	.len_hi = 7,
> > +	.threshold = 50,
> > +	}, {
> > +	.len_lo = 8,
> > +	.len_hi = 8,
> > +	.threshold = 950,
> > +	}, {
> > +	.len_lo = 9,
> > +	.len_hi = 32,
> > +	.threshold = 1000,
> > +	}
> > +};
> > +
> > +/* 90% legal keys of size 24, rest illegal between 0 and 32 */
> > +static const struct len_range_sel des3_klen_template[] = {
> > +	{
> > +	.len_lo = 0,
> > +	.len_hi = 23,
> > +	.threshold = 50,
> > +	}, {
> > +	.len_lo = 24,
> > +	.len_hi = 24,
> > +	.threshold = 950,
> > +	}, {
> > +	.len_lo = 25,
> > +	.len_hi = 32,
> > +	.threshold = 1000,
> > +	}
> > +};
> > +
> > +/*
> > + * For HMAC's, favour the actual digest size for both key
> > + * size and authenticator size, but do verify some tag
> > + * truncation cases and some larger keys, including keys
> > + * exceeding the block size.
> > + */
> > +
> > +static const struct len_range_sel md5_klen_template[] = {
> 
> This really should be called "hmac_md5_klen", since md5 by itself is unkeyed.
> 
> Likewise for sha1, sha256, etc.
> 
Good point

> > +	{
> > +	.len_lo = 0, /* Allow 0 here? */
> > +	.len_hi = 15,
> > +	.threshold = 50,
> > +	}, {
> > +	.len_lo = 16,
> > +	.len_hi = 16,
> > +	.threshold = 950,
> > +	}, {
> > +	.len_lo = 17,
> > +	.len_hi = 256,
> > +	.threshold = 1000,
> > +	}
> > +};
> > +
> > +static const struct len_range_sel md5_alen_template[] = {
> 
> Likewise here: it should be "hmac_md5".
> 
Idem

> Also, "alen" is used elsewhere in the test code, including in the test vectors
> themselves, to mean the associated data length, *not* the authentication tag
> length.  But here these lengths are for authentication tags.  So please use
> "authsize".  Likewise for sha1, sha256, etc.
> 
Fair enough

> > +
> > +static const struct len_range_sel aead_alen_template[] = {
> > +	{
> > +	.len_lo = 0,
> > +	.len_hi = 0,
> > +	.threshold = 200,
> > +	}, {
> > +	.len_lo = 1,
> > +	.len_hi = 32,
> > +	.threshold = 900,
> > +	}, {
> > +	.len_lo = 33,
> > +	.len_hi = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN,
> > +	.threshold = 1000,
> > +	}
> > +};
> 
> Is this for authenc or for all AEADs?  Likewise for aead_plen_template[].
> 
I believe these *could* be used for all AEAD's (that don't have specific limits on
AAD length, which some rfcxxxx AEAD's seem to have as I just learned recently).

> Again, "alen" => "authsize".
> 
Ok

> - Eric

Regards,
Pascal van Leeuwen
Silicon IP Architect, Multi-Protocol Engines @ Verimatrix
www.insidesecure.com




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

  Powered by Linux