Index: xc/config/cf/FreeBSD.cf =================================================================== RCS file: /home/x-cvs/xc/config/cf/FreeBSD.cf,v retrieving revision 3.112.2.1 diff -u -r3.112.2.1 FreeBSD.cf --- xc/config/cf/FreeBSD.cf 2002/09/04 02:38:08 3.112.2.1 +++ xc/config/cf/FreeBSD.cf 2002/09/12 20:51:03 @@ -191,6 +191,10 @@ #define HasSetUserContext YES #endif +#if OSMajorVersion >= 5 || (OSMajorVersion == 4 && OSMinorVersion >= 6) +#define HasGetpeereid YES +#endif + /* 3.3(?) and later has support for setting MTRRs */ #ifndef HasMTRRSupport #if OSMajorVersion > 3 || (OSMajorVersion == 3 && OSMinorVersion >= 3) Index: xc/config/cf/Imake.tmpl =================================================================== RCS file: /home/x-cvs/xc/config/cf/Imake.tmpl,v retrieving revision 3.116.2.1 diff -u -r3.116.2.1 Imake.tmpl --- xc/config/cf/Imake.tmpl 2002/09/04 02:38:08 3.116.2.1 +++ xc/config/cf/Imake.tmpl 2002/09/12 20:51:06 @@ -395,6 +395,9 @@ #ifndef HasPamMisc #define HasPamMisc NO #endif +#ifndef HasGetpeereid +#define HasGetpeereid NO +#endif /* byte-order defaults */ #ifndef ByteOrder #if defined(VaxArchitecture) Index: xc/config/cf/OpenBSD.cf =================================================================== RCS file: /home/x-cvs/xc/config/cf/OpenBSD.cf,v retrieving revision 3.66.2.1 diff -u -r3.66.2.1 OpenBSD.cf --- xc/config/cf/OpenBSD.cf 2002/09/04 02:38:08 3.66.2.1 +++ xc/config/cf/OpenBSD.cf 2002/09/12 20:51:06 @@ -97,6 +97,11 @@ # define HasBSDAuth YES #endif +/* OpenBSD 3.0 and later has getpeereid() */ +#if OSMajorVersion >= 3 +# define HasGetpeereid YES +#endif + /* OpenBSD 3.0 has APM with kqueue interface */ #if OSMajorVersion >= 3 # define HasApmKqueue YES Index: xc/doc/specs/Xext/mit-shm.ms =================================================================== RCS file: /home/x-cvs/xc/doc/specs/Xext/mit-shm.ms,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 mit-shm.ms --- xc/doc/specs/Xext/mit-shm.ms 1994/04/27 07:25:28 1.1.1.1 +++ xc/doc/specs/Xext/mit-shm.ms 2002/09/12 20:51:18 @@ -213,6 +213,13 @@ shminfo structure. The server will need that ID to attach itself to the segment. .LP +Also note that, on many systems for security reasons, the X server +will only accept to attach to the shared memory segment if it's +readable and writeable by ``other''. On systems where the X server is +able to determine the uid of the X client over a local transport, the +shared memory segment can be readable and writeable only by the uid of +the client. +.LP Next, attach this shared memory segment to your process: .Cs shminfo.shmaddr = image->data = shmat (shminfo.shmid, 0, 0); Index: xc/programs/Xserver/Xext/shm.c =================================================================== RCS file: /home/x-cvs/xc/programs/Xserver/Xext/shm.c,v retrieving revision 3.33.2.2 diff -u -r3.33.2.2 shm.c --- xc/programs/Xserver/Xext/shm.c 2002/05/29 23:03:19 3.33.2.2 +++ xc/programs/Xserver/Xext/shm.c 2002/09/12 20:51:36 @@ -38,6 +38,7 @@ #include #endif #include +#include #define NEED_REPLIES #define NEED_EVENTS #include "X.h" @@ -64,12 +65,6 @@ #include "panoramiXsrv.h" #endif -#if defined(SVR4) || defined(__linux__) || defined(CSRG_BASED) -#define HAS_SAVED_IDS_AND_SETEUID -#else -#include -#endif - typedef struct _ShmDesc { struct _ShmDesc *next; int shmid; @@ -361,35 +356,38 @@ return (client->noClientException); } -#ifndef HAS_SAVED_IDS_AND_SETEUID /* * Simulate the access() system call for a shared memory segement, - * using the real user and group id of the process + * using the credentials from the client if available */ static int -shm_access(uid_t uid, gid_t gid, struct ipc_perm *perm, int readonly) +shm_access(ClientPtr client, struct ipc_perm *perm, int readonly) { + int uid, gid; mode_t mask; - /* User id 0 always gets access */ - if (uid == 0) { - return 0; - } - /* Check the owner */ - if (perm->uid == uid || perm->cuid == uid) { - mask = S_IRUSR; - if (!readonly) { - mask |= S_IWUSR; + if (LocalClientCred(client, &uid, &gid) != -1) { + + /* User id 0 always gets access */ + if (uid == 0) { + return 0; } - return (perm->mode & mask) == mask ? 0 : -1; - } - /* Check the group */ - if (perm->gid == gid || perm->cgid == gid) { - mask = S_IRGRP; - if (!readonly) { - mask |= S_IWGRP; + /* Check the owner */ + if (perm->uid == uid || perm->cuid == uid) { + mask = S_IRUSR; + if (!readonly) { + mask |= S_IWUSR; + } + return (perm->mode & mask) == mask ? 0 : -1; + } + /* Check the group */ + if (perm->gid == gid || perm->cgid == gid) { + mask = S_IRGRP; + if (!readonly) { + mask |= S_IWGRP; + } + return (perm->mode & mask) == mask ? 0 : -1; } - return (perm->mode & mask) == mask ? 0 : -1; } /* Otherwise, check everyone else */ mask = S_IROTH; @@ -398,7 +396,6 @@ } return (perm->mode & mask) == mask ? 0 : -1; } -#endif static int ProcShmAttach(client) @@ -407,12 +404,6 @@ struct shmid_ds buf; ShmDescPtr shmdesc; REQUEST(xShmAttachReq); - uid_t ruid; - gid_t rgid; -#ifdef HAS_SAVED_IDS_AND_SETEUID - uid_t euid; - gid_t egid; -#endif REQUEST_SIZE_MATCH(xShmAttachReq); LEGAL_NEW_RESOURCE(stuff->shmseg, client); @@ -436,44 +427,25 @@ shmdesc = (ShmDescPtr) xalloc(sizeof(ShmDescRec)); if (!shmdesc) return BadAlloc; - ruid = getuid(); - rgid = getgid(); -#ifdef HAS_SAVED_IDS_AND_SETEUID - euid = geteuid(); - egid = getegid(); - - if (euid != ruid || egid != rgid) { - /* Temporarly switch back to real ids */ - if (seteuid(ruid) == -1 || setegid(rgid) == -1) { - return BadAccess; - } - } -#endif shmdesc->addr = shmat(stuff->shmid, 0, stuff->readOnly ? SHM_RDONLY : 0); -#ifdef HAS_SAVED_IDS_AND_SETEUID - if (euid != ruid || egid != rgid) { - /* Switch back to root privs */ - if (seteuid(euid) == -1 || setegid(egid) == -1) { - return BadAccess; - } - } -#endif if ((shmdesc->addr == ((char *)-1)) || shmctl(stuff->shmid, IPC_STAT, &buf)) { xfree(shmdesc); return BadAccess; } -#ifndef HAS_SAVED_IDS_AND_SETEUID + /* The attach was performed with root privs. We must - * do manual checking of access rights for the real uid/gid */ - if (shm_access(ruid, rgid, &(buf.shm_perm), stuff->readOnly) == -1) { + * do manual checking of access rights for the credentials + * of the client */ + + if (shm_access(client, &(buf.shm_perm), stuff->readOnly) == -1) { shmdt(shmdesc->addr); xfree(shmdesc); return BadAccess; } -#endif + shmdesc->shmid = stuff->shmid; shmdesc->refcnt = 1; shmdesc->writable = !stuff->readOnly; Index: xc/programs/Xserver/include/os.h =================================================================== RCS file: /home/x-cvs/xc/programs/Xserver/include/os.h,v retrieving revision 3.40 diff -u -r3.40 os.h --- xc/programs/Xserver/include/os.h 2001/12/14 19:59:55 3.40 +++ xc/programs/Xserver/include/os.h 2002/09/12 20:51:42 @@ -639,6 +639,8 @@ #endif ); +extern int LocalClientCred(ClientPtr, int *, int *); + extern int ChangeAccessControl( #if NeedFunctionPrototypes ClientPtr /*client*/, Index: xc/programs/Xserver/os/Imakefile =================================================================== RCS file: /home/x-cvs/xc/programs/Xserver/os/Imakefile,v retrieving revision 3.34 diff -u -r3.34 Imakefile --- xc/programs/Xserver/os/Imakefile 2001/10/28 03:34:16 3.34 +++ xc/programs/Xserver/os/Imakefile 2002/09/12 20:51:42 @@ -78,6 +78,10 @@ MALLOC_OBJS=xalloc.o #endif +#if HasGetpeereid +GETPEEREID_DEFINES = -DHAS_GETPEEREID +#endif + BOOTSTRAPCFLAGS = SRCS = WaitFor.c access.c connection.c io.c $(COLOR_SRCS) \ osinit.c utils.c auth.c mitauth.c secauth.c $(XDMAUTHSRCS) \ @@ -111,7 +115,7 @@ #endif DEFINES = -DXSERV_t -DTRANS_SERVER $(CONNECTION_FLAGS) $(MEM_DEFINES) \ $(XDMAUTHDEFS) $(RPCDEFS) $(SIGNAL_DEFINES) $(OS_DEFINES) \ - $(KRB5_DEFINES) $(RGB_DEFINES) + $(KRB5_DEFINES) $(RGB_DEFINES) $(GETPEEREID_DEFINES) INCLUDES = -I. -I../include -I$(XINCLUDESRC) -I$(EXTINCSRC) \ -I$(SERVERSRC)/Xext -I$(FONTINCSRC) \ -I$(TOP)/lib/Xau -I../lbx Krb5Includes Index: xc/programs/Xserver/os/access.c =================================================================== RCS file: /home/x-cvs/xc/programs/Xserver/os/access.c,v retrieving revision 3.39 diff -u -r3.39 access.c --- xc/programs/Xserver/os/access.c 2002/01/07 20:38:29 3.39 +++ xc/programs/Xserver/os/access.c 2002/09/12 20:51:44 @@ -1007,6 +1007,55 @@ return FALSE; } +/* + * Return the uid and gid of a connected local client + * or the uid/gid for nobody those ids cannot be determinded + * + * Used by XShm to test access rights to shared memory segments + */ +int +LocalClientCred(ClientPtr client, int *pUid, int *pGid) +{ + int fd; + XtransConnInfo ci; +#ifdef HAS_GETPEEREID + uid_t uid; + gid_t gid; +#elif defined(SO_PEERCRED) + struct ucred peercred; + socklen_t so_len = sizeof(peercred); +#endif + + if (client == NULL) + return -1; + ci = ((OsCommPtr)client->osPrivate)->trans_conn; + /* We can only determine peer credentials for Unix domain sockets */ + if (!_XSERVTransIsLocal(ci)) { + return -1; + } + fd = _XSERVTransGetConnectionNumber(ci); +#ifdef HAS_GETPEEREID + if (getpeereid(fd, &uid, &gid) == -1) + return -1; + if (pUid != NULL) + *pUid = uid; + if (pGid != NULL) + *pGid = gid; + return 0; +#elif defined(SO_PEERCRED) + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1) + return -1; + if (pUid != NULL) + *pUid = peercred.uid; + if (pGid != NULL) + *pGid = peercred.gid; + return 0; +#else + /* No system call available to get the credentials of the peer */ + return -1; +#endif +} + static Bool AuthorizedClient(ClientPtr client) {