shm.c revision 65b04b38
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 30#define SHM 31 32#ifdef HAVE_DIX_CONFIG_H 33#include <dix-config.h> 34#endif 35 36#include <sys/types.h> 37#include <sys/ipc.h> 38#include <sys/shm.h> 39#include <unistd.h> 40#include <sys/stat.h> 41#include <X11/X.h> 42#include <X11/Xproto.h> 43#include "misc.h" 44#include "os.h" 45#include "dixstruct.h" 46#include "resource.h" 47#include "scrnintstr.h" 48#include "windowstr.h" 49#include "pixmapstr.h" 50#include "gcstruct.h" 51#include "extnsionst.h" 52#include "servermd.h" 53#include "shmint.h" 54#include "xace.h" 55#include <X11/extensions/shmproto.h> 56#include <X11/Xfuncproto.h> 57#include "protocol-versions.h" 58 59/* Needed for Solaris cross-zone shared memory extension */ 60#ifdef HAVE_SHMCTL64 61#include <sys/ipc_impl.h> 62#define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf) 63#define SHMSTAT_TYPE struct shmid_ds64 64#define SHMPERM_TYPE struct ipc_perm64 65#define SHM_PERM(buf) buf.shmx_perm 66#define SHM_SEGSZ(buf) buf.shmx_segsz 67#define SHMPERM_UID(p) p->ipcx_uid 68#define SHMPERM_CUID(p) p->ipcx_cuid 69#define SHMPERM_GID(p) p->ipcx_gid 70#define SHMPERM_CGID(p) p->ipcx_cgid 71#define SHMPERM_MODE(p) p->ipcx_mode 72#define SHMPERM_ZONEID(p) p->ipcx_zoneid 73#else 74#define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf) 75#define SHMSTAT_TYPE struct shmid_ds 76#define SHMPERM_TYPE struct ipc_perm 77#define SHM_PERM(buf) buf.shm_perm 78#define SHM_SEGSZ(buf) buf.shm_segsz 79#define SHMPERM_UID(p) p->uid 80#define SHMPERM_CUID(p) p->cuid 81#define SHMPERM_GID(p) p->gid 82#define SHMPERM_CGID(p) p->cgid 83#define SHMPERM_MODE(p) p->mode 84#endif 85 86#ifdef PANORAMIX 87#include "panoramiX.h" 88#include "panoramiXsrv.h" 89#endif 90 91#include "modinit.h" 92 93typedef struct _ShmDesc { 94 struct _ShmDesc *next; 95 int shmid; 96 int refcnt; 97 char *addr; 98 Bool writable; 99 unsigned long size; 100} ShmDescRec, *ShmDescPtr; 101 102typedef struct _ShmScrPrivateRec { 103 CloseScreenProcPtr CloseScreen; 104 ShmFuncsPtr shmFuncs; 105 DestroyPixmapProcPtr destroyPixmap; 106} ShmScrPrivateRec; 107 108static PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); 109static int ShmDetachSegment( 110 pointer /* value */, 111 XID /* shmseg */ 112 ); 113static void ShmResetProc( 114 ExtensionEntry * /* extEntry */ 115 ); 116static void SShmCompletionEvent( 117 xShmCompletionEvent * /* from */, 118 xShmCompletionEvent * /* to */ 119 ); 120 121static Bool ShmDestroyPixmap (PixmapPtr pPixmap); 122 123 124static unsigned char ShmReqCode; 125int ShmCompletionCode; 126int BadShmSegCode; 127RESTYPE ShmSegType; 128static ShmDescPtr Shmsegs; 129static Bool sharedPixmaps; 130static DevPrivateKeyRec shmScrPrivateKeyRec; 131#define shmScrPrivateKey (&shmScrPrivateKeyRec) 132static DevPrivateKeyRec shmPixmapPrivateKeyRec; 133#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec) 134static ShmFuncs miFuncs = {NULL, NULL}; 135static ShmFuncs fbFuncs = {fbShmCreatePixmap, NULL}; 136 137#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey)) 138 139#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ 140{ \ 141 int rc; \ 142 rc = dixLookupResourceByType((pointer *)&(shmdesc), shmseg, ShmSegType, \ 143 client, DixReadAccess); \ 144 if (rc != Success) \ 145 return rc; \ 146} 147 148#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ 149{ \ 150 VERIFY_SHMSEG(shmseg, shmdesc, client); \ 151 if ((offset & 3) || (offset > shmdesc->size)) \ 152 { \ 153 client->errorValue = offset; \ 154 return BadValue; \ 155 } \ 156 if (needwrite && !shmdesc->writable) \ 157 return BadAccess; \ 158} 159 160#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ 161{ \ 162 if ((offset + len) > shmdesc->size) \ 163 { \ 164 return BadAccess; \ 165 } \ 166} 167 168 169#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) 170#include <sys/signal.h> 171 172static Bool badSysCall = FALSE; 173 174static void 175SigSysHandler(int signo) 176{ 177 badSysCall = TRUE; 178} 179 180static Bool CheckForShmSyscall(void) 181{ 182 void (*oldHandler)(); 183 int shmid = -1; 184 185 /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ 186 oldHandler = signal(SIGSYS, SigSysHandler); 187 188 badSysCall = FALSE; 189 shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); 190 191 if (shmid != -1) 192 { 193 /* Successful allocation - clean up */ 194 shmctl(shmid, IPC_RMID, NULL); 195 } 196 else 197 { 198 /* Allocation failed */ 199 badSysCall = TRUE; 200 } 201 signal(SIGSYS, oldHandler); 202 return !badSysCall; 203} 204 205#define MUST_CHECK_FOR_SHM_SYSCALL 206 207#endif 208 209static Bool 210ShmCloseScreen(int i, ScreenPtr pScreen) 211{ 212 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 213 pScreen->CloseScreen = screen_priv->CloseScreen; 214 dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL); 215 free(screen_priv); 216 return (*pScreen->CloseScreen) (i, pScreen); 217} 218 219static ShmScrPrivateRec * 220ShmInitScreenPriv(ScreenPtr pScreen) 221{ 222 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 223 if (!screen_priv) 224 { 225 screen_priv = calloc(1, sizeof (ShmScrPrivateRec)); 226 screen_priv->CloseScreen = pScreen->CloseScreen; 227 dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv); 228 pScreen->CloseScreen = ShmCloseScreen; 229 } 230 return screen_priv; 231} 232 233static Bool 234ShmRegisterPrivates(void) 235{ 236 if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0)) 237 return FALSE; 238 if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 239 return FALSE; 240 return TRUE; 241} 242 243/*ARGSUSED*/ 244static void 245ShmResetProc(ExtensionEntry *extEntry) 246{ 247 int i; 248 for (i = 0; i < screenInfo.numScreens; i++) 249 ShmRegisterFuncs(screenInfo.screens[i], NULL); 250} 251 252void 253ShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) 254{ 255 if (!ShmRegisterPrivates()) 256 return; 257 ShmInitScreenPriv(pScreen)->shmFuncs = funcs; 258} 259 260static Bool 261ShmDestroyPixmap (PixmapPtr pPixmap) 262{ 263 ScreenPtr pScreen = pPixmap->drawable.pScreen; 264 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 265 Bool ret; 266 if (pPixmap->refcnt == 1) 267 { 268 ShmDescPtr shmdesc; 269 shmdesc = (ShmDescPtr)dixLookupPrivate(&pPixmap->devPrivates, 270 shmPixmapPrivateKey); 271 if (shmdesc) 272 ShmDetachSegment ((pointer) shmdesc, pPixmap->drawable.id); 273 } 274 275 pScreen->DestroyPixmap = screen_priv->destroyPixmap; 276 ret = (*pScreen->DestroyPixmap) (pPixmap); 277 screen_priv->destroyPixmap = pScreen->DestroyPixmap; 278 pScreen->DestroyPixmap = ShmDestroyPixmap; 279 return ret; 280} 281 282void 283ShmRegisterFbFuncs(ScreenPtr pScreen) 284{ 285 ShmRegisterFuncs(pScreen, &fbFuncs); 286} 287 288static int 289ProcShmQueryVersion(ClientPtr client) 290{ 291 xShmQueryVersionReply rep; 292 int n; 293 294 REQUEST_SIZE_MATCH(xShmQueryVersionReq); 295 memset(&rep, 0, sizeof(xShmQueryVersionReply)); 296 rep.type = X_Reply; 297 rep.length = 0; 298 rep.sequenceNumber = client->sequence; 299 rep.sharedPixmaps = sharedPixmaps; 300 rep.pixmapFormat = sharedPixmaps ? ZPixmap : 0; 301 rep.majorVersion = SERVER_SHM_MAJOR_VERSION; 302 rep.minorVersion = SERVER_SHM_MINOR_VERSION; 303 rep.uid = geteuid(); 304 rep.gid = getegid(); 305 if (client->swapped) { 306 swaps(&rep.sequenceNumber, n); 307 swapl(&rep.length, n); 308 swaps(&rep.majorVersion, n); 309 swaps(&rep.minorVersion, n); 310 swaps(&rep.uid, n); 311 swaps(&rep.gid, n); 312 } 313 WriteToClient(client, sizeof(xShmQueryVersionReply), (char *)&rep); 314 return Success; 315} 316 317/* 318 * Simulate the access() system call for a shared memory segement, 319 * using the credentials from the client if available 320 */ 321static int 322shm_access(ClientPtr client, SHMPERM_TYPE *perm, int readonly) 323{ 324 int uid, gid; 325 mode_t mask; 326 int uidset = 0, gidset = 0; 327 LocalClientCredRec *lcc; 328 329 if (GetLocalClientCreds(client, &lcc) != -1) { 330 331 if (lcc->fieldsSet & LCC_UID_SET) { 332 uid = lcc->euid; 333 uidset = 1; 334 } 335 if (lcc->fieldsSet & LCC_GID_SET) { 336 gid = lcc->egid; 337 gidset = 1; 338 } 339 340#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID) 341 if ( ((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1) 342 || (lcc->zoneid != SHMPERM_ZONEID(perm))) { 343 uidset = 0; 344 gidset = 0; 345 } 346#endif 347 FreeLocalClientCreds(lcc); 348 349 if (uidset) { 350 /* User id 0 always gets access */ 351 if (uid == 0) { 352 return 0; 353 } 354 /* Check the owner */ 355 if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) { 356 mask = S_IRUSR; 357 if (!readonly) { 358 mask |= S_IWUSR; 359 } 360 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 361 } 362 } 363 364 if (gidset) { 365 /* Check the group */ 366 if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) { 367 mask = S_IRGRP; 368 if (!readonly) { 369 mask |= S_IWGRP; 370 } 371 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 372 } 373 } 374 } 375 /* Otherwise, check everyone else */ 376 mask = S_IROTH; 377 if (!readonly) { 378 mask |= S_IWOTH; 379 } 380 return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 381} 382 383static int 384ProcShmAttach(ClientPtr client) 385{ 386 SHMSTAT_TYPE buf; 387 ShmDescPtr shmdesc; 388 REQUEST(xShmAttachReq); 389 390 REQUEST_SIZE_MATCH(xShmAttachReq); 391 LEGAL_NEW_RESOURCE(stuff->shmseg, client); 392 if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) 393 { 394 client->errorValue = stuff->readOnly; 395 return BadValue; 396 } 397 for (shmdesc = Shmsegs; 398 shmdesc && (shmdesc->shmid != stuff->shmid); 399 shmdesc = shmdesc->next) 400 ; 401 if (shmdesc) 402 { 403 if (!stuff->readOnly && !shmdesc->writable) 404 return BadAccess; 405 shmdesc->refcnt++; 406 } 407 else 408 { 409 shmdesc = malloc(sizeof(ShmDescRec)); 410 if (!shmdesc) 411 return BadAlloc; 412 shmdesc->addr = shmat(stuff->shmid, 0, 413 stuff->readOnly ? SHM_RDONLY : 0); 414 if ((shmdesc->addr == ((char *)-1)) || 415 SHMSTAT(stuff->shmid, &buf)) 416 { 417 free(shmdesc); 418 return BadAccess; 419 } 420 421 /* The attach was performed with root privs. We must 422 * do manual checking of access rights for the credentials 423 * of the client */ 424 425 if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) { 426 shmdt(shmdesc->addr); 427 free(shmdesc); 428 return BadAccess; 429 } 430 431 shmdesc->shmid = stuff->shmid; 432 shmdesc->refcnt = 1; 433 shmdesc->writable = !stuff->readOnly; 434 shmdesc->size = SHM_SEGSZ(buf); 435 shmdesc->next = Shmsegs; 436 Shmsegs = shmdesc; 437 } 438 if (!AddResource(stuff->shmseg, ShmSegType, (pointer)shmdesc)) 439 return BadAlloc; 440 return Success; 441} 442 443/*ARGSUSED*/ 444static int 445ShmDetachSegment(pointer value, /* must conform to DeleteType */ 446 XID shmseg) 447{ 448 ShmDescPtr shmdesc = (ShmDescPtr)value; 449 ShmDescPtr *prev; 450 451 if (--shmdesc->refcnt) 452 return TRUE; 453 shmdt(shmdesc->addr); 454 for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next) 455 ; 456 *prev = shmdesc->next; 457 free(shmdesc); 458 return Success; 459} 460 461static int 462ProcShmDetach(ClientPtr client) 463{ 464 ShmDescPtr shmdesc; 465 REQUEST(xShmDetachReq); 466 467 REQUEST_SIZE_MATCH(xShmDetachReq); 468 VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); 469 FreeResource(stuff->shmseg, RT_NONE); 470 return Success; 471} 472 473/* 474 * If the given request doesn't exactly match PutImage's constraints, 475 * wrap the image in a scratch pixmap header and let CopyArea sort it out. 476 */ 477static void 478doShmPutImage(DrawablePtr dst, GCPtr pGC, 479 int depth, unsigned int format, 480 int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, 481 char *data) 482{ 483 PixmapPtr pPixmap; 484 485 if (format == ZPixmap || depth == 1) { 486 pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, 487 BitsPerPixel(depth), 488 PixmapBytePad(w, depth), 489 data); 490 if (!pPixmap) 491 return; 492 pGC->ops->CopyArea((DrawablePtr)pPixmap, dst, pGC, sx, sy, sw, sh, dx, dy); 493 FreeScratchPixmapHeader(pPixmap); 494 } else { 495 GCPtr putGC = GetScratchGC(depth, dst->pScreen); 496 497 if (!putGC) 498 return; 499 500 pPixmap = (*dst->pScreen->CreatePixmap)(dst->pScreen, sw, sh, depth, 501 CREATE_PIXMAP_USAGE_SCRATCH); 502 if (!pPixmap) { 503 FreeScratchGC(putGC); 504 return; 505 } 506 ValidateGC(&pPixmap->drawable, putGC); 507 (*putGC->ops->PutImage)(&pPixmap->drawable, putGC, depth, -sx, -sy, w, h, 0, 508 (format == XYPixmap) ? XYPixmap : ZPixmap, data); 509 FreeScratchGC(putGC); 510 if (format == XYBitmap) 511 (void)(*pGC->ops->CopyPlane)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, 512 dx, dy, 1L); 513 else 514 (void)(*pGC->ops->CopyArea)(&pPixmap->drawable, dst, pGC, 0, 0, sw, sh, 515 dx, dy); 516 (*pPixmap->drawable.pScreen->DestroyPixmap)(pPixmap); 517 } 518} 519 520static int 521ProcShmPutImage(ClientPtr client) 522{ 523 GCPtr pGC; 524 DrawablePtr pDraw; 525 long length; 526 ShmDescPtr shmdesc; 527 REQUEST(xShmPutImageReq); 528 529 REQUEST_SIZE_MATCH(xShmPutImageReq); 530 VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); 531 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); 532 if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) 533 return BadValue; 534 if (stuff->format == XYBitmap) 535 { 536 if (stuff->depth != 1) 537 return BadMatch; 538 length = PixmapBytePad(stuff->totalWidth, 1); 539 } 540 else if (stuff->format == XYPixmap) 541 { 542 if (pDraw->depth != stuff->depth) 543 return BadMatch; 544 length = PixmapBytePad(stuff->totalWidth, 1); 545 length *= stuff->depth; 546 } 547 else if (stuff->format == ZPixmap) 548 { 549 if (pDraw->depth != stuff->depth) 550 return BadMatch; 551 length = PixmapBytePad(stuff->totalWidth, stuff->depth); 552 } 553 else 554 { 555 client->errorValue = stuff->format; 556 return BadValue; 557 } 558 559 /* 560 * There's a potential integer overflow in this check: 561 * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, 562 * client); 563 * the version below ought to avoid it 564 */ 565 if (stuff->totalHeight != 0 && 566 length > (shmdesc->size - stuff->offset)/stuff->totalHeight) { 567 client->errorValue = stuff->totalWidth; 568 return BadValue; 569 } 570 if (stuff->srcX > stuff->totalWidth) 571 { 572 client->errorValue = stuff->srcX; 573 return BadValue; 574 } 575 if (stuff->srcY > stuff->totalHeight) 576 { 577 client->errorValue = stuff->srcY; 578 return BadValue; 579 } 580 if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) 581 { 582 client->errorValue = stuff->srcWidth; 583 return BadValue; 584 } 585 if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) 586 { 587 client->errorValue = stuff->srcHeight; 588 return BadValue; 589 } 590 591 if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) || 592 ((stuff->format != ZPixmap) && 593 (stuff->srcX < screenInfo.bitmapScanlinePad) && 594 ((stuff->format == XYBitmap) || 595 ((stuff->srcY == 0) && 596 (stuff->srcHeight == stuff->totalHeight))))) && 597 ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth)) 598 (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, 599 stuff->dstX, stuff->dstY, 600 stuff->totalWidth, stuff->srcHeight, 601 stuff->srcX, stuff->format, 602 shmdesc->addr + stuff->offset + 603 (stuff->srcY * length)); 604 else 605 doShmPutImage(pDraw, pGC, stuff->depth, stuff->format, 606 stuff->totalWidth, stuff->totalHeight, 607 stuff->srcX, stuff->srcY, 608 stuff->srcWidth, stuff->srcHeight, 609 stuff->dstX, stuff->dstY, 610 shmdesc->addr + stuff->offset); 611 612 if (stuff->sendEvent) 613 { 614 xShmCompletionEvent ev; 615 616 ev.type = ShmCompletionCode; 617 ev.drawable = stuff->drawable; 618 ev.minorEvent = X_ShmPutImage; 619 ev.majorEvent = ShmReqCode; 620 ev.shmseg = stuff->shmseg; 621 ev.offset = stuff->offset; 622 WriteEventsToClient(client, 1, (xEvent *) &ev); 623 } 624 625 return Success; 626} 627 628static int 629ProcShmGetImage(ClientPtr client) 630{ 631 DrawablePtr pDraw; 632 long lenPer = 0, length; 633 Mask plane = 0; 634 xShmGetImageReply xgi; 635 ShmDescPtr shmdesc; 636 int n, rc; 637 638 REQUEST(xShmGetImageReq); 639 640 REQUEST_SIZE_MATCH(xShmGetImageReq); 641 if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) 642 { 643 client->errorValue = stuff->format; 644 return BadValue; 645 } 646 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, 647 DixReadAccess); 648 if (rc != Success) 649 return rc; 650 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 651 if (pDraw->type == DRAWABLE_WINDOW) 652 { 653 if( /* check for being viewable */ 654 !((WindowPtr) pDraw)->realized || 655 /* check for being on screen */ 656 pDraw->x + stuff->x < 0 || 657 pDraw->x + stuff->x + (int)stuff->width > pDraw->pScreen->width || 658 pDraw->y + stuff->y < 0 || 659 pDraw->y + stuff->y + (int)stuff->height > pDraw->pScreen->height || 660 /* check for being inside of border */ 661 stuff->x < - wBorderWidth((WindowPtr)pDraw) || 662 stuff->x + (int)stuff->width > 663 wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || 664 stuff->y < -wBorderWidth((WindowPtr)pDraw) || 665 stuff->y + (int)stuff->height > 666 wBorderWidth((WindowPtr)pDraw) + (int)pDraw->height 667 ) 668 return BadMatch; 669 xgi.visual = wVisual(((WindowPtr)pDraw)); 670 } 671 else 672 { 673 if (stuff->x < 0 || 674 stuff->x+(int)stuff->width > pDraw->width || 675 stuff->y < 0 || 676 stuff->y+(int)stuff->height > pDraw->height 677 ) 678 return BadMatch; 679 xgi.visual = None; 680 } 681 xgi.type = X_Reply; 682 xgi.length = 0; 683 xgi.sequenceNumber = client->sequence; 684 xgi.depth = pDraw->depth; 685 if(stuff->format == ZPixmap) 686 { 687 length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; 688 } 689 else 690 { 691 lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; 692 plane = ((Mask)1) << (pDraw->depth - 1); 693 /* only planes asked for */ 694 length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); 695 } 696 697 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 698 xgi.size = length; 699 700 if (length == 0) 701 { 702 /* nothing to do */ 703 } 704 else if (stuff->format == ZPixmap) 705 { 706 (*pDraw->pScreen->GetImage)(pDraw, stuff->x, stuff->y, 707 stuff->width, stuff->height, 708 stuff->format, stuff->planeMask, 709 shmdesc->addr + stuff->offset); 710 } 711 else 712 { 713 714 length = stuff->offset; 715 for (; plane; plane >>= 1) 716 { 717 if (stuff->planeMask & plane) 718 { 719 (*pDraw->pScreen->GetImage)(pDraw, 720 stuff->x, stuff->y, 721 stuff->width, stuff->height, 722 stuff->format, plane, 723 shmdesc->addr + length); 724 length += lenPer; 725 } 726 } 727 } 728 729 if (client->swapped) { 730 swaps(&xgi.sequenceNumber, n); 731 swapl(&xgi.length, n); 732 swapl(&xgi.visual, n); 733 swapl(&xgi.size, n); 734 } 735 WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); 736 737 return Success; 738} 739 740#ifdef PANORAMIX 741static int 742ProcPanoramiXShmPutImage(ClientPtr client) 743{ 744 int j, result, orig_x, orig_y; 745 PanoramiXRes *draw, *gc; 746 Bool sendEvent, isRoot; 747 748 REQUEST(xShmPutImageReq); 749 REQUEST_SIZE_MATCH(xShmPutImageReq); 750 751 result = dixLookupResourceByClass((pointer *)&draw, stuff->drawable, 752 XRC_DRAWABLE, client, DixWriteAccess); 753 if (result != Success) 754 return (result == BadValue) ? BadDrawable : result; 755 756 result = dixLookupResourceByType((pointer *)&gc, stuff->gc, 757 XRT_GC, client, DixReadAccess); 758 if (result != Success) 759 return result; 760 761 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 762 763 orig_x = stuff->dstX; 764 orig_y = stuff->dstY; 765 sendEvent = stuff->sendEvent; 766 stuff->sendEvent = 0; 767 FOR_NSCREENS(j) { 768 if(!j) stuff->sendEvent = sendEvent; 769 stuff->drawable = draw->info[j].id; 770 stuff->gc = gc->info[j].id; 771 if (isRoot) { 772 stuff->dstX = orig_x - screenInfo.screens[j]->x; 773 stuff->dstY = orig_y - screenInfo.screens[j]->y; 774 } 775 result = ProcShmPutImage(client); 776 if(result != Success) break; 777 } 778 return result; 779} 780 781static int 782ProcPanoramiXShmGetImage(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((pointer *)&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, 812 DixReadAccess); 813 if (rc != Success) 814 return rc; 815 816 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 817 818 x = stuff->x; 819 y = stuff->y; 820 w = stuff->width; 821 h = stuff->height; 822 format = stuff->format; 823 planemask = stuff->planeMask; 824 825 isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 826 827 if(isRoot) { 828 if( /* check for being onscreen */ 829 x < 0 || x + w > PanoramiXPixWidth || 830 y < 0 || y + h > PanoramiXPixHeight ) 831 return BadMatch; 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 /* check for being inside of border */ 839 x < - wBorderWidth((WindowPtr)pDraw) || 840 x + w > wBorderWidth((WindowPtr)pDraw) + (int)pDraw->width || 841 y < -wBorderWidth((WindowPtr)pDraw) || 842 y + h > wBorderWidth ((WindowPtr)pDraw) + (int)pDraw->height) 843 return BadMatch; 844 } 845 846 drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr)); 847 if(!drawables) 848 return BadAlloc; 849 850 drawables[0] = pDraw; 851 for(i = 1; i < PanoramiXNumScreens; i++) { 852 rc = dixLookupDrawable(drawables+i, draw->info[i].id, client, 0, 853 DixReadAccess); 854 if (rc != Success) 855 { 856 free(drawables); 857 return rc; 858 } 859 } 860 861 xgi.visual = wVisual(((WindowPtr)pDraw)); 862 xgi.type = X_Reply; 863 xgi.length = 0; 864 xgi.sequenceNumber = client->sequence; 865 xgi.depth = pDraw->depth; 866 867 if(format == ZPixmap) { 868 widthBytesLine = PixmapBytePad(w, pDraw->depth); 869 length = widthBytesLine * h; 870 } else { 871 widthBytesLine = PixmapBytePad(w, 1); 872 lenPer = widthBytesLine * h; 873 plane = ((Mask)1) << (pDraw->depth - 1); 874 length = lenPer * Ones(planemask & (plane | (plane - 1))); 875 } 876 877 VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 878 xgi.size = length; 879 880 if (length == 0) {/* nothing to do */ } 881 else if (format == ZPixmap) { 882 XineramaGetImageData(drawables, x, y, w, h, format, planemask, 883 shmdesc->addr + stuff->offset, 884 widthBytesLine, isRoot); 885 } else { 886 887 length = stuff->offset; 888 for (; plane; plane >>= 1) { 889 if (planemask & plane) { 890 XineramaGetImageData(drawables, x, y, w, h, 891 format, plane, shmdesc->addr + length, 892 widthBytesLine, isRoot); 893 length += lenPer; 894 } 895 } 896 } 897 free(drawables); 898 899 if (client->swapped) { 900 int n; 901 swaps(&xgi.sequenceNumber, n); 902 swapl(&xgi.length, n); 903 swapl(&xgi.visual, n); 904 swapl(&xgi.size, n); 905 } 906 WriteToClient(client, sizeof(xShmGetImageReply), (char *)&xgi); 907 908 return Success; 909} 910 911static int 912ProcPanoramiXShmCreatePixmap(ClientPtr client) 913{ 914 ScreenPtr pScreen = NULL; 915 PixmapPtr pMap = NULL; 916 DrawablePtr pDraw; 917 DepthPtr pDepth; 918 int i, j, result, rc; 919 ShmDescPtr shmdesc; 920 REQUEST(xShmCreatePixmapReq); 921 unsigned int width, height, depth; 922 unsigned long size; 923 PanoramiXRes *newPix; 924 925 REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 926 client->errorValue = stuff->pid; 927 if (!sharedPixmaps) 928 return BadImplementation; 929 LEGAL_NEW_RESOURCE(stuff->pid, client); 930 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 931 DixGetAttrAccess); 932 if (rc != Success) 933 return rc; 934 935 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 936 937 width = stuff->width; 938 height = stuff->height; 939 depth = stuff->depth; 940 if (!width || !height || !depth) 941 { 942 client->errorValue = 0; 943 return BadValue; 944 } 945 if (width > 32767 || height > 32767) 946 return BadAlloc; 947 948 if (stuff->depth != 1) 949 { 950 pDepth = pDraw->pScreen->allowedDepths; 951 for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++) 952 if (pDepth->depth == stuff->depth) 953 goto CreatePmap; 954 client->errorValue = stuff->depth; 955 return BadValue; 956 } 957 958CreatePmap: 959 size = PixmapBytePad(width, depth) * height; 960 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 961 if (size < width * height) 962 return BadAlloc; 963 } 964 /* thankfully, offset is unsigned */ 965 if (stuff->offset + size < size) 966 return BadAlloc; 967 968 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 969 970 if(!(newPix = malloc(sizeof(PanoramiXRes)))) 971 return BadAlloc; 972 973 newPix->type = XRT_PIXMAP; 974 newPix->u.pix.shared = TRUE; 975 newPix->info[0].id = stuff->pid; 976 for(j = 1; j < PanoramiXNumScreens; j++) 977 newPix->info[j].id = FakeClientID(client->index); 978 979 result = Success; 980 981 FOR_NSCREENS(j) { 982 ShmScrPrivateRec *screen_priv; 983 pScreen = screenInfo.screens[j]; 984 985 screen_priv = ShmGetScreenPriv(pScreen); 986 pMap = (*screen_priv->shmFuncs->CreatePixmap)(pScreen, 987 stuff->width, stuff->height, stuff->depth, 988 shmdesc->addr + stuff->offset); 989 990 if (pMap) { 991 dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc); 992 shmdesc->refcnt++; 993 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 994 pMap->drawable.id = newPix->info[j].id; 995 if (!AddResource(newPix->info[j].id, RT_PIXMAP, (pointer)pMap)) { 996 (*pScreen->DestroyPixmap)(pMap); 997 result = BadAlloc; 998 break; 999 } 1000 } else { 1001 result = BadAlloc; 1002 break; 1003 } 1004 } 1005 1006 if(result == BadAlloc) { 1007 while(j--) { 1008 (*pScreen->DestroyPixmap)(pMap); 1009 FreeResource(newPix->info[j].id, RT_NONE); 1010 } 1011 free(newPix); 1012 } else 1013 AddResource(stuff->pid, XRT_PIXMAP, newPix); 1014 1015 return result; 1016} 1017#endif 1018 1019static PixmapPtr 1020fbShmCreatePixmap (ScreenPtr pScreen, 1021 int width, int height, int depth, char *addr) 1022{ 1023 PixmapPtr pPixmap; 1024 1025 pPixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, pScreen->rootDepth, 0); 1026 if (!pPixmap) 1027 return NullPixmap; 1028 1029 if (!(*pScreen->ModifyPixmapHeader)(pPixmap, width, height, depth, 1030 BitsPerPixel(depth), PixmapBytePad(width, depth), (pointer)addr)) { 1031 (*pScreen->DestroyPixmap)(pPixmap); 1032 return NullPixmap; 1033 } 1034 return pPixmap; 1035} 1036 1037static int 1038ProcShmCreatePixmap(ClientPtr client) 1039{ 1040 PixmapPtr pMap; 1041 DrawablePtr pDraw; 1042 DepthPtr pDepth; 1043 int i, rc; 1044 ShmDescPtr shmdesc; 1045 ShmScrPrivateRec *screen_priv; 1046 REQUEST(xShmCreatePixmapReq); 1047 unsigned int width, height, depth; 1048 unsigned long size; 1049 1050 REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1051 client->errorValue = stuff->pid; 1052 if (!sharedPixmaps) 1053 return BadImplementation; 1054 LEGAL_NEW_RESOURCE(stuff->pid, client); 1055 rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 1056 DixGetAttrAccess); 1057 if (rc != Success) 1058 return rc; 1059 1060 VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 1061 1062 width = stuff->width; 1063 height = stuff->height; 1064 depth = stuff->depth; 1065 if (!width || !height || !depth) 1066 { 1067 client->errorValue = 0; 1068 return BadValue; 1069 } 1070 if (width > 32767 || height > 32767) 1071 return BadAlloc; 1072 1073 if (stuff->depth != 1) 1074 { 1075 pDepth = pDraw->pScreen->allowedDepths; 1076 for (i=0; i<pDraw->pScreen->numDepths; i++, pDepth++) 1077 if (pDepth->depth == stuff->depth) 1078 goto CreatePmap; 1079 client->errorValue = stuff->depth; 1080 return BadValue; 1081 } 1082 1083CreatePmap: 1084 size = PixmapBytePad(width, depth) * height; 1085 if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 1086 if (size < width * height) 1087 return BadAlloc; 1088 } 1089 /* thankfully, offset is unsigned */ 1090 if (stuff->offset + size < size) 1091 return BadAlloc; 1092 1093 VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 1094 screen_priv = ShmGetScreenPriv(pDraw->pScreen); 1095 pMap = (*screen_priv->shmFuncs->CreatePixmap)( 1096 pDraw->pScreen, stuff->width, 1097 stuff->height, stuff->depth, 1098 shmdesc->addr + stuff->offset); 1099 if (pMap) 1100 { 1101 rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, 1102 pMap, RT_NONE, NULL, DixCreateAccess); 1103 if (rc != Success) { 1104 pDraw->pScreen->DestroyPixmap(pMap); 1105 return rc; 1106 } 1107 dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc); 1108 shmdesc->refcnt++; 1109 pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 1110 pMap->drawable.id = stuff->pid; 1111 if (AddResource(stuff->pid, RT_PIXMAP, (pointer)pMap)) 1112 { 1113 return Success; 1114 } 1115 pDraw->pScreen->DestroyPixmap(pMap); 1116 } 1117 return BadAlloc; 1118} 1119 1120static int 1121ProcShmDispatch (ClientPtr client) 1122{ 1123 REQUEST(xReq); 1124 switch (stuff->data) 1125 { 1126 case X_ShmQueryVersion: 1127 return ProcShmQueryVersion(client); 1128 case X_ShmAttach: 1129 return ProcShmAttach(client); 1130 case X_ShmDetach: 1131 return ProcShmDetach(client); 1132 case X_ShmPutImage: 1133#ifdef PANORAMIX 1134 if ( !noPanoramiXExtension ) 1135 return ProcPanoramiXShmPutImage(client); 1136#endif 1137 return ProcShmPutImage(client); 1138 case X_ShmGetImage: 1139#ifdef PANORAMIX 1140 if ( !noPanoramiXExtension ) 1141 return ProcPanoramiXShmGetImage(client); 1142#endif 1143 return ProcShmGetImage(client); 1144 case X_ShmCreatePixmap: 1145#ifdef PANORAMIX 1146 if ( !noPanoramiXExtension ) 1147 return ProcPanoramiXShmCreatePixmap(client); 1148#endif 1149 return ProcShmCreatePixmap(client); 1150 default: 1151 return BadRequest; 1152 } 1153} 1154 1155static void 1156SShmCompletionEvent(xShmCompletionEvent *from, xShmCompletionEvent *to) 1157{ 1158 to->type = from->type; 1159 cpswaps(from->sequenceNumber, to->sequenceNumber); 1160 cpswapl(from->drawable, to->drawable); 1161 cpswaps(from->minorEvent, to->minorEvent); 1162 to->majorEvent = from->majorEvent; 1163 cpswapl(from->shmseg, to->shmseg); 1164 cpswapl(from->offset, to->offset); 1165} 1166 1167static int 1168SProcShmQueryVersion(ClientPtr client) 1169{ 1170 int n; 1171 REQUEST(xShmQueryVersionReq); 1172 1173 swaps(&stuff->length, n); 1174 return ProcShmQueryVersion(client); 1175} 1176 1177static int 1178SProcShmAttach(ClientPtr client) 1179{ 1180 int n; 1181 REQUEST(xShmAttachReq); 1182 swaps(&stuff->length, n); 1183 REQUEST_SIZE_MATCH(xShmAttachReq); 1184 swapl(&stuff->shmseg, n); 1185 swapl(&stuff->shmid, n); 1186 return ProcShmAttach(client); 1187} 1188 1189static int 1190SProcShmDetach(ClientPtr client) 1191{ 1192 int n; 1193 REQUEST(xShmDetachReq); 1194 swaps(&stuff->length, n); 1195 REQUEST_SIZE_MATCH(xShmDetachReq); 1196 swapl(&stuff->shmseg, n); 1197 return ProcShmDetach(client); 1198} 1199 1200static int 1201SProcShmPutImage(ClientPtr client) 1202{ 1203 int n; 1204 REQUEST(xShmPutImageReq); 1205 swaps(&stuff->length, n); 1206 REQUEST_SIZE_MATCH(xShmPutImageReq); 1207 swapl(&stuff->drawable, n); 1208 swapl(&stuff->gc, n); 1209 swaps(&stuff->totalWidth, n); 1210 swaps(&stuff->totalHeight, n); 1211 swaps(&stuff->srcX, n); 1212 swaps(&stuff->srcY, n); 1213 swaps(&stuff->srcWidth, n); 1214 swaps(&stuff->srcHeight, n); 1215 swaps(&stuff->dstX, n); 1216 swaps(&stuff->dstY, n); 1217 swapl(&stuff->shmseg, n); 1218 swapl(&stuff->offset, n); 1219 return ProcShmPutImage(client); 1220} 1221 1222static int 1223SProcShmGetImage(ClientPtr client) 1224{ 1225 int n; 1226 REQUEST(xShmGetImageReq); 1227 swaps(&stuff->length, n); 1228 REQUEST_SIZE_MATCH(xShmGetImageReq); 1229 swapl(&stuff->drawable, n); 1230 swaps(&stuff->x, n); 1231 swaps(&stuff->y, n); 1232 swaps(&stuff->width, n); 1233 swaps(&stuff->height, n); 1234 swapl(&stuff->planeMask, n); 1235 swapl(&stuff->shmseg, n); 1236 swapl(&stuff->offset, n); 1237 return ProcShmGetImage(client); 1238} 1239 1240static int 1241SProcShmCreatePixmap(ClientPtr client) 1242{ 1243 int n; 1244 REQUEST(xShmCreatePixmapReq); 1245 swaps(&stuff->length, n); 1246 REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1247 swapl(&stuff->pid, n); 1248 swapl(&stuff->drawable, n); 1249 swaps(&stuff->width, n); 1250 swaps(&stuff->height, n); 1251 swapl(&stuff->shmseg, n); 1252 swapl(&stuff->offset, n); 1253 return ProcShmCreatePixmap(client); 1254} 1255 1256static int 1257SProcShmDispatch (ClientPtr client) 1258{ 1259 REQUEST(xReq); 1260 switch (stuff->data) 1261 { 1262 case X_ShmQueryVersion: 1263 return SProcShmQueryVersion(client); 1264 case X_ShmAttach: 1265 return SProcShmAttach(client); 1266 case X_ShmDetach: 1267 return SProcShmDetach(client); 1268 case X_ShmPutImage: 1269 return SProcShmPutImage(client); 1270 case X_ShmGetImage: 1271 return SProcShmGetImage(client); 1272 case X_ShmCreatePixmap: 1273 return SProcShmCreatePixmap(client); 1274 default: 1275 return BadRequest; 1276 } 1277} 1278 1279void 1280ShmExtensionInit(INITARGS) 1281{ 1282 ExtensionEntry *extEntry; 1283 int i; 1284 1285#ifdef MUST_CHECK_FOR_SHM_SYSCALL 1286 if (!CheckForShmSyscall()) 1287 { 1288 ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); 1289 return; 1290 } 1291#endif 1292 1293 if (!ShmRegisterPrivates()) 1294 return; 1295 1296 sharedPixmaps = xFalse; 1297 { 1298 sharedPixmaps = xTrue; 1299 for (i = 0; i < screenInfo.numScreens; i++) 1300 { 1301 ShmScrPrivateRec *screen_priv = ShmInitScreenPriv(screenInfo.screens[i]); 1302 if (!screen_priv->shmFuncs) 1303 screen_priv->shmFuncs = &miFuncs; 1304 if (!screen_priv->shmFuncs->CreatePixmap) 1305 sharedPixmaps = xFalse; 1306 } 1307 if (sharedPixmaps) 1308 for (i = 0; i < screenInfo.numScreens; i++) 1309 { 1310 ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(screenInfo.screens[i]); 1311 screen_priv->destroyPixmap = screenInfo.screens[i]->DestroyPixmap; 1312 screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; 1313 } 1314 } 1315 ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg"); 1316 if (ShmSegType && 1317 (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, 1318 ProcShmDispatch, SProcShmDispatch, 1319 ShmResetProc, StandardMinorOpcode))) 1320 { 1321 ShmReqCode = (unsigned char)extEntry->base; 1322 ShmCompletionCode = extEntry->eventBase; 1323 BadShmSegCode = extEntry->errorBase; 1324 SetResourceTypeErrorValue(ShmSegType, BadShmSegCode); 1325 EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; 1326 } 1327} 1328