This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug nptl/13690] New: pthread_mutex_unlock potentially cause invalid access
- From: "anemo at mba dot ocn.ne.jp" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sources dot redhat dot com
- Date: Tue, 14 Feb 2012 14:27:49 +0000
- Subject: [Bug nptl/13690] New: pthread_mutex_unlock potentially cause invalid access
- Auto-submitted: auto-generated
http://sourceware.org/bugzilla/show_bug.cgi?id=13690
Bug #: 13690
Summary: pthread_mutex_unlock potentially cause invalid access
Product: glibc
Version: 2.15
Status: NEW
Severity: normal
Priority: P2
Component: nptl
AssignedTo: drepper.fsp@gmail.com
ReportedBy: anemo@mba.ocn.ne.jp
Classification: Unclassified
It seems pthread_mutex_unlock() potentially cause invalid access on
most platforms (except for i386 and x86_64).
In nptl/pthread_mutex_unlock.c, lll_unlock() is called like this:
lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
And PTHREAD_MUTEX_PSHARED() is defined like this:
# define PTHREAD_MUTEX_PSHARED(m) \
((m)->__data.__kind & 128)
On most platforms, lll_unlock() is defined as a macro like this:
#define lll_unlock(lock, private) \
((void) ({ \
int *__futex = &(lock); \
int __val = atomic_exchange_rel (__futex, 0); \
if (__builtin_expect (__val > 1, 0)) \
lll_futex_wake (__futex, 1, private); \
}))
Thus, the lll_unlock() call in pthread_mutex_unlock.c will be expanded as:
int *__futex = &(mutex->__data.__lock);
int __val = atomic_exchange_rel (__futex, 0);
if (__builtin_expect (__val > 1, 0)) /* A */
lll_futex_wake (__futex, 1, ((mutex)->__data.__kind & 128)); /* B */
On point "A", the mutex is actually unlocked, so other threads can
lock the mutex, unlock, destroy and free. If the mutex was destroyed
and freed by other thread, reading '__kind' on point "B" is not valid.
This can happen with this example in pthread_mutex_destroy manual.
http://pubs.opengroup.org/onlinepubs/007904875/functions/pthread_mutex_destroy.html
------------------------------------------------------------------------
Destroying Mutexes
A mutex can be destroyed immediately after it is unlocked. For
example, consider the following code:
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.
It can happen in this way (explanation by KOSAKI-san):
1) Thread-1) atomic_exchange_rel(0)
2) preempt
3) Thread-2) call mutex_lock(). (ok, it's success)
4) Thread-2) call mutex_unlock()
5) Thread-2) call mutex_destroy()
6) Thread-2) free(mutex)
7) preempt
8) Thread-3) reuse memory of the mutex
9) preempt
10) Thread-1) dereference (mutex)->__data__.__kind
Copying __kind to a local variable before atomic_exchange_rel
will fix this.
--
Configure bugmail: http://sourceware.org/bugzilla/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.