You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Randy Terbush <ra...@zyzzyva.com> on 1996/07/26 21:26:17 UTC

setrlimit patch (cut 2)

I think that the following patch should address Ben's concerns.
The set_limit_??? functions now do considerably more.

1. log an error if the RLimit functionality is not supported.
 (Alexei's suggestion)

2. check to make sure there are parameters passed with the directive,
   and only require one parameter. This will probably be the norm
   unless the server is running as root. As Ben points out, the
   max can only be changed IF we are root. The call to setrlimit()
   would likely fail if we are not root and attempt to set it.

3. it's possible to use a parameter of "max" to set the softlimit
   to the system hardlimit.


Index: src/http_core.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.c,v
retrieving revision 1.19
diff -c -r1.19 http_core.c
*** http_core.c	1996/07/25 19:32:28	1.19
--- http_core.c	1996/07/26 19:18:37
***************
*** 94,99 ****
--- 94,120 ----
      conf->hostname_lookups = 2;/* binary, but will use 2 as an "unset = on" */
      conf->do_rfc1413 = DEFAULT_RFC1413 | 2;  /* set bit 1 to indicate default */
  
+ #ifdef RLIMIT_CPU
+     conf->limit_cpu = (struct rlimit *) pcalloc (a, sizeof (struct rlimit));
+     if ((getrlimit(RLIMIT_CPU, conf->limit_cpu)) != 0)
+ 	conf->limit_cpu = NULL;
+ #endif
+ #ifdef RLIMIT_DATA
+     conf->limit_mem = (struct rlimit *) pcalloc (a, sizeof (struct rlimit));
+     if ((getrlimit(RLIMIT_DATA, conf->limit_mem)) != 0)
+ 	conf->limit_mem = NULL;
+ #endif
+ #ifdef RLIMIT_VMEM
+     conf->limit_mem = (struct rlimit *) pcalloc (a, sizeof (struct rlimit));
+     if ((getrlimit(RLIMIT_VMEM, conf->limit_mem)) != 0)
+ 	conf->limit_mem = NULL;
+ #endif
+ #ifdef RLIMIT_NPROC
+     conf->limit_nproc = (struct rlimit *) pcalloc (a, sizeof (struct rlimit));
+     if ((getrlimit(RLIMIT_NPROC, conf->limit_nproc)) != 0)
+ 	conf->limit_nproc = NULL;
+ #endif
+ 
      conf->sec = make_array (a, 2, sizeof(void *));
  
      return (void *)conf;
***************
*** 128,133 ****
--- 149,164 ----
      if ((new->do_rfc1413 & 2) == 0) conf->do_rfc1413 = new->do_rfc1413;
      if ((new->content_md5 & 2) == 0) conf->content_md5 = new->content_md5;
  
+ #ifdef RLIMIT_CPU
+     if (new->limit_cpu) conf->limit_cpu = new->limit_cpu;
+ #endif
+ #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM)
+     if (new->limit_mem) conf->limit_mem = new->limit_mem;
+ #endif
+ #ifdef RLIMIT_NPROC    
+     if (new->limit_nproc) conf->limit_nproc = new->limit_nproc;
+ #endif
+ 
      conf->sec = append_arrays (a, base->sec, new->sec);
  
      return (void*)conf;
***************
*** 808,813 ****
--- 839,958 ----
      return NULL;
  }
  
