diff --git a/Makefile.in b/Makefile.in index c2346c3..591a607 100644 --- a/Makefile.in +++ b/Makefile.in @@ -4,7 +4,16 @@ CLEAN_SUBDIRS = test PROGRAM_NAME = $(progname) PROGRAM_SOURCES = modules.c -PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) + +ifneq (,$(findstring itk,$(CURDIR))) +CONLDD = -ldl -lselinux +else +CONLDD = -lselinux +endif +PROGRAM_LDADD = buildmark.o $(HTTPD_LDFLAGS) $(PROGRAM_DEPENDENCIES) $(EXTRA_LIBS) $(AP_LIBS) $(LIBS) $(CONLDD) + + + PROGRAM_PRELINK = $(COMPILE) -c $(top_srcdir)/server/buildmark.c PROGRAM_DEPENDENCIES = \ server/libmain.la \ diff --git a/apache2.2-mpm-itk-seculrelve10.patch b/apache2.2-mpm-itk-seculrelve10.patch new file mode 100644 index 0000000..01d2e06 diff --git a/server/mpm/experimental/itk/itk.c b/server/mpm/experimental/itk/itk.c index 642d600..0bc0738 100644 --- a/server/mpm/experimental/itk/itk.c +++ b/server/mpm/experimental/itk/itk.c @@ -42,6 +42,11 @@ #include #endif +#include "apr_general.h" +#include "apr_lib.h" +#include "apr_hash.h" +#include "apr_tables.h" + #define CORE_PRIVATE #include "ap_config.h" @@ -61,6 +66,11 @@ #include "ap_mmn.h" #include "apr_poll.h" +#include "mod_core.h" +#include "util_filter.h" +#include "http_protocol.h" +#include "util_script.h" + #ifdef HAVE_BSTRING_H #include /* for IRIX, FD_SET calls bzero() */ #endif @@ -77,6 +87,10 @@ #include #include +#include + +#include + /* Limit on the total --- clients will be locked out if more servers than * this are needed. It is intended solely to keep the server from crashing @@ -104,6 +118,13 @@ #define HARD_THREAD_LIMIT 1 #endif +// HTTP error code to return to client if resources limit is reached AND LVEErrorCode directive is not present in module configuration +#define DEFAULT_HTTP_ERROR_CODE 508 + +// HTTP error code should be in these limits +#define MAX_HTTP_SERVER_ERROR_CODE 510 +#define MIN_HTTP_SERVER_ERROR_CODE 500 + /* config globals */ int ap_threads_per_child=0; /* Worker threads per child */ @@ -155,6 +176,8 @@ char tpf_server_name[INETD_SERVNAME_LENGTH+1]; #endif /* TPF */ static volatile int die_now = 0; +static int use_lve = 1; +static int use_cagefs = 1; #define UNSET_NICE_VALUE 100 @@ -164,6 +187,11 @@ typedef struct gid_t gid; char *username; int nice_value; + unsigned int http_error_code; + int err_doc_found; + uint32_t retryAfter; + uint32_t lve_id; + const char *lve_user; } itk_per_dir_conf; typedef struct @@ -171,6 +199,35 @@ typedef struct int max_clients_vhost; } itk_server_conf; +static void *lve_lib_handle = NULL; +typedef void liblve; + +enum liblve_enter_flags { + LVE_NO_UBC = 1 << 0, + LVE_NO_NAMESPACE = 1 << 1, + LVE_NO_MAXENTER = 1 << 2, + LVE_SILENCE = 1 << 3, +}; + +typedef void *(*liblve_alloc)(size_t size); +typedef void (*liblve_free)(void *ptr); + +APR_DECLARE_OPTIONAL_FN (struct liblve *, init_lve_tp, (liblve_alloc alloc, liblve_free free)); +APR_OPTIONAL_FN_TYPE(init_lve_tp) *init_lve_fn = NULL; +APR_DECLARE_OPTIONAL_FN (int, destroy_lve_tp, (struct liblve *lve)); +APR_OPTIONAL_FN_TYPE(destroy_lve_tp) *destroy_lve_fn = NULL; +APR_DECLARE_OPTIONAL_FN (int, lve_enter_flags_tp, (struct liblve *lve, uint32_t lve_id, uint32_t *cookie, enum liblve_enter_flags flags)); +APR_OPTIONAL_FN_TYPE(lve_enter_flags_tp) *lve_enter_flags_fn = NULL; +APR_DECLARE_OPTIONAL_FN (int, jail_tp, (struct passwd *pw, char * error_str)); +APR_OPTIONAL_FN_TYPE(jail_tp) *jail_fn = NULL; + +static int found_lve = 0; + +static inline struct liblve *init_lve_generic_fn() +{ + return init_lve_fn(malloc, free); +} + module AP_MODULE_DECLARE_DATA mpm_itk_module; #ifdef GPROF @@ -1432,12 +1489,32 @@ static int itk_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) return OK; } +static int lve_itk_enter(uid_t uid){ + uint32_t cookie; + struct liblve *lve; + if(!found_lve) return 0; + lve = init_lve_generic_fn(); + if (lve == NULL) { + return 0; + } + if (lve_enter_flags_fn(lve, uid, &cookie, LVE_SILENCE )) { + destroy_lve_fn(lve); + return 0; + } + return 1; +} + +__thread int lve_error_flag = 0; + static int itk_post_perdir_config(request_rec *r) { uid_t wanted_uid; gid_t wanted_gid; const char *wanted_username; int err = 0; + struct passwd *pw = NULL; + char error_str[1024]=""; + itk_server_conf *sconf = (itk_server_conf *) ap_get_module_config(r->server->module_config, &mpm_itk_module); @@ -1482,16 +1559,51 @@ static int itk_post_perdir_config(request_rec *r) } if (!err && wanted_uid != -1 && wanted_gid != -1 && (getuid() != wanted_uid || getgid() != wanted_gid)) { - if (setgid(wanted_gid)) { - _DBG("setgid(%d): %s", wanted_gid, strerror(errno)); - err = 1; - } else if (initgroups(wanted_username, wanted_gid)) { - _DBG("initgroups(%s, %d): %s", wanted_username, wanted_gid, strerror(errno)); - err = 1; - } else if (setuid(wanted_uid)) { - _DBG("setuid(%d): %s", wanted_uid, strerror(errno)); - err = 1; - } + if(found_lve && use_lve){ + + uid_t lve_id = wanted_uid; + if(dconf->lve_id>0){ + lve_id = dconf->lve_id; + } else if (dconf->lve_user) { + lve_id = (int) ap_uname2id (dconf->lve_user); + if (lve_id < 1) lve_id = wanted_uid; + } + + pw = getpwuid(wanted_uid); + if(pw){ + if (!lve_itk_enter(lve_id)){ + _DBG("lve_enter(%d), %s", lve_id, strerror(errno)); + lve_error_flag = 1; + } + } + if (!pw) { + _DBG("getpwuid(%d): %s", wanted_uid, strerror(errno)); + err = 1; + } else if (use_cagefs && jail_fn(pw, error_str) < 0) { + _DBG("jail(%d): %s", wanted_uid, error_str); + err = 1; + } else if (setgid(wanted_gid)) { + _DBG("setgid(%d): %s", wanted_gid, strerror(errno)); + err = 1; + } else if (initgroups(wanted_username, wanted_gid)) { + _DBG("initgroups(%s, %d): %s", wanted_username, wanted_gid, strerror(errno)); + err = 1; + } else if (setuid(wanted_uid)) { + _DBG("setuid(%d): %s", wanted_uid, strerror(errno)); + err = 1; + } + } else { + if (setgid(wanted_gid)) { + _DBG("setgid(%d): %s", wanted_gid, strerror(errno)); + err = 1; + } else if (initgroups(wanted_username, wanted_gid)) { + _DBG("initgroups(%s, %d): %s", wanted_username, wanted_gid, strerror(errno)); + err = 1; + } else if (setuid(wanted_uid)) { + _DBG("setuid(%d): %s", wanted_uid, strerror(errno)); + err = 1; + } + } } /* @@ -1508,6 +1620,81 @@ static int itk_post_perdir_config(request_rec *r) return OK; } +static int +process_lve_error_itk (request_rec * r, itk_per_dir_conf * cfg) +{ + //Set out header LVE_RETRY_AFTER + if (cfg->retryAfter) + { + apr_table_setn (r->err_headers_out, "Retry-After", + apr_ltoa (r->pool, cfg->retryAfter * 60)); + } + // LVEErrorCode is NOT 508 or "ErrorDocument 508" directive is present in Apache configuration ? + if ((cfg->http_error_code != 508) || (cfg->err_doc_found)) + return cfg->http_error_code; + + int i; + r->status = 508; + r->content_type = "text/html"; + apr_bucket_brigade *bb = apr_brigade_create (r->pool, + r->connection->bucket_alloc); + ap_basic_http_header (r, bb); + + // Send header information only (HEAD request) ? + if (r->header_only) + return DONE; + + ap_rvputs (r, "\n" + DOCTYPE_HTML_2_0 + "\n508 Resource Limit Is Reached(ITK)\n" + "\n" "

