Skip to content

Commit

Permalink
Security: update to LiteSpeed SAPI v7.7 to address an buffer overflow…
Browse files Browse the repository at this point in the history
…, and some log message tunings.
  • Loading branch information
George Wang committed Jul 23, 2020
1 parent c68d48d commit c39f5fe
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 14 deletions.
6 changes: 3 additions & 3 deletions sapi/litespeed/lsapi_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
#include "lscriu.c"
#endif

#define SAPI_LSAPI_MAX_HEADER_LENGTH 2048
#define SAPI_LSAPI_MAX_HEADER_LENGTH LSAPI_RESP_HTTP_HEADER_MAX

/* Key for each cache entry is dirname(PATH_TRANSLATED).
*
Expand Down Expand Up @@ -621,7 +621,7 @@ static int sapi_lsapi_activate()
static sapi_module_struct lsapi_sapi_module =
{
"litespeed",
"LiteSpeed V7.6",
"LiteSpeed V7.7",

php_lsapi_startup, /* startup */
php_module_shutdown_wrapper, /* shutdown */
Expand Down Expand Up @@ -1768,7 +1768,7 @@ PHP_FUNCTION(litespeed_response_headers)
if ( h->header_len > 0 ) {
p = strchr( h->header, ':' );
len = p - h->header;
if (( p )&&( len > 0 )) {
if (p && len > 0 && len < LSAPI_RESP_HTTP_HEADER_MAX) {
memmove( headerBuf, h->header, len );
while( len > 0 && (isspace( headerBuf[len-1])) ) {
--len;
Expand Down
233 changes: 223 additions & 10 deletions sapi/litespeed/lsapilib.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ enum
LSAPI_STATE_ACCEPTING,
};

typedef struct _lsapi_child_status
typedef struct lsapi_child_status
{
int m_pid;
long m_tmStart;
Expand Down Expand Up @@ -790,10 +790,10 @@ static int lsapi_load_lve_lib(void)
int uid = getuid();
if ( uid )
{
setreuid( s_uid, uid );
if (setreuid( s_uid, uid )) {};
if ( !(*fp_lve_is_available)() )
s_enable_lve = 0;
setreuid( uid, s_uid );
if (setreuid( uid, s_uid )) {};
}
}
}
Expand Down Expand Up @@ -898,7 +898,7 @@ static int LSAPI_perror_r( LSAPI_Request * pReq, const char * pErr1, const char
if ( pReq )
LSAPI_Write_Stderr_r( pReq, achError, n );
else
write( STDERR_FILENO, achError, n );
if (write( STDERR_FILENO, achError, n )) {};
return 0;
}

Expand Down Expand Up @@ -2775,6 +2775,9 @@ int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
g_prefork_server->m_iMaxIdleChildren = 1;
g_prefork_server->m_iChildrenMaxIdleTime = 300;
g_prefork_server->m_iMaxReqProcessTime = 3600;

setsid();

return 0;
}

Expand Down Expand Up @@ -2830,6 +2833,11 @@ static lsapi_child_status * find_child_status( int pid )
{
if ( pStatus->m_pid == pid )
{
if (pid == 0)
{
memset(pStatus, 0, sizeof( *pStatus ) );
pStatus->m_pid = -1;
}
if ( pStatus + 1 > g_prefork_server->m_pChildrenStatusCur )
g_prefork_server->m_pChildrenStatusCur = pStatus + 1;
return pStatus;
Expand Down Expand Up @@ -2928,7 +2936,10 @@ static void lsapi_sigchild( int signal )
static int lsapi_init_children_status(void)
{
int size = 4096;
int max_children = g_prefork_server->m_iMaxChildren
int max_children;
if (g_prefork_server->m_pChildrenStatus)
return 0;
max_children = g_prefork_server->m_iMaxChildren
+ g_prefork_server->m_iExtraChildren;

char * pBuf;
Expand All @@ -2949,6 +2960,8 @@ static int lsapi_init_children_status(void)
s_accepting_workers = s_busy_workers + 1;
s_global_counter = s_accepting_workers + 1;
s_avail_pages = (size_t *)(s_global_counter + 1);

setsid();
return 0;
}

Expand Down Expand Up @@ -3118,8 +3131,6 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,

lsapi_init_children_status();

setsid();

act.sa_flags = 0;
act.sa_handler = lsapi_sigchild;
sigemptyset(&(act.sa_mask));
Expand All @@ -3141,7 +3152,7 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
perror( "Can't set signals" );
return -1;
}
s_stop = 0;

while( !s_stop )
{
if (s_proc_group_timer_cb != NULL) {
Expand Down Expand Up @@ -3219,8 +3230,6 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
{
wait_secs = 0;
child_status = find_child_status( 0 );
if ( child_status )
memset( child_status, 0, sizeof( *child_status ) );

sigemptyset( &mask );
sigaddset( &mask, SIGCHLD );
Expand Down Expand Up @@ -3312,6 +3321,210 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
}


static struct sigaction old_term, old_quit, old_int,
old_usr1, old_child;


int LSAPI_Postfork_Child(LSAPI_Request * pReq)
{
int max_children = g_prefork_server->m_iMaxChildren;
s_pid = getpid();
__sync_lock_test_and_set(&pReq->child_status->m_pid, s_pid);
s_worker_status = pReq->child_status;

setsid();
g_prefork_server = NULL;
s_ppid = getppid();
s_req_processed = 0;
s_proc_group_timer_cb = NULL;

if (pthread_atfork_func)
(*pthread_atfork_func)(NULL, NULL, set_skip_write);

__sync_lock_test_and_set(&s_worker_status->m_state,
LSAPI_STATE_CONNECTED);
if (s_busy_workers)
__sync_add_and_fetch(s_busy_workers, 1);
lsapi_set_nblock( pReq->m_fd, 0 );
//keep it open if busy_count is used.
if (s_busy_workers
&& *s_busy_workers > (max_children >> 1))
s_keepListener = 1;
if ((s_uid == 0 || !s_keepListener || !is_enough_free_mem())
&& pReq->m_fdListen != -1 )
{
close(pReq->m_fdListen);
pReq->m_fdListen = -1;
}

//init_conn_key( pReq->m_fd );
lsapi_notify_pid(pReq->m_fd);
s_notified_pid = 1;
//if ( s_accept_notify )
// return notify_req_received( pReq->m_fd );
return 0;
}


int LSAPI_Postfork_Parent(LSAPI_Request * pReq)
{
++g_prefork_server->m_iCurChildren;
if (pReq->child_status)
{
time_t curTime = time( NULL );
pReq->child_status->m_tmWaitBegin = curTime;
pReq->child_status->m_tmStart = curTime;
}
close(pReq->m_fd);
pReq->m_fd = -1;
return 0;
}


int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq)
{
time_t lastTime = 0;
time_t curTime = 0;
fd_set readfds;
struct timeval timeout;
int wait_secs = 0;
int ret = 0;

lsapi_prefork_server * pServer = g_prefork_server;

struct sigaction act;

lsapi_init_children_status();

act.sa_flags = 0;
act.sa_handler = lsapi_sigchild;
sigemptyset(&(act.sa_mask));
if (sigaction(SIGCHLD, &act, &old_child))
{
perror( "Can't set signal handler for SIGCHILD" );
return -1;
}

/* Set up handler to kill children upon exit */
act.sa_flags = 0;
act.sa_handler = lsapi_cleanup;
sigemptyset(&(act.sa_mask));
if (sigaction(SIGTERM, &act, &old_term) ||
sigaction(SIGINT, &act, &old_int ) ||
sigaction(SIGUSR1, &act, &old_usr1) ||
sigaction(SIGQUIT, &act, &old_quit))
{
perror( "Can't set signals" );
return -1;
}
s_stop = 0;
pReq->m_reqState = 0;

while(!s_stop)
{
if (s_proc_group_timer_cb != NULL) {
s_proc_group_timer_cb(&s_ignore_pid);
}

curTime = time(NULL);
if (curTime != lastTime)
{
lastTime = curTime;
if (lsapi_parent_dead())
break;
lsapi_check_child_status(curTime);
if (pServer->m_iServerMaxIdle)
{
if (pServer->m_iCurChildren <= 0)
{
++wait_secs;
if ( wait_secs > pServer->m_iServerMaxIdle )
return -1;
}
else
wait_secs = 0;
}
}

#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
*s_avail_pages = sysconf(_SC_AVPHYS_PAGES);
// lsapi_log("Memory total: %zd, free: %zd, free %%%zd\n",
// s_total_pages, *s_avail_pages, *s_avail_pages * 100 / s_total_pages);

#endif
FD_ZERO(&readfds);
FD_SET(pServer->m_fd, &readfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout);
if (ret == 1 )
{
int accepting = 0;
if (s_accepting_workers)
accepting = __sync_add_and_fetch(s_accepting_workers, 0);

if (pServer->m_iCurChildren > 0
&& accepting > 0)
{
usleep( 400);
while(accepting-- > 0)
sched_yield();
continue;
}
}
else if (ret == -1)
{
if (errno == EINTR)
continue;
/* perror( "select()" ); */
break;
}
else
{
continue;
}

if (pServer->m_iCurChildren >=
pServer->m_iMaxChildren + pServer->m_iExtraChildren)
{
lsapi_log("Reached max children process limit: %d, extra: %d,"
" current: %d, busy: %d, please increase LSAPI_CHILDREN.\n",
pServer->m_iMaxChildren, pServer->m_iExtraChildren,
pServer->m_iCurChildren,
s_busy_workers ? *s_busy_workers : -1);
usleep(100000);
continue;
}

pReq->m_fd = lsapi_accept(pServer->m_fd);
if (pReq->m_fd != -1)
{
wait_secs = 0;
pReq->child_status = find_child_status(0);

ret = 0;
break;
}
else
{
if ((errno == EINTR) || (errno == EAGAIN))
continue;
perror( "accept() failed" );
ret = -1;
break;
}
}

sigaction(SIGCHLD, &old_child, 0);
sigaction(SIGTERM, &old_term, 0);
sigaction(SIGQUIT, &old_quit, 0);
sigaction(SIGINT, &old_int, 0);
sigaction(SIGUSR1, &old_usr1, 0);

return ret;
}


void lsapi_perror( const char * pMessage, int err_no )
{
lsapi_log("%s, errno: %d (%s)\n", pMessage, err_no,
Expand Down
9 changes: 8 additions & 1 deletion sapi/litespeed/lsapilib.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct LSAPI_key_value_pair
int valLen;
};


struct lsapi_child_status;
#define LSAPI_MAX_RESP_HEADERS 1000

typedef struct lsapi_request
Expand All @@ -91,6 +91,7 @@ typedef struct lsapi_request
char * m_pRespHeaderBuf;
char * m_pRespHeaderBufEnd;
char * m_pRespHeaderBufPos;
struct lsapi_child_status * child_status;


struct iovec * m_pIovec;
Expand Down Expand Up @@ -395,6 +396,12 @@ void LSAPI_Register_Pgrp_Timer_Callback(LSAPI_On_Timer_pf);

int LSAPI_Inc_Req_Processed(int cnt);

int LSAPI_Accept_Before_Fork(LSAPI_Request * pReq);

int LSAPI_Postfork_Child(LSAPI_Request * pReq);

int LSAPI_Postfork_Parent(LSAPI_Request * pReq);

#define LSAPI_LOG_LEVEL_BITS 0xff
#define LSAPI_LOG_FLAG_NONE 0
#define LSAPI_LOG_FLAG_DEBUG 1
Expand Down

0 comments on commit c39f5fe

Please sign in to comment.