xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

shm.c (46430B)


      1 /************************************************************
      2 
      3 Copyright 1989, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 ********************************************************/
     26 
     27 /* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */
     28 
     29 #define SHM
     30 
     31 #ifdef HAVE_DIX_CONFIG_H
     32 #include <dix-config.h>
     33 #endif
     34 
     35 #include <sys/types.h>
     36 #include <sys/ipc.h>
     37 #include <sys/shm.h>
     38 #ifdef HAVE_MEMFD_CREATE
     39 #include <sys/mman.h>
     40 #endif
     41 #include <unistd.h>
     42 #include <sys/stat.h>
     43 #include <fcntl.h>
     44 #include <X11/X.h>
     45 #include <X11/Xproto.h>
     46 #include "misc.h"
     47 #include "os.h"
     48 #include "dixstruct.h"
     49 #include "resource.h"
     50 #include "scrnintstr.h"
     51 #include "windowstr.h"
     52 #include "pixmapstr.h"
     53 #include "gcstruct.h"
     54 #include "extnsionst.h"
     55 #include "servermd.h"
     56 #include "shmint.h"
     57 #include "xace.h"
     58 #include <X11/extensions/shmproto.h>
     59 #include <X11/Xfuncproto.h>
     60 #include <sys/mman.h>
     61 #include "protocol-versions.h"
     62 #include "busfault.h"
     63 
     64 /* Needed for Solaris cross-zone shared memory extension */
     65 #ifdef HAVE_SHMCTL64
     66 #include <sys/ipc_impl.h>
     67 #define SHMSTAT(id, buf)	shmctl64(id, IPC_STAT64, buf)
     68 #define SHMSTAT_TYPE 		struct shmid_ds64
     69 #define SHMPERM_TYPE 		struct ipc_perm64
     70 #define SHM_PERM(buf) 		buf.shmx_perm
     71 #define SHM_SEGSZ(buf)		buf.shmx_segsz
     72 #define SHMPERM_UID(p)		p->ipcx_uid
     73 #define SHMPERM_CUID(p)		p->ipcx_cuid
     74 #define SHMPERM_GID(p)		p->ipcx_gid
     75 #define SHMPERM_CGID(p)		p->ipcx_cgid
     76 #define SHMPERM_MODE(p)		p->ipcx_mode
     77 #define SHMPERM_ZONEID(p)	p->ipcx_zoneid
     78 #else
     79 #define SHMSTAT(id, buf) 	shmctl(id, IPC_STAT, buf)
     80 #define SHMSTAT_TYPE 		struct shmid_ds
     81 #define SHMPERM_TYPE 		struct ipc_perm
     82 #define SHM_PERM(buf) 		buf.shm_perm
     83 #define SHM_SEGSZ(buf)		buf.shm_segsz
     84 #define SHMPERM_UID(p)		p->uid
     85 #define SHMPERM_CUID(p)		p->cuid
     86 #define SHMPERM_GID(p)		p->gid
     87 #define SHMPERM_CGID(p)		p->cgid
     88 #define SHMPERM_MODE(p)		p->mode
     89 #endif
     90 
     91 #ifdef PANORAMIX
     92 #include "panoramiX.h"
     93 #include "panoramiXsrv.h"
     94 #endif
     95 
     96 #include "extinit.h"
     97 
     98 typedef struct _ShmScrPrivateRec {
     99     CloseScreenProcPtr CloseScreen;
    100     ShmFuncsPtr shmFuncs;
    101     DestroyPixmapProcPtr destroyPixmap;
    102 } ShmScrPrivateRec;
    103 
    104 static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS);
    105 static int ShmDetachSegment(void *value, XID shmseg);
    106 static void ShmResetProc(ExtensionEntry *extEntry);
    107 static void SShmCompletionEvent(xShmCompletionEvent *from,
    108                                 xShmCompletionEvent *to);
    109 
    110 static Bool ShmDestroyPixmap(PixmapPtr pPixmap);
    111 
    112 static unsigned char ShmReqCode;
    113 int ShmCompletionCode;
    114 int BadShmSegCode;
    115 RESTYPE ShmSegType;
    116 static ShmDescPtr Shmsegs;
    117 static Bool sharedPixmaps;
    118 static DevPrivateKeyRec shmScrPrivateKeyRec;
    119 
    120 #define shmScrPrivateKey (&shmScrPrivateKeyRec)
    121 static DevPrivateKeyRec shmPixmapPrivateKeyRec;
    122 
    123 #define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec)
    124 static ShmFuncs miFuncs = { NULL, NULL };
    125 static ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL };
    126 
    127 #define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey))
    128 
    129 #define VERIFY_SHMSEG(shmseg,shmdesc,client) \
    130 { \
    131     int tmprc; \
    132     tmprc = dixLookupResourceByType((void **)&(shmdesc), shmseg, ShmSegType, \
    133                                     client, DixReadAccess); \
    134     if (tmprc != Success) \
    135 	return tmprc; \
    136 }
    137 
    138 #define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \
    139 { \
    140     VERIFY_SHMSEG(shmseg, shmdesc, client); \
    141     if ((offset & 3) || (offset > shmdesc->size)) \
    142     { \
    143 	client->errorValue = offset; \
    144 	return BadValue; \
    145     } \
    146     if (needwrite && !shmdesc->writable) \
    147 	return BadAccess; \
    148 }
    149 
    150 #define VERIFY_SHMSIZE(shmdesc,offset,len,client) \
    151 { \
    152     if ((offset + len) > shmdesc->size) \
    153     { \
    154 	return BadAccess; \
    155     } \
    156 }
    157 
    158 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__)
    159 
    160 static Bool badSysCall = FALSE;
    161 
    162 static void
    163 SigSysHandler(int signo)
    164 {
    165     badSysCall = TRUE;
    166 }
    167 
    168 static Bool
    169 CheckForShmSyscall(void)
    170 {
    171     void (*oldHandler) (int);
    172     int shmid = -1;
    173 
    174     /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */
    175     oldHandler = OsSignal(SIGSYS, SigSysHandler);
    176 
    177     badSysCall = FALSE;
    178     shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT);
    179 
    180     if (shmid != -1) {
    181         /* Successful allocation - clean up */
    182         shmctl(shmid, IPC_RMID, NULL);
    183     }
    184     else {
    185         /* Allocation failed */
    186         badSysCall = TRUE;
    187     }
    188     OsSignal(SIGSYS, oldHandler);
    189     return !badSysCall;
    190 }
    191 
    192 #define MUST_CHECK_FOR_SHM_SYSCALL
    193 
    194 #endif
    195 
    196 static Bool
    197 ShmCloseScreen(ScreenPtr pScreen)
    198 {
    199     ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
    200 
    201     pScreen->CloseScreen = screen_priv->CloseScreen;
    202     dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL);
    203     free(screen_priv);
    204     return (*pScreen->CloseScreen) (pScreen);
    205 }
    206 
    207 static ShmScrPrivateRec *
    208 ShmInitScreenPriv(ScreenPtr pScreen)
    209 {
    210     ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
    211 
    212     if (!screen_priv) {
    213         screen_priv = calloc(1, sizeof(ShmScrPrivateRec));
    214         screen_priv->CloseScreen = pScreen->CloseScreen;
    215         dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv);
    216         pScreen->CloseScreen = ShmCloseScreen;
    217     }
    218     return screen_priv;
    219 }
    220 
    221 static Bool
    222 ShmRegisterPrivates(void)
    223 {
    224     if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0))
    225         return FALSE;
    226     if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0))
    227         return FALSE;
    228     return TRUE;
    229 }
    230 
    231  /*ARGSUSED*/ static void
    232 ShmResetProc(ExtensionEntry * extEntry)
    233 {
    234     int i;
    235 
    236     for (i = 0; i < screenInfo.numScreens; i++)
    237         ShmRegisterFuncs(screenInfo.screens[i], NULL);
    238 }
    239 
    240 void
    241 ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
    242 {
    243     if (!ShmRegisterPrivates())
    244         return;
    245     ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
    246 }
    247 
    248 static Bool
    249 ShmDestroyPixmap(PixmapPtr pPixmap)
    250 {
    251     ScreenPtr pScreen = pPixmap->drawable.pScreen;
    252     ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen);
    253     void *shmdesc = NULL;
    254     Bool ret;
    255 
    256     if (pPixmap->refcnt == 1)
    257         shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey);
    258 
    259     pScreen->DestroyPixmap = screen_priv->destroyPixmap;
    260     ret = (*pScreen->DestroyPixmap) (pPixmap);
    261     screen_priv->destroyPixmap = pScreen->DestroyPixmap;
    262     pScreen->DestroyPixmap = ShmDestroyPixmap;
    263 
    264     if (shmdesc)
    265 	ShmDetachSegment(shmdesc, 0);
    266 
    267     return ret;
    268 }
    269 
    270 void
    271 ShmRegisterFbFuncs(ScreenPtr pScreen)
    272 {
    273     ShmRegisterFuncs(pScreen, &fbFuncs);
    274 }
    275 
    276 static int
    277 ProcShmQueryVersion(ClientPtr client)
    278 {
    279     xShmQueryVersionReply rep = {
    280         .type = X_Reply,
    281         .sharedPixmaps = sharedPixmaps,
    282         .sequenceNumber = client->sequence,
    283         .length = 0,
    284         .majorVersion = SERVER_SHM_MAJOR_VERSION,
    285         .minorVersion = SERVER_SHM_MINOR_VERSION,
    286         .uid = geteuid(),
    287         .gid = getegid(),
    288         .pixmapFormat = sharedPixmaps ? ZPixmap : 0
    289     };
    290 
    291     REQUEST_SIZE_MATCH(xShmQueryVersionReq);
    292 
    293     if (client->swapped) {
    294         swaps(&rep.sequenceNumber);
    295         swapl(&rep.length);
    296         swaps(&rep.majorVersion);
    297         swaps(&rep.minorVersion);
    298         swaps(&rep.uid);
    299         swaps(&rep.gid);
    300     }
    301     WriteToClient(client, sizeof(xShmQueryVersionReply), &rep);
    302     return Success;
    303 }
    304 
    305 /*
    306  * Simulate the access() system call for a shared memory segment,
    307  * using the credentials from the client if available.
    308  */
    309 static int
    310 shm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly)
    311 {
    312     int uid, gid;
    313     mode_t mask;
    314     int uidset = 0, gidset = 0;
    315     LocalClientCredRec *lcc;
    316 
    317     if (GetLocalClientCreds(client, &lcc) != -1) {
    318 
    319         if (lcc->fieldsSet & LCC_UID_SET) {
    320             uid = lcc->euid;
    321             uidset = 1;
    322         }
    323         if (lcc->fieldsSet & LCC_GID_SET) {
    324             gid = lcc->egid;
    325             gidset = 1;
    326         }
    327 
    328 #if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID)
    329         if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1)
    330             || (lcc->zoneid != SHMPERM_ZONEID(perm))) {
    331             uidset = 0;
    332             gidset = 0;
    333         }
    334 #endif
    335         FreeLocalClientCreds(lcc);
    336 
    337         if (uidset) {
    338             /* User id 0 always gets access */
    339             if (uid == 0) {
    340                 return 0;
    341             }
    342             /* Check the owner */
    343             if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) {
    344                 mask = S_IRUSR;
    345                 if (!readonly) {
    346                     mask |= S_IWUSR;
    347                 }
    348                 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
    349             }
    350         }
    351 
    352         if (gidset) {
    353             /* Check the group */
    354             if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) {
    355                 mask = S_IRGRP;
    356                 if (!readonly) {
    357                     mask |= S_IWGRP;
    358                 }
    359                 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
    360             }
    361         }
    362     }
    363     /* Otherwise, check everyone else */
    364     mask = S_IROTH;
    365     if (!readonly) {
    366         mask |= S_IWOTH;
    367     }
    368     return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1;
    369 }
    370 
    371 static int
    372 ProcShmAttach(ClientPtr client)
    373 {
    374     SHMSTAT_TYPE buf;
    375     ShmDescPtr shmdesc;
    376 
    377     REQUEST(xShmAttachReq);
    378 
    379     REQUEST_SIZE_MATCH(xShmAttachReq);
    380     LEGAL_NEW_RESOURCE(stuff->shmseg, client);
    381     if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
    382         client->errorValue = stuff->readOnly;
    383         return BadValue;
    384     }
    385     for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) {
    386         if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid)
    387             break;
    388     }
    389     if (shmdesc) {
    390         if (!stuff->readOnly && !shmdesc->writable)
    391             return BadAccess;
    392         shmdesc->refcnt++;
    393     }
    394     else {
    395         shmdesc = malloc(sizeof(ShmDescRec));
    396         if (!shmdesc)
    397             return BadAlloc;
    398 #ifdef SHM_FD_PASSING
    399         shmdesc->is_fd = FALSE;
    400 #endif
    401         shmdesc->addr = shmat(stuff->shmid, 0,
    402                               stuff->readOnly ? SHM_RDONLY : 0);
    403         if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) {
    404             free(shmdesc);
    405             return BadAccess;
    406         }
    407 
    408         /* The attach was performed with root privs. We must
    409          * do manual checking of access rights for the credentials
    410          * of the client */
    411 
    412         if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) {
    413             shmdt(shmdesc->addr);
    414             free(shmdesc);
    415             return BadAccess;
    416         }
    417 
    418         shmdesc->shmid = stuff->shmid;
    419         shmdesc->refcnt = 1;
    420         shmdesc->writable = !stuff->readOnly;
    421         shmdesc->size = SHM_SEGSZ(buf);
    422         shmdesc->next = Shmsegs;
    423         Shmsegs = shmdesc;
    424     }
    425     if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
    426         return BadAlloc;
    427     return Success;
    428 }
    429 
    430  /*ARGSUSED*/ static int
    431 ShmDetachSegment(void *value, /* must conform to DeleteType */
    432                  XID unused)
    433 {
    434     ShmDescPtr shmdesc = (ShmDescPtr) value;
    435     ShmDescPtr *prev;
    436 
    437     if (--shmdesc->refcnt)
    438         return TRUE;
    439 #if SHM_FD_PASSING
    440     if (shmdesc->is_fd) {
    441         if (shmdesc->busfault)
    442             busfault_unregister(shmdesc->busfault);
    443         munmap(shmdesc->addr, shmdesc->size);
    444     } else
    445 #endif
    446         shmdt(shmdesc->addr);
    447     for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next);
    448     *prev = shmdesc->next;
    449     free(shmdesc);
    450     return Success;
    451 }
    452 
    453 static int
    454 ProcShmDetach(ClientPtr client)
    455 {
    456     ShmDescPtr shmdesc;
    457 
    458     REQUEST(xShmDetachReq);
    459 
    460     REQUEST_SIZE_MATCH(xShmDetachReq);
    461     VERIFY_SHMSEG(stuff->shmseg, shmdesc, client);
    462     FreeResource(stuff->shmseg, RT_NONE);
    463     return Success;
    464 }
    465 
    466 /*
    467  * If the given request doesn't exactly match PutImage's constraints,
    468  * wrap the image in a scratch pixmap header and let CopyArea sort it out.
    469  */
    470 static void
    471 doShmPutImage(DrawablePtr dst, GCPtr pGC,
    472               int depth, unsigned int format,
    473               int w, int h, int sx, int sy, int sw, int sh, int dx, int dy,
    474               char *data)
    475 {
    476     PixmapPtr pPixmap;
    477 
    478     if (format == ZPixmap || (format == XYPixmap && depth == 1)) {
    479         pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth,
    480                                          BitsPerPixel(depth),
    481                                          PixmapBytePad(w, depth), data);
    482         if (!pPixmap)
    483             return;
    484         pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx,
    485                            dy);
    486         FreeScratchPixmapHeader(pPixmap);
    487     }
    488     else {
    489         GCPtr putGC = GetScratchGC(depth, dst->pScreen);
    490 
    491         if (!putGC)
    492             return;
    493 
    494         pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth,
    495                                                  CREATE_PIXMAP_USAGE_SCRATCH);
    496         if (!pPixmap) {
    497             FreeScratchGC(putGC);
    498             return;
    499         }
    500         ValidateGC(&pPixmap->drawable, putGC);
    501         (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w,
    502                                  h, 0,
    503                                  (format == XYPixmap) ? XYPixmap : ZPixmap,
    504                                  data);
    505         FreeScratchGC(putGC);
    506         if (format == XYBitmap)
    507             (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0,
    508                                            sw, sh, dx, dy, 1L);
    509         else
    510             (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0,
    511                                           sw, sh, dx, dy);
    512         (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap);
    513     }
    514 }
    515 
    516 static int
    517 ProcShmPutImage(ClientPtr client)
    518 {
    519     GCPtr pGC;
    520     DrawablePtr pDraw;
    521     long length;
    522     ShmDescPtr shmdesc;
    523 
    524     REQUEST(xShmPutImageReq);
    525 
    526     REQUEST_SIZE_MATCH(xShmPutImageReq);
    527     VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess);
    528     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client);
    529     if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse))
    530         return BadValue;
    531     if (stuff->format == XYBitmap) {
    532         if (stuff->depth != 1)
    533             return BadMatch;
    534         length = PixmapBytePad(stuff->totalWidth, 1);
    535     }
    536     else if (stuff->format == XYPixmap) {
    537         if (pDraw->depth != stuff->depth)
    538             return BadMatch;
    539         length = PixmapBytePad(stuff->totalWidth, 1);
    540         length *= stuff->depth;
    541     }
    542     else if (stuff->format == ZPixmap) {
    543         if (pDraw->depth != stuff->depth)
    544             return BadMatch;
    545         length = PixmapBytePad(stuff->totalWidth, stuff->depth);
    546     }
    547     else {
    548         client->errorValue = stuff->format;
    549         return BadValue;
    550     }
    551 
    552     /*
    553      * There's a potential integer overflow in this check:
    554      * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight,
    555      *                client);
    556      * the version below ought to avoid it
    557      */
    558     if (stuff->totalHeight != 0 &&
    559         length > (shmdesc->size - stuff->offset) / stuff->totalHeight) {
    560         client->errorValue = stuff->totalWidth;
    561         return BadValue;
    562     }
    563     if (stuff->srcX > stuff->totalWidth) {
    564         client->errorValue = stuff->srcX;
    565         return BadValue;
    566     }
    567     if (stuff->srcY > stuff->totalHeight) {
    568         client->errorValue = stuff->srcY;
    569         return BadValue;
    570     }
    571     if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) {
    572         client->errorValue = stuff->srcWidth;
    573         return BadValue;
    574     }
    575     if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) {
    576         client->errorValue = stuff->srcHeight;
    577         return BadValue;
    578     }
    579 
    580     if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) ||
    581          ((stuff->format != ZPixmap) &&
    582           (stuff->srcX < screenInfo.bitmapScanlinePad) &&
    583           ((stuff->format == XYBitmap) ||
    584            ((stuff->srcY == 0) &&
    585             (stuff->srcHeight == stuff->totalHeight))))) &&
    586         ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth))
    587         (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth,
    588                                stuff->dstX, stuff->dstY,
    589                                stuff->totalWidth, stuff->srcHeight,
    590                                stuff->srcX, stuff->format,
    591                                shmdesc->addr + stuff->offset +
    592                                (stuff->srcY * length));
    593     else
    594         doShmPutImage(pDraw, pGC, stuff->depth, stuff->format,
    595                       stuff->totalWidth, stuff->totalHeight,
    596                       stuff->srcX, stuff->srcY,
    597                       stuff->srcWidth, stuff->srcHeight,
    598                       stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset);
    599 
    600     if (stuff->sendEvent) {
    601         xShmCompletionEvent ev = {
    602             .type = ShmCompletionCode,
    603             .drawable = stuff->drawable,
    604             .minorEvent = X_ShmPutImage,
    605             .majorEvent = ShmReqCode,
    606             .shmseg = stuff->shmseg,
    607             .offset = stuff->offset
    608         };
    609         WriteEventsToClient(client, 1, (xEvent *) &ev);
    610     }
    611 
    612     return Success;
    613 }
    614 
    615 static int
    616 ProcShmGetImage(ClientPtr client)
    617 {
    618     DrawablePtr pDraw;
    619     long lenPer = 0, length;
    620     Mask plane = 0;
    621     xShmGetImageReply xgi;
    622     ShmDescPtr shmdesc;
    623     VisualID visual = None;
    624     RegionPtr pVisibleRegion = NULL;
    625     int rc;
    626 
    627     REQUEST(xShmGetImageReq);
    628 
    629     REQUEST_SIZE_MATCH(xShmGetImageReq);
    630     if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
    631         client->errorValue = stuff->format;
    632         return BadValue;
    633     }
    634     rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
    635     if (rc != Success)
    636         return rc;
    637     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
    638     if (pDraw->type == DRAWABLE_WINDOW) {
    639         if (   /* check for being viewable */
    640                !((WindowPtr) pDraw)->realized ||
    641                /* check for being on screen */
    642                pDraw->x + stuff->x < 0 ||
    643                pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width
    644                || pDraw->y + stuff->y < 0 ||
    645                pDraw->y + stuff->y + (int) stuff->height >
    646                pDraw->pScreen->height ||
    647                /* check for being inside of border */
    648                stuff->x < -wBorderWidth((WindowPtr) pDraw) ||
    649                stuff->x + (int) stuff->width >
    650                wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
    651                stuff->y < -wBorderWidth((WindowPtr) pDraw) ||
    652                stuff->y + (int) stuff->height >
    653                wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
    654             return BadMatch;
    655         visual = wVisual(((WindowPtr) pDraw));
    656         if (pDraw->type == DRAWABLE_WINDOW)
    657             pVisibleRegion = &((WindowPtr) pDraw)->borderClip;
    658         pDraw->pScreen->SourceValidate(pDraw, stuff->x, stuff->y,
    659                                        stuff->width, stuff->height,
    660                                        IncludeInferiors);
    661     }
    662     else {
    663         if (stuff->x < 0 ||
    664             stuff->x + (int) stuff->width > pDraw->width ||
    665             stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height)
    666             return BadMatch;
    667         visual = None;
    668     }
    669     xgi = (xShmGetImageReply) {
    670         .type = X_Reply,
    671         .sequenceNumber = client->sequence,
    672         .length = 0,
    673         .visual = visual,
    674         .depth = pDraw->depth
    675     };
    676     if (stuff->format == ZPixmap) {
    677         length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height;
    678     }
    679     else {
    680         lenPer = PixmapBytePad(stuff->width, 1) * stuff->height;
    681         plane = ((Mask) 1) << (pDraw->depth - 1);
    682         /* only planes asked for */
    683         length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1)));
    684     }
    685 
    686     VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
    687     xgi.size = length;
    688 
    689     if (length == 0) {
    690         /* nothing to do */
    691     }
    692     else if (stuff->format == ZPixmap) {
    693         (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y,
    694                                      stuff->width, stuff->height,
    695                                      stuff->format, stuff->planeMask,
    696                                      shmdesc->addr + stuff->offset);
    697         if (pVisibleRegion)
    698             XaceCensorImage(client, pVisibleRegion,
    699                     PixmapBytePad(stuff->width, pDraw->depth), pDraw,
    700                     stuff->x, stuff->y, stuff->width, stuff->height,
    701                     stuff->format, shmdesc->addr + stuff->offset);
    702     }
    703     else {
    704 
    705         length = stuff->offset;
    706         for (; plane; plane >>= 1) {
    707             if (stuff->planeMask & plane) {
    708                 (*pDraw->pScreen->GetImage) (pDraw,
    709                                              stuff->x, stuff->y,
    710                                              stuff->width, stuff->height,
    711                                              stuff->format, plane,
    712                                              shmdesc->addr + length);
    713                 if (pVisibleRegion)
    714                     XaceCensorImage(client, pVisibleRegion,
    715                             BitmapBytePad(stuff->width), pDraw,
    716                             stuff->x, stuff->y, stuff->width, stuff->height,
    717                             stuff->format, shmdesc->addr + length);
    718                 length += lenPer;
    719             }
    720         }
    721     }
    722 
    723     if (client->swapped) {
    724         swaps(&xgi.sequenceNumber);
    725         swapl(&xgi.length);
    726         swapl(&xgi.visual);
    727         swapl(&xgi.size);
    728     }
    729     WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
    730 
    731     return Success;
    732 }
    733 
    734 #ifdef PANORAMIX
    735 static int
    736 ProcPanoramiXShmPutImage(ClientPtr client)
    737 {
    738     int j, result, orig_x, orig_y;
    739     PanoramiXRes *draw, *gc;
    740     Bool sendEvent, isRoot;
    741 
    742     REQUEST(xShmPutImageReq);
    743     REQUEST_SIZE_MATCH(xShmPutImageReq);
    744 
    745     result = dixLookupResourceByClass((void **) &draw, stuff->drawable,
    746                                       XRC_DRAWABLE, client, DixWriteAccess);
    747     if (result != Success)
    748         return (result == BadValue) ? BadDrawable : result;
    749 
    750     result = dixLookupResourceByType((void **) &gc, stuff->gc,
    751                                      XRT_GC, client, DixReadAccess);
    752     if (result != Success)
    753         return result;
    754 
    755     isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
    756 
    757     orig_x = stuff->dstX;
    758     orig_y = stuff->dstY;
    759     sendEvent = stuff->sendEvent;
    760     stuff->sendEvent = 0;
    761     FOR_NSCREENS(j) {
    762         if (!j)
    763             stuff->sendEvent = sendEvent;
    764         stuff->drawable = draw->info[j].id;
    765         stuff->gc = gc->info[j].id;
    766         if (isRoot) {
    767             stuff->dstX = orig_x - screenInfo.screens[j]->x;
    768             stuff->dstY = orig_y - screenInfo.screens[j]->y;
    769         }
    770         result = ProcShmPutImage(client);
    771         if (result != Success)
    772             break;
    773     }
    774     return result;
    775 }
    776 
    777 static int
    778 ProcPanoramiXShmGetImage(ClientPtr client)
    779 {
    780     PanoramiXRes *draw;
    781     DrawablePtr *drawables;
    782     DrawablePtr pDraw;
    783     xShmGetImageReply xgi;
    784     ShmDescPtr shmdesc;
    785     int i, x, y, w, h, format, rc;
    786     Mask plane = 0, planemask;
    787     long lenPer = 0, length, widthBytesLine;
    788     Bool isRoot;
    789 
    790     REQUEST(xShmGetImageReq);
    791 
    792     REQUEST_SIZE_MATCH(xShmGetImageReq);
    793 
    794     if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) {
    795         client->errorValue = stuff->format;
    796         return BadValue;
    797     }
    798 
    799     rc = dixLookupResourceByClass((void **) &draw, stuff->drawable,
    800                                   XRC_DRAWABLE, client, DixWriteAccess);
    801     if (rc != Success)
    802         return (rc == BadValue) ? BadDrawable : rc;
    803 
    804     if (draw->type == XRT_PIXMAP)
    805         return ProcShmGetImage(client);
    806 
    807     rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess);
    808     if (rc != Success)
    809         return rc;
    810 
    811     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
    812 
    813     x = stuff->x;
    814     y = stuff->y;
    815     w = stuff->width;
    816     h = stuff->height;
    817     format = stuff->format;
    818     planemask = stuff->planeMask;
    819 
    820     isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root;
    821 
    822     if (isRoot) {
    823         if (                    /* check for being onscreen */
    824                x < 0 || x + w > PanoramiXPixWidth ||
    825                y < 0 || y + h > PanoramiXPixHeight)
    826             return BadMatch;
    827     }
    828     else {
    829         if (                    /* check for being onscreen */
    830                screenInfo.screens[0]->x + pDraw->x + x < 0 ||
    831                screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth
    832                || screenInfo.screens[0]->y + pDraw->y + y < 0 ||
    833                screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight
    834                ||
    835                /* check for being inside of border */
    836                x < -wBorderWidth((WindowPtr) pDraw) ||
    837                x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width ||
    838                y < -wBorderWidth((WindowPtr) pDraw) ||
    839                y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height)
    840             return BadMatch;
    841     }
    842 
    843     if (format == ZPixmap) {
    844         widthBytesLine = PixmapBytePad(w, pDraw->depth);
    845         length = widthBytesLine * h;
    846     }
    847     else {
    848         widthBytesLine = PixmapBytePad(w, 1);
    849         lenPer = widthBytesLine * h;
    850         plane = ((Mask) 1) << (pDraw->depth - 1);
    851         length = lenPer * Ones(planemask & (plane | (plane - 1)));
    852     }
    853 
    854     VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client);
    855 
    856     drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr));
    857     if (!drawables)
    858         return BadAlloc;
    859 
    860     drawables[0] = pDraw;
    861     FOR_NSCREENS_FORWARD_SKIP(i) {
    862         rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0,
    863                                DixReadAccess);
    864         if (rc != Success) {
    865             free(drawables);
    866             return rc;
    867         }
    868     }
    869     FOR_NSCREENS_FORWARD(i) {
    870         drawables[i]->pScreen->SourceValidate(drawables[i], 0, 0,
    871                                               drawables[i]->width,
    872                                               drawables[i]->height,
    873                                               IncludeInferiors);
    874     }
    875 
    876     xgi = (xShmGetImageReply) {
    877         .type = X_Reply,
    878         .sequenceNumber = client->sequence,
    879         .length = 0,
    880         .visual = wVisual(((WindowPtr) pDraw)),
    881         .depth = pDraw->depth
    882     };
    883 
    884     xgi.size = length;
    885 
    886     if (length == 0) {          /* nothing to do */
    887     }
    888     else if (format == ZPixmap) {
    889         XineramaGetImageData(drawables, x, y, w, h, format, planemask,
    890                              shmdesc->addr + stuff->offset,
    891                              widthBytesLine, isRoot);
    892     }
    893     else {
    894 
    895         length = stuff->offset;
    896         for (; plane; plane >>= 1) {
    897             if (planemask & plane) {
    898                 XineramaGetImageData(drawables, x, y, w, h,
    899                                      format, plane, shmdesc->addr + length,
    900                                      widthBytesLine, isRoot);
    901                 length += lenPer;
    902             }
    903         }
    904     }
    905     free(drawables);
    906 
    907     if (client->swapped) {
    908         swaps(&xgi.sequenceNumber);
    909         swapl(&xgi.length);
    910         swapl(&xgi.visual);
    911         swapl(&xgi.size);
    912     }
    913     WriteToClient(client, sizeof(xShmGetImageReply), &xgi);
    914 
    915     return Success;
    916 }
    917 
    918 static int
    919 ProcPanoramiXShmCreatePixmap(ClientPtr client)
    920 {
    921     ScreenPtr pScreen = NULL;
    922     PixmapPtr pMap = NULL;
    923     DrawablePtr pDraw;
    924     DepthPtr pDepth;
    925     int i, j, result, rc;
    926     ShmDescPtr shmdesc;
    927 
    928     REQUEST(xShmCreatePixmapReq);
    929     unsigned int width, height, depth;
    930     unsigned long size;
    931     PanoramiXRes *newPix;
    932 
    933     REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
    934     client->errorValue = stuff->pid;
    935     if (!sharedPixmaps)
    936         return BadImplementation;
    937     LEGAL_NEW_RESOURCE(stuff->pid, client);
    938     rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
    939                            DixGetAttrAccess);
    940     if (rc != Success)
    941         return rc;
    942 
    943     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
    944 
    945     width = stuff->width;
    946     height = stuff->height;
    947     depth = stuff->depth;
    948     if (!width || !height || !depth) {
    949         client->errorValue = 0;
    950         return BadValue;
    951     }
    952     if (width > 32767 || height > 32767)
    953         return BadAlloc;
    954 
    955     if (stuff->depth != 1) {
    956         pDepth = pDraw->pScreen->allowedDepths;
    957         for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
    958             if (pDepth->depth == stuff->depth)
    959                 goto CreatePmap;
    960         client->errorValue = stuff->depth;
    961         return BadValue;
    962     }
    963 
    964  CreatePmap:
    965     size = PixmapBytePad(width, depth) * height;
    966     if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
    967         if (size < width * height)
    968             return BadAlloc;
    969     }
    970     /* thankfully, offset is unsigned */
    971     if (stuff->offset + size < size)
    972         return BadAlloc;
    973 
    974     VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
    975 
    976     if (!(newPix = malloc(sizeof(PanoramiXRes))))
    977         return BadAlloc;
    978 
    979     newPix->type = XRT_PIXMAP;
    980     newPix->u.pix.shared = TRUE;
    981     panoramix_setup_ids(newPix, client, stuff->pid);
    982 
    983     result = Success;
    984 
    985     FOR_NSCREENS(j) {
    986         ShmScrPrivateRec *screen_priv;
    987 
    988         pScreen = screenInfo.screens[j];
    989 
    990         screen_priv = ShmGetScreenPriv(pScreen);
    991         pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen,
    992                                                        stuff->width,
    993                                                        stuff->height,
    994                                                        stuff->depth,
    995                                                        shmdesc->addr +
    996                                                        stuff->offset);
    997 
    998         if (pMap) {
    999             result = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid,
   1000                               RT_PIXMAP, pMap, RT_NONE, NULL, DixCreateAccess);
   1001             if (result != Success) {
   1002                 pDraw->pScreen->DestroyPixmap(pMap);
   1003                 break;
   1004             }
   1005             dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
   1006             shmdesc->refcnt++;
   1007             pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
   1008             pMap->drawable.id = newPix->info[j].id;
   1009             if (!AddResource(newPix->info[j].id, RT_PIXMAP, (void *) pMap)) {
   1010                 result = BadAlloc;
   1011                 break;
   1012             }
   1013         }
   1014         else {
   1015             result = BadAlloc;
   1016             break;
   1017         }
   1018     }
   1019 
   1020     if (result != Success) {
   1021         while (j--)
   1022             FreeResource(newPix->info[j].id, RT_NONE);
   1023         free(newPix);
   1024     }
   1025     else
   1026         AddResource(stuff->pid, XRT_PIXMAP, newPix);
   1027 
   1028     return result;
   1029 }
   1030 #endif
   1031 
   1032 static PixmapPtr
   1033 fbShmCreatePixmap(ScreenPtr pScreen,
   1034                   int width, int height, int depth, char *addr)
   1035 {
   1036     PixmapPtr pPixmap;
   1037 
   1038     pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0);
   1039     if (!pPixmap)
   1040         return NullPixmap;
   1041 
   1042     if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth,
   1043                                          BitsPerPixel(depth),
   1044                                          PixmapBytePad(width, depth),
   1045                                          (void *) addr)) {
   1046         (*pScreen->DestroyPixmap) (pPixmap);
   1047         return NullPixmap;
   1048     }
   1049     return pPixmap;
   1050 }
   1051 
   1052 static int
   1053 ProcShmCreatePixmap(ClientPtr client)
   1054 {
   1055     PixmapPtr pMap;
   1056     DrawablePtr pDraw;
   1057     DepthPtr pDepth;
   1058     int i, rc;
   1059     ShmDescPtr shmdesc;
   1060     ShmScrPrivateRec *screen_priv;
   1061 
   1062     REQUEST(xShmCreatePixmapReq);
   1063     unsigned int width, height, depth;
   1064     unsigned long size;
   1065 
   1066     REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
   1067     client->errorValue = stuff->pid;
   1068     if (!sharedPixmaps)
   1069         return BadImplementation;
   1070     LEGAL_NEW_RESOURCE(stuff->pid, client);
   1071     rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY,
   1072                            DixGetAttrAccess);
   1073     if (rc != Success)
   1074         return rc;
   1075 
   1076     VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client);
   1077 
   1078     width = stuff->width;
   1079     height = stuff->height;
   1080     depth = stuff->depth;
   1081     if (!width || !height || !depth) {
   1082         client->errorValue = 0;
   1083         return BadValue;
   1084     }
   1085     if (width > 32767 || height > 32767)
   1086         return BadAlloc;
   1087 
   1088     if (stuff->depth != 1) {
   1089         pDepth = pDraw->pScreen->allowedDepths;
   1090         for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++)
   1091             if (pDepth->depth == stuff->depth)
   1092                 goto CreatePmap;
   1093         client->errorValue = stuff->depth;
   1094         return BadValue;
   1095     }
   1096 
   1097  CreatePmap:
   1098     size = PixmapBytePad(width, depth) * height;
   1099     if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) {
   1100         if (size < width * height)
   1101             return BadAlloc;
   1102     }
   1103     /* thankfully, offset is unsigned */
   1104     if (stuff->offset + size < size)
   1105         return BadAlloc;
   1106 
   1107     VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client);
   1108     screen_priv = ShmGetScreenPriv(pDraw->pScreen);
   1109     pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width,
   1110                                                    stuff->height, stuff->depth,
   1111                                                    shmdesc->addr +
   1112                                                    stuff->offset);
   1113     if (pMap) {
   1114         rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP,
   1115                       pMap, RT_NONE, NULL, DixCreateAccess);
   1116         if (rc != Success) {
   1117             pDraw->pScreen->DestroyPixmap(pMap);
   1118             return rc;
   1119         }
   1120         dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc);
   1121         shmdesc->refcnt++;
   1122         pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER;
   1123         pMap->drawable.id = stuff->pid;
   1124         if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap)) {
   1125             return Success;
   1126         }
   1127     }
   1128     return BadAlloc;
   1129 }
   1130 
   1131 #ifdef SHM_FD_PASSING
   1132 
   1133 static void
   1134 ShmBusfaultNotify(void *context)
   1135 {
   1136     ShmDescPtr shmdesc = context;
   1137 
   1138     ErrorF("shared memory 0x%x truncated by client\n",
   1139            (unsigned int) shmdesc->resource);
   1140     busfault_unregister(shmdesc->busfault);
   1141     shmdesc->busfault = NULL;
   1142     FreeResource (shmdesc->resource, RT_NONE);
   1143 }
   1144 
   1145 static int
   1146 ProcShmAttachFd(ClientPtr client)
   1147 {
   1148     int fd;
   1149     ShmDescPtr shmdesc;
   1150     REQUEST(xShmAttachFdReq);
   1151     struct stat statb;
   1152 
   1153     SetReqFds(client, 1);
   1154     REQUEST_SIZE_MATCH(xShmAttachFdReq);
   1155     LEGAL_NEW_RESOURCE(stuff->shmseg, client);
   1156     if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
   1157         client->errorValue = stuff->readOnly;
   1158         return BadValue;
   1159     }
   1160     fd = ReadFdFromClient(client);
   1161     if (fd < 0)
   1162         return BadMatch;
   1163 
   1164     if (fstat(fd, &statb) < 0 || statb.st_size == 0) {
   1165         close(fd);
   1166         return BadMatch;
   1167     }
   1168 
   1169     shmdesc = malloc(sizeof(ShmDescRec));
   1170     if (!shmdesc) {
   1171         close(fd);
   1172         return BadAlloc;
   1173     }
   1174     shmdesc->is_fd = TRUE;
   1175     shmdesc->addr = mmap(NULL, statb.st_size,
   1176                          stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
   1177                          MAP_SHARED,
   1178                          fd, 0);
   1179 
   1180     close(fd);
   1181     if (shmdesc->addr == ((char *) -1)) {
   1182         free(shmdesc);
   1183         return BadAccess;
   1184     }
   1185 
   1186     shmdesc->refcnt = 1;
   1187     shmdesc->writable = !stuff->readOnly;
   1188     shmdesc->size = statb.st_size;
   1189     shmdesc->resource = stuff->shmseg;
   1190 
   1191     shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
   1192     if (!shmdesc->busfault) {
   1193         munmap(shmdesc->addr, shmdesc->size);
   1194         free(shmdesc);
   1195         return BadAlloc;
   1196     }
   1197 
   1198     shmdesc->next = Shmsegs;
   1199     Shmsegs = shmdesc;
   1200 
   1201     if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc))
   1202         return BadAlloc;
   1203     return Success;
   1204 }
   1205 
   1206 static int
   1207 shm_tmpfile(void)
   1208 {
   1209     const char *shmdirs[] = {
   1210         "/run/shm",
   1211         "/var/tmp",
   1212         "/tmp",
   1213     };
   1214     int	fd;
   1215 
   1216 #ifdef HAVE_MEMFD_CREATE
   1217     fd = memfd_create("xorg", MFD_CLOEXEC|MFD_ALLOW_SEALING);
   1218     if (fd != -1) {
   1219         fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK);
   1220         DebugF ("Using memfd_create\n");
   1221         return fd;
   1222     }
   1223 #endif
   1224 
   1225 #ifdef O_TMPFILE
   1226     for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
   1227         fd = open(shmdirs[i], O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666);
   1228         if (fd >= 0) {
   1229             DebugF ("Using O_TMPFILE\n");
   1230             return fd;
   1231         }
   1232     }
   1233     ErrorF ("Not using O_TMPFILE\n");
   1234 #endif
   1235 
   1236     for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) {
   1237         char template[PATH_MAX];
   1238         snprintf(template, ARRAY_SIZE(template), "%s/shmfd-XXXXXX", shmdirs[i]);
   1239 #ifdef HAVE_MKOSTEMP
   1240         fd = mkostemp(template, O_CLOEXEC);
   1241 #else
   1242         fd = mkstemp(template);
   1243 #endif
   1244         if (fd < 0)
   1245             continue;
   1246         unlink(template);
   1247 #ifndef HAVE_MKOSTEMP
   1248         int flags = fcntl(fd, F_GETFD);
   1249         if (flags != -1) {
   1250             flags |= FD_CLOEXEC;
   1251             (void) fcntl(fd, F_SETFD, flags);
   1252         }
   1253 #endif
   1254         return fd;
   1255     }
   1256 
   1257     return -1;
   1258 }
   1259 
   1260 static int
   1261 ProcShmCreateSegment(ClientPtr client)
   1262 {
   1263     int fd;
   1264     ShmDescPtr shmdesc;
   1265     REQUEST(xShmCreateSegmentReq);
   1266     xShmCreateSegmentReply rep = {
   1267         .type = X_Reply,
   1268         .nfd = 1,
   1269         .sequenceNumber = client->sequence,
   1270         .length = 0,
   1271     };
   1272 
   1273     REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
   1274     LEGAL_NEW_RESOURCE(stuff->shmseg, client);
   1275     if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) {
   1276         client->errorValue = stuff->readOnly;
   1277         return BadValue;
   1278     }
   1279     fd = shm_tmpfile();
   1280     if (fd < 0)
   1281         return BadAlloc;
   1282     if (ftruncate(fd, stuff->size) < 0) {
   1283         close(fd);
   1284         return BadAlloc;
   1285     }
   1286     shmdesc = malloc(sizeof(ShmDescRec));
   1287     if (!shmdesc) {
   1288         close(fd);
   1289         return BadAlloc;
   1290     }
   1291     shmdesc->is_fd = TRUE;
   1292     shmdesc->addr = mmap(NULL, stuff->size,
   1293                          stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE,
   1294                          MAP_SHARED,
   1295                          fd, 0);
   1296 
   1297     if (shmdesc->addr == ((char *) -1)) {
   1298         close(fd);
   1299         free(shmdesc);
   1300         return BadAccess;
   1301     }
   1302 
   1303     shmdesc->refcnt = 1;
   1304     shmdesc->writable = !stuff->readOnly;
   1305     shmdesc->size = stuff->size;
   1306 
   1307     shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc);
   1308     if (!shmdesc->busfault) {
   1309         close(fd);
   1310         munmap(shmdesc->addr, shmdesc->size);
   1311         free(shmdesc);
   1312         return BadAlloc;
   1313     }
   1314 
   1315     shmdesc->next = Shmsegs;
   1316     Shmsegs = shmdesc;
   1317 
   1318     if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) {
   1319         close(fd);
   1320         return BadAlloc;
   1321     }
   1322 
   1323     if (WriteFdToClient(client, fd, TRUE) < 0) {
   1324         FreeResource(stuff->shmseg, RT_NONE);
   1325         close(fd);
   1326         return BadAlloc;
   1327     }
   1328     WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep);
   1329     return Success;
   1330 }
   1331 #endif /* SHM_FD_PASSING */
   1332 
   1333 static int
   1334 ProcShmDispatch(ClientPtr client)
   1335 {
   1336     REQUEST(xReq);
   1337 
   1338     if (stuff->data == X_ShmQueryVersion)
   1339         return ProcShmQueryVersion(client);
   1340 
   1341     if (!client->local)
   1342         return BadRequest;
   1343 
   1344     switch (stuff->data) {
   1345     case X_ShmAttach:
   1346         return ProcShmAttach(client);
   1347     case X_ShmDetach:
   1348         return ProcShmDetach(client);
   1349     case X_ShmPutImage:
   1350 #ifdef PANORAMIX
   1351         if (!noPanoramiXExtension)
   1352             return ProcPanoramiXShmPutImage(client);
   1353 #endif
   1354         return ProcShmPutImage(client);
   1355     case X_ShmGetImage:
   1356 #ifdef PANORAMIX
   1357         if (!noPanoramiXExtension)
   1358             return ProcPanoramiXShmGetImage(client);
   1359 #endif
   1360         return ProcShmGetImage(client);
   1361     case X_ShmCreatePixmap:
   1362 #ifdef PANORAMIX
   1363         if (!noPanoramiXExtension)
   1364             return ProcPanoramiXShmCreatePixmap(client);
   1365 #endif
   1366         return ProcShmCreatePixmap(client);
   1367 #ifdef SHM_FD_PASSING
   1368     case X_ShmAttachFd:
   1369         return ProcShmAttachFd(client);
   1370     case X_ShmCreateSegment:
   1371         return ProcShmCreateSegment(client);
   1372 #endif
   1373     default:
   1374         return BadRequest;
   1375     }
   1376 }
   1377 
   1378 static void _X_COLD
   1379 SShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to)
   1380 {
   1381     to->type = from->type;
   1382     cpswaps(from->sequenceNumber, to->sequenceNumber);
   1383     cpswapl(from->drawable, to->drawable);
   1384     cpswaps(from->minorEvent, to->minorEvent);
   1385     to->majorEvent = from->majorEvent;
   1386     cpswapl(from->shmseg, to->shmseg);
   1387     cpswapl(from->offset, to->offset);
   1388 }
   1389 
   1390 static int _X_COLD
   1391 SProcShmQueryVersion(ClientPtr client)
   1392 {
   1393     REQUEST(xShmQueryVersionReq);
   1394 
   1395     swaps(&stuff->length);
   1396     return ProcShmQueryVersion(client);
   1397 }
   1398 
   1399 static int _X_COLD
   1400 SProcShmAttach(ClientPtr client)
   1401 {
   1402     REQUEST(xShmAttachReq);
   1403     swaps(&stuff->length);
   1404     REQUEST_SIZE_MATCH(xShmAttachReq);
   1405     swapl(&stuff->shmseg);
   1406     swapl(&stuff->shmid);
   1407     return ProcShmAttach(client);
   1408 }
   1409 
   1410 static int _X_COLD
   1411 SProcShmDetach(ClientPtr client)
   1412 {
   1413     REQUEST(xShmDetachReq);
   1414     swaps(&stuff->length);
   1415     REQUEST_SIZE_MATCH(xShmDetachReq);
   1416     swapl(&stuff->shmseg);
   1417     return ProcShmDetach(client);
   1418 }
   1419 
   1420 static int _X_COLD
   1421 SProcShmPutImage(ClientPtr client)
   1422 {
   1423     REQUEST(xShmPutImageReq);
   1424     swaps(&stuff->length);
   1425     REQUEST_SIZE_MATCH(xShmPutImageReq);
   1426     swapl(&stuff->drawable);
   1427     swapl(&stuff->gc);
   1428     swaps(&stuff->totalWidth);
   1429     swaps(&stuff->totalHeight);
   1430     swaps(&stuff->srcX);
   1431     swaps(&stuff->srcY);
   1432     swaps(&stuff->srcWidth);
   1433     swaps(&stuff->srcHeight);
   1434     swaps(&stuff->dstX);
   1435     swaps(&stuff->dstY);
   1436     swapl(&stuff->shmseg);
   1437     swapl(&stuff->offset);
   1438     return ProcShmPutImage(client);
   1439 }
   1440 
   1441 static int _X_COLD
   1442 SProcShmGetImage(ClientPtr client)
   1443 {
   1444     REQUEST(xShmGetImageReq);
   1445     swaps(&stuff->length);
   1446     REQUEST_SIZE_MATCH(xShmGetImageReq);
   1447     swapl(&stuff->drawable);
   1448     swaps(&stuff->x);
   1449     swaps(&stuff->y);
   1450     swaps(&stuff->width);
   1451     swaps(&stuff->height);
   1452     swapl(&stuff->planeMask);
   1453     swapl(&stuff->shmseg);
   1454     swapl(&stuff->offset);
   1455     return ProcShmGetImage(client);
   1456 }
   1457 
   1458 static int _X_COLD
   1459 SProcShmCreatePixmap(ClientPtr client)
   1460 {
   1461     REQUEST(xShmCreatePixmapReq);
   1462     swaps(&stuff->length);
   1463     REQUEST_SIZE_MATCH(xShmCreatePixmapReq);
   1464     swapl(&stuff->pid);
   1465     swapl(&stuff->drawable);
   1466     swaps(&stuff->width);
   1467     swaps(&stuff->height);
   1468     swapl(&stuff->shmseg);
   1469     swapl(&stuff->offset);
   1470     return ProcShmCreatePixmap(client);
   1471 }
   1472 
   1473 #ifdef SHM_FD_PASSING
   1474 static int _X_COLD
   1475 SProcShmAttachFd(ClientPtr client)
   1476 {
   1477     REQUEST(xShmAttachFdReq);
   1478     SetReqFds(client, 1);
   1479     swaps(&stuff->length);
   1480     REQUEST_SIZE_MATCH(xShmAttachFdReq);
   1481     swapl(&stuff->shmseg);
   1482     return ProcShmAttachFd(client);
   1483 }
   1484 
   1485 static int _X_COLD
   1486 SProcShmCreateSegment(ClientPtr client)
   1487 {
   1488     REQUEST(xShmCreateSegmentReq);
   1489     swaps(&stuff->length);
   1490     REQUEST_SIZE_MATCH(xShmCreateSegmentReq);
   1491     swapl(&stuff->shmseg);
   1492     swapl(&stuff->size);
   1493     return ProcShmCreateSegment(client);
   1494 }
   1495 #endif  /* SHM_FD_PASSING */
   1496 
   1497 static int _X_COLD
   1498 SProcShmDispatch(ClientPtr client)
   1499 {
   1500     REQUEST(xReq);
   1501 
   1502     if (stuff->data == X_ShmQueryVersion)
   1503         return SProcShmQueryVersion(client);
   1504 
   1505     if (!client->local)
   1506         return BadRequest;
   1507 
   1508     switch (stuff->data) {
   1509     case X_ShmAttach:
   1510         return SProcShmAttach(client);
   1511     case X_ShmDetach:
   1512         return SProcShmDetach(client);
   1513     case X_ShmPutImage:
   1514         return SProcShmPutImage(client);
   1515     case X_ShmGetImage:
   1516         return SProcShmGetImage(client);
   1517     case X_ShmCreatePixmap:
   1518         return SProcShmCreatePixmap(client);
   1519 #ifdef SHM_FD_PASSING
   1520     case X_ShmAttachFd:
   1521         return SProcShmAttachFd(client);
   1522     case X_ShmCreateSegment:
   1523         return SProcShmCreateSegment(client);
   1524 #endif
   1525     default:
   1526         return BadRequest;
   1527     }
   1528 }
   1529 
   1530 void
   1531 ShmExtensionInit(void)
   1532 {
   1533     ExtensionEntry *extEntry;
   1534     int i;
   1535 
   1536 #ifdef MUST_CHECK_FOR_SHM_SYSCALL
   1537     if (!CheckForShmSyscall()) {
   1538         ErrorF("MIT-SHM extension disabled due to lack of kernel support\n");
   1539         return;
   1540     }
   1541 #endif
   1542 
   1543     if (!ShmRegisterPrivates())
   1544         return;
   1545 
   1546     sharedPixmaps = xFalse;
   1547     {
   1548         sharedPixmaps = xTrue;
   1549         for (i = 0; i < screenInfo.numScreens; i++) {
   1550             ShmScrPrivateRec *screen_priv =
   1551                 ShmInitScreenPriv(screenInfo.screens[i]);
   1552             if (!screen_priv->shmFuncs)
   1553                 screen_priv->shmFuncs = &miFuncs;
   1554             if (!screen_priv->shmFuncs->CreatePixmap)
   1555                 sharedPixmaps = xFalse;
   1556         }
   1557         if (sharedPixmaps)
   1558             for (i = 0; i < screenInfo.numScreens; i++) {
   1559                 ShmScrPrivateRec *screen_priv =
   1560                     ShmGetScreenPriv(screenInfo.screens[i]);
   1561                 screen_priv->destroyPixmap =
   1562                     screenInfo.screens[i]->DestroyPixmap;
   1563                 screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap;
   1564             }
   1565     }
   1566     ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg");
   1567     if (ShmSegType &&
   1568         (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors,
   1569                                  ProcShmDispatch, SProcShmDispatch,
   1570                                  ShmResetProc, StandardMinorOpcode))) {
   1571         ShmReqCode = (unsigned char) extEntry->base;
   1572         ShmCompletionCode = extEntry->eventBase;
   1573         BadShmSegCode = extEntry->errorBase;
   1574         SetResourceTypeErrorValue(ShmSegType, BadShmSegCode);
   1575         EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent;
   1576     }
   1577 }