Resource Limit Is Reached

\n", NULL); + for (i = 0; i < 1000; i++) + ap_rvputs (r, " \n", NULL); + ap_rputs + ("The website is temporarily unable to service your request as it exceeded resource limit.\n" + "Please try again later.\n", r); + ap_rputs (ap_psignature ("
\n", r), r); + ap_rputs ("\n", r); + ap_finalize_request_protocol (r); + ap_rflush (r); + return DONE; +} + +static int +enter_jail_handler (request_rec * r){ + itk_per_dir_conf *dconf = + (itk_per_dir_conf *) ap_get_module_config(r->per_dir_config, &mpm_itk_module); + if(lve_error_flag){ + lve_error_flag = 0; + return process_lve_error_itk (r, dconf); + } + return DECLINED; +} + +static int +lve_init_post_config (apr_pool_t * pconf, apr_pool_t * plog, + apr_pool_t * ptemp, server_rec * s) +{ + + if (found_lve) + { + ap_log_error (APLOG_MARK, + APLOG_NOTICE, + 0, + s, + "LVE functions found"); + } else { + ap_log_error (APLOG_MARK, + APLOG_NOTICE, + 0, + s, + "LVE functions not found"); + } + return OK; +} + + + static void itk_hooks(apr_pool_t *p) { /* The itk open_logs phase must run before the core's, or stderr @@ -1528,8 +1715,35 @@ static void itk_hooks(apr_pool_t *p) /* set the uid as fast as possible, but not before merging per-dit config */ ap_hook_header_parser(itk_post_perdir_config, NULL, NULL, APR_HOOK_REALLY_FIRST); + + ap_hook_handler (enter_jail_handler, NULL, NULL, APR_HOOK_REALLY_FIRST); + + ap_hook_post_config (lve_init_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST); + + lve_lib_handle = dlopen("liblve.so.0", RTLD_LAZY); + if (lve_lib_handle) { + apr_pool_cleanup_register (p, lve_lib_handle, (void *) dlclose, + apr_pool_cleanup_null); + + init_lve_fn = dlsym(lve_lib_handle, "init_lve"); + destroy_lve_fn = dlsym(lve_lib_handle, "destroy_lve"); + lve_enter_flags_fn = dlsym(lve_lib_handle, "lve_enter_flags"); + jail_fn = dlsym(lve_lib_handle, "jail"); + if(!init_lve_fn || !destroy_lve_fn || !lve_enter_flags_fn || !jail_fn){ + init_lve_fn = NULL; + destroy_lve_fn = NULL; + lve_enter_flags_fn = NULL; + jail_fn = NULL; + found_lve = 0; + } else { + found_lve = 1; + } + + } + } + static const char *set_daemons_to_start(cmd_parms *cmd, void *dummy, const char *arg) { const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); @@ -1678,6 +1892,105 @@ static const char *set_nice_value (cmd_parms *cmd, void *ptr, const char *arg) return NULL; } +static unsigned int +get_valid_http_error_code_itk (unsigned int code) +{ + if ((code < MIN_HTTP_SERVER_ERROR_CODE) + || (code > MAX_HTTP_SERVER_ERROR_CODE)) + return DEFAULT_HTTP_ERROR_CODE; + else + return code; +} + +static const char * +set_lve_error_code_itk (cmd_parms * cmd, void *mcfg, const char *lve_error_code) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (lve_error_code) + { + cfg->http_error_code = get_valid_http_error_code_itk ((unsigned int)apr_atoi64 (lve_error_code)); + } + return NULL; +} + +static const char * +error_doc_func_itk (cmd_parms * cmd, void *mcfg, const char *par1, const char *par2) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (par1) + if (strstr (par1, "508")) + cfg->err_doc_found = 1; + + return NULL; +} + +static const char * +set_lve_retryafter_itk (cmd_parms * cmd, void *mcfg, const char *minutes) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (minutes) + { + cfg->retryAfter = (uint32_t) apr_atoi64 (minutes); + } + return NULL; +} + +static const char * +set_lve_itkid (cmd_parms * cmd, void *mcfg, const char *lve_id) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (lve_id) + { + cfg->lve_id = (uint32_t) apr_atoi64 (lve_id); + } + return NULL; +} + +static const char * +set_lve_itkuser (cmd_parms * cmd, void *mcfg, const char *lve_user) +{ + itk_per_dir_conf *cfg = (itk_per_dir_conf *) mcfg; + if (lve_user) + { + cfg->lve_user = lve_user; + } + return NULL; +} + +static const char * +set_lve_disable_itk (cmd_parms * cmd, void *mcfg, const char *arg) +{ + const char *err = ap_check_cmd_context (cmd, + GLOBAL_ONLY); + if (err != NULL) + { + return err; + } + if (!apr_strnatcasecmp (arg, "Off")) + { + use_lve = 0; + } + + return NULL; +} + +static const char * +set_lve_cagefs_itk (cmd_parms * cmd, void *mcfg, const char *arg) +{ + const char *err = ap_check_cmd_context (cmd, + GLOBAL_ONLY); + if (err != NULL) + { + return err; + } + if (!apr_strnatcasecmp (arg, "Off")) + { + use_cagefs = 0; + } + + return NULL; +} + static const command_rec itk_cmds[] = { UNIX_DAEMON_COMMANDS, LISTEN_COMMANDS, @@ -1698,6 +2011,20 @@ AP_INIT_TAKE1("MaxClientsVHost", set_max_clients_vhost, NULL, RSRC_CONF, AP_INIT_TAKE1("NiceValue", set_nice_value, NULL, RSRC_CONF|ACCESS_CONF, "Set nice value for the given vhost, from -20 (highest priority) to 19 (lowest priority)."), AP_GRACEFUL_SHUTDOWN_TIMEOUT_COMMAND, +AP_INIT_TAKE1 ("LVEErrorCodeITK", set_lve_error_code_itk, NULL, RSRC_CONF, + "Integer HTTP error code to return to client if resources limit is reached"), +AP_INIT_TAKE2 ("ErrorDocument", error_doc_func_itk, NULL, OR_FILEINFO, + "ErrorDocument Apache configuration directive"), +AP_INIT_TAKE1 ("LVERetryAfterITK", set_lve_retryafter_itk, NULL, RSRC_CONF, + "Set minutes of LVE_RETRY_AFTER header, which comes with 508 error. O - disabled"), +AP_INIT_TAKE1 ("LVEId", set_lve_itkid, NULL, ACCESS_CONF | RSRC_CONF, + "LVE Id"), +AP_INIT_TAKE1 ("LVEUser", set_lve_itkuser, NULL, ACCESS_CONF | RSRC_CONF, + "LVE User"), +AP_INIT_TAKE1 ("LVEDisableITK", set_lve_disable_itk, NULL, RSRC_CONF, + "Disable LVE"), +AP_INIT_TAKE1 ("LVECageFSDisableITK", set_lve_cagefs_itk, NULL, RSRC_CONF, + "Disable Cagefs"), { NULL } }; @@ -1708,6 +2035,11 @@ static void *itk_create_dir_config(apr_pool_t *p, char *dummy) apr_pcalloc(p, sizeof(itk_per_dir_conf)); c->uid = c->gid = -1; c->nice_value = UNSET_NICE_VALUE; + c->http_error_code = DEFAULT_HTTP_ERROR_CODE; + c->err_doc_found = 0; + c->retryAfter = 240; + c->lve_id = 0; + c->lve_user = NULL; return c; } @@ -1733,6 +2065,14 @@ static void *itk_merge_dir_config(apr_pool_t *p, void *parent_ptr, void *child_p } else { c->nice_value = parent->nice_value; } + c->http_error_code = + (child->http_error_code != DEFAULT_HTTP_ERROR_CODE) ? child->http_error_code : parent->http_error_code; + c->retryAfter = (child->retryAfter) ? child->retryAfter : parent->retryAfter; + c->err_doc_found = + (child->err_doc_found) ? child->err_doc_found : parent->err_doc_found; + c->lve_id = (child->lve_id) ? child->lve_id : parent->lve_id; + c->lve_user = (child->lve_user) ? child->lve_user : parent->lve_user; + return c; }