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