pthread_mutex_unlock potentially cause invalid access

Jakub Jelinek jakub@redhat.com
Mon Feb 13 15:03:00 GMT 2012


On Mon, Feb 13, 2012 at 09:39:34AM -0500, Carlos O'Donell wrote:
> >    struct obj {
> >    pthread_mutex_t om;
> >        int refcnt;
> >        ...
> >    };
> >
> >    obj_done(struct obj *op)
> >    {
> >        pthread_mutex_lock(&op->om);
> >        if (--op->refcnt == 0) {
> >            pthread_mutex_unlock(&op->om);
> >    (A)     pthread_mutex_destroy(&op->om);
> >    (B)     free(op);
> >        } else
> >    (C)     pthread_mutex_unlock(&op->om);
> >    }
> >
> >    In this case obj is reference counted and obj_done() is called
> >    whenever a reference to the object is dropped. Implementations are
> >    required to allow an object to be destroyed and freed and potentially
> >    unmapped (for example, lines A and B) immediately after the object is
> >    unlocked (line C).
> > ------------------------------------------------------------------------
> >
> > In this example, (A) and (B) can be executed in middle of (C) execution.
> > Thus, problem can be happen even on a fully conforming program, no?
> 
> No. (A) and (B) can not be executed in the middle of (C).

It can, the reporter is correct, the bug can be either fixed by ensuring in
the generic code (pthread_mutex_*lock.c etc.) that
lll_unlock/lll_robust_unlock is always
called with either constant or some automatic variable as second argument
(i.e. initialize a temporary from the currently used macros, then pass that
down), or by adjusting all target's lll_unlock/lll_robust_unlock macros,
or by turning them into inline functions.  The atomic operation will act as
a compiler/CPU barrier, so all that is needed is to make sure the read
in the source doesn't happen after the sync operation.

	Jakub



More information about the Libc-alpha mailing list