Closed Bug 334448 Opened 18 years ago Closed 18 years ago

oom Crash in crmf_copy_cert_req_msg

Categories

(NSS :: Libraries, defect, P2)

3.11
All
Linux
defect

Tracking

(Not tracked)

RESOLVED FIXED
3.11.2

People

(Reporter: timeless, Assigned: alvolkov.bgs)

References

()

Details

(4 keywords, Whiteboard: CID 212)

Attachments

(2 files, 2 obsolete files)

found by coverity
Attachment #218791 - Flags: review?(nelson)
Comment on attachment 218791 [details] [diff] [review]
free arena if object isn't constructed

>     newReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
>     newReqMsg->poolp = poolp;
>     if (newReqMsg == NULL) {
>         goto loser;

As long as you're here, check for null /before/ dereferencing newReqMsg->poolp.

>     newReqMsg->pop = crmf_copy_pop(poolp, srcReqMsg->pop);
>     if (newReqMsg->pop == NULL) {
>         goto loser;

This is fine here, but looking in crmf_copy_pop it looks like it leaks newPOP if it hits any of the three "goto loser" cases.
Target Milestone: --- → 3.11.1
Priority: -- → P2
Hardware: PC → All
Comment on attachment 218791 [details] [diff] [review]
free arena if object isn't constructed


>     newReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
>     newReqMsg->poolp = poolp;
>     if (newReqMsg == NULL) {

Dan's right.  That crash has to be fixed.  This patch didn't address that.

>  loser:
>     if (newReqMsg != NULL) {
>-        CRMF_DestroyCertReqMsg(newReqMsg);
>+        if (newReqMsg->certReq) {
>+            CRMF_DestroyCertReqMsg(newReqMsg);
>+        } else {
>+            PORT_FreeArena(poolp, PR_TRUE);
>+        }

The right way to destroy a CertReqMsg is to call CRMF_DestroyCertReqMsg, 
even if the CertReqMsg is incomplete.  If CRMF_DestroyCertReqMsg crashes
when the CertReqMsg is incomplete, then the patch should fix THAT, rather
than incorporate some of the logic that belongs in CRMF_DestroyCertReqMsg
into every one of its callers.
Attachment #218791 - Flags: review?(nelson) → review-
> >     newReqMsg->pop = crmf_copy_pop(poolp, srcReqMsg->pop);
> >     if (newReqMsg->pop == NULL) {
> >         goto loser;
> 
> This is fine here, but looking in crmf_copy_pop it looks like it leaks newPOP
> if it hits any of the three "goto loser" cases.
> 
Yes, the newPOP object leaks in crmf_copy_pop. 

PORT_ArenaMark, PORT_ArenaUnmark, PORT_ArenaRelease should be used in the function.
Attached patch fix for crash and some leaks (obsolete) — Splinter Review
Assignee: nobody → alexei.volkov.bugs
Status: NEW → ASSIGNED
Attachment #219376 - Flags: review?(nelson)
Comment on attachment 219376 [details] [diff] [review]
fix for crash and some leaks

r-
I see no calls to PORT_ArenaUnmark here.

Every ArenaMark has to be either Released or Unmarked.  
On some platforms, in some builds, a Mark acquires a lock.
That lock is release by calling either Release or Unmark.
Unmark removes the mark, and leaves the arena intact, and 
clears the lock.  Release frees anything allocating since the 
mark was made, removes the mark, and clears the lock.
Attachment #219376 - Flags: review?(nelson) → review-
Attached patch Be more conservative with pool. (obsolete) — Splinter Review
Modification to the previous patch: PORT_ArenaUnmark is added.
Attachment #219376 - Attachment is obsolete: true
Attachment #219767 - Flags: review?(nelson)
Comment on attachment 219767 [details] [diff] [review]
Be more conservative with pool.

This patch is fine, as far as it goes, but it doesn't address the
original OOM crash.  Here's the change that's needed for that.

>     newReqMsg = PORT_ArenaZNew(poolp, CRMFCertReqMsg);
>-    newReqMsg->poolp = poolp;
>     if (newReqMsg == NULL) {
>         goto loser;
>+    newReqMsg->poolp = poolp;
Attachment #219767 - Attachment description: fix → Be more conservative with pool.
Comment on attachment 219767 [details] [diff] [review]
Be more conservative with pool.

r- because it doesn't prevent the oom crash.
Otherwise it's OK.
Attachment #219767 - Flags: review?(nelson) → review-
I think moving pool assignment below "if" is not enough. When failure occures at 517, we still have crash in CRMF_DestroyCertReqMsg function.

517     newReqMsg->certReq = crmf_copy_cert_request(poolp, srcReqMsg->certReq);
518     if (newReqMsg->certReq == NULL) {
519         goto loser;
520     }


This is why the third patch has changes to CRMF_DestroyCertReqMsg function.
Attachment #219767 - Attachment is obsolete: true
Attachment #220067 - Flags: review?(nelson)
Comment on attachment 220067 [details] [diff] [review]
address the root issue of the bug

r=nelson for the 3.11 branch (not 3.11.1 branch) and the trunk.
I think this patch is no less correct than the old code in all
respects, but as I review the patched code, there are still a few
areas where the original code seems, uh, suspicious.  

So, IMO, it's ok to check in these changes (on the branches 
indicated above), but before marking the bug resolved/fixed there
might be a few more changes worth consideration.


>Index: crmfreq.c

> SECStatus 
> CRMF_DestroyCertReqMsg(CRMFCertReqMsg *inCertReqMsg)
> {
>     PORT_Assert(inCertReqMsg != NULL && inCertReqMsg->poolp != NULL);

That assertion should be followed by an if statement that detects 
those conditions and deal with them gracefully in non-debug builds,
e.g. set an error code and return SECFailure.

>-    if (!inCertReqMsg->isDecoded) {
>+    if (!inCertReqMsg->isDecoded && inCertReqMsg->certReq) {
>         if (inCertReqMsg->certReq->certTemplate.extensions != NULL) {
> 	    PORT_Free(inCertReqMsg->certReq->certTemplate.extensions);
> 	}
> 	if (inCertReqMsg->certReq->controls != NULL) {
> 	    PORT_Free(inCertReqMsg->certReq->controls);
> 	}
>     }
>     PORT_FreeArena(inCertReqMsg->poolp, PR_TRUE);
>     return SECSuccess;
> }

The above block is a part that seems suspicious.  Cert request messages
can be either (a) locally generated (to be DER encoded and then sent off 
to a remote server) or (b) received in the server from a remote client and 
then DER decoded.  IOW, the message can be either input to encoder or output
of decoder. The "isDecoded" flag serves to tell us which case we're dealing 
with on this stack.  

The decoded case always implies that the decoded parts are in an arena pool 
(because the decoder always decodes into a pool).  The code here seems to be 
saying: if we're in a pool, and we're decoded, then explicitly free the 
extensions (rather than implicitly freeing them when the pool is freed).  
That's suspicious.  It might be right (in which case it must be that the 
extensions and controls were not allocated from the pool), but there should 
be some comments explaining that, if so.
Attachment #220067 - Flags: review?(nelson) → review+
Target Milestone: 3.11.1 → 3.11.2
Status: ASSIGNED → RESOLVED
Closed: 18 years ago
Resolution: --- → FIXED
CID 212
Whiteboard: CID 212
should this be considered for fixing in firefox 2.0.0.4?
Flags: blocking1.8.1.4?
Flags: blocking1.8.1.4?
Group: security
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: