105b261ecSmrg/************************************************************ 205b261ecSmrg 305b261ecSmrgCopyright 1989, 1998 The Open Group 405b261ecSmrg 505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its 605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that 705b261ecSmrgthe above copyright notice appear in all copies and that both that 805b261ecSmrgcopyright notice and this permission notice appear in supporting 905b261ecSmrgdocumentation. 1005b261ecSmrg 1105b261ecSmrgThe above copyright notice and this permission notice shall be included in 1205b261ecSmrgall copies or substantial portions of the Software. 1305b261ecSmrg 1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2005b261ecSmrg 2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be 2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings 2305b261ecSmrgin this Software without prior written authorization from The Open Group. 2405b261ecSmrg 2505b261ecSmrg********************************************************/ 2605b261ecSmrg 2705b261ecSmrg/* THIS IS NOT AN X CONSORTIUM STANDARD OR AN X PROJECT TEAM SPECIFICATION */ 2805b261ecSmrg 2905b261ecSmrg#define SHM 3005b261ecSmrg 3105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H 3205b261ecSmrg#include <dix-config.h> 3305b261ecSmrg#endif 3405b261ecSmrg 3505b261ecSmrg#include <sys/types.h> 3605b261ecSmrg#include <sys/ipc.h> 3705b261ecSmrg#include <sys/shm.h> 384e185dc0Smrg#ifdef HAVE_MEMFD_CREATE 394e185dc0Smrg#include <sys/mman.h> 404e185dc0Smrg#endif 4105b261ecSmrg#include <unistd.h> 4205b261ecSmrg#include <sys/stat.h> 43f7df2e56Smrg#include <fcntl.h> 4405b261ecSmrg#include <X11/X.h> 4505b261ecSmrg#include <X11/Xproto.h> 4605b261ecSmrg#include "misc.h" 4705b261ecSmrg#include "os.h" 4805b261ecSmrg#include "dixstruct.h" 4905b261ecSmrg#include "resource.h" 5005b261ecSmrg#include "scrnintstr.h" 5105b261ecSmrg#include "windowstr.h" 5205b261ecSmrg#include "pixmapstr.h" 5305b261ecSmrg#include "gcstruct.h" 5405b261ecSmrg#include "extnsionst.h" 5505b261ecSmrg#include "servermd.h" 564642e01fSmrg#include "shmint.h" 574642e01fSmrg#include "xace.h" 58684baedfSmrg#include <X11/extensions/shmproto.h> 5905b261ecSmrg#include <X11/Xfuncproto.h> 60f7df2e56Smrg#include <sys/mman.h> 614202a189Smrg#include "protocol-versions.h" 62f7df2e56Smrg#include "busfault.h" 6305b261ecSmrg 644642e01fSmrg/* Needed for Solaris cross-zone shared memory extension */ 654642e01fSmrg#ifdef HAVE_SHMCTL64 664642e01fSmrg#include <sys/ipc_impl.h> 674642e01fSmrg#define SHMSTAT(id, buf) shmctl64(id, IPC_STAT64, buf) 684642e01fSmrg#define SHMSTAT_TYPE struct shmid_ds64 694642e01fSmrg#define SHMPERM_TYPE struct ipc_perm64 704642e01fSmrg#define SHM_PERM(buf) buf.shmx_perm 714642e01fSmrg#define SHM_SEGSZ(buf) buf.shmx_segsz 724642e01fSmrg#define SHMPERM_UID(p) p->ipcx_uid 734642e01fSmrg#define SHMPERM_CUID(p) p->ipcx_cuid 744642e01fSmrg#define SHMPERM_GID(p) p->ipcx_gid 754642e01fSmrg#define SHMPERM_CGID(p) p->ipcx_cgid 764642e01fSmrg#define SHMPERM_MODE(p) p->ipcx_mode 774642e01fSmrg#define SHMPERM_ZONEID(p) p->ipcx_zoneid 784642e01fSmrg#else 794642e01fSmrg#define SHMSTAT(id, buf) shmctl(id, IPC_STAT, buf) 804642e01fSmrg#define SHMSTAT_TYPE struct shmid_ds 814642e01fSmrg#define SHMPERM_TYPE struct ipc_perm 824642e01fSmrg#define SHM_PERM(buf) buf.shm_perm 834642e01fSmrg#define SHM_SEGSZ(buf) buf.shm_segsz 844642e01fSmrg#define SHMPERM_UID(p) p->uid 854642e01fSmrg#define SHMPERM_CUID(p) p->cuid 864642e01fSmrg#define SHMPERM_GID(p) p->gid 874642e01fSmrg#define SHMPERM_CGID(p) p->cgid 884642e01fSmrg#define SHMPERM_MODE(p) p->mode 894642e01fSmrg#endif 904642e01fSmrg 9105b261ecSmrg#ifdef PANORAMIX 9205b261ecSmrg#include "panoramiX.h" 9305b261ecSmrg#include "panoramiXsrv.h" 9405b261ecSmrg#endif 9505b261ecSmrg 96f7df2e56Smrg#include "extinit.h" 9705b261ecSmrg 984202a189Smrgtypedef struct _ShmScrPrivateRec { 994202a189Smrg CloseScreenProcPtr CloseScreen; 1004202a189Smrg ShmFuncsPtr shmFuncs; 1014202a189Smrg DestroyPixmapProcPtr destroyPixmap; 1024202a189Smrg} ShmScrPrivateRec; 1034202a189Smrg 10405b261ecSmrgstatic PixmapPtr fbShmCreatePixmap(XSHM_CREATE_PIXMAP_ARGS); 105f7df2e56Smrgstatic int ShmDetachSegment(void *value, XID shmseg); 106f7df2e56Smrgstatic void ShmResetProc(ExtensionEntry *extEntry); 107f7df2e56Smrgstatic void SShmCompletionEvent(xShmCompletionEvent *from, 108f7df2e56Smrg xShmCompletionEvent *to); 10905b261ecSmrg 110f7df2e56Smrgstatic Bool ShmDestroyPixmap(PixmapPtr pPixmap); 11105b261ecSmrg 11205b261ecSmrgstatic unsigned char ShmReqCode; 1134202a189Smrgint ShmCompletionCode; 1144202a189Smrgint BadShmSegCode; 1154202a189SmrgRESTYPE ShmSegType; 11605b261ecSmrgstatic ShmDescPtr Shmsegs; 11705b261ecSmrgstatic Bool sharedPixmaps; 1184202a189Smrgstatic DevPrivateKeyRec shmScrPrivateKeyRec; 119f7df2e56Smrg 1204202a189Smrg#define shmScrPrivateKey (&shmScrPrivateKeyRec) 1214202a189Smrgstatic DevPrivateKeyRec shmPixmapPrivateKeyRec; 122f7df2e56Smrg 1234202a189Smrg#define shmPixmapPrivateKey (&shmPixmapPrivateKeyRec) 124f7df2e56Smrgstatic ShmFuncs miFuncs = { NULL, NULL }; 125f7df2e56Smrgstatic ShmFuncs fbFuncs = { fbShmCreatePixmap, NULL }; 12605b261ecSmrg 1274202a189Smrg#define ShmGetScreenPriv(s) ((ShmScrPrivateRec *)dixLookupPrivate(&(s)->devPrivates, shmScrPrivateKey)) 1284202a189Smrg 12905b261ecSmrg#define VERIFY_SHMSEG(shmseg,shmdesc,client) \ 13005b261ecSmrg{ \ 131f7df2e56Smrg int tmprc; \ 132f7df2e56Smrg tmprc = dixLookupResourceByType((void **)&(shmdesc), shmseg, ShmSegType, \ 133f7df2e56Smrg client, DixReadAccess); \ 134f7df2e56Smrg if (tmprc != Success) \ 135f7df2e56Smrg return tmprc; \ 13605b261ecSmrg} 13705b261ecSmrg 13805b261ecSmrg#define VERIFY_SHMPTR(shmseg,offset,needwrite,shmdesc,client) \ 13905b261ecSmrg{ \ 14005b261ecSmrg VERIFY_SHMSEG(shmseg, shmdesc, client); \ 14105b261ecSmrg if ((offset & 3) || (offset > shmdesc->size)) \ 14205b261ecSmrg { \ 14305b261ecSmrg client->errorValue = offset; \ 14405b261ecSmrg return BadValue; \ 14505b261ecSmrg } \ 14605b261ecSmrg if (needwrite && !shmdesc->writable) \ 14705b261ecSmrg return BadAccess; \ 14805b261ecSmrg} 14905b261ecSmrg 15005b261ecSmrg#define VERIFY_SHMSIZE(shmdesc,offset,len,client) \ 15105b261ecSmrg{ \ 15205b261ecSmrg if ((offset + len) > shmdesc->size) \ 15305b261ecSmrg { \ 15405b261ecSmrg return BadAccess; \ 15505b261ecSmrg } \ 15605b261ecSmrg} 15705b261ecSmrg 15805b261ecSmrg#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__) || defined(__DragonFly__) 15905b261ecSmrg 16005b261ecSmrgstatic Bool badSysCall = FALSE; 16105b261ecSmrg 16205b261ecSmrgstatic void 1634642e01fSmrgSigSysHandler(int signo) 16405b261ecSmrg{ 16505b261ecSmrg badSysCall = TRUE; 16605b261ecSmrg} 16705b261ecSmrg 168f7df2e56Smrgstatic Bool 169f7df2e56SmrgCheckForShmSyscall(void) 17005b261ecSmrg{ 171f7df2e56Smrg void (*oldHandler) (int); 17205b261ecSmrg int shmid = -1; 17305b261ecSmrg 17405b261ecSmrg /* If no SHM support in the kernel, the bad syscall will generate SIGSYS */ 1757e31ba66Smrg oldHandler = OsSignal(SIGSYS, SigSysHandler); 17605b261ecSmrg 17705b261ecSmrg badSysCall = FALSE; 17805b261ecSmrg shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT); 17905b261ecSmrg 180f7df2e56Smrg if (shmid != -1) { 18105b261ecSmrg /* Successful allocation - clean up */ 182f7df2e56Smrg shmctl(shmid, IPC_RMID, NULL); 18305b261ecSmrg } 184f7df2e56Smrg else { 18505b261ecSmrg /* Allocation failed */ 18605b261ecSmrg badSysCall = TRUE; 18705b261ecSmrg } 1887e31ba66Smrg OsSignal(SIGSYS, oldHandler); 1894202a189Smrg return !badSysCall; 19005b261ecSmrg} 19105b261ecSmrg 19205b261ecSmrg#define MUST_CHECK_FOR_SHM_SYSCALL 19305b261ecSmrg 19405b261ecSmrg#endif 19505b261ecSmrg 1964202a189Smrgstatic Bool 197f7df2e56SmrgShmCloseScreen(ScreenPtr pScreen) 1984202a189Smrg{ 1994202a189Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 200f7df2e56Smrg 2014202a189Smrg pScreen->CloseScreen = screen_priv->CloseScreen; 2024202a189Smrg dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, NULL); 2034202a189Smrg free(screen_priv); 204f7df2e56Smrg return (*pScreen->CloseScreen) (pScreen); 2054202a189Smrg} 2064202a189Smrg 2074202a189Smrgstatic ShmScrPrivateRec * 2084202a189SmrgShmInitScreenPriv(ScreenPtr pScreen) 2094202a189Smrg{ 2104202a189Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 211f7df2e56Smrg 212f7df2e56Smrg if (!screen_priv) { 213f7df2e56Smrg screen_priv = calloc(1, sizeof(ShmScrPrivateRec)); 214f7df2e56Smrg screen_priv->CloseScreen = pScreen->CloseScreen; 215f7df2e56Smrg dixSetPrivate(&pScreen->devPrivates, shmScrPrivateKey, screen_priv); 216f7df2e56Smrg pScreen->CloseScreen = ShmCloseScreen; 2174202a189Smrg } 2184202a189Smrg return screen_priv; 2194202a189Smrg} 2204202a189Smrg 2214202a189Smrgstatic Bool 2224202a189SmrgShmRegisterPrivates(void) 2234202a189Smrg{ 2244202a189Smrg if (!dixRegisterPrivateKey(&shmScrPrivateKeyRec, PRIVATE_SCREEN, 0)) 225f7df2e56Smrg return FALSE; 2264202a189Smrg if (!dixRegisterPrivateKey(&shmPixmapPrivateKeyRec, PRIVATE_PIXMAP, 0)) 227f7df2e56Smrg return FALSE; 2284202a189Smrg return TRUE; 2294202a189Smrg} 2304202a189Smrg 231f7df2e56Smrg /*ARGSUSED*/ static void 232f7df2e56SmrgShmResetProc(ExtensionEntry * extEntry) 23305b261ecSmrg{ 23405b261ecSmrg int i; 235f7df2e56Smrg 2364202a189Smrg for (i = 0; i < screenInfo.numScreens; i++) 237f7df2e56Smrg ShmRegisterFuncs(screenInfo.screens[i], NULL); 23805b261ecSmrg} 23905b261ecSmrg 2404202a189Smrgvoid 2414642e01fSmrgShmRegisterFuncs(ScreenPtr pScreen, ShmFuncsPtr funcs) 24205b261ecSmrg{ 2434202a189Smrg if (!ShmRegisterPrivates()) 244f7df2e56Smrg return; 2454202a189Smrg ShmInitScreenPriv(pScreen)->shmFuncs = funcs; 24605b261ecSmrg} 24705b261ecSmrg 24805b261ecSmrgstatic Bool 249f7df2e56SmrgShmDestroyPixmap(PixmapPtr pPixmap) 25005b261ecSmrg{ 251f7df2e56Smrg ScreenPtr pScreen = pPixmap->drawable.pScreen; 2524202a189Smrg ShmScrPrivateRec *screen_priv = ShmGetScreenPriv(pScreen); 253f7df2e56Smrg void *shmdesc = NULL; 254f7df2e56Smrg Bool ret; 255f7df2e56Smrg 25605b261ecSmrg if (pPixmap->refcnt == 1) 257f7df2e56Smrg shmdesc = dixLookupPrivate(&pPixmap->devPrivates, shmPixmapPrivateKey); 258f7df2e56Smrg 2594202a189Smrg pScreen->DestroyPixmap = screen_priv->destroyPixmap; 26005b261ecSmrg ret = (*pScreen->DestroyPixmap) (pPixmap); 2614202a189Smrg screen_priv->destroyPixmap = pScreen->DestroyPixmap; 26205b261ecSmrg pScreen->DestroyPixmap = ShmDestroyPixmap; 263f7df2e56Smrg 264f7df2e56Smrg if (shmdesc) 265f7df2e56Smrg ShmDetachSegment(shmdesc, 0); 266f7df2e56Smrg 26705b261ecSmrg return ret; 26805b261ecSmrg} 26905b261ecSmrg 2704202a189Smrgvoid 2714642e01fSmrgShmRegisterFbFuncs(ScreenPtr pScreen) 27205b261ecSmrg{ 2734202a189Smrg ShmRegisterFuncs(pScreen, &fbFuncs); 27405b261ecSmrg} 27505b261ecSmrg 27605b261ecSmrgstatic int 2774642e01fSmrgProcShmQueryVersion(ClientPtr client) 27805b261ecSmrg{ 279f7df2e56Smrg xShmQueryVersionReply rep = { 280f7df2e56Smrg .type = X_Reply, 281f7df2e56Smrg .sharedPixmaps = sharedPixmaps, 282f7df2e56Smrg .sequenceNumber = client->sequence, 283f7df2e56Smrg .length = 0, 284f7df2e56Smrg .majorVersion = SERVER_SHM_MAJOR_VERSION, 285f7df2e56Smrg .minorVersion = SERVER_SHM_MINOR_VERSION, 286f7df2e56Smrg .uid = geteuid(), 287f7df2e56Smrg .gid = getegid(), 288f7df2e56Smrg .pixmapFormat = sharedPixmaps ? ZPixmap : 0 289f7df2e56Smrg }; 29005b261ecSmrg 29105b261ecSmrg REQUEST_SIZE_MATCH(xShmQueryVersionReq); 292f7df2e56Smrg 29305b261ecSmrg if (client->swapped) { 294f7df2e56Smrg swaps(&rep.sequenceNumber); 295f7df2e56Smrg swapl(&rep.length); 296f7df2e56Smrg swaps(&rep.majorVersion); 297f7df2e56Smrg swaps(&rep.minorVersion); 298f7df2e56Smrg swaps(&rep.uid); 299f7df2e56Smrg swaps(&rep.gid); 300f7df2e56Smrg } 301f7df2e56Smrg WriteToClient(client, sizeof(xShmQueryVersionReply), &rep); 3024202a189Smrg return Success; 30305b261ecSmrg} 30405b261ecSmrg 30505b261ecSmrg/* 3065a112b11Smrg * Simulate the access() system call for a shared memory segment, 3075a112b11Smrg * using the credentials from the client if available. 30805b261ecSmrg */ 30905b261ecSmrgstatic int 310f7df2e56Smrgshm_access(ClientPtr client, SHMPERM_TYPE * perm, int readonly) 31105b261ecSmrg{ 31205b261ecSmrg int uid, gid; 31305b261ecSmrg mode_t mask; 3144642e01fSmrg int uidset = 0, gidset = 0; 3154642e01fSmrg LocalClientCredRec *lcc; 316f7df2e56Smrg 3174642e01fSmrg if (GetLocalClientCreds(client, &lcc) != -1) { 31805b261ecSmrg 319f7df2e56Smrg if (lcc->fieldsSet & LCC_UID_SET) { 320f7df2e56Smrg uid = lcc->euid; 321f7df2e56Smrg uidset = 1; 322f7df2e56Smrg } 323f7df2e56Smrg if (lcc->fieldsSet & LCC_GID_SET) { 324f7df2e56Smrg gid = lcc->egid; 325f7df2e56Smrg gidset = 1; 326f7df2e56Smrg } 3274642e01fSmrg 3284642e01fSmrg#if defined(HAVE_GETZONEID) && defined(SHMPERM_ZONEID) 329f7df2e56Smrg if (((lcc->fieldsSet & LCC_ZID_SET) == 0) || (lcc->zoneid == -1) 330f7df2e56Smrg || (lcc->zoneid != SHMPERM_ZONEID(perm))) { 331f7df2e56Smrg uidset = 0; 332f7df2e56Smrg gidset = 0; 333f7df2e56Smrg } 3344642e01fSmrg#endif 335f7df2e56Smrg FreeLocalClientCreds(lcc); 336f7df2e56Smrg 337f7df2e56Smrg if (uidset) { 338f7df2e56Smrg /* User id 0 always gets access */ 339f7df2e56Smrg if (uid == 0) { 340f7df2e56Smrg return 0; 341f7df2e56Smrg } 342f7df2e56Smrg /* Check the owner */ 343f7df2e56Smrg if (SHMPERM_UID(perm) == uid || SHMPERM_CUID(perm) == uid) { 344f7df2e56Smrg mask = S_IRUSR; 345f7df2e56Smrg if (!readonly) { 346f7df2e56Smrg mask |= S_IWUSR; 347f7df2e56Smrg } 348f7df2e56Smrg return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 349f7df2e56Smrg } 350f7df2e56Smrg } 351f7df2e56Smrg 352f7df2e56Smrg if (gidset) { 353f7df2e56Smrg /* Check the group */ 354f7df2e56Smrg if (SHMPERM_GID(perm) == gid || SHMPERM_CGID(perm) == gid) { 355f7df2e56Smrg mask = S_IRGRP; 356f7df2e56Smrg if (!readonly) { 357f7df2e56Smrg mask |= S_IWGRP; 358f7df2e56Smrg } 359f7df2e56Smrg return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 360f7df2e56Smrg } 361f7df2e56Smrg } 36205b261ecSmrg } 36305b261ecSmrg /* Otherwise, check everyone else */ 36405b261ecSmrg mask = S_IROTH; 36505b261ecSmrg if (!readonly) { 366f7df2e56Smrg mask |= S_IWOTH; 36705b261ecSmrg } 3684642e01fSmrg return (SHMPERM_MODE(perm) & mask) == mask ? 0 : -1; 36905b261ecSmrg} 37005b261ecSmrg 37105b261ecSmrgstatic int 3724642e01fSmrgProcShmAttach(ClientPtr client) 37305b261ecSmrg{ 3744642e01fSmrg SHMSTAT_TYPE buf; 37505b261ecSmrg ShmDescPtr shmdesc; 376f7df2e56Smrg 37705b261ecSmrg REQUEST(xShmAttachReq); 37805b261ecSmrg 37905b261ecSmrg REQUEST_SIZE_MATCH(xShmAttachReq); 38005b261ecSmrg LEGAL_NEW_RESOURCE(stuff->shmseg, client); 381f7df2e56Smrg if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) { 382f7df2e56Smrg client->errorValue = stuff->readOnly; 3834202a189Smrg return BadValue; 38405b261ecSmrg } 385f7df2e56Smrg for (shmdesc = Shmsegs; shmdesc; shmdesc = shmdesc->next) { 386f7df2e56Smrg if (!SHMDESC_IS_FD(shmdesc) && shmdesc->shmid == stuff->shmid) 387f7df2e56Smrg break; 38805b261ecSmrg } 389f7df2e56Smrg if (shmdesc) { 390f7df2e56Smrg if (!stuff->readOnly && !shmdesc->writable) 391f7df2e56Smrg return BadAccess; 392f7df2e56Smrg shmdesc->refcnt++; 393f7df2e56Smrg } 394f7df2e56Smrg else { 395f7df2e56Smrg shmdesc = malloc(sizeof(ShmDescRec)); 396f7df2e56Smrg if (!shmdesc) 397f7df2e56Smrg return BadAlloc; 398f7df2e56Smrg#ifdef SHM_FD_PASSING 399f7df2e56Smrg shmdesc->is_fd = FALSE; 400f7df2e56Smrg#endif 401f7df2e56Smrg shmdesc->addr = shmat(stuff->shmid, 0, 402f7df2e56Smrg stuff->readOnly ? SHM_RDONLY : 0); 403f7df2e56Smrg if ((shmdesc->addr == ((char *) -1)) || SHMSTAT(stuff->shmid, &buf)) { 404f7df2e56Smrg free(shmdesc); 405f7df2e56Smrg return BadAccess; 406f7df2e56Smrg } 407f7df2e56Smrg 408f7df2e56Smrg /* The attach was performed with root privs. We must 409f7df2e56Smrg * do manual checking of access rights for the credentials 410f7df2e56Smrg * of the client */ 411f7df2e56Smrg 412f7df2e56Smrg if (shm_access(client, &(SHM_PERM(buf)), stuff->readOnly) == -1) { 413f7df2e56Smrg shmdt(shmdesc->addr); 414f7df2e56Smrg free(shmdesc); 415f7df2e56Smrg return BadAccess; 416f7df2e56Smrg } 417f7df2e56Smrg 418f7df2e56Smrg shmdesc->shmid = stuff->shmid; 419f7df2e56Smrg shmdesc->refcnt = 1; 420f7df2e56Smrg shmdesc->writable = !stuff->readOnly; 421f7df2e56Smrg shmdesc->size = SHM_SEGSZ(buf); 422f7df2e56Smrg shmdesc->next = Shmsegs; 423f7df2e56Smrg Shmsegs = shmdesc; 42405b261ecSmrg } 425f7df2e56Smrg if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) 426f7df2e56Smrg return BadAlloc; 4274202a189Smrg return Success; 42805b261ecSmrg} 42905b261ecSmrg 430f7df2e56Smrg /*ARGSUSED*/ static int 431f7df2e56SmrgShmDetachSegment(void *value, /* must conform to DeleteType */ 432f7df2e56Smrg XID unused) 43305b261ecSmrg{ 434f7df2e56Smrg ShmDescPtr shmdesc = (ShmDescPtr) value; 43505b261ecSmrg ShmDescPtr *prev; 43605b261ecSmrg 43705b261ecSmrg if (--shmdesc->refcnt) 438f7df2e56Smrg return TRUE; 439f7df2e56Smrg#if SHM_FD_PASSING 440f7df2e56Smrg if (shmdesc->is_fd) { 441f7df2e56Smrg if (shmdesc->busfault) 442f7df2e56Smrg busfault_unregister(shmdesc->busfault); 443f7df2e56Smrg munmap(shmdesc->addr, shmdesc->size); 444f7df2e56Smrg } else 445f7df2e56Smrg#endif 446f7df2e56Smrg shmdt(shmdesc->addr); 447f7df2e56Smrg for (prev = &Shmsegs; *prev != shmdesc; prev = &(*prev)->next); 44805b261ecSmrg *prev = shmdesc->next; 4494202a189Smrg free(shmdesc); 45005b261ecSmrg return Success; 45105b261ecSmrg} 45205b261ecSmrg 45305b261ecSmrgstatic int 4544642e01fSmrgProcShmDetach(ClientPtr client) 45505b261ecSmrg{ 45605b261ecSmrg ShmDescPtr shmdesc; 457f7df2e56Smrg 45805b261ecSmrg REQUEST(xShmDetachReq); 45905b261ecSmrg 46005b261ecSmrg REQUEST_SIZE_MATCH(xShmDetachReq); 46105b261ecSmrg VERIFY_SHMSEG(stuff->shmseg, shmdesc, client); 46205b261ecSmrg FreeResource(stuff->shmseg, RT_NONE); 4634202a189Smrg return Success; 46405b261ecSmrg} 46505b261ecSmrg 4664642e01fSmrg/* 4674642e01fSmrg * If the given request doesn't exactly match PutImage's constraints, 4684642e01fSmrg * wrap the image in a scratch pixmap header and let CopyArea sort it out. 4694642e01fSmrg */ 47005b261ecSmrgstatic void 4714642e01fSmrgdoShmPutImage(DrawablePtr dst, GCPtr pGC, 472f7df2e56Smrg int depth, unsigned int format, 473f7df2e56Smrg int w, int h, int sx, int sy, int sw, int sh, int dx, int dy, 474f7df2e56Smrg char *data) 47505b261ecSmrg{ 4764642e01fSmrg PixmapPtr pPixmap; 4774202a189Smrg 47845bb0b75Smrg if (format == ZPixmap || (format == XYPixmap && depth == 1)) { 479f7df2e56Smrg pPixmap = GetScratchPixmapHeader(dst->pScreen, w, h, depth, 480f7df2e56Smrg BitsPerPixel(depth), 481f7df2e56Smrg PixmapBytePad(w, depth), data); 482f7df2e56Smrg if (!pPixmap) 483f7df2e56Smrg return; 484f7df2e56Smrg pGC->ops->CopyArea((DrawablePtr) pPixmap, dst, pGC, sx, sy, sw, sh, dx, 485f7df2e56Smrg dy); 486f7df2e56Smrg FreeScratchPixmapHeader(pPixmap); 487f7df2e56Smrg } 488f7df2e56Smrg else { 489f7df2e56Smrg GCPtr putGC = GetScratchGC(depth, dst->pScreen); 490f7df2e56Smrg 491f7df2e56Smrg if (!putGC) 492f7df2e56Smrg return; 493f7df2e56Smrg 494f7df2e56Smrg pPixmap = (*dst->pScreen->CreatePixmap) (dst->pScreen, sw, sh, depth, 495f7df2e56Smrg CREATE_PIXMAP_USAGE_SCRATCH); 496f7df2e56Smrg if (!pPixmap) { 497f7df2e56Smrg FreeScratchGC(putGC); 498f7df2e56Smrg return; 499f7df2e56Smrg } 500f7df2e56Smrg ValidateGC(&pPixmap->drawable, putGC); 501f7df2e56Smrg (*putGC->ops->PutImage) (&pPixmap->drawable, putGC, depth, -sx, -sy, w, 502f7df2e56Smrg h, 0, 503f7df2e56Smrg (format == XYPixmap) ? XYPixmap : ZPixmap, 504f7df2e56Smrg data); 505f7df2e56Smrg FreeScratchGC(putGC); 506f7df2e56Smrg if (format == XYBitmap) 507f7df2e56Smrg (void) (*pGC->ops->CopyPlane) (&pPixmap->drawable, dst, pGC, 0, 0, 508f7df2e56Smrg sw, sh, dx, dy, 1L); 509f7df2e56Smrg else 510f7df2e56Smrg (void) (*pGC->ops->CopyArea) (&pPixmap->drawable, dst, pGC, 0, 0, 511f7df2e56Smrg sw, sh, dx, dy); 512f7df2e56Smrg (*pPixmap->drawable.pScreen->DestroyPixmap) (pPixmap); 5134202a189Smrg } 51405b261ecSmrg} 51505b261ecSmrg 51665b04b38Smrgstatic int 51765b04b38SmrgProcShmPutImage(ClientPtr client) 51805b261ecSmrg{ 51965b04b38Smrg GCPtr pGC; 52065b04b38Smrg DrawablePtr pDraw; 52165b04b38Smrg long length; 52265b04b38Smrg ShmDescPtr shmdesc; 523f7df2e56Smrg 52405b261ecSmrg REQUEST(xShmPutImageReq); 52565b04b38Smrg 52605b261ecSmrg REQUEST_SIZE_MATCH(xShmPutImageReq); 52765b04b38Smrg VALIDATE_DRAWABLE_AND_GC(stuff->drawable, pDraw, DixWriteAccess); 52865b04b38Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, FALSE, shmdesc, client); 52965b04b38Smrg if ((stuff->sendEvent != xTrue) && (stuff->sendEvent != xFalse)) 530f7df2e56Smrg return BadValue; 531f7df2e56Smrg if (stuff->format == XYBitmap) { 53265b04b38Smrg if (stuff->depth != 1) 53365b04b38Smrg return BadMatch; 53465b04b38Smrg length = PixmapBytePad(stuff->totalWidth, 1); 53565b04b38Smrg } 536f7df2e56Smrg else if (stuff->format == XYPixmap) { 53765b04b38Smrg if (pDraw->depth != stuff->depth) 53865b04b38Smrg return BadMatch; 53965b04b38Smrg length = PixmapBytePad(stuff->totalWidth, 1); 540f7df2e56Smrg length *= stuff->depth; 54165b04b38Smrg } 542f7df2e56Smrg else if (stuff->format == ZPixmap) { 54365b04b38Smrg if (pDraw->depth != stuff->depth) 54465b04b38Smrg return BadMatch; 54565b04b38Smrg length = PixmapBytePad(stuff->totalWidth, stuff->depth); 54665b04b38Smrg } 547f7df2e56Smrg else { 548f7df2e56Smrg client->errorValue = stuff->format; 54965b04b38Smrg return BadValue; 55065b04b38Smrg } 55105b261ecSmrg 55265b04b38Smrg /* 55365b04b38Smrg * There's a potential integer overflow in this check: 55465b04b38Smrg * VERIFY_SHMSIZE(shmdesc, stuff->offset, length * stuff->totalHeight, 55565b04b38Smrg * client); 55665b04b38Smrg * the version below ought to avoid it 55765b04b38Smrg */ 55865b04b38Smrg if (stuff->totalHeight != 0 && 559f7df2e56Smrg length > (shmdesc->size - stuff->offset) / stuff->totalHeight) { 560f7df2e56Smrg client->errorValue = stuff->totalWidth; 561f7df2e56Smrg return BadValue; 56265b04b38Smrg } 563f7df2e56Smrg if (stuff->srcX > stuff->totalWidth) { 564f7df2e56Smrg client->errorValue = stuff->srcX; 565f7df2e56Smrg return BadValue; 56665b04b38Smrg } 567f7df2e56Smrg if (stuff->srcY > stuff->totalHeight) { 568f7df2e56Smrg client->errorValue = stuff->srcY; 569f7df2e56Smrg return BadValue; 57065b04b38Smrg } 571f7df2e56Smrg if ((stuff->srcX + stuff->srcWidth) > stuff->totalWidth) { 572f7df2e56Smrg client->errorValue = stuff->srcWidth; 573f7df2e56Smrg return BadValue; 57465b04b38Smrg } 575f7df2e56Smrg if ((stuff->srcY + stuff->srcHeight) > stuff->totalHeight) { 576f7df2e56Smrg client->errorValue = stuff->srcHeight; 577f7df2e56Smrg return BadValue; 57865b04b38Smrg } 57905b261ecSmrg 58065b04b38Smrg if ((((stuff->format == ZPixmap) && (stuff->srcX == 0)) || 581f7df2e56Smrg ((stuff->format != ZPixmap) && 582f7df2e56Smrg (stuff->srcX < screenInfo.bitmapScanlinePad) && 583f7df2e56Smrg ((stuff->format == XYBitmap) || 584f7df2e56Smrg ((stuff->srcY == 0) && 585f7df2e56Smrg (stuff->srcHeight == stuff->totalHeight))))) && 586f7df2e56Smrg ((stuff->srcX + stuff->srcWidth) == stuff->totalWidth)) 587f7df2e56Smrg (*pGC->ops->PutImage) (pDraw, pGC, stuff->depth, 588f7df2e56Smrg stuff->dstX, stuff->dstY, 589f7df2e56Smrg stuff->totalWidth, stuff->srcHeight, 590f7df2e56Smrg stuff->srcX, stuff->format, 591f7df2e56Smrg shmdesc->addr + stuff->offset + 592f7df2e56Smrg (stuff->srcY * length)); 59365b04b38Smrg else 594f7df2e56Smrg doShmPutImage(pDraw, pGC, stuff->depth, stuff->format, 595f7df2e56Smrg stuff->totalWidth, stuff->totalHeight, 596f7df2e56Smrg stuff->srcX, stuff->srcY, 597f7df2e56Smrg stuff->srcWidth, stuff->srcHeight, 598f7df2e56Smrg stuff->dstX, stuff->dstY, shmdesc->addr + stuff->offset); 599f7df2e56Smrg 600f7df2e56Smrg if (stuff->sendEvent) { 601f7df2e56Smrg xShmCompletionEvent ev = { 602f7df2e56Smrg .type = ShmCompletionCode, 603f7df2e56Smrg .drawable = stuff->drawable, 604f7df2e56Smrg .minorEvent = X_ShmPutImage, 605f7df2e56Smrg .majorEvent = ShmReqCode, 606f7df2e56Smrg .shmseg = stuff->shmseg, 607f7df2e56Smrg .offset = stuff->offset 608f7df2e56Smrg }; 609f7df2e56Smrg WriteEventsToClient(client, 1, (xEvent *) &ev); 61005b261ecSmrg } 61165b04b38Smrg 61265b04b38Smrg return Success; 61305b261ecSmrg} 61405b261ecSmrg 61565b04b38Smrgstatic int 61665b04b38SmrgProcShmGetImage(ClientPtr client) 61705b261ecSmrg{ 618f7df2e56Smrg DrawablePtr pDraw; 619f7df2e56Smrg long lenPer = 0, length; 620f7df2e56Smrg Mask plane = 0; 621f7df2e56Smrg xShmGetImageReply xgi; 622f7df2e56Smrg ShmDescPtr shmdesc; 623f7df2e56Smrg VisualID visual = None; 624f7df2e56Smrg RegionPtr pVisibleRegion = NULL; 625f7df2e56Smrg int rc; 62605b261ecSmrg 62705b261ecSmrg REQUEST(xShmGetImageReq); 62805b261ecSmrg 62905b261ecSmrg REQUEST_SIZE_MATCH(xShmGetImageReq); 630f7df2e56Smrg if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { 631f7df2e56Smrg client->errorValue = stuff->format; 6324202a189Smrg return BadValue; 63305b261ecSmrg } 634f7df2e56Smrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess); 63505b261ecSmrg if (rc != Success) 636f7df2e56Smrg return rc; 63705b261ecSmrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 638f7df2e56Smrg if (pDraw->type == DRAWABLE_WINDOW) { 639f7df2e56Smrg if ( /* check for being viewable */ 640f7df2e56Smrg !((WindowPtr) pDraw)->realized || 641f7df2e56Smrg /* check for being on screen */ 642f7df2e56Smrg pDraw->x + stuff->x < 0 || 643f7df2e56Smrg pDraw->x + stuff->x + (int) stuff->width > pDraw->pScreen->width 644f7df2e56Smrg || pDraw->y + stuff->y < 0 || 645f7df2e56Smrg pDraw->y + stuff->y + (int) stuff->height > 646f7df2e56Smrg pDraw->pScreen->height || 647f7df2e56Smrg /* check for being inside of border */ 648f7df2e56Smrg stuff->x < -wBorderWidth((WindowPtr) pDraw) || 649f7df2e56Smrg stuff->x + (int) stuff->width > 650f7df2e56Smrg wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width || 651f7df2e56Smrg stuff->y < -wBorderWidth((WindowPtr) pDraw) || 652f7df2e56Smrg stuff->y + (int) stuff->height > 653f7df2e56Smrg wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height) 654f7df2e56Smrg return BadMatch; 655f7df2e56Smrg visual = wVisual(((WindowPtr) pDraw)); 6567e31ba66Smrg if (pDraw->type == DRAWABLE_WINDOW) 6577e31ba66Smrg pVisibleRegion = &((WindowPtr) pDraw)->borderClip; 6584e185dc0Smrg pDraw->pScreen->SourceValidate(pDraw, stuff->x, stuff->y, 6594e185dc0Smrg stuff->width, stuff->height, 6604e185dc0Smrg IncludeInferiors); 66165b04b38Smrg } 662f7df2e56Smrg else { 663f7df2e56Smrg if (stuff->x < 0 || 664f7df2e56Smrg stuff->x + (int) stuff->width > pDraw->width || 665f7df2e56Smrg stuff->y < 0 || stuff->y + (int) stuff->height > pDraw->height) 666f7df2e56Smrg return BadMatch; 667f7df2e56Smrg visual = None; 66865b04b38Smrg } 669f7df2e56Smrg xgi = (xShmGetImageReply) { 670f7df2e56Smrg .type = X_Reply, 671f7df2e56Smrg .sequenceNumber = client->sequence, 672f7df2e56Smrg .length = 0, 673f7df2e56Smrg .visual = visual, 674f7df2e56Smrg .depth = pDraw->depth 675f7df2e56Smrg }; 676f7df2e56Smrg if (stuff->format == ZPixmap) { 677f7df2e56Smrg length = PixmapBytePad(stuff->width, pDraw->depth) * stuff->height; 678f7df2e56Smrg } 679f7df2e56Smrg else { 680f7df2e56Smrg lenPer = PixmapBytePad(stuff->width, 1) * stuff->height; 681f7df2e56Smrg plane = ((Mask) 1) << (pDraw->depth - 1); 682f7df2e56Smrg /* only planes asked for */ 683f7df2e56Smrg length = lenPer * Ones(stuff->planeMask & (plane | (plane - 1))); 68465b04b38Smrg } 68565b04b38Smrg 68665b04b38Smrg VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 68765b04b38Smrg xgi.size = length; 68865b04b38Smrg 689f7df2e56Smrg if (length == 0) { 690f7df2e56Smrg /* nothing to do */ 69165b04b38Smrg } 692f7df2e56Smrg else if (stuff->format == ZPixmap) { 693f7df2e56Smrg (*pDraw->pScreen->GetImage) (pDraw, stuff->x, stuff->y, 694f7df2e56Smrg stuff->width, stuff->height, 695f7df2e56Smrg stuff->format, stuff->planeMask, 696f7df2e56Smrg shmdesc->addr + stuff->offset); 697f7df2e56Smrg if (pVisibleRegion) 698f7df2e56Smrg XaceCensorImage(client, pVisibleRegion, 699f7df2e56Smrg PixmapBytePad(stuff->width, pDraw->depth), pDraw, 700f7df2e56Smrg stuff->x, stuff->y, stuff->width, stuff->height, 701f7df2e56Smrg stuff->format, shmdesc->addr + stuff->offset); 70265b04b38Smrg } 703f7df2e56Smrg else { 70465b04b38Smrg 705f7df2e56Smrg length = stuff->offset; 706f7df2e56Smrg for (; plane; plane >>= 1) { 707f7df2e56Smrg if (stuff->planeMask & plane) { 708f7df2e56Smrg (*pDraw->pScreen->GetImage) (pDraw, 709f7df2e56Smrg stuff->x, stuff->y, 710f7df2e56Smrg stuff->width, stuff->height, 711f7df2e56Smrg stuff->format, plane, 712f7df2e56Smrg shmdesc->addr + length); 713f7df2e56Smrg if (pVisibleRegion) 714f7df2e56Smrg XaceCensorImage(client, pVisibleRegion, 715f7df2e56Smrg BitmapBytePad(stuff->width), pDraw, 716f7df2e56Smrg stuff->x, stuff->y, stuff->width, stuff->height, 717f7df2e56Smrg stuff->format, shmdesc->addr + length); 718f7df2e56Smrg length += lenPer; 719f7df2e56Smrg } 720f7df2e56Smrg } 72165b04b38Smrg } 72265b04b38Smrg 72365b04b38Smrg if (client->swapped) { 724f7df2e56Smrg swaps(&xgi.sequenceNumber); 725f7df2e56Smrg swapl(&xgi.length); 726f7df2e56Smrg swapl(&xgi.visual); 727f7df2e56Smrg swapl(&xgi.size); 72865b04b38Smrg } 729f7df2e56Smrg WriteToClient(client, sizeof(xShmGetImageReply), &xgi); 73065b04b38Smrg 73165b04b38Smrg return Success; 73265b04b38Smrg} 73365b04b38Smrg 73465b04b38Smrg#ifdef PANORAMIX 735f7df2e56Smrgstatic int 73665b04b38SmrgProcPanoramiXShmPutImage(ClientPtr client) 73765b04b38Smrg{ 738f7df2e56Smrg int j, result, orig_x, orig_y; 739f7df2e56Smrg PanoramiXRes *draw, *gc; 740f7df2e56Smrg Bool sendEvent, isRoot; 74165b04b38Smrg 74265b04b38Smrg REQUEST(xShmPutImageReq); 74365b04b38Smrg REQUEST_SIZE_MATCH(xShmPutImageReq); 74465b04b38Smrg 745f7df2e56Smrg result = dixLookupResourceByClass((void **) &draw, stuff->drawable, 746f7df2e56Smrg XRC_DRAWABLE, client, DixWriteAccess); 74765b04b38Smrg if (result != Success) 74865b04b38Smrg return (result == BadValue) ? BadDrawable : result; 74965b04b38Smrg 750f7df2e56Smrg result = dixLookupResourceByType((void **) &gc, stuff->gc, 751f7df2e56Smrg XRT_GC, client, DixReadAccess); 75265b04b38Smrg if (result != Success) 75365b04b38Smrg return result; 75465b04b38Smrg 75565b04b38Smrg isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 75665b04b38Smrg 75765b04b38Smrg orig_x = stuff->dstX; 75865b04b38Smrg orig_y = stuff->dstY; 75965b04b38Smrg sendEvent = stuff->sendEvent; 76065b04b38Smrg stuff->sendEvent = 0; 76165b04b38Smrg FOR_NSCREENS(j) { 762f7df2e56Smrg if (!j) 763f7df2e56Smrg stuff->sendEvent = sendEvent; 764f7df2e56Smrg stuff->drawable = draw->info[j].id; 765f7df2e56Smrg stuff->gc = gc->info[j].id; 766f7df2e56Smrg if (isRoot) { 767f7df2e56Smrg stuff->dstX = orig_x - screenInfo.screens[j]->x; 768f7df2e56Smrg stuff->dstY = orig_y - screenInfo.screens[j]->y; 769f7df2e56Smrg } 770f7df2e56Smrg result = ProcShmPutImage(client); 771f7df2e56Smrg if (result != Success) 772f7df2e56Smrg break; 77365b04b38Smrg } 77465b04b38Smrg return result; 77565b04b38Smrg} 77665b04b38Smrg 777f7df2e56Smrgstatic int 77865b04b38SmrgProcPanoramiXShmGetImage(ClientPtr client) 77965b04b38Smrg{ 780f7df2e56Smrg PanoramiXRes *draw; 781f7df2e56Smrg DrawablePtr *drawables; 782f7df2e56Smrg DrawablePtr pDraw; 783f7df2e56Smrg xShmGetImageReply xgi; 784f7df2e56Smrg ShmDescPtr shmdesc; 785f7df2e56Smrg int i, x, y, w, h, format, rc; 786f7df2e56Smrg Mask plane = 0, planemask; 787f7df2e56Smrg long lenPer = 0, length, widthBytesLine; 788f7df2e56Smrg Bool isRoot; 78965b04b38Smrg 79065b04b38Smrg REQUEST(xShmGetImageReq); 79165b04b38Smrg 79265b04b38Smrg REQUEST_SIZE_MATCH(xShmGetImageReq); 79365b04b38Smrg 79465b04b38Smrg if ((stuff->format != XYPixmap) && (stuff->format != ZPixmap)) { 795f7df2e56Smrg client->errorValue = stuff->format; 79665b04b38Smrg return BadValue; 79765b04b38Smrg } 79865b04b38Smrg 799f7df2e56Smrg rc = dixLookupResourceByClass((void **) &draw, stuff->drawable, 800f7df2e56Smrg XRC_DRAWABLE, client, DixWriteAccess); 80165b04b38Smrg if (rc != Success) 802f7df2e56Smrg return (rc == BadValue) ? BadDrawable : rc; 80365b04b38Smrg 80465b04b38Smrg if (draw->type == XRT_PIXMAP) 805f7df2e56Smrg return ProcShmGetImage(client); 80665b04b38Smrg 807f7df2e56Smrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, 0, DixReadAccess); 80865b04b38Smrg if (rc != Success) 809f7df2e56Smrg return rc; 81065b04b38Smrg 81165b04b38Smrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 81265b04b38Smrg 81365b04b38Smrg x = stuff->x; 81465b04b38Smrg y = stuff->y; 81565b04b38Smrg w = stuff->width; 81665b04b38Smrg h = stuff->height; 81765b04b38Smrg format = stuff->format; 81865b04b38Smrg planemask = stuff->planeMask; 81965b04b38Smrg 82065b04b38Smrg isRoot = (draw->type == XRT_WINDOW) && draw->u.win.root; 82165b04b38Smrg 822f7df2e56Smrg if (isRoot) { 823f7df2e56Smrg if ( /* check for being onscreen */ 824f7df2e56Smrg x < 0 || x + w > PanoramiXPixWidth || 825f7df2e56Smrg y < 0 || y + h > PanoramiXPixHeight) 826f7df2e56Smrg return BadMatch; 827f7df2e56Smrg } 828f7df2e56Smrg else { 829f7df2e56Smrg if ( /* check for being onscreen */ 830f7df2e56Smrg screenInfo.screens[0]->x + pDraw->x + x < 0 || 831f7df2e56Smrg screenInfo.screens[0]->x + pDraw->x + x + w > PanoramiXPixWidth 832f7df2e56Smrg || screenInfo.screens[0]->y + pDraw->y + y < 0 || 833f7df2e56Smrg screenInfo.screens[0]->y + pDraw->y + y + h > PanoramiXPixHeight 834f7df2e56Smrg || 835f7df2e56Smrg /* check for being inside of border */ 836f7df2e56Smrg x < -wBorderWidth((WindowPtr) pDraw) || 837f7df2e56Smrg x + w > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->width || 838f7df2e56Smrg y < -wBorderWidth((WindowPtr) pDraw) || 839f7df2e56Smrg y + h > wBorderWidth((WindowPtr) pDraw) + (int) pDraw->height) 840f7df2e56Smrg return BadMatch; 84165b04b38Smrg } 84265b04b38Smrg 8437e31ba66Smrg if (format == ZPixmap) { 8447e31ba66Smrg widthBytesLine = PixmapBytePad(w, pDraw->depth); 8457e31ba66Smrg length = widthBytesLine * h; 8467e31ba66Smrg } 8477e31ba66Smrg else { 8487e31ba66Smrg widthBytesLine = PixmapBytePad(w, 1); 8497e31ba66Smrg lenPer = widthBytesLine * h; 8507e31ba66Smrg plane = ((Mask) 1) << (pDraw->depth - 1); 8517e31ba66Smrg length = lenPer * Ones(planemask & (plane | (plane - 1))); 8527e31ba66Smrg } 8537e31ba66Smrg 8547e31ba66Smrg VERIFY_SHMSIZE(shmdesc, stuff->offset, length, client); 8557e31ba66Smrg 8564202a189Smrg drawables = calloc(PanoramiXNumScreens, sizeof(DrawablePtr)); 857f7df2e56Smrg if (!drawables) 858f7df2e56Smrg return BadAlloc; 8594202a189Smrg 86005b261ecSmrg drawables[0] = pDraw; 861f7df2e56Smrg FOR_NSCREENS_FORWARD_SKIP(i) { 862f7df2e56Smrg rc = dixLookupDrawable(drawables + i, draw->info[i].id, client, 0, 863f7df2e56Smrg DixReadAccess); 864f7df2e56Smrg if (rc != Success) { 865f7df2e56Smrg free(drawables); 866f7df2e56Smrg return rc; 867f7df2e56Smrg } 86805b261ecSmrg } 8694e185dc0Smrg FOR_NSCREENS_FORWARD(i) { 8704e185dc0Smrg drawables[i]->pScreen->SourceValidate(drawables[i], 0, 0, 8714e185dc0Smrg drawables[i]->width, 8724e185dc0Smrg drawables[i]->height, 8734e185dc0Smrg IncludeInferiors); 8744e185dc0Smrg } 87505b261ecSmrg 876f7df2e56Smrg xgi = (xShmGetImageReply) { 877f7df2e56Smrg .type = X_Reply, 878f7df2e56Smrg .sequenceNumber = client->sequence, 879f7df2e56Smrg .length = 0, 880f7df2e56Smrg .visual = wVisual(((WindowPtr) pDraw)), 881f7df2e56Smrg .depth = pDraw->depth 882f7df2e56Smrg }; 883f7df2e56Smrg 88405b261ecSmrg xgi.size = length; 88505b261ecSmrg 886f7df2e56Smrg if (length == 0) { /* nothing to do */ 887f7df2e56Smrg } 88805b261ecSmrg else if (format == ZPixmap) { 889f7df2e56Smrg XineramaGetImageData(drawables, x, y, w, h, format, planemask, 890f7df2e56Smrg shmdesc->addr + stuff->offset, 891f7df2e56Smrg widthBytesLine, isRoot); 892f7df2e56Smrg } 893f7df2e56Smrg else { 89405b261ecSmrg 895f7df2e56Smrg length = stuff->offset; 89605b261ecSmrg for (; plane; plane >>= 1) { 897f7df2e56Smrg if (planemask & plane) { 898f7df2e56Smrg XineramaGetImageData(drawables, x, y, w, h, 899f7df2e56Smrg format, plane, shmdesc->addr + length, 900f7df2e56Smrg widthBytesLine, isRoot); 901f7df2e56Smrg length += lenPer; 902f7df2e56Smrg } 903f7df2e56Smrg } 90405b261ecSmrg } 9054202a189Smrg free(drawables); 906f7df2e56Smrg 90705b261ecSmrg if (client->swapped) { 908f7df2e56Smrg swaps(&xgi.sequenceNumber); 909f7df2e56Smrg swapl(&xgi.length); 910f7df2e56Smrg swapl(&xgi.visual); 911f7df2e56Smrg swapl(&xgi.size); 91205b261ecSmrg } 913f7df2e56Smrg WriteToClient(client, sizeof(xShmGetImageReply), &xgi); 91405b261ecSmrg 9154202a189Smrg return Success; 91605b261ecSmrg} 91705b261ecSmrg 91805b261ecSmrgstatic int 9194642e01fSmrgProcPanoramiXShmCreatePixmap(ClientPtr client) 92005b261ecSmrg{ 92105b261ecSmrg ScreenPtr pScreen = NULL; 92205b261ecSmrg PixmapPtr pMap = NULL; 92305b261ecSmrg DrawablePtr pDraw; 92405b261ecSmrg DepthPtr pDepth; 92505b261ecSmrg int i, j, result, rc; 92605b261ecSmrg ShmDescPtr shmdesc; 927f7df2e56Smrg 92805b261ecSmrg REQUEST(xShmCreatePixmapReq); 92905b261ecSmrg unsigned int width, height, depth; 93005b261ecSmrg unsigned long size; 93105b261ecSmrg PanoramiXRes *newPix; 93205b261ecSmrg 93305b261ecSmrg REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 93405b261ecSmrg client->errorValue = stuff->pid; 93505b261ecSmrg if (!sharedPixmaps) 936f7df2e56Smrg return BadImplementation; 93705b261ecSmrg LEGAL_NEW_RESOURCE(stuff->pid, client); 93805b261ecSmrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 939f7df2e56Smrg DixGetAttrAccess); 94005b261ecSmrg if (rc != Success) 941f7df2e56Smrg return rc; 94205b261ecSmrg 94305b261ecSmrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 94405b261ecSmrg 94505b261ecSmrg width = stuff->width; 94605b261ecSmrg height = stuff->height; 94705b261ecSmrg depth = stuff->depth; 948f7df2e56Smrg if (!width || !height || !depth) { 949f7df2e56Smrg client->errorValue = 0; 95005b261ecSmrg return BadValue; 95105b261ecSmrg } 95205b261ecSmrg if (width > 32767 || height > 32767) 95305b261ecSmrg return BadAlloc; 95405b261ecSmrg 955f7df2e56Smrg if (stuff->depth != 1) { 95605b261ecSmrg pDepth = pDraw->pScreen->allowedDepths; 957f7df2e56Smrg for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++) 958f7df2e56Smrg if (pDepth->depth == stuff->depth) 959f7df2e56Smrg goto CreatePmap; 960f7df2e56Smrg client->errorValue = stuff->depth; 96105b261ecSmrg return BadValue; 96205b261ecSmrg } 96305b261ecSmrg 964f7df2e56Smrg CreatePmap: 96505b261ecSmrg size = PixmapBytePad(width, depth) * height; 96605b261ecSmrg if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 96705b261ecSmrg if (size < width * height) 96805b261ecSmrg return BadAlloc; 96905b261ecSmrg } 97005b261ecSmrg /* thankfully, offset is unsigned */ 97105b261ecSmrg if (stuff->offset + size < size) 972f7df2e56Smrg return BadAlloc; 97305b261ecSmrg 97405b261ecSmrg VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 97505b261ecSmrg 976f7df2e56Smrg if (!(newPix = malloc(sizeof(PanoramiXRes)))) 977f7df2e56Smrg return BadAlloc; 97805b261ecSmrg 97905b261ecSmrg newPix->type = XRT_PIXMAP; 98005b261ecSmrg newPix->u.pix.shared = TRUE; 981f7df2e56Smrg panoramix_setup_ids(newPix, client, stuff->pid); 98205b261ecSmrg 9834202a189Smrg result = Success; 98405b261ecSmrg 98505b261ecSmrg FOR_NSCREENS(j) { 986f7df2e56Smrg ShmScrPrivateRec *screen_priv; 987f7df2e56Smrg 988f7df2e56Smrg pScreen = screenInfo.screens[j]; 989f7df2e56Smrg 990f7df2e56Smrg screen_priv = ShmGetScreenPriv(pScreen); 991f7df2e56Smrg pMap = (*screen_priv->shmFuncs->CreatePixmap) (pScreen, 992f7df2e56Smrg stuff->width, 993f7df2e56Smrg stuff->height, 994f7df2e56Smrg stuff->depth, 995f7df2e56Smrg shmdesc->addr + 996f7df2e56Smrg stuff->offset); 997f7df2e56Smrg 998f7df2e56Smrg if (pMap) { 999f7df2e56Smrg result = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, 1000f7df2e56Smrg RT_PIXMAP, pMap, RT_NONE, NULL, DixCreateAccess); 1001f7df2e56Smrg if (result != Success) { 1002f7df2e56Smrg pDraw->pScreen->DestroyPixmap(pMap); 10037e31ba66Smrg break; 1004f7df2e56Smrg } 1005f7df2e56Smrg dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc); 100605b261ecSmrg shmdesc->refcnt++; 1007f7df2e56Smrg pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 1008f7df2e56Smrg pMap->drawable.id = newPix->info[j].id; 1009f7df2e56Smrg if (!AddResource(newPix->info[j].id, RT_PIXMAP, (void *) pMap)) { 1010f7df2e56Smrg result = BadAlloc; 1011f7df2e56Smrg break; 1012f7df2e56Smrg } 1013f7df2e56Smrg } 1014f7df2e56Smrg else { 1015f7df2e56Smrg result = BadAlloc; 1016f7df2e56Smrg break; 1017f7df2e56Smrg } 101805b261ecSmrg } 101905b261ecSmrg 10207e31ba66Smrg if (result != Success) { 1021f7df2e56Smrg while (j--) 1022f7df2e56Smrg FreeResource(newPix->info[j].id, RT_NONE); 1023f7df2e56Smrg free(newPix); 1024f7df2e56Smrg } 1025f7df2e56Smrg else 1026f7df2e56Smrg AddResource(stuff->pid, XRT_PIXMAP, newPix); 102705b261ecSmrg 102805b261ecSmrg return result; 102905b261ecSmrg} 103005b261ecSmrg#endif 103105b261ecSmrg 103205b261ecSmrgstatic PixmapPtr 1033f7df2e56SmrgfbShmCreatePixmap(ScreenPtr pScreen, 1034f7df2e56Smrg int width, int height, int depth, char *addr) 103505b261ecSmrg{ 10364642e01fSmrg PixmapPtr pPixmap; 103705b261ecSmrg 1038f7df2e56Smrg pPixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, pScreen->rootDepth, 0); 103905b261ecSmrg if (!pPixmap) 1040f7df2e56Smrg return NullPixmap; 1041f7df2e56Smrg 1042f7df2e56Smrg if (!(*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, 1043f7df2e56Smrg BitsPerPixel(depth), 1044f7df2e56Smrg PixmapBytePad(width, depth), 1045f7df2e56Smrg (void *) addr)) { 1046f7df2e56Smrg (*pScreen->DestroyPixmap) (pPixmap); 1047f7df2e56Smrg return NullPixmap; 104805b261ecSmrg } 104905b261ecSmrg return pPixmap; 105005b261ecSmrg} 105105b261ecSmrg 105205b261ecSmrgstatic int 10534642e01fSmrgProcShmCreatePixmap(ClientPtr client) 105405b261ecSmrg{ 105505b261ecSmrg PixmapPtr pMap; 105605b261ecSmrg DrawablePtr pDraw; 105705b261ecSmrg DepthPtr pDepth; 10584642e01fSmrg int i, rc; 105905b261ecSmrg ShmDescPtr shmdesc; 10604202a189Smrg ShmScrPrivateRec *screen_priv; 1061f7df2e56Smrg 106205b261ecSmrg REQUEST(xShmCreatePixmapReq); 106305b261ecSmrg unsigned int width, height, depth; 106405b261ecSmrg unsigned long size; 106505b261ecSmrg 106605b261ecSmrg REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 106705b261ecSmrg client->errorValue = stuff->pid; 106805b261ecSmrg if (!sharedPixmaps) 1069f7df2e56Smrg return BadImplementation; 107005b261ecSmrg LEGAL_NEW_RESOURCE(stuff->pid, client); 107105b261ecSmrg rc = dixLookupDrawable(&pDraw, stuff->drawable, client, M_ANY, 1072f7df2e56Smrg DixGetAttrAccess); 107305b261ecSmrg if (rc != Success) 1074f7df2e56Smrg return rc; 107505b261ecSmrg 107605b261ecSmrg VERIFY_SHMPTR(stuff->shmseg, stuff->offset, TRUE, shmdesc, client); 1077f7df2e56Smrg 107805b261ecSmrg width = stuff->width; 107905b261ecSmrg height = stuff->height; 108005b261ecSmrg depth = stuff->depth; 1081f7df2e56Smrg if (!width || !height || !depth) { 1082f7df2e56Smrg client->errorValue = 0; 108305b261ecSmrg return BadValue; 108405b261ecSmrg } 108505b261ecSmrg if (width > 32767 || height > 32767) 1086f7df2e56Smrg return BadAlloc; 108705b261ecSmrg 1088f7df2e56Smrg if (stuff->depth != 1) { 108905b261ecSmrg pDepth = pDraw->pScreen->allowedDepths; 1090f7df2e56Smrg for (i = 0; i < pDraw->pScreen->numDepths; i++, pDepth++) 1091f7df2e56Smrg if (pDepth->depth == stuff->depth) 1092f7df2e56Smrg goto CreatePmap; 1093f7df2e56Smrg client->errorValue = stuff->depth; 109405b261ecSmrg return BadValue; 109505b261ecSmrg } 109605b261ecSmrg 1097f7df2e56Smrg CreatePmap: 109805b261ecSmrg size = PixmapBytePad(width, depth) * height; 109905b261ecSmrg if (sizeof(size) == 4 && BitsPerPixel(depth) > 8) { 1100f7df2e56Smrg if (size < width * height) 1101f7df2e56Smrg return BadAlloc; 110205b261ecSmrg } 110305b261ecSmrg /* thankfully, offset is unsigned */ 110405b261ecSmrg if (stuff->offset + size < size) 1105f7df2e56Smrg return BadAlloc; 110605b261ecSmrg 110705b261ecSmrg VERIFY_SHMSIZE(shmdesc, stuff->offset, size, client); 11084202a189Smrg screen_priv = ShmGetScreenPriv(pDraw->pScreen); 1109f7df2e56Smrg pMap = (*screen_priv->shmFuncs->CreatePixmap) (pDraw->pScreen, stuff->width, 1110f7df2e56Smrg stuff->height, stuff->depth, 1111f7df2e56Smrg shmdesc->addr + 1112f7df2e56Smrg stuff->offset); 1113f7df2e56Smrg if (pMap) { 1114f7df2e56Smrg rc = XaceHook(XACE_RESOURCE_ACCESS, client, stuff->pid, RT_PIXMAP, 1115f7df2e56Smrg pMap, RT_NONE, NULL, DixCreateAccess); 1116f7df2e56Smrg if (rc != Success) { 1117f7df2e56Smrg pDraw->pScreen->DestroyPixmap(pMap); 1118f7df2e56Smrg return rc; 1119f7df2e56Smrg } 1120f7df2e56Smrg dixSetPrivate(&pMap->devPrivates, shmPixmapPrivateKey, shmdesc); 1121f7df2e56Smrg shmdesc->refcnt++; 1122f7df2e56Smrg pMap->drawable.serialNumber = NEXT_SERIAL_NUMBER; 1123f7df2e56Smrg pMap->drawable.id = stuff->pid; 1124f7df2e56Smrg if (AddResource(stuff->pid, RT_PIXMAP, (void *) pMap)) { 1125f7df2e56Smrg return Success; 1126f7df2e56Smrg } 1127f7df2e56Smrg } 1128f7df2e56Smrg return BadAlloc; 1129f7df2e56Smrg} 1130f7df2e56Smrg 1131f7df2e56Smrg#ifdef SHM_FD_PASSING 1132f7df2e56Smrg 1133f7df2e56Smrgstatic void 1134f7df2e56SmrgShmBusfaultNotify(void *context) 1135f7df2e56Smrg{ 1136f7df2e56Smrg ShmDescPtr shmdesc = context; 1137f7df2e56Smrg 1138f7df2e56Smrg ErrorF("shared memory 0x%x truncated by client\n", 1139f7df2e56Smrg (unsigned int) shmdesc->resource); 1140f7df2e56Smrg busfault_unregister(shmdesc->busfault); 1141f7df2e56Smrg shmdesc->busfault = NULL; 1142f7df2e56Smrg FreeResource (shmdesc->resource, RT_NONE); 1143f7df2e56Smrg} 1144f7df2e56Smrg 1145f7df2e56Smrgstatic int 1146f7df2e56SmrgProcShmAttachFd(ClientPtr client) 1147f7df2e56Smrg{ 1148f7df2e56Smrg int fd; 1149f7df2e56Smrg ShmDescPtr shmdesc; 1150f7df2e56Smrg REQUEST(xShmAttachFdReq); 1151f7df2e56Smrg struct stat statb; 1152f7df2e56Smrg 1153f7df2e56Smrg SetReqFds(client, 1); 1154f7df2e56Smrg REQUEST_SIZE_MATCH(xShmAttachFdReq); 1155f7df2e56Smrg LEGAL_NEW_RESOURCE(stuff->shmseg, client); 1156f7df2e56Smrg if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) { 1157f7df2e56Smrg client->errorValue = stuff->readOnly; 1158f7df2e56Smrg return BadValue; 1159f7df2e56Smrg } 1160f7df2e56Smrg fd = ReadFdFromClient(client); 1161f7df2e56Smrg if (fd < 0) 1162f7df2e56Smrg return BadMatch; 1163f7df2e56Smrg 1164f7df2e56Smrg if (fstat(fd, &statb) < 0 || statb.st_size == 0) { 1165f7df2e56Smrg close(fd); 1166f7df2e56Smrg return BadMatch; 1167f7df2e56Smrg } 1168f7df2e56Smrg 1169f7df2e56Smrg shmdesc = malloc(sizeof(ShmDescRec)); 1170f7df2e56Smrg if (!shmdesc) { 1171f7df2e56Smrg close(fd); 1172f7df2e56Smrg return BadAlloc; 1173f7df2e56Smrg } 1174f7df2e56Smrg shmdesc->is_fd = TRUE; 1175f7df2e56Smrg shmdesc->addr = mmap(NULL, statb.st_size, 1176f7df2e56Smrg stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE, 1177f7df2e56Smrg MAP_SHARED, 1178f7df2e56Smrg fd, 0); 1179f7df2e56Smrg 1180f7df2e56Smrg close(fd); 1181f7df2e56Smrg if (shmdesc->addr == ((char *) -1)) { 1182f7df2e56Smrg free(shmdesc); 1183f7df2e56Smrg return BadAccess; 1184f7df2e56Smrg } 1185f7df2e56Smrg 1186f7df2e56Smrg shmdesc->refcnt = 1; 1187f7df2e56Smrg shmdesc->writable = !stuff->readOnly; 1188f7df2e56Smrg shmdesc->size = statb.st_size; 1189f7df2e56Smrg shmdesc->resource = stuff->shmseg; 1190f7df2e56Smrg 1191f7df2e56Smrg shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc); 1192f7df2e56Smrg if (!shmdesc->busfault) { 1193f7df2e56Smrg munmap(shmdesc->addr, shmdesc->size); 1194f7df2e56Smrg free(shmdesc); 1195f7df2e56Smrg return BadAlloc; 1196f7df2e56Smrg } 1197f7df2e56Smrg 1198f7df2e56Smrg shmdesc->next = Shmsegs; 1199f7df2e56Smrg Shmsegs = shmdesc; 1200f7df2e56Smrg 1201f7df2e56Smrg if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) 1202f7df2e56Smrg return BadAlloc; 1203f7df2e56Smrg return Success; 1204f7df2e56Smrg} 1205f7df2e56Smrg 1206f7df2e56Smrgstatic int 1207f7df2e56Smrgshm_tmpfile(void) 1208f7df2e56Smrg{ 12094e185dc0Smrg const char *shmdirs[] = { 12104e185dc0Smrg "/run/shm", 12114e185dc0Smrg "/var/tmp", 12124e185dc0Smrg "/tmp", 12134e185dc0Smrg }; 12144e185dc0Smrg int fd; 12154e185dc0Smrg 12164e185dc0Smrg#ifdef HAVE_MEMFD_CREATE 12174e185dc0Smrg fd = memfd_create("xorg", MFD_CLOEXEC|MFD_ALLOW_SEALING); 12184e185dc0Smrg if (fd != -1) { 12194e185dc0Smrg fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK); 12204e185dc0Smrg DebugF ("Using memfd_create\n"); 12214e185dc0Smrg return fd; 12224e185dc0Smrg } 12234e185dc0Smrg#endif 12244e185dc0Smrg 1225f7df2e56Smrg#ifdef O_TMPFILE 12264e185dc0Smrg for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) { 12274e185dc0Smrg fd = open(shmdirs[i], O_TMPFILE|O_RDWR|O_CLOEXEC|O_EXCL, 0666); 12284e185dc0Smrg if (fd >= 0) { 12294e185dc0Smrg DebugF ("Using O_TMPFILE\n"); 12304e185dc0Smrg return fd; 12314e185dc0Smrg } 12324e185dc0Smrg } 12334e185dc0Smrg ErrorF ("Not using O_TMPFILE\n"); 1234f7df2e56Smrg#endif 12354e185dc0Smrg 12364e185dc0Smrg for (int i = 0; i < ARRAY_SIZE(shmdirs); i++) { 12374e185dc0Smrg char template[PATH_MAX]; 12384e185dc0Smrg snprintf(template, ARRAY_SIZE(template), "%s/shmfd-XXXXXX", shmdirs[i]); 12397e31ba66Smrg#ifdef HAVE_MKOSTEMP 12404e185dc0Smrg fd = mkostemp(template, O_CLOEXEC); 12417e31ba66Smrg#else 12424e185dc0Smrg fd = mkstemp(template); 12437e31ba66Smrg#endif 12444e185dc0Smrg if (fd < 0) 12454e185dc0Smrg continue; 12464e185dc0Smrg unlink(template); 12477e31ba66Smrg#ifndef HAVE_MKOSTEMP 12484e185dc0Smrg int flags = fcntl(fd, F_GETFD); 12494e185dc0Smrg if (flags != -1) { 12504e185dc0Smrg flags |= FD_CLOEXEC; 12515a112b11Smrg (void) fcntl(fd, F_SETFD, flags); 12524e185dc0Smrg } 1253f7df2e56Smrg#endif 12544e185dc0Smrg return fd; 12554e185dc0Smrg } 12564e185dc0Smrg 12574e185dc0Smrg return -1; 1258f7df2e56Smrg} 1259f7df2e56Smrg 1260f7df2e56Smrgstatic int 1261f7df2e56SmrgProcShmCreateSegment(ClientPtr client) 1262f7df2e56Smrg{ 1263f7df2e56Smrg int fd; 1264f7df2e56Smrg ShmDescPtr shmdesc; 1265f7df2e56Smrg REQUEST(xShmCreateSegmentReq); 1266f7df2e56Smrg xShmCreateSegmentReply rep = { 1267f7df2e56Smrg .type = X_Reply, 1268f7df2e56Smrg .nfd = 1, 1269f7df2e56Smrg .sequenceNumber = client->sequence, 1270f7df2e56Smrg .length = 0, 1271f7df2e56Smrg }; 1272f7df2e56Smrg 1273f7df2e56Smrg REQUEST_SIZE_MATCH(xShmCreateSegmentReq); 12747e31ba66Smrg LEGAL_NEW_RESOURCE(stuff->shmseg, client); 1275f7df2e56Smrg if ((stuff->readOnly != xTrue) && (stuff->readOnly != xFalse)) { 1276f7df2e56Smrg client->errorValue = stuff->readOnly; 1277f7df2e56Smrg return BadValue; 127805b261ecSmrg } 1279f7df2e56Smrg fd = shm_tmpfile(); 1280f7df2e56Smrg if (fd < 0) 1281f7df2e56Smrg return BadAlloc; 1282f7df2e56Smrg if (ftruncate(fd, stuff->size) < 0) { 1283f7df2e56Smrg close(fd); 1284f7df2e56Smrg return BadAlloc; 1285f7df2e56Smrg } 1286f7df2e56Smrg shmdesc = malloc(sizeof(ShmDescRec)); 1287f7df2e56Smrg if (!shmdesc) { 1288f7df2e56Smrg close(fd); 1289f7df2e56Smrg return BadAlloc; 1290f7df2e56Smrg } 1291f7df2e56Smrg shmdesc->is_fd = TRUE; 1292f7df2e56Smrg shmdesc->addr = mmap(NULL, stuff->size, 1293f7df2e56Smrg stuff->readOnly ? PROT_READ : PROT_READ|PROT_WRITE, 1294f7df2e56Smrg MAP_SHARED, 1295f7df2e56Smrg fd, 0); 1296f7df2e56Smrg 1297f7df2e56Smrg if (shmdesc->addr == ((char *) -1)) { 1298f7df2e56Smrg close(fd); 1299f7df2e56Smrg free(shmdesc); 1300f7df2e56Smrg return BadAccess; 1301f7df2e56Smrg } 1302f7df2e56Smrg 1303f7df2e56Smrg shmdesc->refcnt = 1; 1304f7df2e56Smrg shmdesc->writable = !stuff->readOnly; 1305f7df2e56Smrg shmdesc->size = stuff->size; 1306f7df2e56Smrg 1307f7df2e56Smrg shmdesc->busfault = busfault_register_mmap(shmdesc->addr, shmdesc->size, ShmBusfaultNotify, shmdesc); 1308f7df2e56Smrg if (!shmdesc->busfault) { 1309f7df2e56Smrg close(fd); 1310f7df2e56Smrg munmap(shmdesc->addr, shmdesc->size); 1311f7df2e56Smrg free(shmdesc); 1312f7df2e56Smrg return BadAlloc; 1313f7df2e56Smrg } 1314f7df2e56Smrg 1315f7df2e56Smrg shmdesc->next = Shmsegs; 1316f7df2e56Smrg Shmsegs = shmdesc; 1317f7df2e56Smrg 1318f7df2e56Smrg if (!AddResource(stuff->shmseg, ShmSegType, (void *) shmdesc)) { 1319f7df2e56Smrg close(fd); 1320f7df2e56Smrg return BadAlloc; 1321f7df2e56Smrg } 1322f7df2e56Smrg 1323f7df2e56Smrg if (WriteFdToClient(client, fd, TRUE) < 0) { 1324f7df2e56Smrg FreeResource(stuff->shmseg, RT_NONE); 1325f7df2e56Smrg close(fd); 1326f7df2e56Smrg return BadAlloc; 1327f7df2e56Smrg } 1328f7df2e56Smrg WriteToClient(client, sizeof (xShmCreateSegmentReply), &rep); 1329f7df2e56Smrg return Success; 133005b261ecSmrg} 1331f7df2e56Smrg#endif /* SHM_FD_PASSING */ 133205b261ecSmrg 133305b261ecSmrgstatic int 1334f7df2e56SmrgProcShmDispatch(ClientPtr client) 133505b261ecSmrg{ 133605b261ecSmrg REQUEST(xReq); 13377e31ba66Smrg 13387e31ba66Smrg if (stuff->data == X_ShmQueryVersion) 1339f7df2e56Smrg return ProcShmQueryVersion(client); 13407e31ba66Smrg 13417e31ba66Smrg if (!client->local) 13427e31ba66Smrg return BadRequest; 13437e31ba66Smrg 13447e31ba66Smrg switch (stuff->data) { 134505b261ecSmrg case X_ShmAttach: 1346f7df2e56Smrg return ProcShmAttach(client); 134705b261ecSmrg case X_ShmDetach: 1348f7df2e56Smrg return ProcShmDetach(client); 134905b261ecSmrg case X_ShmPutImage: 135005b261ecSmrg#ifdef PANORAMIX 1351f7df2e56Smrg if (!noPanoramiXExtension) 1352f7df2e56Smrg return ProcPanoramiXShmPutImage(client); 135305b261ecSmrg#endif 1354f7df2e56Smrg return ProcShmPutImage(client); 135505b261ecSmrg case X_ShmGetImage: 135605b261ecSmrg#ifdef PANORAMIX 1357f7df2e56Smrg if (!noPanoramiXExtension) 1358f7df2e56Smrg return ProcPanoramiXShmGetImage(client); 135905b261ecSmrg#endif 1360f7df2e56Smrg return ProcShmGetImage(client); 136105b261ecSmrg case X_ShmCreatePixmap: 136205b261ecSmrg#ifdef PANORAMIX 1363f7df2e56Smrg if (!noPanoramiXExtension) 1364f7df2e56Smrg return ProcPanoramiXShmCreatePixmap(client); 1365f7df2e56Smrg#endif 1366f7df2e56Smrg return ProcShmCreatePixmap(client); 1367f7df2e56Smrg#ifdef SHM_FD_PASSING 1368f7df2e56Smrg case X_ShmAttachFd: 1369f7df2e56Smrg return ProcShmAttachFd(client); 1370f7df2e56Smrg case X_ShmCreateSegment: 1371f7df2e56Smrg return ProcShmCreateSegment(client); 137205b261ecSmrg#endif 137305b261ecSmrg default: 1374f7df2e56Smrg return BadRequest; 137505b261ecSmrg } 137605b261ecSmrg} 137705b261ecSmrg 13787e31ba66Smrgstatic void _X_COLD 1379f7df2e56SmrgSShmCompletionEvent(xShmCompletionEvent * from, xShmCompletionEvent * to) 138005b261ecSmrg{ 138105b261ecSmrg to->type = from->type; 138205b261ecSmrg cpswaps(from->sequenceNumber, to->sequenceNumber); 138305b261ecSmrg cpswapl(from->drawable, to->drawable); 138405b261ecSmrg cpswaps(from->minorEvent, to->minorEvent); 138505b261ecSmrg to->majorEvent = from->majorEvent; 138605b261ecSmrg cpswapl(from->shmseg, to->shmseg); 138705b261ecSmrg cpswapl(from->offset, to->offset); 138805b261ecSmrg} 138905b261ecSmrg 13907e31ba66Smrgstatic int _X_COLD 13914642e01fSmrgSProcShmQueryVersion(ClientPtr client) 139205b261ecSmrg{ 139305b261ecSmrg REQUEST(xShmQueryVersionReq); 139405b261ecSmrg 1395f7df2e56Smrg swaps(&stuff->length); 139605b261ecSmrg return ProcShmQueryVersion(client); 139705b261ecSmrg} 139805b261ecSmrg 13997e31ba66Smrgstatic int _X_COLD 14004642e01fSmrgSProcShmAttach(ClientPtr client) 140105b261ecSmrg{ 140205b261ecSmrg REQUEST(xShmAttachReq); 1403f7df2e56Smrg swaps(&stuff->length); 140405b261ecSmrg REQUEST_SIZE_MATCH(xShmAttachReq); 1405f7df2e56Smrg swapl(&stuff->shmseg); 1406f7df2e56Smrg swapl(&stuff->shmid); 140705b261ecSmrg return ProcShmAttach(client); 140805b261ecSmrg} 140905b261ecSmrg 14107e31ba66Smrgstatic int _X_COLD 14114642e01fSmrgSProcShmDetach(ClientPtr client) 141205b261ecSmrg{ 141305b261ecSmrg REQUEST(xShmDetachReq); 1414f7df2e56Smrg swaps(&stuff->length); 141505b261ecSmrg REQUEST_SIZE_MATCH(xShmDetachReq); 1416f7df2e56Smrg swapl(&stuff->shmseg); 141705b261ecSmrg return ProcShmDetach(client); 141805b261ecSmrg} 141905b261ecSmrg 14207e31ba66Smrgstatic int _X_COLD 14214642e01fSmrgSProcShmPutImage(ClientPtr client) 142205b261ecSmrg{ 142305b261ecSmrg REQUEST(xShmPutImageReq); 1424f7df2e56Smrg swaps(&stuff->length); 142505b261ecSmrg REQUEST_SIZE_MATCH(xShmPutImageReq); 1426f7df2e56Smrg swapl(&stuff->drawable); 1427f7df2e56Smrg swapl(&stuff->gc); 1428f7df2e56Smrg swaps(&stuff->totalWidth); 1429f7df2e56Smrg swaps(&stuff->totalHeight); 1430f7df2e56Smrg swaps(&stuff->srcX); 1431f7df2e56Smrg swaps(&stuff->srcY); 1432f7df2e56Smrg swaps(&stuff->srcWidth); 1433f7df2e56Smrg swaps(&stuff->srcHeight); 1434f7df2e56Smrg swaps(&stuff->dstX); 1435f7df2e56Smrg swaps(&stuff->dstY); 1436f7df2e56Smrg swapl(&stuff->shmseg); 1437f7df2e56Smrg swapl(&stuff->offset); 143805b261ecSmrg return ProcShmPutImage(client); 143905b261ecSmrg} 144005b261ecSmrg 14417e31ba66Smrgstatic int _X_COLD 14424642e01fSmrgSProcShmGetImage(ClientPtr client) 144305b261ecSmrg{ 144405b261ecSmrg REQUEST(xShmGetImageReq); 1445f7df2e56Smrg swaps(&stuff->length); 144605b261ecSmrg REQUEST_SIZE_MATCH(xShmGetImageReq); 1447f7df2e56Smrg swapl(&stuff->drawable); 1448f7df2e56Smrg swaps(&stuff->x); 1449f7df2e56Smrg swaps(&stuff->y); 1450f7df2e56Smrg swaps(&stuff->width); 1451f7df2e56Smrg swaps(&stuff->height); 1452f7df2e56Smrg swapl(&stuff->planeMask); 1453f7df2e56Smrg swapl(&stuff->shmseg); 1454f7df2e56Smrg swapl(&stuff->offset); 145505b261ecSmrg return ProcShmGetImage(client); 145605b261ecSmrg} 145705b261ecSmrg 14587e31ba66Smrgstatic int _X_COLD 14594642e01fSmrgSProcShmCreatePixmap(ClientPtr client) 146005b261ecSmrg{ 146105b261ecSmrg REQUEST(xShmCreatePixmapReq); 1462f7df2e56Smrg swaps(&stuff->length); 146305b261ecSmrg REQUEST_SIZE_MATCH(xShmCreatePixmapReq); 1464f7df2e56Smrg swapl(&stuff->pid); 1465f7df2e56Smrg swapl(&stuff->drawable); 1466f7df2e56Smrg swaps(&stuff->width); 1467f7df2e56Smrg swaps(&stuff->height); 1468f7df2e56Smrg swapl(&stuff->shmseg); 1469f7df2e56Smrg swapl(&stuff->offset); 147005b261ecSmrg return ProcShmCreatePixmap(client); 147105b261ecSmrg} 147205b261ecSmrg 1473f7df2e56Smrg#ifdef SHM_FD_PASSING 14747e31ba66Smrgstatic int _X_COLD 1475f7df2e56SmrgSProcShmAttachFd(ClientPtr client) 1476f7df2e56Smrg{ 1477f7df2e56Smrg REQUEST(xShmAttachFdReq); 1478f7df2e56Smrg SetReqFds(client, 1); 1479f7df2e56Smrg swaps(&stuff->length); 1480f7df2e56Smrg REQUEST_SIZE_MATCH(xShmAttachFdReq); 1481f7df2e56Smrg swapl(&stuff->shmseg); 1482f7df2e56Smrg return ProcShmAttachFd(client); 1483f7df2e56Smrg} 1484f7df2e56Smrg 14857e31ba66Smrgstatic int _X_COLD 1486f7df2e56SmrgSProcShmCreateSegment(ClientPtr client) 1487f7df2e56Smrg{ 1488f7df2e56Smrg REQUEST(xShmCreateSegmentReq); 1489f7df2e56Smrg swaps(&stuff->length); 1490f7df2e56Smrg REQUEST_SIZE_MATCH(xShmCreateSegmentReq); 1491f7df2e56Smrg swapl(&stuff->shmseg); 1492f7df2e56Smrg swapl(&stuff->size); 1493f7df2e56Smrg return ProcShmCreateSegment(client); 1494f7df2e56Smrg} 1495f7df2e56Smrg#endif /* SHM_FD_PASSING */ 1496f7df2e56Smrg 14977e31ba66Smrgstatic int _X_COLD 1498f7df2e56SmrgSProcShmDispatch(ClientPtr client) 149905b261ecSmrg{ 150005b261ecSmrg REQUEST(xReq); 15017e31ba66Smrg 15027e31ba66Smrg if (stuff->data == X_ShmQueryVersion) 1503f7df2e56Smrg return SProcShmQueryVersion(client); 15047e31ba66Smrg 15057e31ba66Smrg if (!client->local) 15067e31ba66Smrg return BadRequest; 15077e31ba66Smrg 15087e31ba66Smrg switch (stuff->data) { 150905b261ecSmrg case X_ShmAttach: 1510f7df2e56Smrg return SProcShmAttach(client); 151105b261ecSmrg case X_ShmDetach: 1512f7df2e56Smrg return SProcShmDetach(client); 151305b261ecSmrg case X_ShmPutImage: 1514f7df2e56Smrg return SProcShmPutImage(client); 151505b261ecSmrg case X_ShmGetImage: 1516f7df2e56Smrg return SProcShmGetImage(client); 151705b261ecSmrg case X_ShmCreatePixmap: 1518f7df2e56Smrg return SProcShmCreatePixmap(client); 1519f7df2e56Smrg#ifdef SHM_FD_PASSING 1520f7df2e56Smrg case X_ShmAttachFd: 1521f7df2e56Smrg return SProcShmAttachFd(client); 1522f7df2e56Smrg case X_ShmCreateSegment: 1523f7df2e56Smrg return SProcShmCreateSegment(client); 1524f7df2e56Smrg#endif 152505b261ecSmrg default: 1526f7df2e56Smrg return BadRequest; 152705b261ecSmrg } 152805b261ecSmrg} 152965b04b38Smrg 153065b04b38Smrgvoid 1531f7df2e56SmrgShmExtensionInit(void) 153265b04b38Smrg{ 153365b04b38Smrg ExtensionEntry *extEntry; 153465b04b38Smrg int i; 153565b04b38Smrg 153665b04b38Smrg#ifdef MUST_CHECK_FOR_SHM_SYSCALL 1537f7df2e56Smrg if (!CheckForShmSyscall()) { 1538f7df2e56Smrg ErrorF("MIT-SHM extension disabled due to lack of kernel support\n"); 1539f7df2e56Smrg return; 154065b04b38Smrg } 154165b04b38Smrg#endif 154265b04b38Smrg 154365b04b38Smrg if (!ShmRegisterPrivates()) 1544f7df2e56Smrg return; 154565b04b38Smrg 154665b04b38Smrg sharedPixmaps = xFalse; 154765b04b38Smrg { 1548f7df2e56Smrg sharedPixmaps = xTrue; 1549f7df2e56Smrg for (i = 0; i < screenInfo.numScreens; i++) { 1550f7df2e56Smrg ShmScrPrivateRec *screen_priv = 1551f7df2e56Smrg ShmInitScreenPriv(screenInfo.screens[i]); 1552f7df2e56Smrg if (!screen_priv->shmFuncs) 1553f7df2e56Smrg screen_priv->shmFuncs = &miFuncs; 1554f7df2e56Smrg if (!screen_priv->shmFuncs->CreatePixmap) 1555f7df2e56Smrg sharedPixmaps = xFalse; 1556f7df2e56Smrg } 1557f7df2e56Smrg if (sharedPixmaps) 1558f7df2e56Smrg for (i = 0; i < screenInfo.numScreens; i++) { 1559f7df2e56Smrg ShmScrPrivateRec *screen_priv = 1560f7df2e56Smrg ShmGetScreenPriv(screenInfo.screens[i]); 1561f7df2e56Smrg screen_priv->destroyPixmap = 1562f7df2e56Smrg screenInfo.screens[i]->DestroyPixmap; 1563f7df2e56Smrg screenInfo.screens[i]->DestroyPixmap = ShmDestroyPixmap; 1564f7df2e56Smrg } 156565b04b38Smrg } 156665b04b38Smrg ShmSegType = CreateNewResourceType(ShmDetachSegment, "ShmSeg"); 156765b04b38Smrg if (ShmSegType && 1568f7df2e56Smrg (extEntry = AddExtension(SHMNAME, ShmNumberEvents, ShmNumberErrors, 1569f7df2e56Smrg ProcShmDispatch, SProcShmDispatch, 1570f7df2e56Smrg ShmResetProc, StandardMinorOpcode))) { 1571f7df2e56Smrg ShmReqCode = (unsigned char) extEntry->base; 1572f7df2e56Smrg ShmCompletionCode = extEntry->eventBase; 1573f7df2e56Smrg BadShmSegCode = extEntry->errorBase; 1574f7df2e56Smrg SetResourceTypeErrorValue(ShmSegType, BadShmSegCode); 1575f7df2e56Smrg EventSwapVector[ShmCompletionCode] = (EventSwapPtr) SShmCompletionEvent; 157665b04b38Smrg } 157765b04b38Smrg} 1578