Commit 084e7a07b70 for php
commit 084e7a07b70e4597853ab9f61a8632bdd152ea49
Author: George Wang <gwang@litespeedtech.com>
Date: Sat Oct 31 17:55:58 2026 -0400
Update LiteSpeed API to v8.4
diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c
index 5d1e37a2b64..c2fa73444f2 100644
--- a/sapi/litespeed/lsapi_main.c
+++ b/sapi/litespeed/lsapi_main.c
@@ -28,6 +28,8 @@
#include "lsapilib.h"
#include "lsapi_main_arginfo.h"
+#include <errno.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -75,6 +77,8 @@ static int ignore_php_ini = 0;
static char * argv0 = NULL;
static int engine = 1;
static int parse_user_ini = 0;
+static size_t argv0_suffix_capacity = 0;
+static int max_cmd_script_path_len = 45;
#ifdef ZTS
zend_compiler_globals *compiler_globals;
@@ -133,27 +137,43 @@ static void sapi_lsapi_ini_defaults(HashTable *configuration_hash)
/* {{{ sapi_lsapi_ub_write */
static size_t sapi_lsapi_ub_write(const char *str, size_t str_length)
{
- int ret;
- int remain;
+ ssize_t ret;
+ size_t written = 0;
if ( lsapi_mode ) {
- ret = LSAPI_Write( str, str_length );
- if ( ret < str_length ) {
- php_handle_aborted_connection();
- return str_length - ret;
+ while (written < str_length) {
+ size_t chunk = str_length - written;
+ if (chunk > (size_t)INT_MAX) {
+ chunk = (size_t)INT_MAX;
+ }
+ ret = LSAPI_Write(str + written, (ssize_t)chunk);
+ if (ret <= 0) {
+ php_handle_aborted_connection();
+ break;
+ }
+ written += (size_t)ret;
+ if ((size_t)ret != chunk) {
+ php_handle_aborted_connection();
+ break;
+ }
}
} else {
- remain = str_length;
- while( remain > 0 ) {
- ret = write( 1, str, remain );
- if ( ret <= 0 ) {
+ while (written < str_length) {
+ size_t chunk = str_length - written;
+ if (chunk > (size_t)INT_MAX) {
+ chunk = (size_t)INT_MAX;
+ }
+ ret = write(1, str + written, chunk);
+ if ( ret > 0 ) {
+ written += ret;
+ } else if ( ret == -1 && errno == EINTR ) {
+ continue;
+ } else {
php_handle_aborted_connection();
- return str_length - remain;
+ break;
}
- str += ret;
- remain -= ret;
}
}
- return str_length;
+ return written;
}
/* }}} */
@@ -361,6 +381,28 @@ static const http_error http_error_codes[] = {
};
+static void lsapi_append_response_header(const char *header, size_t len)
+{
+ const char *colon;
+ size_t name_len;
+ char msg[160];
+
+ if (!header)
+ return;
+ if (len <= INT_MAX && LSAPI_AppendRespHeader((char *)header, (int)len) == 0)
+ return;
+
+ colon = memchr(header, ':', len);
+ name_len = colon ? (size_t)(colon - header) : len;
+ if (name_len > 64)
+ name_len = 64;
+ snprintf(msg, sizeof(msg),
+ "LiteSpeed SAPI: dropped response header '%.*s' (%zu bytes)\n",
+ (int)name_len, header, len);
+ LSAPI_Write_Stderr(msg, strlen(msg));
+}
+
+
static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
{
char buf[SAPI_LSAPI_MAX_HEADER_LENGTH];
@@ -370,8 +412,8 @@ static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
int response_status = SG(sapi_headers).http_response_code;
if (SG(request_info).no_headers == 1) {
- LSAPI_FinalizeRespHeaders();
- return SAPI_HEADER_SENT_SUCCESSFULLY;
+ return LSAPI_FinalizeRespHeaders() == -1
+ ? SAPI_HEADER_SEND_FAILED : SAPI_HEADER_SENT_SUCCESSFULLY;
}
if (SG(sapi_headers).http_response_code != 200)
@@ -417,7 +459,8 @@ static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
}
if (!has_status) {
- LSAPI_AppendRespHeader( buf, len );
+ if (len > 0)
+ lsapi_append_response_header(buf, (size_t)len);
ignore_status = 1;
}
}
@@ -431,7 +474,7 @@ static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
) {
if (!ignore_status) {
ignore_status = 1;
- LSAPI_AppendRespHeader(h->header, h->header_len);
+ lsapi_append_response_header(h->header, h->header_len);
}
} else if (response_status == 304 && h->header_len > sizeof("Content-Type:")-1 &&
strncasecmp(h->header, "Content-Type:", sizeof("Content-Type:")-1) == 0
@@ -439,14 +482,14 @@ static int sapi_lsapi_send_headers_like_cgi(sapi_headers_struct *sapi_headers)
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
continue;
} else {
- LSAPI_AppendRespHeader(h->header, h->header_len);
+ lsapi_append_response_header(h->header, h->header_len);
}
}
h = (sapi_header_struct*)zend_llist_get_next_ex(&sapi_headers->headers, &pos);
}
- LSAPI_FinalizeRespHeaders();
- return SAPI_HEADER_SENT_SUCCESSFULLY;
+ return LSAPI_FinalizeRespHeaders() == -1
+ ? SAPI_HEADER_SEND_FAILED : SAPI_HEADER_SENT_SUCCESSFULLY;
}
/*
@@ -461,6 +504,9 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers)
sapi_header_struct *h;
zend_llist_position pos;
+ if (!lsapi_mode)
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+
if ( mod_lsapi_mode ) {
/* mod_lsapi mode */
return sapi_lsapi_send_headers_like_cgi(sapi_headers);
@@ -468,12 +514,13 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers)
/* Legacy mode */
if ( lsapi_mode ) {
- LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
+ if (LSAPI_SetRespStatus(SG(sapi_headers).http_response_code) == -1)
+ return SAPI_HEADER_SEND_FAILED;
h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
while (h) {
if ( h->header_len > 0 ) {
- LSAPI_AppendRespHeader(h->header, h->header_len);
+ lsapi_append_response_header(h->header, h->header_len);
}
h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
}
@@ -483,15 +530,16 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers)
char headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
hd = sapi_get_default_content_type();
- len = snprintf( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
+ len = snprintf( headerBuf, sizeof(headerBuf),
"Content-type: %s", hd );
efree(hd);
- LSAPI_AppendRespHeader( headerBuf, len );
+ if ( len > 0 && (size_t)len < sizeof(headerBuf) )
+ lsapi_append_response_header( headerBuf, len );
}
}
- LSAPI_FinalizeRespHeaders();
- return SAPI_HEADER_SENT_SUCCESSFULLY;
+ return LSAPI_FinalizeRespHeaders() == -1
+ ? SAPI_HEADER_SEND_FAILED : SAPI_HEADER_SENT_SUCCESSFULLY;
}
@@ -502,16 +550,34 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers)
static void sapi_lsapi_log_message(const char *message, int syslog_type_int)
{
char buf[8192];
- int len = strlen( message );
- if ( *(message + len - 1 ) != '\n' )
+ size_t len;
+
+ if (!message)
+ return;
+ len = strlen(message);
+ if ( len == 0 || message[len - 1] != '\n' )
{
- snprintf( buf, 8191, "%s\n", message );
+ if (len > sizeof(buf) - 2)
+ len = sizeof(buf) - 2;
+ memcpy( buf, message, len );
+ buf[len++] = '\n';
message = buf;
- if (len > 8191)
- len = 8191;
- ++len;
}
- LSAPI_Write_Stderr( message, len );
+ if (lsapi_mode) {
+ (void)LSAPI_Write_Stderr(message, (ssize_t)len);
+ } else {
+ size_t written = 0;
+ while (written < len) {
+ ssize_t ret = write(STDERR_FILENO, message + written,
+ len - written);
+ if (ret > 0)
+ written += (size_t)ret;
+ else if (ret == -1 && errno == EINTR)
+ continue;
+ else
+ break;
+ }
+ }
}
/* }}} */
@@ -591,7 +657,7 @@ static int sapi_lsapi_activate(void)
static sapi_module_struct lsapi_sapi_module =
{
"litespeed",
- "LiteSpeed V8.3",
+ "LiteSpeed V8.4",
php_lsapi_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
@@ -645,19 +711,28 @@ static void init_request_info( void )
static int lsapi_execute_script(void)
{
zend_file_handle file_handle;
- char *p;
- int len;
+ const char *script_path;
+ size_t copy_len;
+ size_t title_len;
zend_stream_init_filename(&file_handle, SG(request_info).path_translated);
file_handle.primary_script = true;
- p = argv0;
- *p++ = ':';
- len = strlen( SG(request_info).path_translated );
- if ( len > 45 )
- len = len - 45;
- else
- len = 0;
- memccpy( p, SG(request_info).path_translated + len, 0, 46 );
+ script_path = SG(request_info).path_translated;
+ if (argv0 && argv0_suffix_capacity > 1) {
+ title_len = (size_t)max_cmd_script_path_len;
+ if (title_len >= argv0_suffix_capacity)
+ title_len = argv0_suffix_capacity - 1;
+
+ copy_len = strlen(script_path);
+ if (copy_len >= title_len)
+ script_path += copy_len - (title_len - 1);
+ else
+ title_len = copy_len + 1;
+
+ argv0[0] = ':';
+ memcpy(argv0 + 1, script_path, title_len - 1);
+ argv0[title_len] = '\0';
+ }
php_execute_script(&file_handle);
zend_destroy_file_handle(&file_handle);
@@ -770,7 +845,8 @@ static int lsapi_module_main(int show_source)
clean_onexit = 1;
- memset( argv0, 0, 46 );
+ if (argv0)
+ memset( argv0, 0, argv0_suffix_capacity );
} zend_end_try();
return 0;
}
@@ -783,7 +859,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va
int type = ZEND_INI_PERDIR;
int stage = PHP_INI_STAGE_RUNTIME;
- if ( '\001' == *pKey ) {
+ if (pKey && pValue && keyLen >= 3 && valLen >= 0 && '\001' == *pKey) {
++pKey;
if ( *pKey == 4 ) {
type = ZEND_INI_SYSTEM;
@@ -806,7 +882,7 @@ static int alter_ini( const char * pKey, int keyLen, const char * pValue, int va
--keyLen;
if (( keyLen == 7 )&&( strncasecmp( pKey, "engine", 6 )== 0 ))
{
- if ( *pValue == '0' )
+ if ( valLen > 0 && *pValue == '0' )
engine = 0;
}
else
@@ -826,7 +902,7 @@ static void user_config_cache_entry_dtor(zval *el)
{
user_config_cache_entry *entry = (user_config_cache_entry *)Z_PTR_P(el);
zend_hash_destroy(&entry->user_config);
- free(entry);
+ pefree(entry, 1);
}
static void user_config_cache_init(void)
@@ -1034,7 +1110,10 @@ static int lsapi_activate_user_ini_walk_down_the_path(_lsapi_activate_user_ini_c
int is_outside_of_docroot = !docroot_len ||
ctx->path_len < docroot_len ||
- strncmp(ctx->path, ctx->doc_root, docroot_len) != 0;
+ strncmp(ctx->path, ctx->doc_root, docroot_len) != 0 ||
+ (ctx->path_len > docroot_len &&
+ !IS_SLASH(ctx->doc_root[docroot_len - 1]) &&
+ !IS_SLASH(ctx->path[docroot_len]));
if (is_outside_of_docroot) {
php_parse_user_ini_file(ctx->path, PG(user_ini_filename),
@@ -1171,21 +1250,35 @@ static int parse_opt( int argc, char * argv[], int *climode,
++p;
switch( c ) {
case 'b':
+ {
+ char *bind;
if ( p >= argend ) {
fprintf( stderr, "TCP or socket address must be specified following '-b' option.\n");
return -1;
}
- *php_bind = strdup(*p++);
+ bind = strdup(*p++);
+ if (!bind)
+ return -1;
+ free(*php_bind);
+ *php_bind = bind;
break;
+ }
case 'c':
+ {
+ char *ini_path;
if ( p >= argend ) {
fprintf( stderr, "<path> or <file> must be specified following '-c' option.\n");
return -1;
}
- *php_ini_path = strdup( *p++ );
+ ini_path = strdup(*p++);
+ if (!ini_path)
+ return -1;
+ free(*php_ini_path);
+ *php_ini_path = ini_path;
break;
+ }
case 's':
source_highlight = 1;
break;
@@ -1413,8 +1506,17 @@ void start_children( int children )
if ( s_stop ) {
break;
}
- pid = wait( &status );
- running--;
+ pid = wait(&status);
+ if (pid > 0)
+ --running;
+ else if (pid == -1 && errno == EINTR)
+ continue;
+ else if (pid == -1 && errno == ECHILD)
+ running = 0;
+ else {
+ perror("php (waiting for child)");
+ break;
+ }
}
kill( -getpgrp(), SIGUSR1 );
exit( 0 );
@@ -1423,8 +1525,10 @@ void start_children( int children )
void setArgv0( int argc, char * argv[] )
{
char * p;
+ char * area_end;
int i;
- argv0 = argv[0] + strlen( argv[0] );
+ area_end = argv[0] + strlen( argv[0] );
+ argv0 = area_end;
p = argv0;
while(( p > argv[0] )&&( p[-1] != '/'))
--p;
@@ -1434,6 +1538,11 @@ void setArgv0( int argc, char * argv[] )
memset( argv[0] + ( argv0 - p ), 0, p - argv[0] );
argv0 = argv[0] + (argv0 - p);
}
+ /* The title may also use argv[1..] that the kernel laid out right after
+ * argv[0]; they are cleared below. */
+ for( i = 1; i < argc && argv[i] == area_end + 1; ++i )
+ area_end = argv[i] + strlen( argv[i] );
+ argv0_suffix_capacity = (size_t)(area_end - argv0) + 1;
for( i = 1; i < argc; ++i )
{
memset( argv[i], 0, strlen( argv[i] ) );
@@ -1473,6 +1582,8 @@ int main( int argc, char * argv[] )
if (argc > 1 ) {
if ( parse_opt( argc, argv, &climode,
&php_ini_path, &php_bind ) == -1 ) {
+ free(php_ini_path);
+ free(php_bind);
return 1;
}
}
@@ -1514,11 +1625,16 @@ int main( int argc, char * argv[] )
#ifdef ZTS
tsrm_shutdown();
#endif
+ free(php_ini_path);
+ free(php_bind);
return FAILURE;
}
if ( climode ) {
- return cli_main(argc, argv);
+ ret = cli_main(argc, argv);
+ free(php_ini_path);
+ free(php_bind);
+ return ret;
}
if ( php_bind ) {
@@ -1534,13 +1650,31 @@ int main( int argc, char * argv[] )
}
}
- LSAPI_Init();
+ if ( LSAPI_Init() == -1 ) {
+ fprintf( stderr, "Failed to initialize LSAPI\n" );
+ php_module_shutdown();
+#ifdef ZTS
+ tsrm_shutdown();
+#endif
+ free(php_ini_path);
+ free(php_bind);
+ return FAILURE;
+ }
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
int is_criu = LSCRIU_Init(); // Must be called before the regular init as it unsets the parameters.
#endif
- LSAPI_Init_Env_Parameters( NULL );
+ if ( LSAPI_Init_Env_Parameters( NULL ) == -1 ) {
+ fprintf( stderr, "Failed to initialize LSAPI environment\n" );
+ php_module_shutdown();
+#ifdef ZTS
+ tsrm_shutdown();
+#endif
+ free(php_ini_path);
+ free(php_bind);
+ return FAILURE;
+ }
lsapi_mode = 1;
slow_script_msec = LSAPI_Get_Slow_Req_Msecs();
@@ -1591,6 +1725,8 @@ int main( int argc, char * argv[] )
#ifdef ZTS
tsrm_shutdown();
#endif
+ free(php_ini_path);
+ free(php_bind);
return ret;
}
@@ -1613,6 +1749,12 @@ static PHP_MINIT_FUNCTION(litespeed)
else if (*p == '0' || 0 == strcasecmp(p, "off"))
do_clean_shutdown = 0;
}
+ p = getenv("LSAPI_MAX_CMD_SCRIPT_PATH_LEN");
+ if (p) {
+ int len = atoi(p);
+ if (len > 0 && len < 256)
+ max_cmd_script_path_len = len;
+ }
/*
* mod_lsapi always sets this env var,
* so we can detect mod_lsapi mode with its presence.
@@ -1681,25 +1823,26 @@ PHP_FUNCTION(litespeed_response_headers)
RETURN_THROWS();
}
- if (!&SG(sapi_headers).headers) {
- RETURN_FALSE;
- }
array_init(return_value);
h = zend_llist_get_first_ex(&SG(sapi_headers).headers, &pos);
while (h) {
if ( h->header_len > 0 ) {
- p = strchr( h->header, ':' );
- len = p - h->header;
- if (p && len > 0 && len < LSAPI_RESP_HTTP_HEADER_MAX) {
+ p = memchr( h->header, ':', h->header_len );
+ len = p ? p - h->header : 0;
+ if (len > 0 && len < LSAPI_RESP_HTTP_HEADER_MAX) {
memmove( headerBuf, h->header, len );
while( len > 0 && (isspace((unsigned char)headerBuf[len - 1])) ) {
--len;
}
headerBuf[len] = 0;
if ( len ) {
- while(isspace((unsigned char)*++p));
- add_assoc_string_ex(return_value, headerBuf, len, p);
+ do {
+ ++p;
+ } while ((size_t)(p - h->header) < h->header_len &&
+ isspace((unsigned char)*p));
+ add_assoc_stringl_ex(return_value, headerBuf, len, p,
+ h->header_len - (p - h->header));
}
}
}
diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c
index 02ef8a0ab22..cc7979f16f2 100644
--- a/sapi/litespeed/lsapilib.c
+++ b/sapi/litespeed/lsapilib.c
@@ -176,6 +176,9 @@ LSAPI_Request g_req =
static char s_secret[24];
static LSAPI_On_Timer_pf s_proc_group_timer_cb = NULL;
+static LSAPI_Fork_Hook_pf s_fork_before = NULL;
+static LSAPI_Fork_Hook_pf s_fork_after_parent = NULL;
+static LSAPI_Fork_Hook_pf s_fork_after_child = NULL;
void Flush_RespBuf_r( LSAPI_Request * pReq );
static int lsapi_reopen_stderr(const char *p);
@@ -375,7 +378,7 @@ static void lsapi_enable_core_dump(void)
mib[0] = CTL_KERN;
mib[1] = KERN_NOSUIDCOREDUMP;
if (sysctl(mib, 2, NULL, 0, &set, len) == 0) {
- s_enable_core_dump = 1;
+ s_enable_core_dump = 1;
}
#endif
@@ -565,12 +568,21 @@ static inline int allocateBuf( LSAPI_Request * pReq, int size )
static int allocateIovec( LSAPI_Request * pReq, int n )
{
+ ptrdiff_t toWriteOff = 0;
+ ptrdiff_t curOff = 0;
+ if (n <= 0)
+ return -1;
+ if (pReq->m_pIovec)
+ {
+ toWriteOff = pReq->m_pIovecToWrite - pReq->m_pIovec;
+ curOff = pReq->m_pIovecCur - pReq->m_pIovec;
+ }
struct iovec * p = (struct iovec *)realloc(
pReq->m_pIovec, sizeof(struct iovec) * n );
if ( !p )
return -1;
- pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec );
- pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec );
+ pReq->m_pIovecToWrite = p + toWriteOff;
+ pReq->m_pIovecCur = p + curOff;
pReq->m_pIovec = p;
pReq->m_pIovecEnd = p + n;
return 0;
@@ -579,10 +591,15 @@ static int allocateIovec( LSAPI_Request * pReq, int n )
static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size )
{
+ ptrdiff_t posOff = 0;
+ if (size <= 0)
+ return -1;
+ if (pReq->m_pRespHeaderBuf)
+ posOff = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf;
char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size );
if ( !p )
return -1;
- pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf );
+ pReq->m_pRespHeaderBufPos = p + posOff;
pReq->m_pRespHeaderBuf = p;
pReq->m_pRespHeaderBufEnd = p + size;
return 0;
@@ -635,8 +652,8 @@ static inline int isPipe( int fd )
{
char achPeer[128];
socklen_t len = 128;
- if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&&
- ( errno == ENOTCONN ))
+ if ((getpeername(fd, (struct sockaddr *)achPeer, &len) != 0 )
+ && (errno == ENOTCONN || errno == ENOTSOCK))
return 0;
else
return 1;
@@ -646,23 +663,31 @@ static inline int isPipe( int fd )
static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
char **pBegin, char * pEnd )
{
- struct LSAPI_key_value_pair * pEnvEnd;
- int keyLen = 0, valLen = 0;
- if ( count > 8192 )
+ int i;
+ int keyLen = 0, valLen = 0;
+ size_t remaining;
+
+ if (count < 0 || count > 8192 || !pBegin || !*pBegin
+ || !pEnd || *pBegin > pEnd || (count && !pEnvList))
return -1;
- pEnvEnd = pEnvList + count;
- while( pEnvList != pEnvEnd )
+ for (i = 0; i < count; ++i, ++pEnvList)
{
- if ( pEnd - *pBegin < 4 )
+ remaining = (size_t)(pEnd - *pBegin);
+ if (remaining < 4)
return -1;
keyLen = *((unsigned char *)((*pBegin)++));
keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++));
valLen = *((unsigned char *)((*pBegin)++));
valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++));
- if ( *pBegin + keyLen + valLen > pEnd )
- return -1;
if (( !keyLen )||( !valLen ))
return -1;
+ remaining = (size_t)(pEnd - *pBegin);
+ if ((size_t)keyLen > remaining
+ || (size_t)valLen > remaining - (size_t)keyLen)
+ return -1;
+ if ((*pBegin)[keyLen - 1] != '\0'
+ || (*pBegin)[keyLen + valLen - 1] != '\0')
+ return -1;
pEnvList->pKey = *pBegin;
*pBegin += keyLen;
@@ -671,9 +696,9 @@ static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
pEnvList->keyLen = keyLen - 1;
pEnvList->valLen = valLen - 1;
- ++pEnvList;
}
- if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 )
+ if ((size_t)(pEnd - *pBegin) < 4
+ || memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 )
return -1;
*pBegin += 4;
return 0;
@@ -712,7 +737,7 @@ static inline void fixEndian( LSAPI_Request * pReq )
static void fixHeaderIndexEndian( LSAPI_Request * pReq )
{
int i;
- for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+ for( i = 0; i <= H_TRANSFER_ENCODING; ++i )
{
if ( pReq->m_pHeaderIndex->m_headerOff[i] )
{
@@ -745,13 +770,16 @@ static int validateHeaders( LSAPI_Request * pReq )
{
int totalLen = pReq->m_pHeader->m_httpHeaderLen;
int i;
- for(i = 0; i < H_TRANSFER_ENCODING; ++i)
+ if (totalLen < 0)
+ return -1;
+ for(i = 0; i <= H_TRANSFER_ENCODING; ++i)
{
if ( pReq->m_pHeaderIndex->m_headerOff[i] )
{
- if (pReq->m_pHeaderIndex->m_headerOff[i] > totalLen
- || pReq->m_pHeaderIndex->m_headerLen[i]
- + pReq->m_pHeaderIndex->m_headerOff[i] > totalLen)
+ int off = pReq->m_pHeaderIndex->m_headerOff[i];
+ int len = pReq->m_pHeaderIndex->m_headerLen[i];
+ if (off < 0 || off >= totalLen || len < 0
+ || len >= totalLen - off)
return -1;
}
}
@@ -762,10 +790,12 @@ static int validateHeaders( LSAPI_Request * pReq )
pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
while( pCur < pEnd )
{
- if (pCur->nameOff > totalLen
- || pCur->nameOff + pCur->nameLen > totalLen
- || pCur->valueOff > totalLen
- || pCur->valueOff + pCur->valueLen > totalLen)
+ if (pCur->nameOff < 0 || pCur->nameLen <= 0
+ || pCur->nameOff >= totalLen
+ || pCur->nameLen >= totalLen - pCur->nameOff
+ || pCur->valueOff < 0 || pCur->valueLen < 0
+ || pCur->valueOff >= totalLen
+ || pCur->valueLen >= totalLen - pCur->valueOff)
return -1;
++pCur;
}
@@ -797,30 +827,33 @@ static int (*fp_lve_leave)(struct liblve *, uint32_t *) = NULL;
static int (*fp_lve_jail)( struct passwd *, char *) = NULL;
static int lsapi_load_lve_lib(void)
{
- s_liblve = DL_LOAD("liblve.so.0");
- if (s_liblve)
+ s_liblve = dlopen("liblve.so.0", RTLD_NOW | RTLD_GLOBAL);
+ if (!s_liblve)
{
- fp_lve_is_available = dlsym(s_liblve, "lve_is_available");
- if (dlerror() == NULL)
+ lsapi_log("LSAPI: configured LVE library could not be loaded: %s\n",
+ dlerror());
+ return -1;
+ }
+
+ fp_lve_is_available = dlsym(s_liblve, "lve_is_available");
+ if (fp_lve_is_available && !(*fp_lve_is_available)())
+ {
+ uid_t uid = getuid();
+ if (uid)
{
- if ( !(*fp_lve_is_available)() )
+ if (setreuid(s_uid, uid) == 0)
{
- int uid = getuid();
- if ( uid )
- {
- if (setreuid( s_uid, uid )) {};
- if ( !(*fp_lve_is_available)() )
- s_enable_lve = 0;
- if (setreuid( uid, s_uid )) {};
- }
+ int available = (*fp_lve_is_available)();
+ if (setreuid(uid, s_uid) == -1)
+ return -1;
+ if (available)
+ return 0;
}
}
+ lsapi_log("LSAPI: configured LVE support is unavailable\n");
+ return -1;
}
- else
- {
- s_enable_lve = LSAPI_LVE_DISABLED;
- }
- return (s_liblve)? 0 : -1;
+ return 0;
}
@@ -835,11 +868,23 @@ static int init_lve_ex(void)
fp_lve_leave = dlsym(s_liblve, "lve_leave");
if ( s_enable_lve >= LSAPI_CAGEFS_ENABLED )
fp_lve_jail = dlsym(s_liblve, "jail" );
+ if (!fp_lve_instance_init || !fp_lve_enter)
+ {
+ lsapi_log("LSAPI: required LVE symbols are unavailable\n");
+ return -1;
+ }
+ if (s_enable_lve >= LSAPI_CAGEFS_ENABLED && !fp_lve_jail)
+ lsapi_log("LSAPI: CageFS jail symbol is unavailable; "
+ "continuing with LVE limits only\n");
if ( s_lve == NULL )
{
rc = (*fp_lve_instance_init)(NULL);
+ if (rc <= 0 || rc > 1024 * 1024)
+ return -1;
s_lve = malloc(rc);
+ if (!s_lve)
+ return -1;
}
rc = (*fp_lve_instance_init)(s_lve);
if (rc != 0)
@@ -860,7 +905,16 @@ static int init_lve_ex(void)
static int readSecret( const char * pSecretFile )
{
struct stat st;
- int fd = open( pSecretFile, O_RDONLY , 0600 );
+ size_t readLen = 0;
+ ssize_t len;
+ int flags = O_RDONLY;
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+#ifdef O_NOFOLLOW
+ flags |= O_NOFOLLOW;
+#endif
+ int fd = open(pSecretFile, flags);
if ( fd == -1 )
{
lsapi_log("LSAPI: failed to open secret file: %s!\n", pSecretFile );
@@ -872,25 +926,34 @@ static int readSecret( const char * pSecretFile )
close( fd );
return -1;
}
-/*
- if ( st.st_uid != s_uid )
+ if (!S_ISREG(st.st_mode) || st.st_uid != s_uid)
{
- lsapi_log("LSAPI: file owner check failure: %s!\n", pSecretFile );
+ lsapi_log("LSAPI: secret file type or owner check failure: %s!\n",
+ pSecretFile);
close( fd );
return -1;
}
-*/
if ( st.st_mode & 0077 )
{
lsapi_log("LSAPI: file permission check failure: %s\n", pSecretFile );
close( fd );
return -1;
}
- if ( read( fd, s_secret, 16 ) < 16 )
+ while (readLen < 16)
{
- lsapi_log("LSAPI: failed to read secret from secret file: %s\n", pSecretFile );
- close( fd );
- return -1;
+ len = read(fd, s_secret + readLen, 16 - readLen);
+ if (len > 0)
+ readLen += len;
+ else if (len == -1 && errno == EINTR)
+ continue;
+ else
+ {
+ lsapi_log("LSAPI: failed to read secret from secret file: %s\n",
+ pSecretFile);
+ memset(s_secret, 0, sizeof(s_secret));
+ close(fd);
+ return -1;
+ }
}
close( fd );
return 0;
@@ -996,12 +1059,9 @@ static int lsapi_initLVE(void)
}
if ( s_enable_lve && !s_uid )
{
- lsapi_load_lve_lib();
- if ( s_enable_lve )
- {
- return init_lve_ex();
- }
-
+ if (lsapi_load_lve_lib() == -1)
+ return -1;
+ return init_lve_ex();
}
return 0;
}
@@ -1032,10 +1092,12 @@ static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * p
}
}
#endif
- //if ( !uid || !gid ) //do not allow root
- //{
- // return -1;
- //}
+ if (!uid || !gid)
+ {
+ errno = EPERM;
+ LSAPI_perror_r(pReq, "LSAPI: refusing root UID or GID", NULL);
+ return -1;
+ }
#if defined(__FreeBSD__ ) || defined(__NetBSD__) || defined(__OpenBSD__) \
|| defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
@@ -1043,12 +1105,6 @@ static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * p
lsapi_enable_core_dump();
#endif
- rv = setgid(gid);
- if (rv == -1)
- {
- LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL);
- return -1;
- }
if ( pw && (pw->pw_gid == gid ))
{
rv = initgroups( pw->pw_name, gid );
@@ -1064,8 +1120,15 @@ static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * p
if (rv == -1)
{
LSAPI_perror_r(pReq, "LSAPI: setgroups()", NULL);
+ return -1;
}
}
+ rv = setgid(gid);
+ if (rv == -1)
+ {
+ LSAPI_perror_r(pReq, "LSAPI: setgid()", NULL);
+ return -1;
+ }
if ( pChroot )
{
rv = chroot( pChroot );
@@ -1074,6 +1137,11 @@ static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * p
LSAPI_perror_r(pReq, "LSAPI: chroot()", NULL);
return -1;
}
+ if (chdir("/") == -1)
+ {
+ LSAPI_perror_r(pReq, "LSAPI: chdir() after chroot", NULL);
+ return -1;
+ }
}
rv = setuid(uid);
if (rv == -1)
@@ -1088,12 +1156,13 @@ static int setUID_LVE(LSAPI_Request * pReq, uid_t uid, gid_t gid, const char * p
return 0;
}
-static int lsapi_suexec_auth( LSAPI_Request *pReq,
- char * pAuth, int len, char * pUgid, int ugidLen )
+static int lsapi_suexec_auth(char *pAuth, int len, char *pUgid, int ugidLen)
{
lsapi_MD5_CTX md5ctx;
unsigned char achMD5[16];
- if ( len < 32 )
+ unsigned char diff = 0;
+ int i;
+ if (len != 32 || ugidLen != 8)
return -1;
memmove( achMD5, pAuth + 16, 16 );
memmove( pAuth + 16, s_secret, 16 );
@@ -1101,21 +1170,89 @@ static int lsapi_suexec_auth( LSAPI_Request *pReq,
lsapi_MD5Update( &md5ctx, (unsigned char *)pAuth, 32 );
lsapi_MD5Update( &md5ctx, (unsigned char *)pUgid, 8 );
lsapi_MD5Final( (unsigned char *)pAuth + 16, &md5ctx);
- if ( memcmp( achMD5, pAuth + 16, 16 ) == 0 )
+ for (i = 0; i < 16; ++i)
+ diff |= achMD5[i] ^ (unsigned char)pAuth[i + 16];
+ if (diff == 0)
return 0;
return 1;
}
+static int lsapi_special_env_is(const struct LSAPI_key_value_pair *pEnv,
+ const char *name)
+{
+ size_t len;
+ if (!pEnv || !pEnv->pKey || !name || pEnv->keyLen < 1)
+ return 0;
+ len = strlen(name);
+ return pEnv->keyLen == (int)len + 1
+ && pEnv->pKey[0] == '\0'
+ && memcmp(pEnv->pKey + 1, name, len) == 0;
+}
+
+
+static void lsapi_process_suexec_auth(LSAPI_Request *pReq,
+ uid_t *uid, gid_t *gid)
+{
+ struct LSAPI_key_value_pair *pAuth;
+ struct LSAPI_key_value_pair *pUgid;
+ uint32_t ugid[2];
+ int count;
+
+ if (!pReq || !pReq->m_pHeader || !uid || !gid)
+ return;
+ count = pReq->m_pHeader->m_cntSpecialEnv;
+ if (count < 1 || !pReq->m_pSpecialEnvList)
+ return;
+
+ pAuth = pReq->m_pSpecialEnvList + count - 1;
+ if (!lsapi_special_env_is(pAuth, "SUEXEC_AUTH"))
+ return;
+
+ /* Never expose the authentication record to the application, including
+ * malformed requests where the matching SUEXEC_UGID record is absent. */
+ --pReq->m_pHeader->m_cntSpecialEnv;
+ if (count < 2)
+ {
+ lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n");
+ *uid = 0;
+ goto clear_auth;
+ }
+
+ pUgid = pAuth - 1;
+ if (!lsapi_special_env_is(pUgid, "SUEXEC_UGID"))
+ {
+ lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n");
+ *uid = 0;
+ goto clear_auth;
+ }
+
+ --pReq->m_pHeader->m_cntSpecialEnv;
+ if (lsapi_suexec_auth(pAuth->pValue, pAuth->valLen,
+ pUgid->pValue, pUgid->valLen) == 0)
+ {
+ memcpy(ugid, pUgid->pValue, sizeof(ugid));
+ *uid = ugid[0];
+ *gid = ugid[1];
+ }
+ else
+ {
+ lsapi_log("LSAPI: SUEXEC_AUTH authentication failed, use default user!\n");
+ *uid = 0;
+ }
+
+clear_auth:
+ if (pAuth->pValue && pAuth->valLen > 0)
+ memset(pAuth->pValue, 0, (size_t)pAuth->valLen);
+}
+
+
static int lsapi_changeUGid( LSAPI_Request * pReq )
{
- int uid = s_defaultUid;
- int gid = s_defaultGid;
+ uid_t uid = s_defaultUid;
+ gid_t gid = s_defaultGid;
const char *pStderrLog;
const char *pChroot = NULL;
- struct LSAPI_key_value_pair * pEnv;
- struct LSAPI_key_value_pair * pAuth;
- int i;
if ( s_uid )
return 0;
//with special ID 0x00
@@ -1123,48 +1260,10 @@ static int lsapi_changeUGid( LSAPI_Request * pReq )
//first one should be MD5( nonce + lscgid secret )
//remember to clear the secret after verification
//it should be set at the end of special env
- i = pReq->m_pHeader->m_cntSpecialEnv - 1;
- if ( i >= 0 )
- {
- pEnv = pReq->m_pSpecialEnvList + i;
- if (( *pEnv->pKey == '\000' )&&
- ( strcmp( pEnv->pKey+1, "SUEXEC_AUTH" ) == 0 ))
- {
- --pReq->m_pHeader->m_cntSpecialEnv;
- pAuth = pEnv--;
- if (( *pEnv->pKey == '\000' )&&
- ( strcmp( pEnv->pKey+1, "SUEXEC_UGID" ) == 0 ))
- {
- --pReq->m_pHeader->m_cntSpecialEnv;
- uid = *(uint32_t *)pEnv->pValue;
- gid = *(((uint32_t *)pEnv->pValue) + 1 );
- //lsapi_log("LSAPI: SUEXEC_UGID set UID: %d, GID: %d\n", uid, gid );
- }
- else
- {
- lsapi_log("LSAPI: missing SUEXEC_UGID env, use default user!\n" );
- pEnv = NULL;
- }
- if ( pEnv&& lsapi_suexec_auth( pReq, pAuth->pValue, pAuth->valLen, pEnv->pValue, pEnv->valLen ) == 0 )
- {
- //read UID, GID from specialEnv
-
- }
- else
- {
- //authentication error
- lsapi_log("LSAPI: SUEXEC_AUTH authentication failed, use default user!\n" );
- uid = 0;
- }
- }
- else
- {
- //lsapi_log("LSAPI: no SUEXEC_AUTH env, use default user!\n" );
- }
- }
+ lsapi_process_suexec_auth(pReq, &uid, &gid);
- if ( !uid )
+ if (!uid || !gid)
{
uid = s_defaultUid;
gid = s_defaultGid;
@@ -1196,8 +1295,22 @@ static int lsapi_changeUGid( LSAPI_Request * pReq )
static int parseContentLenFromHeader(LSAPI_Request * pReq)
{
const char * pContentLen = LSAPI_GetHeader_r( pReq, H_CONTENT_LENGTH );
- if ( pContentLen )
- pReq->m_reqBodyLen = strtoll( pContentLen, NULL, 10 );
+ char *pEnd;
+ long long len;
+ /* A missing Content-Length is valid for chunked HTTP/1 requests and for
+ * HTTP/2 or HTTP/3 streams. Keep the protocol's unknown-length sentinel
+ * in that case; producers that buffer the body may replace it with the
+ * decoded length before forwarding the request. */
+ if (!pContentLen)
+ return 0;
+
+ errno = 0;
+ len = strtoll(pContentLen, &pEnd, 10);
+ while (*pEnd && isspace((unsigned char)*pEnd))
+ ++pEnd;
+ if (errno == ERANGE || pEnd == pContentLen || *pEnd || len < 0)
+ return -1;
+ pReq->m_reqBodyLen = len;
return 0;
}
@@ -1205,14 +1318,31 @@ static int parseContentLenFromHeader(LSAPI_Request * pReq)
static int parseRequest( LSAPI_Request * pReq, int totalLen )
{
int shouldFixEndian;
- char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header );
- char * pEnd = pReq->m_pReqBuf + totalLen;
+ char *pBegin;
+ char *pEnd;
+ size_t used;
+ size_t aligned;
+ size_t remaining;
+ size_t unknownSize;
+
+ if (!pReq || !pReq->m_pReqBuf || totalLen < (int)sizeof(struct lsapi_req_header)
+ || totalLen > pReq->m_reqBufSize)
+ return -1;
+ pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header );
+ pEnd = pReq->m_pReqBuf + totalLen;
shouldFixEndian = ( LSAPI_ENDIAN != (
pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) );
if ( shouldFixEndian )
{
fixEndian( pReq );
}
+ if (pReq->m_pHeader->m_cntSpecialEnv < 0
+ || pReq->m_pHeader->m_cntSpecialEnv > 8192
+ || pReq->m_pHeader->m_cntEnv < 0
+ || pReq->m_pHeader->m_cntEnv > 8192
+ || pReq->m_pHeader->m_cntUnknownHeaders < 0
+ || pReq->m_pHeader->m_httpHeaderLen < 0)
+ return -1;
if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&&
allocateEnvList( &pReq->m_pSpecialEnvList,
&pReq->m_specialEnvListSize,
@@ -1246,21 +1376,46 @@ static int parseRequest( LSAPI_Request * pReq, int totalLen )
pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff;
pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff;
pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff;
+ if (!memchr(pReq->m_pScriptFile, '\0',
+ (size_t)(pEnd - pReq->m_pScriptFile))
+ || !memchr(pReq->m_pScriptName, '\0',
+ (size_t)(pEnd - pReq->m_pScriptName))
+ || !memchr(pReq->m_pQueryString, '\0',
+ (size_t)(pEnd - pReq->m_pQueryString))
+ || !memchr(pReq->m_pRequestMethod, '\0',
+ (size_t)(pEnd - pReq->m_pRequestMethod)))
+ return -1;
- pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7));
+ used = (size_t)(pBegin - pReq->m_pReqBuf);
+ if (used > (size_t)totalLen || used > SIZE_MAX - 7)
+ return -1;
+ aligned = (used + 7) & ~(size_t)7;
+ if (aligned > (size_t)totalLen)
+ return -1;
+ pBegin = pReq->m_pReqBuf + aligned;
+ remaining = (size_t)(pEnd - pBegin);
+ if (remaining < sizeof(struct lsapi_http_header_index))
+ return -1;
pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin;
pBegin += sizeof( struct lsapi_http_header_index );
pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin;
- pBegin += sizeof( struct lsapi_header_offset) *
- pReq->m_pHeader->m_cntUnknownHeaders;
+ remaining = (size_t)(pEnd - pBegin);
+ if ((size_t)pReq->m_pHeader->m_cntUnknownHeaders
+ > remaining / sizeof(struct lsapi_header_offset))
+ return -1;
+ unknownSize = sizeof(struct lsapi_header_offset)
+ * (size_t)pReq->m_pHeader->m_cntUnknownHeaders;
+ pBegin += unknownSize;
pReq->m_pHttpHeader = pBegin;
- pBegin += pReq->m_pHeader->m_httpHeaderLen;
- if ( pBegin != pEnd )
+ remaining = (size_t)(pEnd - pBegin);
+ if ((size_t)pReq->m_pHeader->m_httpHeaderLen != remaining)
{
- lsapi_log("Request header does match total size, total: %d, "
- "real: %ld\n", totalLen, pBegin - pReq->m_pReqBuf );
+ lsapi_log("Request header does not match total size, total: %d, "
+ "real: %ld\n", totalLen,
+ pBegin - pReq->m_pReqBuf
+ + pReq->m_pHeader->m_httpHeaderLen );
return -1;
}
if ( shouldFixEndian )
@@ -1277,7 +1432,8 @@ static int parseRequest( LSAPI_Request * pReq, int totalLen )
pReq->m_reqBodyLen = pReq->m_pHeader->m_reqBodyLen;
if ( pReq->m_reqBodyLen == -2 )
{
- parseContentLenFromHeader(pReq);
+ if (parseContentLenFromHeader(pReq) == -1)
+ return -1;
}
return 0;
@@ -1374,7 +1530,8 @@ static int readReq( LSAPI_Request * pReq )
while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN )
{
- len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize );
+ len = lsapi_read(pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead,
+ pReq->m_reqBufSize - pReq->m_bufRead);
if ( len <= 0 )
return -1;
pReq->m_bufRead += len;
@@ -1387,6 +1544,11 @@ static int readReq( LSAPI_Request * pReq )
lsapi_log("packetLen < 0\n");
return -1;
}
+ if (packetLen < (int)sizeof(struct lsapi_req_header))
+ {
+ lsapi_log("packetLen < request header size\n");
+ return -1;
+ }
if ( packetLen > LSAPI_MAX_HEADER_LEN )
{
lsapi_log("packetLen > %d\n", LSAPI_MAX_HEADER_LEN );
@@ -1478,6 +1640,16 @@ void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf cb)
}
+void LSAPI_Set_Fork_Hooks(LSAPI_Fork_Hook_pf before,
+ LSAPI_Fork_Hook_pf after_parent,
+ LSAPI_Fork_Hook_pf after_child)
+{
+ s_fork_before = before;
+ s_fork_after_parent = after_parent;
+ s_fork_after_child = after_child;
+}
+
+
int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
{
int newfd;
@@ -1485,21 +1657,44 @@ int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
return -1;
memset( pReq, 0, sizeof( LSAPI_Request ) );
if ( allocateIovec( pReq, 16 ) == -1 )
+ {
+ LSAPI_Release_r(pReq);
return -1;
+ }
pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE );
if ( !pReq->m_pRespBuf )
+ {
+ LSAPI_Release_r(pReq);
return -1;
+ }
pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE;
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5];
if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 )
+ {
+ LSAPI_Release_r(pReq);
return -1;
+ }
if ( fd == STDIN_FILENO )
{
fd = dup( fd );
+ if (fd == -1)
+ {
+ LSAPI_Release_r(pReq);
+ return -1;
+ }
newfd = open( "/dev/null", O_RDWR );
- dup2( newfd, STDIN_FILENO );
+ if (newfd == -1 || dup2(newfd, STDIN_FILENO) == -1)
+ {
+ if (newfd != -1)
+ close(newfd);
+ close(fd);
+ LSAPI_Release_r(pReq);
+ return -1;
+ }
+ if (newfd != STDIN_FILENO)
+ close(newfd);
}
if ( isPipe( fd ) )
@@ -1674,6 +1869,8 @@ void LSAPI_Reset_r( LSAPI_Request * pReq )
int LSAPI_Release_r( LSAPI_Request * pReq )
{
+ if (!pReq)
+ return -1;
if ( pReq->m_pReqBuf )
free( pReq->m_pReqBuf );
if ( pReq->m_pSpecialEnvList )
@@ -1682,6 +1879,13 @@ int LSAPI_Release_r( LSAPI_Request * pReq )
free( pReq->m_pEnvList );
if ( pReq->m_pRespHeaderBuf )
free( pReq->m_pRespHeaderBuf );
+ if ( pReq->m_pRespBuf )
+ free( pReq->m_pRespBuf );
+ if ( pReq->m_pIovec )
+ free( pReq->m_pIovec );
+ memset(pReq, 0, sizeof(*pReq));
+ pReq->m_fdListen = -1;
+ pReq->m_fd = -1;
return 0;
}
@@ -1708,11 +1912,13 @@ static int readBodyToReqBuf( LSAPI_Request * pReq )
{
off_t bodyLeft;
ssize_t len = pReq->m_bufRead - pReq->m_bufProcessed;
+ bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
+ if (bodyLeft <= 0)
+ return 0;
if ( len > 0 )
- return len;
+ return len > bodyLeft ? bodyLeft : len;
pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen;
- bodyLeft = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
len = pReq->m_reqBufSize - pReq->m_bufRead;
if ( len < 0 )
return -1;
@@ -1730,6 +1936,8 @@ int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq )
{
if (!pReq || (pReq->m_fd ==-1) )
return EOF;
+ if (pReq->m_reqBodyRead >= pReq->m_reqBodyLen)
+ return EOF;
if ( pReq->m_bufProcessed >= pReq->m_bufRead )
{
if ( readBodyToReqBuf( pReq ) <= 0 )
@@ -1748,20 +1956,18 @@ int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen, in
char * pBufCur = pBuf;
char * pCur;
char * p;
- if (!pReq || pReq->m_fd == -1 || !pBuf || !getLF)
+ if (!pReq || pReq->m_fd == -1 || !pBuf || !getLF || bufLen == 0
+ || bufLen > (size_t)SSIZE_MAX)
return -1;
*getLF = 0;
while( (left = pBufEnd - pBufCur ) > 0 )
{
- len = pReq->m_bufRead - pReq->m_bufProcessed;
- if ( len <= 0 )
+ len = readBodyToReqBuf(pReq);
+ if (len <= 0)
{
- if ( (len = readBodyToReqBuf( pReq )) <= 0 )
- {
- *getLF = 1;
- break;
- }
+ *getLF = 1;
+ break;
}
if ( len > left )
len = left;
@@ -1792,7 +1998,7 @@ ssize_t LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, size_t bufLen )
ssize_t len;
off_t total;
/* char *pOldBuf = pBuf; */
- if (!pReq || pReq->m_fd == -1 || !pBuf || (ssize_t)bufLen < 0)
+ if (!pReq || pReq->m_fd == -1 || !pBuf || bufLen > (size_t)SSIZE_MAX)
return -1;
total = pReq->m_reqBodyLen - pReq->m_reqBodyRead;
@@ -1846,7 +2052,7 @@ ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
ssize_t packetLen;
int skip = 0;
- if (!pReq || !pBuf)
+ if (!pReq || !pBuf || len > (size_t)SSIZE_MAX)
return -1;
if (pReq->m_reqState & LSAPI_ST_BACKGROUND)
return len;
@@ -1954,24 +2160,25 @@ ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size )
}
while (size > 0) {
- size_t tor = size > sizeof(in) ? sizeof(in) : size;
- ssize_t c = read(fdIn, in, tor);
- if (c <= 0) {
- goto end;
- }
+ size_t tor = size > sizeof(in) ? sizeof(in) : size;
+ ssize_t c = read(fdIn, in, tor);
+ if (c <= 0) {
+ goto end;
+ }
- ssize_t w = write(fdOut, in, c);
- if (w != c) {
- goto end;
- }
+ ssize_t w = write(fdOut, in, c);
+ if (w > 0)
+ written += w;
- written += w;
- size -= c;
+ if (w != c) {
+ goto end;
+ }
+ size -= c;
}
end:
*off += written;
- return 0;
+ return written;
}
#endif
@@ -1982,7 +2189,7 @@ ssize_t gsendfile( int fdOut, int fdIn, off_t* off, size_t size )
ssize_t ret;
off_t len = size;
ret = sendfile( fdIn, fdOut, *off, &len, NULL, 0 );
- if (( ret == 0 )&&( len > 0 ))
+ if (len > 0)
{
ret = len;
*off += len;
@@ -2030,28 +2237,120 @@ ssize_t gsendfile( int fdOut, int fdIn, off_t * off, size_t size )
}
#endif
+#ifndef LSAPI_GSENDFILE
+#define LSAPI_GSENDFILE gsendfile
+#endif
+
+
+static int lsapi_sendfile_write_header(LSAPI_Request *pReq,
+ const struct lsapi_packet_header *header)
+{
+ const char *p = (const char *)header;
+ size_t left = LSAPI_PACKET_HEADER_LEN;
+
+ while (left > 0 && g_running)
+ {
+ ssize_t written = write(pReq->m_fd, p, left);
+ if (written > 0)
+ {
+ p += written;
+ left -= (size_t)written;
+ }
+ else if (written == -1 && errno == EINTR)
+ continue;
+ else
+ break;
+ }
+ if (left == 0)
+ return 0;
+ lsapi_close_connection(pReq);
+ return -1;
+}
+
ssize_t LSAPI_sendfile_r( LSAPI_Request * pReq, int fdIn, off_t* off, size_t size )
{
- struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
- if ( !pReq || (pReq->m_fd == -1) || fdIn == -1 )
+ struct lsapi_packet_header *pHeader;
+ struct stat st;
+ size_t remaining;
+ size_t totalSent = 0;
+
+ if (!pReq || pReq->m_fd == -1 || fdIn == -1 || !off || *off < 0
+ || size > (size_t)SSIZE_MAX)
return -1;
+ if (fstat(fdIn, &st) == 0 && S_ISREG(st.st_mode))
+ {
+ uintmax_t available;
+ if (*off >= st.st_size)
+ return 0;
+ available = (uintmax_t)(st.st_size - *off);
+ if ((uintmax_t)size > available)
+ size = (size_t)available;
+ }
+ if (size == 0)
+ return 0;
+
+ pHeader = pReq->m_respPktHeader;
if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
{
- LSAPI_FinalizeRespHeaders_r( pReq );
+ if (LSAPI_FinalizeRespHeaders_r(pReq) == -1)
+ return -1;
}
pReq->m_reqState |= LSAPI_ST_RESP_BODY;
- LSAPI_Flush_r(pReq);
-
- lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
- size + LSAPI_PACKET_HEADER_LEN );
-
-
- if (write(pReq->m_fd, (const char *) pHeader, LSAPI_PACKET_HEADER_LEN ) != LSAPI_PACKET_HEADER_LEN)
+ if (LSAPI_Flush_r(pReq) == -1)
return -1;
- return gsendfile( pReq->m_fd, fdIn, off, size );
+ remaining = size;
+ while (remaining > 0)
+ {
+ size_t packetLeft = remaining;
+ if (!g_running)
+ {
+ lsapi_close_connection(pReq);
+ return -1;
+ }
+ if (packetLeft > LSAPI_MAX_DATA_PACKET_LEN)
+ packetLeft = LSAPI_MAX_DATA_PACKET_LEN;
+ lsapi_buildPacketHeader(pHeader, LSAPI_RESP_STREAM,
+ (int)packetLeft + LSAPI_PACKET_HEADER_LEN);
+ if (lsapi_sendfile_write_header(pReq, pHeader) == -1)
+ return -1;
+
+ while (packetLeft > 0)
+ {
+ ssize_t sent;
+ if (!g_running)
+ {
+ lsapi_close_connection(pReq);
+ return -1;
+ }
+ sent = LSAPI_GSENDFILE(pReq->m_fd, fdIn, off, packetLeft);
+ if (sent > 0 && (size_t)sent <= packetLeft)
+ {
+ packetLeft -= (size_t)sent;
+ remaining -= (size_t)sent;
+ totalSent += (size_t)sent;
+ }
+ else if (sent == -1 && errno == EINTR)
+ {
+ if (!g_running)
+ {
+ lsapi_close_connection(pReq);
+ return -1;
+ }
+ continue;
+ }
+ else
+ {
+ /* Once a packet header has been written, the connection must
+ * not be reused unless its complete payload is delivered. */
+ lsapi_close_connection(pReq);
+ return -1;
+ }
+ }
+ }
+ return (ssize_t)totalSent;
}
@@ -2133,7 +2432,7 @@ ssize_t LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, size_t le
struct iovec iov[2];
struct iovec *pIov;
- if ( !pReq )
+ if (!pReq || !pBuf || len > (size_t)SSIZE_MAX)
return -1;
if (s_stderr_log_path || pReq->m_fd == -1 || pReq->m_fd == pReq->m_fdListen)
return write( 2, pBuf, len );
@@ -2213,7 +2512,7 @@ static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
while(( pKey < pKeyEnd )&&( *p ))
{
- char ch = toupper( (unsigned char)*pKey );
+ char ch = toupper((unsigned char)*pKey);
if ((ch != *p )||(( *p == '_' )&&( ch != '-')))
break;
++p; ++pKey;
@@ -2237,10 +2536,19 @@ static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
{
- struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList;
- struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv;
+ struct LSAPI_key_value_pair *pBegin;
+ struct LSAPI_key_value_pair *pEnd;
if ( !pReq || !name )
return NULL;
+ if (!pReq->m_pHeader || pReq->m_pHeader->m_cntEnv <= 0
+ || !pReq->m_pEnvList)
+ {
+ if (strncmp(name, "HTTP_", 5) == 0 && pReq->m_pHeaderIndex)
+ return GetHeaderVar(pReq, name);
+ return NULL;
+ }
+ pBegin = pReq->m_pEnvList;
+ pEnd = pBegin + pReq->m_pHeader->m_cntEnv;
if ( strncmp( name, "HTTP_", 5 ) == 0 )
{
return GetHeaderVar( pReq, name );
@@ -2266,8 +2574,9 @@ struct _headerInfo
int compareValueLocation(const void * v1, const void *v2 )
{
- return ((const struct _headerInfo *)v1)->_value -
- ((const struct _headerInfo *)v2)->_value;
+ const char *p1 = ((const struct _headerInfo *)v1)->_value;
+ const char *p2 = ((const struct _headerInfo *)v2)->_value;
+ return (p1 > p2) - (p1 < p2);
}
@@ -2397,7 +2706,7 @@ int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
if ( ch == '-' )
*p++ = '_';
else
- *p++ = toupper( (unsigned char)ch );
+ *p++ = toupper((unsigned char)ch);
}
*p = 0;
keyLen += 5;
@@ -2494,7 +2803,8 @@ int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
const char * pHeaderValue )
{
- int nameLen, valLen, len;
+ size_t nameLen, valLen;
+ int len;
if ( !pReq || !pHeaderName || !pHeaderValue )
return -1;
if ( pReq->m_reqState & LSAPI_ST_RESP_BODY )
@@ -2503,7 +2813,8 @@ int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
return -1;
nameLen = strlen( pHeaderName );
valLen = strlen( pHeaderValue );
- if ( nameLen == 0 )
+ if (nameLen == 0 || nameLen > LSAPI_RESP_HTTP_HEADER_MAX
+ || valLen > LSAPI_RESP_HTTP_HEADER_MAX)
return -1;
while( nameLen > 0 )
{
@@ -2523,9 +2834,14 @@ int LSAPI_AppendRespHeader2_r( LSAPI_Request * pReq, const char * pHeaderName,
else
break;
}
- len = nameLen + valLen + 1;
- if ( len > LSAPI_RESP_HTTP_HEADER_MAX )
+ if (memchr(pHeaderName, '\r', nameLen) || memchr(pHeaderName, '\n', nameLen)
+ || memchr(pHeaderName, ':', nameLen)
+ || memchr(pHeaderValue, '\r', valLen)
+ || memchr(pHeaderValue, '\n', valLen))
return -1;
+ if (nameLen + valLen + 2 > SHRT_MAX)
+ return -1;
+ len = (int)(nameLen + valLen + 1);
if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
{
@@ -2565,6 +2881,9 @@ int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, const char * pBuf, int len )
}
if ( len <= 0 )
return 0;
+ if (len >= SHRT_MAX || memchr(pBuf, '\0', len)
+ || memchr(pBuf, '\r', len) || memchr(pBuf, '\n', len))
+ return -1;
if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd )
{
int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
@@ -2588,19 +2907,42 @@ int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
int fd;
int flag = 1;
int addr_len;
+ struct stat st;
+
+ if (!pServerAddr)
+ return -1;
switch( pServerAddr->sa_family )
{
case AF_INET:
- addr_len = 16;
+ addr_len = sizeof(struct sockaddr_in);
break;
case AF_INET6:
addr_len = sizeof( struct sockaddr_in6 );
break;
case AF_UNIX:
- addr_len = sizeof( struct sockaddr_un );
- unlink( ((struct sockaddr_un *)pServerAddr)->sun_path );
+ {
+ const char *path = ((const struct sockaddr_un *)pServerAddr)->sun_path;
+ size_t pathLen = strnlen(path,
+ sizeof(((const struct sockaddr_un *)pServerAddr)->sun_path));
+ if (pathLen == 0
+ || pathLen == sizeof(((const struct sockaddr_un *)pServerAddr)->sun_path))
+ return -1;
+ addr_len = offsetof(struct sockaddr_un, sun_path) + pathLen + 1;
+ if (lstat(path, &st) == 0)
+ {
+ if (!S_ISSOCK(st.st_mode))
+ {
+ errno = EEXIST;
+ return -1;
+ }
+ if (unlink(path) == -1)
+ return -1;
+ }
+ else if (errno != ENOENT)
+ return -1;
break;
+ }
default:
return -1;
}
@@ -2639,22 +2981,28 @@ int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
int doAddrInfo = 0;
int port;
- if ( !pBind )
+ if ( !pBind || !pAddr )
return -1;
- while(isspace( (unsigned char)*pBind ) )
+ while (isspace((unsigned char)*pBind))
++pBind;
- strncpy(achAddr, pBind, 255);
- achAddr[255] = 0;
+ if (strlen(pBind) >= sizeof(achAddr))
+ return -1;
+ strcpy(achAddr, pBind);
switch( *p )
{
case '/':
+ {
+ size_t pathLen = strlen(p);
+ if (pathLen >= sizeof(((struct sockaddr_un *)pAddr)->sun_path))
+ return -1;
pAddr->sa_family = AF_UNIX;
memccpy(((struct sockaddr_un *)pAddr)->sun_path, p, 0,
sizeof(((struct sockaddr_un *)pAddr)->sun_path));
return 0;
+ }
case '[':
pAddr->sa_family = AF_INET6;
@@ -2910,7 +3258,6 @@ static void lsapi_sigchild( int signal )
if ( WIFSIGNALED( status ))
{
int sig_num = WTERMSIG( status );
-
#ifdef WCOREDUMP
const char * dump = WCOREDUMP( status ) ? "yes" : "no";
#else
@@ -3013,12 +3360,14 @@ static void dump_debug_info( lsapi_child_status * pStatus, long tmCur )
s_pid_dump_debug_info = fork();
if (s_pid_dump_debug_info == 0)
{
- snprintf( achCmd, 1024, "gdb --batch -ex \"attach %d\" -ex \"set height 0\" "
- "-ex \"bt\" >&2;PATH=$PATH:/usr/sbin lsof -p %d >&2",
+ snprintf(achCmd, sizeof(achCmd),
+ "PATH=/usr/bin:/bin:/usr/sbin:/sbin; export PATH; "
+ "gdb --batch -ex \"attach %d\" -ex \"set height 0\" "
+ "-ex \"bt\" >&2; lsof -p %d >&2",
pStatus->m_pid, pStatus->m_pid );
if ( system( achCmd ) == -1 )
perror( "system()" );
- exit( 0 );
+ _exit( 0 );
}
}
@@ -3271,6 +3620,8 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
perror( "sigprocmask(SIG_BLOCK) to block SIGCHLD" );
}
+ if (s_fork_before)
+ (*s_fork_before)();
pid = fork();
if ( !pid )
@@ -3278,6 +3629,8 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
setsid();
if (sigprocmask(SIG_SETMASK, &orig_mask, NULL) < 0)
perror( "sigprocmask( SIG_SETMASK ) to restore SIGMASK in child" );
+ if (s_fork_after_child)
+ (*s_fork_after_child)();
g_prefork_server = NULL;
s_ppid = getppid();
s_pid = getpid();
@@ -3318,12 +3671,17 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
}
else if ( pid == -1 )
{
- lsapi_perror("fork() failed, please increase process limit", errno);
+ int fork_errno = errno;
+ if (s_fork_after_parent)
+ (*s_fork_after_parent)();
+ lsapi_perror("fork() failed, please increase process limit", fork_errno);
if (child_status)
child_status->m_pid = 0;
}
else
{
+ if (s_fork_after_parent)
+ (*s_fork_after_parent)();
++pServer->m_iCurChildren;
if ( child_status )
{
@@ -3423,6 +3781,8 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
struct timeval timeout;
int wait_secs = 0;
int ret = 0;
+ int accepted = 0;
+ sigset_t chld_mask, orig_mask;
lsapi_prefork_server * pServer = g_prefork_server;
@@ -3438,6 +3798,13 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
perror( "Can't set signal handler for SIGCHILD" );
return -1;
}
+ /* The caller forks between calls, with the caller's SIGCHLD handler in
+ * place; reap workers that exited meanwhile, or they stay counted. */
+ sigemptyset(&chld_mask);
+ sigaddset(&chld_mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &chld_mask, &orig_mask);
+ lsapi_sigchild(SIGCHLD);
+ sigprocmask(SIG_SETMASK, &orig_mask, NULL);
/* Set up handler to kill children upon exit */
act.sa_flags = 0;
@@ -3454,7 +3821,9 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
s_stop = 0;
pReq->m_reqState = 0;
- while(!s_stop)
+ /* A stop signal that arrives between calls (while the caller forks) is
+ * handled by lsapi_siguser1(), which only clears g_running. */
+ while(!s_stop && g_running)
{
if (s_proc_group_timer_cb != NULL) {
s_proc_group_timer_cb(&s_ignore_pid);
@@ -3536,7 +3905,7 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
wait_secs = 0;
pReq->child_status = find_child_status(0);
- ret = 0;
+ accepted = 1;
break;
}
else
@@ -3555,7 +3924,7 @@ int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
sigaction(SIGINT, &old_int, 0);
sigaction(SIGUSR1, &old_usr1, 0);
- return ret;
+ return accepted ? 0 : -1;
}
@@ -3883,34 +4252,70 @@ static int lsapi_initSuEXEC(void)
s_defaultGid = 10000;
}
}
+ if (!s_defaultUid || !s_defaultGid)
+ return -1;
return 0;
}
+static int lsapi_path_is_forbidden(const char *path)
+{
+ return strcmp(path, "/etc") == 0 || strncmp(path, "/etc/", 5) == 0;
+}
+
+
static int lsapi_check_path(const char *p, char *final, int max_len)
{
char resolved_path[PATH_MAX+1];
- int len = 0;
- char *end;
+ char parent_path[PATH_MAX+1];
+ size_t len = 0;
+ size_t inputLen;
+ char *slash;
+
+ if (!p || !*p || !final || max_len <= 1)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ inputLen = strlen(p);
if (*p != '/')
{
if (getcwd(final, max_len) == NULL)
return -1;
len = strlen(final);
- *(final + len) = '/';
- ++len;
+ if (len + 1 >= (size_t)max_len)
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ final[len++] = '/';
}
- end = memccpy(&final[len], p, '\0', PATH_MAX - len);
- if (!end)
+ if (inputLen >= (size_t)max_len - len)
{
- errno = EINVAL;
+ errno = ENAMETOOLONG;
return -1;
}
- p = final;
- if (realpath(p, resolved_path) == NULL
- && errno != ENOENT && errno != EACCES)
- return -1;
- if (strncmp(resolved_path, "/etc/", 5) == 0)
+ memcpy(final + len, p, inputLen + 1);
+
+ if (realpath(final, resolved_path) == NULL)
+ {
+ if (errno != ENOENT)
+ return -1;
+ memcpy(parent_path, final, strlen(final) + 1);
+ slash = strrchr(parent_path, '/');
+ if (!slash)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (slash == parent_path)
+ slash[1] = '\0';
+ else
+ *slash = '\0';
+ if (realpath(parent_path, resolved_path) == NULL)
+ return -1;
+ }
+ if (lsapi_path_is_forbidden(resolved_path))
{
errno = EPERM;
return -1;
@@ -3921,7 +4326,14 @@ static int lsapi_check_path(const char *p, char *final, int max_len)
static int lsapi_reopen_stderr2(const char *full_path)
{
- int newfd = open(full_path, O_WRONLY | O_CREAT | O_APPEND, 0644);
+ int flags = O_WRONLY | O_CREAT | O_APPEND;
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+#ifdef O_NOFOLLOW
+ flags |= O_NOFOLLOW;
+#endif
+ int newfd = open(full_path, flags, 0644);
if (newfd == -1)
{
LSAPI_perror_r(NULL, "Failed to open custom stderr log", full_path);
@@ -3929,10 +4341,15 @@ static int lsapi_reopen_stderr2(const char *full_path)
}
if (newfd != 2)
{
- dup2(newfd, 2);
+ if (dup2(newfd, 2) == -1)
+ {
+ close(newfd);
+ return -1;
+ }
close(newfd);
- dup2(2, 1);
}
+ if (dup2(2, 1) == -1)
+ return -1;
if (s_stderr_log_path && full_path != s_stderr_log_path)
{
free(s_stderr_log_path);
@@ -4092,7 +4509,14 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
if ( lsapi_initSuEXEC() == -1 )
return -1;
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
- lsapi_initLVE();
+ if (lsapi_initLVE() == -1)
+ {
+ /* Some historical callers ignored this function's return value.
+ * Stop the accept loop as well so configured LVE enforcement can
+ * never degrade silently. */
+ g_running = 0;
+ return -1;
+ }
#endif
}
unset_lsapi_envs();
diff --git a/sapi/litespeed/lsapilib.h b/sapi/litespeed/lsapilib.h
index 58850eadb17..757d53177b5 100644
--- a/sapi/litespeed/lsapilib.h
+++ b/sapi/litespeed/lsapilib.h
@@ -320,7 +320,11 @@ static inline int LSAPI_ReqBodyGetChar(void)
{ return LSAPI_ReqBodyGetChar_r( &g_req ); }
static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF )
-{ return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF ); }
+{
+ if (len <= 0)
+ return -1;
+ return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, (size_t)len, getLF );
+}
@@ -328,7 +332,11 @@ static inline int LSAPI_FinalizeRespHeaders(void)
{ return LSAPI_FinalizeRespHeaders_r( &g_req ); }
static inline ssize_t LSAPI_Write( const char * pBuf, ssize_t len )
-{ return LSAPI_Write_r( &g_req, pBuf, len ); }
+{
+ if (len < 0)
+ return -1;
+ return LSAPI_Write_r( &g_req, pBuf, (size_t)len );
+}
static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size )
{
@@ -336,7 +344,11 @@ static inline ssize_t LSAPI_sendfile( int fdIn, off_t* off, size_t size )
}
static inline ssize_t LSAPI_Write_Stderr( const char * pBuf, ssize_t len )
-{ return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); }
+{
+ if (len < 0)
+ return -1;
+ return LSAPI_Write_Stderr_r( &g_req, pBuf, (size_t)len );
+}
static inline int LSAPI_Flush(void)
{ return LSAPI_Flush_r( &g_req ); }
@@ -392,6 +404,14 @@ int LSAPI_Set_Restored_Parent_Pid(int pid);
typedef void (*LSAPI_On_Timer_pf)(int *forked_child_pid);
void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf);
+/* Called around the fork() of each worker by the prefork server
+ * (LSAPI_Prefork_Accept_r): before in the parent, then after_parent in the
+ * parent (also when fork() fails) or after_child in the new worker. */
+typedef void (*LSAPI_Fork_Hook_pf)(void);
+void LSAPI_Set_Fork_Hooks(LSAPI_Fork_Hook_pf before,
+ LSAPI_Fork_Hook_pf after_parent,
+ LSAPI_Fork_Hook_pf after_child);
+
int LSAPI_Inc_Req_Processed(int cnt);
int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq);