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     return (*pScreen->CloseScreen) (pScreen);
205 }
206 
207 static ShmScrPrivateRec *
ShmInitScreenPriv(ScreenPtr pScreen)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
ShmRegisterPrivates(void)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
ShmResetProc(ExtensionEntry * extEntry)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
ShmRegisterFuncs(ScreenPtr pScreen,ShmFuncsPtr funcs)241 ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs)
242 {
243     if (!ShmRegisterPrivates())
244         return;
245     ShmInitScreenPriv(pScreen)->shmFuncs = funcs;
246 }
247 
248 static Bool
ShmDestroyPixmap(PixmapPtr pPixmap)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
ShmRegisterFbFuncs(ScreenPtr pScreen)271 ShmRegisterFbFuncs(ScreenPtr pScreen)
272 {
273     ShmRegisterFuncs(pScreen, &fbFuncs);
274 }
275 
276 static int
ProcShmQueryVersion(ClientPtr client)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 segement,
307  * using the credentials from the client if available
308  */
309 static int
shm_access(ClientPtr client,SHMPERM_TYPE * perm,int readonly)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
ProcShmAttach(ClientPtr client)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
ShmDetachSegment(void * value,XID unused)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
ProcShmDetach(ClientPtr client)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
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)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
ProcShmPutImage(ClientPtr client)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
ProcShmGetImage(ClientPtr client)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
ProcPanoramiXShmPutImage(ClientPtr client)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
ProcPanoramiXShmGetImage(ClientPtr client)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
ProcPanoramiXShmCreatePixmap(ClientPtr client)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
fbShmCreatePixmap(ScreenPtr pScreen,int width,int height,int depth,char * addr)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
ProcShmCreatePixmap(ClientPtr client)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
ShmBusfaultNotify(void * context)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
ProcShmAttachFd(ClientPtr client)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
shm_tmpfile(void)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
ProcShmCreateSegment(ClientPtr client)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
ProcShmDispatch(ClientPtr client)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
SShmCompletionEvent(xShmCompletionEvent * from,xShmCompletionEvent * to)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
SProcShmQueryVersion(ClientPtr client)1391 SProcShmQueryVersion(ClientPtr client)
1392 {
1393     REQUEST(xShmQueryVersionReq);
1394 
1395     swaps(&stuff->length);
1396     return ProcShmQueryVersion(client);
1397 }
1398 
1399 static int _X_COLD
SProcShmAttach(ClientPtr client)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
SProcShmDetach(ClientPtr client)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
SProcShmPutImage(ClientPtr client)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
SProcShmGetImage(ClientPtr client)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
SProcShmCreatePixmap(ClientPtr client)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
SProcShmAttachFd(ClientPtr client)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
SProcShmCreateSegment(ClientPtr client)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
SProcShmDispatch(ClientPtr client)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
ShmExtensionInit(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 }
1578