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