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