From d0fa93e2f8da9d7fc1187b524f1b05758cc81922 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 10 Jun 2015 16:52:28 -0400 Subject: [PATCH] CVE-2015-3164 http://lists.freedesktop.org/archives/wayland-devel/2015-June/022548.html --- ...access-control-on-open-sockets-CVE-2.patch | 90 ++++ ...mplicit-local-user-access-mode-CVE-2.patch | 484 ++++++++++++++++++ ...-to-local-user-if-no-xauth-file-give.patch | 63 +++ xorg-x11-server.spec | 10 +- 4 files changed, 646 insertions(+), 1 deletion(-) create mode 100644 0001-xwayland-Enable-access-control-on-open-sockets-CVE-2.patch create mode 100644 0002-os-support-new-implicit-local-user-access-mode-CVE-2.patch create mode 100644 0003-xwayland-default-to-local-user-if-no-xauth-file-give.patch diff --git a/0001-xwayland-Enable-access-control-on-open-sockets-CVE-2.patch b/0001-xwayland-Enable-access-control-on-open-sockets-CVE-2.patch new file mode 100644 index 0000000..c8045a4 --- /dev/null +++ b/0001-xwayland-Enable-access-control-on-open-sockets-CVE-2.patch @@ -0,0 +1,90 @@ +From d80ec479f17bf0931b9332b4f3959c19ec62aba1 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 23 Apr 2015 14:10:23 -0400 +Subject: [PATCH 1/3] xwayland: Enable access control on open sockets + [CVE-2015-3164 1/3] + +Xwayland currently allows wide-open access to the X sockets +it listens on, ignoring Xauth access control. + +This commit makes sure to enable access control on the sockets, +so one user can't snoop on another user's X-over-wayland +applications. + +Signed-off-by: Ray Strode +Reviewed-by: Daniel Stone +Reviewed-by: Alan Coopersmith +--- + hw/xwayland/xwayland.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c +index 7e8d667..c5bee77 100644 +--- a/hw/xwayland/xwayland.c ++++ b/hw/xwayland/xwayland.c +@@ -456,61 +456,61 @@ block_handler(void *data, struct timeval **tv, void *read_mask) + FatalError("failed to dispatch Wayland events: %s\n", + strerror(errno)); + } + + xwl_screen->prepare_read = 1; + + ret = wl_display_flush(xwl_screen->display); + if (ret == -1) + FatalError("failed to write to XWayland fd: %s\n", strerror(errno)); + } + + static CARD32 + add_client_fd(OsTimerPtr timer, CARD32 time, void *arg) + { + struct xwl_screen *xwl_screen = arg; + + if (!AddClientOnOpenFD(xwl_screen->wm_fd)) + FatalError("Failed to add wm client\n"); + + TimerFree(timer); + + return 0; + } + + static void + listen_on_fds(struct xwl_screen *xwl_screen) + { + int i; + + for (i = 0; i < xwl_screen->listen_fd_count; i++) +- ListenOnOpenFD(xwl_screen->listen_fds[i], TRUE); ++ ListenOnOpenFD(xwl_screen->listen_fds[i], FALSE); + } + + static void + wm_selection_callback(CallbackListPtr *p, void *data, void *arg) + { + SelectionInfoRec *info = arg; + struct xwl_screen *xwl_screen = data; + static const char atom_name[] = "WM_S0"; + static Atom atom_wm_s0; + + if (atom_wm_s0 == None) + atom_wm_s0 = MakeAtom(atom_name, strlen(atom_name), TRUE); + if (info->selection->selection != atom_wm_s0 || + info->kind != SelectionSetOwner) + return; + + listen_on_fds(xwl_screen); + + DeleteCallback(&SelectionCallback, wm_selection_callback, xwl_screen); + } + + static Bool + xwl_screen_init(ScreenPtr pScreen, int argc, char **argv) + { + struct xwl_screen *xwl_screen; + Pixel red_mask, blue_mask, green_mask; + int ret, bpc, green_bpc, i; + + xwl_screen = calloc(sizeof *xwl_screen, 1); + if (xwl_screen == NULL) +-- +2.3.7 + diff --git a/0002-os-support-new-implicit-local-user-access-mode-CVE-2.patch b/0002-os-support-new-implicit-local-user-access-mode-CVE-2.patch new file mode 100644 index 0000000..ee60215 --- /dev/null +++ b/0002-os-support-new-implicit-local-user-access-mode-CVE-2.patch @@ -0,0 +1,484 @@ +From 6003510f40dd64f8cd1c060b6fd5ca40d48d3e6d Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 23 Apr 2015 15:36:09 -0400 +Subject: [PATCH 2/3] os: support new implicit local user access mode + [CVE-2015-3164 2/3] + +If the X server is started without a '-auth' argument, then +it gets started wide open to all local users on the system. + +This isn't a great default access model, but changing it in +Xorg at this point would break backward compatibility. + +Xwayland, on the other hand is new, and much more targeted +in scope. It could, in theory, be changed to allow the much +more secure default of a "user who started X server can connect +clients to that server." + +This commit paves the way for that change, by adding a mechanism +for DDXs to opt-in to that behavior. They merely need to call + +LocalAccessScopeUser() + +in their init functions. + +A subsequent commit will add that call for Xwayland. + +Signed-off-by: Ray Strode +Reviewed-by: Daniel Stone +Reviewed-by: Alan Coopersmith +--- + include/os.h | 17 ++++++++++ + os/access.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + os/auth.c | 8 ++--- + 3 files changed, 130 insertions(+), 4 deletions(-) + +diff --git a/include/os.h b/include/os.h +index 3e68c49..3c3954f 100644 +--- a/include/os.h ++++ b/include/os.h +@@ -386,65 +386,82 @@ InvalidHost(sockaddrPtr /*saddr */ , int /*len */ , ClientPtr client); + #define LCC_ZID_SET (1 << 3) + + typedef struct { + int fieldsSet; /* Bit mask of fields set */ + int euid; /* Effective uid */ + int egid; /* Primary effective group id */ + int nSuppGids; /* Number of supplementary group ids */ + int *pSuppGids; /* Array of supplementary group ids */ + int pid; /* Process id */ + int zoneid; /* Only set on Solaris 10 & later */ + } LocalClientCredRec; + + extern _X_EXPORT int + GetLocalClientCreds(ClientPtr, LocalClientCredRec **); + extern _X_EXPORT void + FreeLocalClientCreds(LocalClientCredRec *); + + extern _X_EXPORT int + ChangeAccessControl(ClientPtr /*client */ , int /*fEnabled */ ); + + extern _X_EXPORT int + GetAccessControl(void); + + extern _X_EXPORT void + AddLocalHosts(void); + + extern _X_EXPORT void + ResetHosts(const char *display); + + extern _X_EXPORT void ++EnableLocalAccess(void); ++ ++extern _X_EXPORT void ++DisableLocalAccess(void); ++ ++extern _X_EXPORT void + EnableLocalHost(void); + + extern _X_EXPORT void + DisableLocalHost(void); + ++#ifndef NO_LOCAL_CLIENT_CRED ++extern _X_EXPORT void ++EnableLocalUser(void); ++ ++extern _X_EXPORT void ++DisableLocalUser(void); ++ ++extern _X_EXPORT void ++LocalAccessScopeUser(void); ++#endif ++ + extern _X_EXPORT void + AccessUsingXdmcp(void); + + extern _X_EXPORT void + DefineSelf(int /*fd */ ); + + #if XDMCP + extern _X_EXPORT void + AugmentSelf(void *from, int len); + + extern _X_EXPORT void + RegisterAuthorizations(void); + #endif + + extern _X_EXPORT void + InitAuthorization(const char * /*filename */ ); + + /* extern int LoadAuthorization(void); */ + + extern _X_EXPORT int + AuthorizationFromID(XID id, + unsigned short *name_lenp, + const char **namep, + unsigned short *data_lenp, char **datap); + + extern _X_EXPORT XID + CheckAuthorization(unsigned int /*namelength */ , + const char * /*name */ , + unsigned int /*datalength */ , + const char * /*data */ , +diff --git a/os/access.c b/os/access.c +index 28f2d32..c9f8a1f 100644 +--- a/os/access.c ++++ b/os/access.c +@@ -75,60 +75,64 @@ SOFTWARE. + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + #ifdef HAVE_DIX_CONFIG_H + #include + #endif + + #ifdef WIN32 + #include + #endif + + #include + #include + #define XSERV_t + #define TRANS_SERVER + #define TRANS_REOPEN + #include + #include + #include + #include + #include "misc.h" + #include "site.h" + #include + #include + #ifndef WIN32 + #include + #include + #include + ++#ifndef NO_LOCAL_CLIENT_CRED ++#include ++#endif ++ + #if defined(TCPCONN) || defined(STREAMSCONN) + #include + #endif /* TCPCONN || STREAMSCONN */ + + #ifdef HAVE_GETPEERUCRED + #include + #ifdef sun + #include + #endif + #endif + + #if defined(SVR4) || (defined(SYSV) && defined(__i386__)) || defined(__GNU__) + #include + #endif + #if defined(SYSV) && defined(__i386__) + #include + #endif + #ifdef __GNU__ + #undef SIOCGIFCONF + #include + #else /*!__GNU__ */ + #include + #endif /*__GNU__ */ + + #ifdef SVR4 + #include + #include + #endif + + #include +@@ -198,97 +202,202 @@ static Bool NewHost(int /*family */ , + int /* addingLocalHosts */ ); + + /* XFree86 bug #156: To keep track of which hosts were explicitly requested in + /etc/X.hosts, we've added a requested field to the HOST struct, + and a LocalHostRequested variable. These default to FALSE, but are set + to TRUE in ResetHosts when reading in /etc/X.hosts. They are + checked in DisableLocalHost(), which is called to disable the default + local host entries when stronger authentication is turned on. */ + + typedef struct _host { + short family; + short len; + unsigned char *addr; + struct _host *next; + int requested; + } HOST; + + #define MakeHost(h,l) (h)=malloc(sizeof *(h)+(l));\ + if (h) { \ + (h)->addr=(unsigned char *) ((h) + 1);\ + (h)->requested = FALSE; \ + } + #define FreeHost(h) free(h) + static HOST *selfhosts = NULL; + static HOST *validhosts = NULL; + static int AccessEnabled = DEFAULT_ACCESS_CONTROL; + static int LocalHostEnabled = FALSE; + static int LocalHostRequested = FALSE; + static int UsingXdmcp = FALSE; + ++static enum { ++ LOCAL_ACCESS_SCOPE_HOST = 0, ++#ifndef NO_LOCAL_CLIENT_CRED ++ LOCAL_ACCESS_SCOPE_USER, ++#endif ++} LocalAccessScope; ++ + /* FamilyServerInterpreted implementation */ + static Bool siAddrMatch(int family, void *addr, int len, HOST * host, + ClientPtr client); + static int siCheckAddr(const char *addrString, int length); + static void siTypesInitialize(void); + + /* + * called when authorization is not enabled to add the + * local host to the access list + */ + + void ++EnableLocalAccess(void) ++{ ++ switch (LocalAccessScope) { ++ case LOCAL_ACCESS_SCOPE_HOST: ++ EnableLocalHost(); ++ break; ++#ifndef NO_LOCAL_CLIENT_CRED ++ case LOCAL_ACCESS_SCOPE_USER: ++ EnableLocalUser(); ++ break; ++#endif ++ } ++} ++ ++void + EnableLocalHost(void) + { + if (!UsingXdmcp) { + LocalHostEnabled = TRUE; + AddLocalHosts(); + } + } + + /* + * called when authorization is enabled to keep us secure + */ + void ++DisableLocalAccess(void) ++{ ++ switch (LocalAccessScope) { ++ case LOCAL_ACCESS_SCOPE_HOST: ++ DisableLocalHost(); ++ break; ++#ifndef NO_LOCAL_CLIENT_CRED ++ case LOCAL_ACCESS_SCOPE_USER: ++ DisableLocalUser(); ++ break; ++#endif ++ } ++} ++ ++void + DisableLocalHost(void) + { + HOST *self; + + if (!LocalHostRequested) /* Fix for XFree86 bug #156 */ + LocalHostEnabled = FALSE; + for (self = selfhosts; self; self = self->next) { + if (!self->requested) /* Fix for XFree86 bug #156 */ + (void) RemoveHost((ClientPtr) NULL, self->family, self->len, + (void *) self->addr); + } + } + ++#ifndef NO_LOCAL_CLIENT_CRED ++static int GetLocalUserAddr(char **addr) ++{ ++ static const char *type = "localuser"; ++ static const char delimiter = '\0'; ++ static const char *value; ++ struct passwd *pw; ++ int length = -1; ++ ++ pw = getpwuid(getuid()); ++ ++ if (pw == NULL || pw->pw_name == NULL) ++ goto out; ++ ++ value = pw->pw_name; ++ ++ length = asprintf(addr, "%s%c%s", type, delimiter, value); ++ ++ if (length == -1) { ++ goto out; ++ } ++ ++ /* Trailing NUL */ ++ length++; ++ ++out: ++ return length; ++} ++ ++void ++EnableLocalUser(void) ++{ ++ char *addr = NULL; ++ int length = -1; ++ ++ length = GetLocalUserAddr(&addr); ++ ++ if (length == -1) ++ return; ++ ++ NewHost(FamilyServerInterpreted, addr, length, TRUE); ++ ++ free(addr); ++} ++ ++void ++DisableLocalUser(void) ++{ ++ char *addr = NULL; ++ int length = -1; ++ ++ length = GetLocalUserAddr(&addr); ++ ++ if (length == -1) ++ return; ++ ++ RemoveHost(NULL, FamilyServerInterpreted, length, addr); ++ ++ free(addr); ++} ++ ++void ++LocalAccessScopeUser(void) ++{ ++ LocalAccessScope = LOCAL_ACCESS_SCOPE_USER; ++} ++#endif ++ + /* + * called at init time when XDMCP will be used; xdmcp always + * adds local hosts manually when needed + */ + + void + AccessUsingXdmcp(void) + { + UsingXdmcp = TRUE; + LocalHostEnabled = FALSE; + } + + #if defined(SVR4) && !defined(sun) && defined(SIOCGIFCONF) && !defined(USE_SIOCGLIFCONF) + + /* Deal with different SIOCGIFCONF ioctl semantics on these OSs */ + + static int + ifioctl(int fd, int cmd, char *arg) + { + struct strioctl ioc; + int ret; + + memset((char *) &ioc, 0, sizeof(ioc)); + ioc.ic_cmd = cmd; + ioc.ic_timout = 0; + if (cmd == SIOCGIFCONF) { + ioc.ic_len = ((struct ifconf *) arg)->ifc_len; + ioc.ic_dp = ((struct ifconf *) arg)->ifc_buf; + } + else { +diff --git a/os/auth.c b/os/auth.c +index 5fcb538..7da6fc6 100644 +--- a/os/auth.c ++++ b/os/auth.c +@@ -154,78 +154,78 @@ RegisterAuthorizations(void) + (int) protocols[i].name_length); + } + #endif + + XID + CheckAuthorization(unsigned int name_length, + const char *name, + unsigned int data_length, + const char *data, ClientPtr client, const char **reason) + { /* failure message. NULL for default msg */ + int i; + struct stat buf; + static time_t lastmod = 0; + static Bool loaded = FALSE; + + if (!authorization_file || stat(authorization_file, &buf)) { + if (lastmod != 0) { + lastmod = 0; + ShouldLoadAuth = TRUE; /* stat lost, so force reload */ + } + } + else if (buf.st_mtime > lastmod) { + lastmod = buf.st_mtime; + ShouldLoadAuth = TRUE; + } + if (ShouldLoadAuth) { + int loadauth = LoadAuthorization(); + + /* + * If the authorization file has at least one entry for this server, +- * disable local host access. (loadauth > 0) ++ * disable local access. (loadauth > 0) + * + * If there are zero entries (either initially or when the + * authorization file is later reloaded), or if a valid +- * authorization file was never loaded, enable local host access. ++ * authorization file was never loaded, enable local access. + * (loadauth == 0 || !loaded) + * + * If the authorization file was loaded initially (with valid + * entries for this server), and reloading it later fails, don't + * change anything. (loadauth == -1 && loaded) + */ + + if (loadauth > 0) { +- DisableLocalHost(); /* got at least one */ ++ DisableLocalAccess(); /* got at least one */ + loaded = TRUE; + } + else if (loadauth == 0 || !loaded) +- EnableLocalHost(); ++ EnableLocalAccess(); + } + if (name_length) { + for (i = 0; i < NUM_AUTHORIZATION; i++) { + if (protocols[i].name_length == name_length && + memcmp(protocols[i].name, name, (int) name_length) == 0) { + return (*protocols[i].Check) (data_length, data, client, + reason); + } + *reason = "Protocol not supported by server\n"; + } + } + else + *reason = "No protocol specified\n"; + return (XID) ~0L; + } + + void + ResetAuthorization(void) + { + int i; + + for (i = 0; i < NUM_AUTHORIZATION; i++) + if (protocols[i].Reset) + (*protocols[i].Reset) (); + ShouldLoadAuth = TRUE; + } + + int + AuthorizationFromID(XID id, + unsigned short *name_lenp, +-- +2.3.7 + diff --git a/0003-xwayland-default-to-local-user-if-no-xauth-file-give.patch b/0003-xwayland-default-to-local-user-if-no-xauth-file-give.patch new file mode 100644 index 0000000..ad73c8f --- /dev/null +++ b/0003-xwayland-default-to-local-user-if-no-xauth-file-give.patch @@ -0,0 +1,63 @@ +From fc11a1d595222932af192e7aef551b98cd3393f2 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 23 Apr 2015 15:39:50 -0400 +Subject: [PATCH 3/3] xwayland: default to local user if no xauth file given. + [CVE-2015-3164 3/3] + +Right now if "-auth" isn't passed on the command line, we let +any user on the system connect to the Xwayland server. + +That's clearly suboptimal, given Xwayland is generally designed +to be used by one user at a time. + +This commit changes the behavior, so only the user who started the +X server can connect clients to it. + +Signed-off-by: Ray Strode +Reviewed-by: Daniel Stone +Reviewed-by: Alan Coopersmith +--- + hw/xwayland/xwayland.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c +index c5bee77..bc92beb 100644 +--- a/hw/xwayland/xwayland.c ++++ b/hw/xwayland/xwayland.c +@@ -675,31 +675,33 @@ static const ExtensionModule xwayland_extensions[] = { + void + InitOutput(ScreenInfo * screen_info, int argc, char **argv) + { + int depths[] = { 1, 4, 8, 15, 16, 24, 32 }; + int bpp[] = { 1, 8, 8, 16, 16, 32, 32 }; + int i; + + for (i = 0; i < ARRAY_SIZE(depths); i++) { + screen_info->formats[i].depth = depths[i]; + screen_info->formats[i].bitsPerPixel = bpp[i]; + screen_info->formats[i].scanlinePad = BITMAP_SCANLINE_PAD; + } + + screen_info->imageByteOrder = IMAGE_BYTE_ORDER; + screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT; + screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD; + screen_info->bitmapBitOrder = BITMAP_BIT_ORDER; + screen_info->numPixmapFormats = ARRAY_SIZE(depths); + + LoadExtensionList(xwayland_extensions, + ARRAY_SIZE(xwayland_extensions), FALSE); + + /* Cast away warning from missing printf annotation for + * wl_log_func_t. Wayland 1.5 will have the annotation, so we can + * remove the cast and require that when it's released. */ + wl_log_set_handler_client((void *) xwl_log_handler); + + if (AddScreen(xwl_screen_init, argc, argv) == -1) { + FatalError("Couldn't add screen\n"); + } ++ ++ LocalAccessScopeUser(); + } +-- +2.3.7 + diff --git a/xorg-x11-server.spec b/xorg-x11-server.spec index 2059de2..1324d82 100644 --- a/xorg-x11-server.spec +++ b/xorg-x11-server.spec @@ -45,7 +45,7 @@ Summary: X.Org X11 X server Name: xorg-x11-server Version: 1.17.1 -Release: 14%{?gitdate:.%{gitdate}}%{dist} +Release: 15%{?gitdate:.%{gitdate}}%{dist} URL: http://www.x.org License: MIT Group: User Interface/X @@ -126,6 +126,11 @@ Patch10007: 0001-modesetting-Fix-software-cursor-fallback.patch Patch10010: 0001-dix-Add-unaccelerated-valuators-to-the-ValuatorMask.patch Patch10011: 0002-dix-hook-up-the-unaccelerated-valuator-masks.patch +# CVE-2015-3164 +Patch201531640: 0001-xwayland-Enable-access-control-on-open-sockets-CVE-2.patch +Patch201531641: 0002-os-support-new-implicit-local-user-access-mode-CVE-2.patch +Patch201531642: 0003-xwayland-default-to-local-user-if-no-xauth-file-give.patch + %global moduledir %{_libdir}/xorg/modules %global drimoduledir %{_libdir}/dri %global sdkdir %{_includedir}/xorg @@ -663,6 +668,9 @@ find %{inst_srcdir}/hw/xfree86 -name \*.c -delete %changelog +* Wed Jun 10 2015 Ray Strode 1.17.1-15 +- CVE-2015-3164 + * Tue May 26 2015 Peter Hutterer 1.17.1-14 - Add the unaccelerated valuator masks, fixes nonmoving mouse in SDL (#1208992)