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>
Signed-off-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
Ray Strode 2015-05-05 16:43:43 -04:00 committed by Keith Packard
parent c4534a38b6
commit 4b4b9086d0
3 changed files with 130 additions and 4 deletions

View File

@ -430,12 +430,29 @@ 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);

View File

@ -102,6 +102,10 @@ SOFTWARE.
#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 */
@ -225,6 +229,13 @@ 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);
@ -236,6 +247,21 @@ static void siTypesInitialize(void);
* 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)
{
@ -248,6 +274,21 @@ EnableLocalHost(void)
/*
* 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)
{
@ -262,6 +303,74 @@ DisableLocalHost(void)
}
}
#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

View File

@ -181,11 +181,11 @@ CheckAuthorization(unsigned int name_length,
/*
* 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
@ -194,11 +194,11 @@ CheckAuthorization(unsigned int name_length,
*/
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++) {