shm.c revision 4e185dc0
1/************************************************************ 2 3Copyright 1989, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in 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 98typedef struct _ShmScrPrivateRec { 99 CloseScreenProcPtr CloseScreen; 100 ShmFuncsPtr shmFuncs; 101 DestroyPixmapProcPtr destroyPixmap; 102} ShmScrPrivateRec; 103 104static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); 105static int ShmDetachSegment(void *value, XID shmseg); 106static void ShmResetProc(ExtensionEntry *extEntry); 107static void SShmCompletionEvent(xShmCompletionEvent *from, 108 xShmCompletionEvent *to); 109 110static Bool ShmDestroyPixmap(PixmapPtr pPixmap); 111 112static unsigned char ShmReqCode; 113int ShmCompletionCode; 114int BadShmSegCode; 115RESTYPE ShmSegType; 116static ShmDescPtr Shmsegs; 117static Bool sharedPixmaps; 118static DevPrivateKeyRec shmScrPrivateKeyRec; 119 120#define shmScrPrivateKey (&shmScrPrivateKeyRec) 121static DevPrivateKeyRec shmPixmapPrivateKeyRec; 122 123#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec) 124static ShmFuncs miFuncs = { NULL, NULL }; 125static 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 160static Bool badSysCall = FALSE; 161 162static void 163SigSysHandler(int signo) 164{ 165 badSysCall = TRUE; 166} 167 168static Bool 169CheckForShmSyscall(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 196static Bool 197ShmCloseScreen(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 207static ShmScrPrivateRec * 208ShmInitScreenPriv(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 221static Bool 222ShmRegisterPrivates(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 232ShmResetProc(ExtensionEntry * extEntry) 233{ 234 int i; 235 236 for (i = 0; i < screenInfo.numScreens; i++) 237 ShmRegisterFuncs(screenInfo.screens[i], NULL); 238} 239 240void 241ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) 242{ 243 if (!ShmRegisterPrivates()) 244 return; 245 ShmInitScreenPriv(pScreen)->shmFuncs = funcs; 246} 247 248static Bool 249ShmDestroyPixmap(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 270void 271ShmRegisterFbFuncs(ScreenPtr pScreen) 272{ 273 ShmRegisterFuncs(pScreen, &fbFuncs); 274} 275 276static int 277ProcShmQueryVersion(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 */ 309static int 310shm_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 371static int 372ProcShmAttach(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 431ShmDetachSegment(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 453static int 454ProcShmDetach(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 */ 470static void 471doShmPutImage(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 516static int 517ProcShmPutImage(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 615static int 616ProcShmGetImage(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 735static int 736ProcPanoramiXShmPutImage(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 777static int 778ProcPanoramiXShmGetImage(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 918static int 919ProcPanoramiXShmCreatePixmap(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 1032static PixmapPtr 1033fbShmCreatePixmap(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 1052static int 1053ProcShmCreatePixmap(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 1133static void 1134ShmBusfaultNotify(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 1145static int 1146ProcShmAttachFd(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 1206static int 1207shm_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 1260static int 1261ProcShmCreateSegment(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 1333static int 1334ProcShmDispatch(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 1378static void _X_COLD 1379SShmCompletionEvent(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 1390static int _X_COLD 1391SProcShmQueryVersion(ClientPtr client) 1392{ 1393 REQUEST(xShmQueryVersionReq); 1394 1395 swaps(&stuff->length); 1396 return ProcShmQueryVersion(client); 1397} 1398 1399static int _X_COLD 1400SProcShmAttach(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 1410static int _X_COLD 1411SProcShmDetach(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 1420static int _X_COLD 1421SProcShmPutImage(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 1441static int _X_COLD 1442SProcShmGetImage(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 1458static int _X_COLD 1459SProcShmCreatePixmap(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 1474static int _X_COLD 1475SProcShmAttachFd(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 1485static int _X_COLD 1486SProcShmCreateSegment(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 1497static int _X_COLD 1498SProcShmDispatch(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 1530void 1531ShmExtensionInit(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