"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "mpm_itk.c" between
mpm-itk-2.4.7-03.tar.gz and mpm-itk-2.4.7-04.tar.gz

About: mpm-itk is an Apache multi-processing module (MPM) that allows to run each vhost under a separate uid and gid.

mpm_itk.c  (mpm-itk-2.4.7-03):mpm_itk.c  (mpm-itk-2.4.7-04)
skipping to change at line 16 skipping to change at line 16
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* *
* Portions copyright 2005-2015 Steinar H. Gunderson <sgunderson@bigfoot.com>. * Portions copyright 2005-2016 Steinar H. Gunderson <sgunderson@bigfoot.com>.
* Licensed under the same terms as the rest of Apache. * Licensed under the same terms as the rest of Apache.
* *
* Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>. * Portions copyright 2008 Knut Auvor Grythe <knut@auvor.no>.
* Licensed under the same terms as the rest of Apache. * Licensed under the same terms as the rest of Apache.
*/ */
#define MPMITK_VERSION "2.4.7-03" #define MPMITK_VERSION "2.4.7-04"
#include "config.h" #include "config.h"
#include "apr.h" #include "apr.h"
#include "apr_portable.h" #include "apr_portable.h"
#include "apr_strings.h" #include "apr_strings.h"
#include "apr_thread_proc.h" #include "apr_thread_proc.h"
#include "apr_signal.h" #include "apr_signal.h"
# define _DBG(text,par...) \ # define _DBG(text,par...) \
skipping to change at line 78 skipping to change at line 78
#include "seccomp.h" #include "seccomp.h"
#ifdef HAVE_TIME_H #ifdef HAVE_TIME_H
#include <time.h> #include <time.h>
#endif #endif
#ifdef HAVE_SYS_PROCESSOR_H #ifdef HAVE_SYS_PROCESSOR_H
#include <sys/processor.h> /* for bindprocessor() */ #include <sys/processor.h> /* for bindprocessor() */
#endif #endif
#include <signal.h>
#include <sys/times.h>
#if HAVE_LIBCAP #if HAVE_LIBCAP
#include <sys/capability.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/capability.h>
#endif #endif
#include <signal.h>
#include <sys/times.h>
/* config globals */ /* config globals */
static uid_t ap_itk_min_uid=1; static uid_t ap_itk_min_uid=1;
static uid_t ap_itk_max_uid=UINT_MAX; static uid_t ap_itk_max_uid=UINT_MAX;
static gid_t ap_itk_min_gid=1; static gid_t ap_itk_min_gid=1;
static gid_t ap_itk_max_gid=UINT_MAX; static gid_t ap_itk_max_gid=UINT_MAX;
#if HAVE_LIBCAP
static int ap_itk_enable_caps=1;
#endif
module AP_MODULE_DECLARE_DATA mpm_itk_module; module AP_MODULE_DECLARE_DATA mpm_itk_module;
#define UNSET_NICE_VALUE 100 #define UNSET_NICE_VALUE 100
typedef struct typedef struct
{ {
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
char *username; char *username;
int nice_value; int nice_value;
skipping to change at line 114 skipping to change at line 118
ap_expr_info_t *gid_expr; ap_expr_info_t *gid_expr;
} itk_per_dir_conf; } itk_per_dir_conf;
typedef struct typedef struct
{ {
int max_clients_vhost; int max_clients_vhost;
} itk_server_conf; } itk_server_conf;
AP_DECLARE_DATA int ap_has_irreversibly_setuid = 0; AP_DECLARE_DATA int ap_has_irreversibly_setuid = 0;
#if !HAVE_LIBCAP /* Only in use if not enabling capabilities. */
AP_DECLARE_DATA uid_t saved_unixd_uid = -1; AP_DECLARE_DATA uid_t saved_unixd_uid = -1;
AP_DECLARE_DATA gid_t saved_unixd_gid = -1; AP_DECLARE_DATA gid_t saved_unixd_gid = -1;
#endif
static int itk_pre_drop_privileges(apr_pool_t *pool, server_rec *s) static int itk_pre_drop_privileges(apr_pool_t *pool, server_rec *s)
{ {
#if HAVE_LIBCAP #if HAVE_LIBCAP
/* mod_unixd will drop down to a normal user. This means that even if an if (ap_itk_enable_caps) {
* attacker manage to execute code before setuid(), he/she cannot write to /* mod_unixd will drop down to a normal user. This means that even if an
* files owned by uid 0, such as /etc/crontab. We'll need to keep our extra * attacker manage to execute code before setuid(), he/she cannot write
* privileges, though, since we need them for the actual query processing to
* later, so specify that we'll keep them across the setuid that is soon to * files owned by uid 0, such as /etc/crontab. We'll need to keep our ex
* come. tra
* * privileges, though, since we need them for the actual query processin
* Note that since we still have CAP_SETUID, an attacker can setuid(0) g
* and get around this. Thus, we disallow setuid(0) if the platform * later, so specify that we'll keep them across the setuid that is soon
* allows it. to
*/ * come.
restrict_setuid_range(ap_itk_min_uid, ap_itk_max_uid, ap_itk_min_gid, ap_itk *
_max_gid); * Note that since we still have CAP_SETUID, an attacker can setuid(0)
if (prctl(PR_SET_KEEPCAPS, 1)) { * and get around this. Thus, we disallow setuid(0) if the platform
ap_log_error(APLOG_MARK, APLOG_EMERG, errno, NULL, "prctl(PR_SET_KEEPCAP * allows it.
S, 1) failed"); */
exit(APEXIT_CHILDFATAL); restrict_setuid_range(ap_itk_min_uid, ap_itk_max_uid, ap_itk_min_gid, ap
_itk_max_gid);
if (prctl(PR_SET_KEEPCAPS, 1)) {
ap_log_error(APLOG_MARK, APLOG_EMERG, errno, NULL, "prctl(PR_SET_KEE
PCAPS, 1) failed");
exit(APEXIT_CHILDFATAL);
}
return OK;
} }
#else #endif
restrict_setuid_range(ap_itk_min_uid, ap_itk_max_uid, ap_itk_min_gid, ap_itk
_max_gid);
/* Fiddle with mod_unixd's structures so that it doesn't drop uid 0; /* Fiddle with mod_unixd's structures so that it doesn't drop uid 0;
* we need that, since we don't have capabilities. * we need that, since we don't have capabilities.
*/ */
saved_unixd_uid = ap_unixd_config.user_id; saved_unixd_uid = ap_unixd_config.user_id;
saved_unixd_gid = ap_unixd_config.group_id; saved_unixd_gid = ap_unixd_config.group_id;
ap_unixd_config.user_id = 0; ap_unixd_config.user_id = 0;
ap_unixd_config.group_id = 0; ap_unixd_config.group_id = 0;
#endif
return OK; return OK;
} }
static int itk_post_drop_privileges(apr_pool_t *pool, server_rec *s) static int itk_post_drop_privileges(apr_pool_t *pool, server_rec *s)
{ {
#if HAVE_LIBCAP #if HAVE_LIBCAP
cap_t caps; if (ap_itk_enable_caps) {
cap_value_t suidcaps[] = { cap_t caps;
CAP_SETUID, cap_value_t suidcaps[] = {
CAP_SETGID, CAP_SETUID,
CAP_DAC_READ_SEARCH, CAP_SETGID,
CAP_SYS_NICE, CAP_DAC_READ_SEARCH,
}; CAP_SYS_NICE,
};
/* We don't need to keep capabilities across setuid anymore, so stop that. *
/ /* We don't need to keep capabilities across setuid anymore, so stop tha
if (prctl(PR_SET_KEEPCAPS, 0)) { t. */
ap_log_error(APLOG_MARK, APLOG_EMERG, errno, NULL, "prctl(PR_SET_KEEPCAP if (prctl(PR_SET_KEEPCAPS, 0)) {
S, 0) failed"); ap_log_error(APLOG_MARK, APLOG_EMERG, errno, NULL, "prctl(PR_SET_KEE
exit(APEXIT_CHILDFATAL); PCAPS, 0) failed");
} exit(APEXIT_CHILDFATAL);
}
/* Now drop as many privileges as we can. We'll still
* access files with uid=0, and we can setuid() to anything, but /* Now drop as many privileges as we can. We'll still
* at least there's tons of other evilness (like loading kernel * access files with uid=0, and we can setuid() to anything, but
* modules) we can't do directly. (The setuid() capability will * at least there's tons of other evilness (like loading kernel
* go away automatically when we setuid() or exec() -- the former * modules) we can't do directly. (The setuid() capability will
* is likely to come first.) * go away automatically when we setuid() or exec() -- the former
*/ * is likely to come first.)
caps = cap_init(); */
cap_clear(caps); caps = cap_init();
cap_set_flag(caps, CAP_PERMITTED, sizeof(suidcaps)/sizeof(cap_value_t), suid cap_clear(caps);
caps, CAP_SET); cap_set_flag(caps, CAP_PERMITTED, sizeof(suidcaps)/sizeof(cap_value_t),
cap_set_flag(caps, CAP_EFFECTIVE, sizeof(suidcaps)/sizeof(cap_value_t), suid suidcaps, CAP_SET);
caps, CAP_SET); cap_set_flag(caps, CAP_EFFECTIVE, sizeof(suidcaps)/sizeof(cap_value_t),
cap_set_proc(caps); suidcaps, CAP_SET);
cap_free(caps); cap_set_proc(caps);
#else cap_free(caps);
return OK;
}
#endif
// Restore the configured unixd uid/gid. // Restore the configured unixd uid/gid.
ap_unixd_config.user_id = saved_unixd_uid; ap_unixd_config.user_id = saved_unixd_uid;
ap_unixd_config.group_id = saved_unixd_gid; ap_unixd_config.group_id = saved_unixd_gid;
#endif
return OK; return OK;
} }
static int have_forked = 0; static int have_forked = 0;
int itk_fork_process(conn_rec *c) int itk_fork_process(conn_rec *c)
{ {
if (have_forked) { if (have_forked) {
return DECLINED; return DECLINED;
} }
skipping to change at line 380 skipping to change at line 388
err = 1; err = 1;
} else if (setuid(wanted_uid)) { } else if (setuid(wanted_uid)) {
_DBG("setuid(%d): %s", wanted_uid, strerror(errno)); _DBG("setuid(%d): %s", wanted_uid, strerror(errno));
if (wanted_uid < ap_itk_min_uid || wanted_uid > ap_itk_max_uid) { if (wanted_uid < ap_itk_min_uid || wanted_uid > ap_itk_max_uid) {
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL,
"This is most likely due to the current LimitUIDRan ge setting."); "This is most likely due to the current LimitUIDRan ge setting.");
} }
err = 1; err = 1;
} else { } else {
#if HAVE_LIBCAP #if HAVE_LIBCAP
/* Drop our remaining privileges. Normally setuid() would do this if (ap_itk_enable_caps) {
* for us, but since we were previously not uid 0 (just a normal /* Drop our remaining privileges. Normally setuid() would do thi
* user with CAP_SETUID), we need to do it ourselves. s
*/ * for us, but since we were previously not uid 0 (just a normal
cap_t caps; * user with CAP_SETUID), we need to do it ourselves.
caps = cap_init(); */
cap_clear(caps); cap_t caps;
cap_set_proc(caps); caps = cap_init();
cap_free(caps); cap_clear(caps);
cap_set_proc(caps);
cap_free(caps);
}
#endif #endif
ap_has_irreversibly_setuid = 1; ap_has_irreversibly_setuid = 1;
} }
} }
if (err) { if (err) {
if (ap_has_irreversibly_setuid) { if (ap_has_irreversibly_setuid) {
/* Most likely a case of switching uid/gid within a persistent /* Most likely a case of switching uid/gid within a persistent
* connection; the RFCs allow us to just close the connection * connection; the RFCs allow us to just close the connection
* at anytime, so we excercise our right. :-) * at anytime, so we excercise our right. :-)
skipping to change at line 534 skipping to change at line 544
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) { if (err != NULL) {
return err; return err;
} }
ap_itk_min_gid = atoi(min_arg); ap_itk_min_gid = atoi(min_arg);
ap_itk_max_gid = atoi(max_arg); ap_itk_max_gid = atoi(max_arg);
return NULL; return NULL;
} }
#if HAVE_LIBCAP
static const char *enable_caps(cmd_parms *cmd, void *dummy, int arg)
{
const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
if (err != NULL) {
return err;
}
ap_itk_enable_caps = arg;
return NULL;
}
#endif
static const char *assign_user_id_expr (cmd_parms *cmd, void *ptr, const char *u ser_name_expr) static const char *assign_user_id_expr (cmd_parms *cmd, void *ptr, const char *u ser_name_expr)
{ {
itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr; itk_per_dir_conf *dconf = (itk_per_dir_conf *) ptr;
const char *err; const char *err;
err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS); err = ap_check_cmd_context(cmd, NOT_IN_HTACCESS);
if (err) { if (err) {
return err; return err;
} }
skipping to change at line 624 skipping to change at line 646
"Choose user ID given an expression. Will override AssignUserID ."), "Choose user ID given an expression. Will override AssignUserID ."),
AP_INIT_RAW_ARGS("AssignGroupIDExpr", assign_group_id_expr, NULL, RSRC_CONF|ACCE SS_CONF, AP_INIT_RAW_ARGS("AssignGroupIDExpr", assign_group_id_expr, NULL, RSRC_CONF|ACCE SS_CONF,
"Choose group ID given an expression. Will override AssignUserI D."), "Choose group ID given an expression. Will override AssignUserI D."),
AP_INIT_TAKE2("LimitUIDRange", limit_uid_range, NULL, RSRC_CONF, AP_INIT_TAKE2("LimitUIDRange", limit_uid_range, NULL, RSRC_CONF,
"If seccomp v2 is available (Linux 3.5.0+), limit the process's po ssible " "If seccomp v2 is available (Linux 3.5.0+), limit the process's po ssible "
"uid to the given range (inclusive endpoints)"), "uid to the given range (inclusive endpoints)"),
AP_INIT_TAKE2("LimitGIDRange", limit_gid_range, NULL, RSRC_CONF, AP_INIT_TAKE2("LimitGIDRange", limit_gid_range, NULL, RSRC_CONF,
"If seccomp v2 is available (Linux 3.5.0+), limit the process's po ssible " "If seccomp v2 is available (Linux 3.5.0+), limit the process's po ssible "
"primary gid to the given range (inclusive endpoints). " "primary gid to the given range (inclusive endpoints). "
"Note that this does not restrict supplemental gids!"), "Note that this does not restrict supplemental gids!"),
#if HAVE_LIBCAP
AP_INIT_FLAG("EnableCapabilities", enable_caps, NULL, RSRC_CONF,
"Drop most root capabilities in the parent process, and instead run
as "
"the user given by the User/Group directives with some extra capabi
lities "
"(in particular setuid). Somewhat more secure, but can cause proble
ms "
"when serving from NFS."),
#endif
AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF, AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF,
"Maximum number of children alive at the same time for this virtua l host."), "Maximum number of children alive at the same time for this virtua l host."),
AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF, AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF,
"Set nice value for the given vhost, from -20 (highest priority) t o 19 (lowest priority)."), "Set nice value for the given vhost, from -20 (highest priority) t o 19 (lowest priority)."),
{ NULL } { NULL }
}; };
/* == allocate a private per-dir config structure == */ /* == allocate a private per-dir config structure == */
static void *itk_create_dir_config(apr_pool_t *p, char *dummy) static void *itk_create_dir_config(apr_pool_t *p, char *dummy)
{ {
 End of changes. 17 change blocks. 
69 lines changed or deleted 107 lines changed or added

Home  |  About  |  All  |  Newest  |  Fossies Dox  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTPS