Ray Strode 2015-06-10 16:52:28 -04:00
parent 2d1fe9d31e
commit d0fa93e2f8
4 changed files with 646 additions and 1 deletions

View File

@ -0,0 +1,90 @@
From d80ec479f17bf0931b9332b4f3959c19ec62aba1 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
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 <rstrode@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com>
---
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

View File

@ -0,0 +1,484 @@
From 6003510f40dd64f8cd1c060b6fd5ca40d48d3e6d Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
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 <rstrode@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com>
---
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 <dix-config.h>
#endif
#ifdef WIN32
#include <X11/Xwinsock.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#define XSERV_t
#define TRANS_SERVER
#define TRANS_REOPEN
#include <X11/Xtrans/Xtrans.h>
#include <X11/Xauth.h>
#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "site.h"
#include <errno.h>
#include <sys/types.h>
#ifndef WIN32
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <ctype.h>
+#ifndef NO_LOCAL_CLIENT_CRED
+#include <pwd.h>
+#endif
+
#if defined(TCPCONN) || defined(STREAMSCONN)
#include <netinet/in.h>
#endif /* TCPCONN || STREAMSCONN */
#ifdef HAVE_GETPEERUCRED
#include <ucred.h>
#ifdef sun
#include <zone.h>
#endif
#endif
#if defined(SVR4) || (defined(SYSV) && defined(__i386__)) || defined(__GNU__)
#include <sys/utsname.h>
#endif
#if defined(SYSV) && defined(__i386__)
#include <sys/stream.h>
#endif
#ifdef __GNU__
#undef SIOCGIFCONF
#include <netdb.h>
#else /*!__GNU__ */
#include <net/if.h>
#endif /*__GNU__ */
#ifdef SVR4
#include <sys/sockio.h>
#include <sys/stropts.h>
#endif
#include <netdb.h>
@@ -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<display>.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<display>.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

View File

@ -0,0 +1,63 @@
From fc11a1d595222932af192e7aef551b98cd3393f2 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
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 <rstrode@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Alan Coopersmith <alan.coopersmith@oracle.com>
---
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

View File

@ -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 <rstrode@redhat.com> 1.17.1-15
- CVE-2015-3164
* Tue May 26 2015 Peter Hutterer <peter.hutterer@redhat.com> 1.17.1-14
- Add the unaccelerated valuator masks, fixes nonmoving mouse in SDL
(#1208992)