+ char *set_limit_cpu (cmd_parms *cmd, core_dir_config *conf, char *arg)
+ {
+ #ifdef RLIMIT_CPU
+     char *str;
+     quad_t cur = 0;
+     quad_t max = 0;
+ 
+     if (str = getword_conf(cmd->pool, &arg))
+ 	if (!strcasecmp(str, "max"))
+ 	    cur = conf->limit_cpu->rlim_max;
+ 	else
+ 	    cur = atol(str);
+     else {
+ 	log_error("Invalid parameters for RLimitCPU", cmd->server);
+ 	return NULL;
+     }
+     
+     if (str = getword_conf(cmd->pool, &arg))
+ 	max = atol(str);
+ 
+     /* if we aren't running as root, cannot increase max */
+     if (geteuid()) {
+ 	conf->limit_cpu->rlim_cur = cur;
+ 	if (max)
+ 	    log_error("Must be uid 0 to raise maximum RLIMIT_CPU", cmd->server);
+     }
+     else {
+ 	if (cur)
+ 	    conf->limit_cpu->rlim_cur = cur;
+ 	if (max)
+ 	    conf->limit_cpu->rlim_max = max;
+     }
+ #else
+     log_error("RLimitCPU not supported on this platform", cmd->server);
+ #endif
+     return NULL;
+ }
+ 
+ char *set_limit_mem (cmd_parms *cmd, core_dir_config *conf, char *arg)
+ {
+ #if defined (RLIMIT_DATA) || defined (RLIMIT_VMEM)
+     char *str;
+     quad_t cur = 0;
+     quad_t max = 0;
+ 
+     if (str = getword_conf(cmd->pool, &arg))
+ 	if (!strcasecmp(str, "max"))
+ 	    cur = conf->limit_mem->rlim_max;
+ 	else
+ 	    cur = atol(str);
+     else {
+ 	log_error("Invalid parameters for RLimitMEM", cmd->server);
+ 	return NULL;
+     }
+     
+     if (str = getword_conf(cmd->pool, &arg))
+ 	max = atol(str);
+ 
+     /* if we aren't running as root, cannot increase max */
+     if (geteuid()) {
+ 	conf->limit_mem->rlim_cur = cur;
+ 	if (max)
+ 	    log_error("Must be uid 0 to change maximum RLIMIT_MEM", cmd->server);
+     }
+     else {
+ 	if (cur)
+ 	    conf->limit_mem->rlim_cur = cur;
+ 	if (max)
+ 	    conf->limit_mem->rlim_max = max;
+     }
+ #else
+     log_error("RLimitMEM not supported on this platform", cmd->server);
+ #endif
+     return NULL;
+ }
+ 
+ char *set_limit_nproc (cmd_parms *cmd, core_dir_config *conf, char *arg)
+ {
+ #ifdef RLIMIT_NPROC
+     char *str;
+     quad_t cur = 0;
+     quad_t max = 0;
+ 
+     if (str = getword_conf(cmd->pool, &arg))
+ 	if (!strcasecmp(str, "max"))
+ 	    cur = conf->limit_nproc->rlim_max;
+ 	else
+ 	    cur = atol(str);
+     else {
+ 	log_error("Invalid parameters for RLimitNPROC", cmd->server);
+ 	return NULL;
+     }
+     
+     if (str = getword_conf(cmd->pool, &arg))
+ 	max = atol(str);
+ 
+     /* if we aren't running as root, cannot increase max */
+     if (geteuid()) {
+ 	conf->limit_nproc->rlim_cur = cur;
+ 	if (max)
+ 	    log_error("Must be uid 0 to raise maximum RLIMIT_NPROC", cmd->server);
+     }
+     else {
+ 	if (cur)
+ 	    conf->limit_nproc->rlim_cur = cur;
+ 	if (max)
+ 	    conf->limit_nproc->rlim_max = max;
+     }
+ #else
+     log_error("RLimitNPROC not supported on this platform", cmd->server);
+ #endif
+     return NULL;
+ }
+ 
  char *set_bind_address (cmd_parms *cmd, void *dummy, char *arg) {
      bind_address.s_addr = get_virthost_addr (arg, NULL);
      return NULL;
***************
*** 919,924 ****
--- 1064,1075 ----
  { "ServersSafetyLimit", set_server_limit, NULL, RSRC_CONF, TAKE1, NULL },
  { "MaxClients", set_server_limit, NULL, RSRC_CONF, TAKE1, NULL },
  { "MaxRequestsPerChild", set_max_requests, NULL, RSRC_CONF, TAKE1, NULL },
+ { "RLimitCPU", set_limit_cpu, (void*)XtOffsetOf(core_dir_config, limit_cpu),
+       OR_ALL, RAW_ARGS, "soft/hard limits for max CPU usage in seconds" },
+ { "RLimitMEM", set_limit_mem, (void*)XtOffsetOf(core_dir_config, limit_mem),
+       OR_ALL, RAW_ARGS, "soft/hard limits for max memory usage per process" },
+ { "RLimitNPROC", set_limit_nproc, (void*)XtOffsetOf(core_dir_config, limit_nproc),
+       OR_ALL, RAW_ARGS, "soft/hard limits for max number of processes per uid" },
  { "BindAddress", set_bind_address, NULL, RSRC_CONF, TAKE1,
    "'*', a numeric IP address, or the name of a host with a unique IP address"},
  { "Listen", set_listener, NULL, RSRC_CONF, TAKE1,
Index: src/http_core.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_core.h,v
retrieving revision 1.7
diff -c -r1.7 http_core.h
*** http_core.h	1996/07/25 19:32:28	1.7
--- http_core.h	1996/07/26 19:18:38
***************
*** 152,157 ****
--- 152,168 ----
      int hostname_lookups;
      int do_rfc1413;   /* See if client is advertising a username? */
  
+     /* System Resource Control */
+ #ifdef RLIMIT_CPU
+     struct rlimit *limit_cpu;
+ #endif
+ #if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM)
+     struct rlimit *limit_mem;
+ #endif
+ #ifdef RLIMIT_NPROC    
+     struct rlimit *limit_nproc;
+ #endif
+ 
      /* Access control */
      array_header *sec;
      regex_t *r;
Index: src/util_script.c
===================================================================
RCS file: /export/home/cvs/apache/src/util_script.c,v
retrieving revision 1.13
diff -c -r1.13 util_script.c
*** util_script.c	1996/07/21 20:03:45	1.13
--- util_script.c	1996/07/26 19:19:13
***************
*** 53,59 ****
--- 53,62 ----
  
  
  
+ #define CORE_PRIVATE
  #include "httpd.h"
+ #include "http_config.h"
+ #include "http_conf_globals.h"
  #include "http_main.h"
  #include "http_log.h"
  #include "http_protocol.h"
***************
*** 61,66 ****
--- 64,70 ----
  #include "http_request.h"       /* for sub_req_lookup_uri() */
  #include "util_script.h"
  
+ 
  /*
   * Various utility functions which are common to a whole lot of
   * script-type extensions mechanisms, and might as well be gathered
***************
*** 365,404 ****
  
  void call_exec (request_rec *r, char *argv0, char **env, int shellcmd) 
  {
!     
! #ifdef RLIMIT_CPU
!     struct rlimit cpulim = { 9, 10 };
! #endif
  
- #ifdef RLIMIT_DATA
-     struct rlimit datalim = { 2000000, 2500000 };
- #endif
- 
- #ifdef RLIMIT_NPROC
-     struct rlimit proclim = { 20, 40 };
- #endif
      
! #ifdef RLIMIT_VMEM
!     struct rlimit vmlim = { 2000000, 2500000 };
! #endif
      
! #ifdef RLIMIT_CPU
!     setrlimit (RLIMIT_CPU, &cpulim);
! #endif
  
! #ifdef RLIMIT_DATA
!     setrlimit (RLIMIT_DATA, &datalim);
  #endif
- 
  #ifdef RLIMIT_NPROC
!     setrlimit (RLIMIT_NPROC, &proclim);
  #endif
-     
  #ifdef RLIMIT_VMEM
!     setrlimit (RLIMIT_VMEM, &vmlim);
  #endif
      
- 
  #ifdef __EMX__    
      if ((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) {
  	int emxloop;
--- 369,402 ----
  
  void call_exec (request_rec *r, char *argv0, char **env, int shellcmd) 
  {
!     char *execuser;
  
      
!     core_dir_config *conf = (core_dir_config *)pcalloc(r->pool, sizeof(core_dir_config));
      
!     conf = (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
  
! #ifdef RLIMIT_CPU
!     if (conf->limit_cpu != NULL)
! 	if ((setrlimit (RLIMIT_CPU, conf->limit_cpu)) != 0)
! 	    log_unixerr("setrlimit", NULL, "failed to set CPU usage limit", r->server);
  #endif
  #ifdef RLIMIT_NPROC
!     if (conf->limit_nproc != NULL)
! 	if ((setrlimit (RLIMIT_NPROC, conf->limit_nproc)) != 0)
! 	    log_unixerr("setrlimit", NULL, "failed to set process limit", r->server);
! #endif
! #ifdef RLIMIT_DATA
!     if (conf->limit_mem != NULL)
! 	if ((setrlimit (RLIMIT_DATA, conf->limit_mem)) != 0)
! 	    log_unixerr("setrlimit", NULL, "failed to set memory usage limit", r->server);
  #endif
  #ifdef RLIMIT_VMEM
!     if (conf->limit_mem != NULL)
! 	if ((setrlimit (RLIMIT_VMEM, conf->limit_mem)) != 0)
! 	    log_unixerr("setrlimit", NULL, "failed to set memory usage limit", r->server);
  #endif
      
  #ifdef __EMX__    
      if ((!r->args) || (!r->args[0]) || (ind(r->args,'=') >= 0)) {
  	int emxloop;
***************
*** 438,444 ****
  	    execv(r->filename, create_argv(r->pool, argv0, r->args));
      }
  #else
! 
      if (shellcmd) 
  	execle(SHELL_PATH, SHELL_PATH, "-c", argv0, NULL, env);
  
--- 436,442 ----
  	    execv(r->filename, create_argv(r->pool, argv0, r->args));
      }
  #else
!     
      if (shellcmd) 
  	execle(SHELL_PATH, SHELL_PATH, "-c", argv0, NULL, env);