mirror of
https://github.com/X11Libre/xserver.git
synced 2026-10-21 01:13:38 +00:00
miext/sync: Handle SIGBUS from truncated shm fences
A client can truncate the shared memory backing a DRI3/xshmfence sync
fence and cause SIGBUS when the server accesses it.
Register the mapping with busfault and wrap xshmfence accesses with
sigsetjmp so truncation unwinds safely, then discard the mapping while
keeping the fence XID.
Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
Assisted-by: AI
Closes: https://gitlab.freedesktop.org/xorg/xserver/-/work_items/1911
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2270>
(cherry picked from commit cd083d9659)
This commit is contained in:
parent
e4b68f9248
commit
84d53bf2f0
1 changed files with 128 additions and 0 deletions
|
|
@ -27,8 +27,10 @@
|
|||
#include <unistd.h>
|
||||
#include <X11/xshmfence.h>
|
||||
|
||||
#include "os/busfault.h"
|
||||
#include "os/osdep.h"
|
||||
|
||||
#include "os.h"
|
||||
#include "scrnintstr.h"
|
||||
#include "misync_priv.h"
|
||||
#include "misyncstr.h"
|
||||
|
|
@ -41,18 +43,106 @@ static DevPrivateKeyRec syncShmFencePrivateKey;
|
|||
typedef struct _SyncShmFencePrivate {
|
||||
struct xshmfence *fence;
|
||||
int fd;
|
||||
#ifdef BUSFAULT
|
||||
struct busfault *busfault;
|
||||
#endif
|
||||
} SyncShmFencePrivateRec, *SyncShmFencePrivatePtr;
|
||||
|
||||
#define SYNC_FENCE_PRIV(pFence) \
|
||||
(SyncShmFencePrivatePtr) dixLookupPrivate(&(pFence)->devPrivates, &syncShmFencePrivateKey)
|
||||
|
||||
#ifdef BUSFAULT
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
#define SYNC_SHM_FENCE_ACCESS(pFence, pPriv, call) \
|
||||
do { \
|
||||
if ((pPriv)->fence && (pPriv)->busfault) { \
|
||||
sigjmp_buf jmp; \
|
||||
if (sigsetjmp(jmp, 1) == 0) { \
|
||||
busfault_set_jmp((pPriv)->busfault, &jmp); \
|
||||
call; \
|
||||
busfault_set_jmp((pPriv)->busfault, NULL); \
|
||||
} else { \
|
||||
ErrorF("shared memory fence 0x%x truncated by client\n",\
|
||||
(unsigned int) (pFence)->sync.id); \
|
||||
miSyncShmFenceDiscard(pFence); \
|
||||
} \
|
||||
} else if ((pPriv)->fence) { \
|
||||
call; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* Cover the full mmap VMA; xshmfence maps a small object which the
|
||||
* kernel rounds up to a page. */
|
||||
static unsigned int pagesize;
|
||||
|
||||
static void
|
||||
initPageSize(void)
|
||||
{
|
||||
if (!pagesize) {
|
||||
#ifdef _SC_PAGESIZE
|
||||
pagesize = sysconf(_SC_PAGESIZE);
|
||||
#else
|
||||
pagesize = getpagesize();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
miSyncShmFenceDiscard(SyncFence *pFence)
|
||||
{
|
||||
SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence);
|
||||
|
||||
if (pPriv->busfault) {
|
||||
busfault_unregister(pPriv->busfault);
|
||||
pPriv->busfault = NULL;
|
||||
}
|
||||
if (pPriv->fence) {
|
||||
xshmfence_unmap_shm(pPriv->fence);
|
||||
pPriv->fence = NULL;
|
||||
close(pPriv->fd);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
miSyncShmFenceBusfaultNotify(void *context)
|
||||
{
|
||||
SyncFence *pFence = context;
|
||||
|
||||
ErrorF("shared memory fence 0x%x truncated by client\n",
|
||||
(unsigned int) pFence->sync.id);
|
||||
/* Drop the mapping; the fence XID remains and further ops use
|
||||
* the in-server SyncFence state only. */
|
||||
miSyncShmFenceDiscard(pFence);
|
||||
}
|
||||
|
||||
static void
|
||||
miSyncShmFenceRegisterBusfault(SyncFence *pFence)
|
||||
{
|
||||
SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence);
|
||||
|
||||
pPriv->busfault = busfault_register_mmap(pPriv->fence, pagesize,
|
||||
miSyncShmFenceBusfaultNotify,
|
||||
pFence);
|
||||
if (!pPriv->busfault)
|
||||
ErrorF("shared memory fence 0x%x could not register for truncation detection\n",
|
||||
(unsigned int) pFence->sync.id);
|
||||
}
|
||||
#endif /* BUSFAULT */
|
||||
|
||||
static void
|
||||
miSyncShmFenceSetTriggered(SyncFence * pFence)
|
||||
{
|
||||
SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence);
|
||||
|
||||
#ifdef BUSFAULT
|
||||
SYNC_SHM_FENCE_ACCESS(pFence, pPriv, xshmfence_trigger(pPriv->fence));
|
||||
#else
|
||||
if (pPriv->fence)
|
||||
xshmfence_trigger(pPriv->fence);
|
||||
#endif
|
||||
miSyncFenceSetTriggered(pFence);
|
||||
}
|
||||
|
||||
|
|
@ -61,8 +151,12 @@ miSyncShmFenceReset(SyncFence * pFence)
|
|||
{
|
||||
SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence);
|
||||
|
||||
#ifdef BUSFAULT
|
||||
SYNC_SHM_FENCE_ACCESS(pFence, pPriv, xshmfence_reset(pPriv->fence));
|
||||
#else
|
||||
if (pPriv->fence)
|
||||
xshmfence_reset(pPriv->fence);
|
||||
#endif
|
||||
miSyncFenceReset(pFence);
|
||||
}
|
||||
|
||||
|
|
@ -71,6 +165,24 @@ miSyncShmFenceCheckTriggered(SyncFence * pFence)
|
|||
{
|
||||
SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence);
|
||||
|
||||
#ifdef BUSFAULT
|
||||
if (pPriv->fence && pPriv->busfault) {
|
||||
sigjmp_buf jmp;
|
||||
if (sigsetjmp(jmp, 1) == 0) {
|
||||
Bool result;
|
||||
|
||||
busfault_set_jmp(pPriv->busfault, &jmp);
|
||||
result = xshmfence_query(pPriv->fence);
|
||||
busfault_set_jmp(pPriv->busfault, NULL);
|
||||
return result;
|
||||
} else {
|
||||
ErrorF("shared memory fence 0x%x truncated by client\n",
|
||||
(unsigned int) pFence->sync.id);
|
||||
miSyncShmFenceDiscard(pFence);
|
||||
return miSyncFenceCheckTriggered(pFence);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (pPriv->fence)
|
||||
return xshmfence_query(pPriv->fence);
|
||||
else
|
||||
|
|
@ -114,9 +226,15 @@ miSyncShmScreenDestroyFence(ScreenPtr pScreen, SyncFence * pFence)
|
|||
SyncShmFencePrivatePtr pPriv = SYNC_FENCE_PRIV(pFence);
|
||||
|
||||
if (pPriv->fence) {
|
||||
#ifdef BUSFAULT
|
||||
/* Wake waiters if possible; SIGBUS discards via longjmp. */
|
||||
SYNC_SHM_FENCE_ACCESS(pFence, pPriv, xshmfence_trigger(pPriv->fence));
|
||||
miSyncShmFenceDiscard(pFence);
|
||||
#else
|
||||
xshmfence_trigger(pPriv->fence);
|
||||
xshmfence_unmap_shm(pPriv->fence);
|
||||
close(pPriv->fd);
|
||||
#endif
|
||||
}
|
||||
miSyncScreenDestroyFence(pScreen, pFence);
|
||||
}
|
||||
|
|
@ -131,6 +249,9 @@ miSyncShmCreateFenceFromFd(ScreenPtr pScreen, SyncFence *pFence, int fd, Bool in
|
|||
fd = os_move_fd(fd);
|
||||
pPriv->fence = xshmfence_map_shm(fd);
|
||||
if (pPriv->fence) {
|
||||
#ifdef BUSFAULT
|
||||
miSyncShmFenceRegisterBusfault(pFence);
|
||||
#endif
|
||||
pPriv->fd = fd;
|
||||
return Success;
|
||||
}
|
||||
|
|
@ -154,6 +275,9 @@ miSyncShmGetFenceFd(ScreenPtr pScreen, SyncFence *pFence)
|
|||
close (pPriv->fd);
|
||||
return -1;
|
||||
}
|
||||
#ifdef BUSFAULT
|
||||
miSyncShmFenceRegisterBusfault(pFence);
|
||||
#endif
|
||||
}
|
||||
return pPriv->fd;
|
||||
}
|
||||
|
|
@ -177,6 +301,10 @@ Bool miSyncShmScreenInit(ScreenPtr pScreen)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#ifdef BUSFAULT
|
||||
initPageSize();
|
||||
#endif
|
||||
|
||||
funcs = miSyncGetScreenFuncs(pScreen);
|
||||
|
||||
funcs->CreateFence = miSyncShmScreenCreateFence;
|
||||
|
|
|
|||
Loading…
Reference in a new issue