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