Skip to content

Commit

Permalink
Fix local privilege escalation to root and sandbox bypasses in scheduler
Browse files Browse the repository at this point in the history
(rdar://37836779, rdar://37836995, rdar://37837252, rdar://37837581)
  • Loading branch information
michaelrsweet committed Jun 5, 2018
1 parent 7c7f431 commit 97cb566
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 106 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ CHANGES - 2.2.8 - 2018-06-04
Changes in CUPS v2.2.8
----------------------

- SECURITY: Fixed local privilege escalation to root and sandbox bypasses in
scheduler (rdar://37836779, rdar://37836995, rdar://37837252, rdar://37837581)
- SECURITY: The scheduler did not validate notify-recipient-uri schemes properly
(rdar://40068936)
- Additional changes for the scheduler to substitute default values for invalid
job attributes when running in "relaxed conformance" mode (Issue #5229)
- The `ipptool` program no longer checks for duplicate attributes when running
Expand Down
6 changes: 6 additions & 0 deletions doc/help/man-cups-files.conf.html
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ <h3><a name="DIRECTIVES">Directives</a></h3>

</pre>
The default is "/var/log/cups/page_log".
<dt><a name="PassEnv"></a><b>PassEnv </b><i>variable </i>[ ... <i>variable </i>]
<dd style="margin-left: 5.0em">Passes the specified environment variable(s) to child processes.
Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
<dt><a name="RemoteRoot"></a><b>RemoteRoot </b><i>username</i>
<dd style="margin-left: 5.0em">Specifies the username that is associated with unauthenticated accesses by clients claiming to be the root user.
The default is "remroot".
Expand All @@ -136,6 +139,9 @@ <h3><a name="DIRECTIVES">Directives</a></h3>
<dt><a name="ServerRoot"></a><b>ServerRoot </b><i>directory</i>
<dd style="margin-left: 5.0em">Specifies the directory containing the server configuration files.
The default is "/etc/cups".
<dt><a name="SetEnv"></a><b>SetEnv </b><i>variable value</i>
<dd style="margin-left: 5.0em">Set the specified environment variable to be passed to child processes.
Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
<dt><a name="StateDir"></a><b>StateDir </b><i>directory</i>
<dd style="margin-left: 5.0em">Specifies the directory to use for PID and local certificate files.
The default is "/var/run/cups" or "/etc/cups" depending on the platform.
Expand Down
4 changes: 0 additions & 4 deletions doc/help/man-cupsd.conf.html
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,6 @@ <h3><a name="TOP_LEVEL_DIRECTIVES">Top-level Directives</a></h3>
<dt><a name="MultipleOperationTimeout"></a><b>MultipleOperationTimeout </b><i>seconds</i>
<dd style="margin-left: 5.0em">Specifies the maximum amount of time to allow between files in a multiple file print job.
The default is "300" (5 minutes).
<dt><a name="PassEnv"></a><b>PassEnv </b><i>variable </i>[ ... <i>variable </i>]
<dd style="margin-left: 5.0em">Passes the specified environment variable(s) to child processes.
<dt><a name="Policy"></a><b>&lt;Policy </b><i>name</i><b>> </b>... <b>&lt;/Policy></b>
<dd style="margin-left: 5.0em">Specifies access control for the named policy.
<dt><a name="Port"></a><b>Port </b><i>number</i>
Expand Down Expand Up @@ -273,8 +271,6 @@ <h3><a name="TOP_LEVEL_DIRECTIVES">Top-level Directives</a></h3>
command.
"Full" reports "CUPS 2.0.0 (UNAME) IPP/2.0".
The default is "Minimal".
<dt><a name="SetEnv"></a><b>SetEnv </b><i>variable value</i>
<dd style="margin-left: 5.0em">Set the specified environment variable to be passed to child processes.
<dt><a name="SSLListen"></a><b>SSLListen </b><i>ipv4-address</i><b>:</b><i>port</i>
<dd style="margin-left: 5.0em"><dt><b>SSLListen [</b><i>ipv6-address</i><b>]:</b><i>port</i>
<dd style="margin-left: 5.0em"><dt><b>SSLListen *:</b><i>port</i>
Expand Down
10 changes: 10 additions & 0 deletions man/cups-files.conf.man.in
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ The server name may be included in filenames using the string "%s", for example:

.fi
The default is "/var/log/cups/page_log".
.\"#PassEnv
.TP 5
\fBPassEnv \fIvariable \fR[ ... \fIvariable \fR]
Passes the specified environment variable(s) to child processes.
Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
.\"#RemoteRoot
.TP 5
\fBRemoteRoot \fIusername\fR
Expand Down Expand Up @@ -191,6 +196,11 @@ macOS uses its keychain database to store certificates and keys while other plat
\fBServerRoot \fIdirectory\fR
Specifies the directory containing the server configuration files.
The default is "/etc/cups".
.\"#SetEnv
.TP 5
\fBSetEnv \fIvariable value\fR
Set the specified environment variable to be passed to child processes.
Note: the standard CUPS filter and backend environment variables cannot be overridden using this directive.
.\"#StateDir
.TP 5
\fBStateDir \fIdirectory\fR
Expand Down
8 changes: 0 additions & 8 deletions man/cupsd.conf.man.in
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,6 @@ The default is "1048576" (1MB).
\fBMultipleOperationTimeout \fIseconds\fR
Specifies the maximum amount of time to allow between files in a multiple file print job.
The default is "300" (5 minutes).
.\"#PassEnv
.TP 5
\fBPassEnv \fIvariable \fR[ ... \fIvariable \fR]
Passes the specified environment variable(s) to child processes.
.\"#Policy
.TP 5
\fB<Policy \fIname\fB> \fR... \fB</Policy>\fR
Expand Down Expand Up @@ -426,10 +422,6 @@ Specifies what information is included in the Server header of HTTP responses.
command.
"Full" reports "CUPS 2.0.0 (UNAME) IPP/2.0".
The default is "Minimal".
.\"#SetEnv
.TP 5
\fBSetEnv \fIvariable value\fR
Set the specified environment variable to be passed to child processes.
.\"#SSLListen
.TP 5
\fBSSLListen \fIipv4-address\fB:\fIport\fR
Expand Down
201 changes: 125 additions & 76 deletions scheduler/conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2928,13 +2928,10 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
/* Line from file */
temp[HTTP_MAX_BUFFER],
/* Temporary buffer for value */
*value, /* Pointer to value */
*valueptr; /* Pointer into value */
*value; /* Pointer to value */
int valuelen; /* Length of value */
http_addrlist_t *addrlist, /* Address list */
*addr; /* Current address */
cups_file_t *incfile; /* Include file */
char incname[1024]; /* Include filename */


/*
Expand All @@ -2949,28 +2946,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
* Decode the directive...
*/

if (!_cups_strcasecmp(line, "Include") && value)
{
/*
* Include filename
*/

if (value[0] == '/')
strlcpy(incname, value, sizeof(incname));
else
snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value);

if ((incfile = cupsFileOpen(incname, "rb")) == NULL)
cupsdLogMessage(CUPSD_LOG_ERROR,
"Unable to include config file \"%s\" - %s",
incname, strerror(errno));
else
{
read_cupsd_conf(incfile);
cupsFileClose(incfile);
}
}
else if (!_cups_strcasecmp(line, "<Location") && value)
if (!_cups_strcasecmp(line, "<Location") && value)
{
/*
* <Location path>
Expand Down Expand Up @@ -3366,31 +3342,6 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d of %s.",
value, linenum, ConfigurationFile);
}
else if (!_cups_strcasecmp(line, "PassEnv") && value)
{
/*
* PassEnv variable [... variable]
*/

for (; *value;)
{
for (valuelen = 0; value[valuelen]; valuelen ++)
if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
break;

if (value[valuelen])
{
value[valuelen] = '\0';
valuelen ++;
}

cupsdSetEnv(value, NULL);

for (value += valuelen; *value; value ++)
if (!_cups_isspace(*value) || *value != ',')
break;
}
}
else if (!_cups_strcasecmp(line, "ServerAlias") && value)
{
/*
Expand Down Expand Up @@ -3419,30 +3370,6 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
break;
}
}
else if (!_cups_strcasecmp(line, "SetEnv") && value)
{
/*
* SetEnv variable value
*/

for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);

if (*valueptr)
{
/*
* Found a value...
*/

while (isspace(*valueptr & 255))
*valueptr++ = '\0';

cupsdSetEnv(value, valueptr);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Missing value for SetEnv directive on line %d of %s.",
linenum, ConfigurationFile);
}
else if (!_cups_strcasecmp(line, "AccessLog") ||
!_cups_strcasecmp(line, "CacheDir") ||
!_cups_strcasecmp(line, "ConfigFilePerm") ||
Expand All @@ -3456,6 +3383,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
!_cups_strcasecmp(line, "LogFilePerm") ||
!_cups_strcasecmp(line, "LPDConfigFile") ||
!_cups_strcasecmp(line, "PageLog") ||
!_cups_strcasecmp(line, "PassEnv") ||
!_cups_strcasecmp(line, "Printcap") ||
!_cups_strcasecmp(line, "PrintcapFormat") ||
!_cups_strcasecmp(line, "RemoteRoot") ||
Expand All @@ -3465,6 +3393,7 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
!_cups_strcasecmp(line, "ServerKey") ||
!_cups_strcasecmp(line, "ServerKeychain") ||
!_cups_strcasecmp(line, "ServerRoot") ||
!_cups_strcasecmp(line, "SetEnv") ||
!_cups_strcasecmp(line, "SMBConfigFile") ||
!_cups_strcasecmp(line, "StateDir") ||
!_cups_strcasecmp(line, "SystemGroup") ||
Expand Down Expand Up @@ -3494,10 +3423,49 @@ read_cupsd_conf(cups_file_t *fp) /* I - File to read from */
static int /* O - 1 on success, 0 on failure */
read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
{
int linenum; /* Current line number */
int i, /* Looping var */
linenum; /* Current line number */
char line[HTTP_MAX_BUFFER], /* Line from file */
*value; /* Value from line */
struct group *group; /* Group */
static const char * const prohibited_env[] =
{ /* Prohibited environment variables */
"APPLE_LANGUAGE",
"AUTH_DOMAIN",
"AUTH_INFO_REQUIRED",
"AUTH_NEGOTIATE",
"AUTH_PASSWORD",
"AUTH_UID",
"AUTH_USERNAME",
"CHARSET",
"CLASS",
"CLASSIFICATION",
"CONTENT_TYPE",
"CUPS_CACHEDIR",
"CUPS_DATADIR",
"CUPS_DOCROOT",
"CUPS_FILETYPE",
"CUPS_FONTPATH",
"CUPS_MAX_MESSAGE",
"CUPS_REQUESTROOT",
"CUPS_SERVERBIN",
"CUPS_SERVERROOT",
"CUPS_STATEDIR",
"DEVICE_URI",
"FINAL_CONTENT_TYPE",
"HOME",
"LANG",
"PPD",
"PRINTER",
"PRINTER_INFO",
"PRINTER_LOCATION",
"PRINTER_STATE_REASONS",
"RIP_CACHE",
"SERVER_ADMIN",
"SOFTWARE",
"TMPDIR",
"USER"
};


/*
Expand Down Expand Up @@ -3535,6 +3503,47 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
}
}
}
else if (!_cups_strcasecmp(line, "PassEnv") && value)
{
/*
* PassEnv variable [... variable]
*/

int valuelen; /* Length of variable name */

for (; *value;)
{
for (valuelen = 0; value[valuelen]; valuelen ++)
if (_cups_isspace(value[valuelen]) || value[valuelen] == ',')
break;

if (value[valuelen])
{
value[valuelen] = '\0';
valuelen ++;
}

for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++)
{
if (!strcmp(value, prohibited_env[i]))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be passed through on line %d of %s.", value, linenum, CupsFilesFile);

if (FatalErrors & CUPSD_FATAL_CONFIG)
return (0);
else
break;
}
}

if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])))
cupsdSetEnv(value, NULL);

