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