NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/44472: opencrypto compression MP-problem - value gets overwriten
>Number: 44472
>Category: kern
>Synopsis: opencrypto compression MP-problem - value gets overwriten
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Jan 27 11:35:01 +0000 2011
>Originator: Dr. Wolfgang Stukenbrock
>Release: NetBSD 5.1
>Organization:
Dr. Nagler & Company GmbH
>Environment:
System: NetBSD test-s0 4.0 NetBSD 4.0 (NSW-WS) #0: Tue Aug 17 17:28:09 CEST
2010 wgstuken@test-s0:/usr/src/sys/arch/amd64/compile/NSW-WS amd64
Architecture: x86_64
Machine: amd64
>Description:
The software implementation of opencrypto uses sessions to store
prepared data - e.g.
prepared key-information. This is stored in a "struct swcr_data" for
each step fot the
procession.
Now it is possible, that the same session is called multiple times with
the same
"struct swcr_data" structures on different CPU's.
In the network (FAST_)IPSEC processing session based information is
stored in the SAV-entries
and if more than one packet is gooing to use the same SAV it may be
used at the same
time by the interrupt-driver routine, the network-soft-interrupt and a
socket send call.
For ESP and AH this is OK, because the prepared data in "struct
swcr_data" is read-only
during work.
But for compression/decompression the resulting size is stored in the
field "SW_size" of this
structure and taken from there a few statements later again by an upper
lever routine.
If now two CPU's are dooing this at the same time, the extracted result
is wrong from one of
them.
>How-To-Repeat:
not easy - under very heavy load with forwarding and local traffic that
is
routed through an ipsec tunnel with compression (esp is optional for
this problem)
you will get sometimes a "strange" crash with a NULL pointer and/or
missing
data in packets - e.g. in ip_forward() while extracting the first 68
bytes.
I've got best reproducability by sending data from a Solaris10 system
via an NetBSD 4.0
system that is one tunnel endpoint to the NetBSD 5.1 system. But it
still runs for a
while before crashing.
>Fix:
This problem was hard to find but is easy to fix ...
Simply to not use any data field in "struct swcr_data" for storing data
while processing
a request. This field is used only by swcr_compdec() to return the
resulting length and it
is static to cryptosoft.c. So we can add another parameter to return
the value and eleminate
SW_size from the "struct swcr_data".
remark: the field SW_crc is completly unused and is removed by this
patch from the struct
definition too.
The following patch will fix for
/usr/src/sys/opencrypto/cryptosoft.[ch] this problem.
===================================================================
RCS file: RCS/cryptosoft.c,v
retrieving revision 1.1
diff -u -r1.1 cryptosoft.c
--- cryptosoft.c 2011/01/27 09:40:49 1.1
+++ cryptosoft.c 2011/01/27 09:47:24
@@ -61,7 +61,7 @@
: cuio_copydata((struct uio *)a,b,c,d)
static int swcr_encdec(struct cryptodesc *, struct swcr_data *, void *, int);
-static int swcr_compdec(struct cryptodesc *, struct swcr_data *, void *, int);
+static int swcr_compdec(struct cryptodesc *, struct swcr_data *, void *, int,
int *);
static int swcr_process(void *, struct cryptop *, int);
static int swcr_newsession(void *, u_int32_t *, struct cryptoini *);
static int swcr_freesession(void *, u_int64_t);
@@ -513,7 +513,7 @@
*/
static int
swcr_compdec(struct cryptodesc *crd, struct swcr_data *sw,
- void *buf, int outtype)
+ void *buf, int outtype, int *res_size)
{
u_int8_t *data, *out;
const struct swcr_comp_algo *cxf;
@@ -544,7 +544,7 @@
/* Copy back the (de)compressed data. m_copyback is
* extending the mbuf as necessary.
*/
- sw->sw_size = result;
+ *res_size = (int)result;
/* Check the compressed size when doing compression */
if (crd->crd_flags & CRD_F_COMP) {
if (result > crd->crd_len) {
@@ -986,10 +986,8 @@
case CRYPTO_GZIP_COMP:
DPRINTF(("swcr_process: compdec for %d\n", sw->sw_alg));
if ((crp->crp_etype = swcr_compdec(crd, sw,
- crp->crp_buf, type)) != 0)
+ crp->crp_buf, type, &crp->crp_olen)) != 0)
goto done;
- else
- crp->crp_olen = (int)sw->sw_size;
break;
default:
===================================================================
RCS file: RCS/cryptosoft.h,v
retrieving revision 1.1
diff -u -r1.1 cryptosoft.h
--- cryptosoft.h 2011/01/27 09:40:49 1.1
+++ cryptosoft.h 2011/01/27 09:42:40
@@ -40,8 +40,6 @@
const struct swcr_enc_xform *SW_exf;
} SWCR_ENC;
struct {
- u_int32_t SW_size;
- u_int32_t SW_crc;
const struct swcr_comp_algo *SW_cxf;
} SWCR_COMP;
} SWCR_UN;
@@ -52,7 +50,6 @@
#define sw_axf SWCR_UN.SWCR_AUTH.SW_axf
#define sw_kschedule SWCR_UN.SWCR_ENC.SW_kschedule
#define sw_exf SWCR_UN.SWCR_ENC.SW_exf
-#define sw_size SWCR_UN.SWCR_COMP.SW_size
#define sw_cxf SWCR_UN.SWCR_COMP.SW_cxf
struct swcr_data *sw_next;
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index