for (value += valuelen; *value; value ++)
if (!_cups_isspace(*value) || *value != ',')
break;
}
}
else if (!_cups_strcasecmp(line, "PrintcapFormat") && value)
{
/*
Expand Down Expand Up @@ -3580,6 +3589,46 @@ read_cups_files_conf(cups_file_t *fp) /* I - File to read from */
return (0);
}
}
else if (!_cups_strcasecmp(line, "SetEnv") && value)
{
/*
* SetEnv variable value
*/

char *valueptr; /* Pointer to environment variable value */

for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++);

if (*valueptr)
{
/*
* Found a value...
*/

while (isspace(*valueptr & 255))
*valueptr++ = '\0';

for (i = 0; i < (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])); i ++)
{
if (!strcmp(value, prohibited_env[i]))
{
cupsdLogMessage(CUPSD_LOG_ERROR, "Environment variable \"%s\" cannot be set on line %d of %s.", value, linenum, CupsFilesFile);

if (FatalErrors & CUPSD_FATAL_CONFIG)
return (0);
else
break;
}
}

if (i >= (int)(sizeof(prohibited_env) / sizeof(prohibited_env[0])))
cupsdSetEnv(value, valueptr);
}
else
cupsdLogMessage(CUPSD_LOG_ERROR,
"Missing value for SetEnv directive on line %d of %s.",
linenum, ConfigurationFile);
}
else if (!_cups_strcasecmp(line, "SystemGroup") && value)
{
/*
Expand Down
14 changes: 13 additions & 1 deletion scheduler/job.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Job management routines for the CUPS scheduler.
*
* Copyright 2007-2017 by Apple Inc.
* Copyright 2007-2018 by Apple Inc.
* Copyright 1997-2007 by Easy Software Products, all rights reserved.
*
* These coded instructions, statements, and computer programs are the
Expand Down Expand Up @@ -4774,6 +4774,18 @@ start_job(cupsd_job_t *job, /* I - Job ID */
job->profile = cupsdCreateProfile(job->id, 0);
job->bprofile = cupsdCreateProfile(job->id, 1);

#ifdef HAVE_SANDBOX_H
if ((!job->profile || !job->bprofile) && UseSandboxing && Sandboxing != CUPSD_SANDBOXING_OFF)
{
/*
* Failure to create the sandbox profile means something really bad has
* happened and we need to shutdown immediately.
*/

return;
}
#endif /* HAVE_SANDBOX_H */

/*
* Create the status pipes and buffer...
*/
Expand Down
Loading

0 comments on commit 97cb566

Please sign in to comment.