mirror of
https://github.com/troglobit/finit.git
synced 2026-11-10 16:31:21 +00:00
Fix Coverty CID #96211: String not NUL terminated.
When receiving a start/stop/reload/restart request from initctl we must make sure to validate and NUL terminate the job ID. The `read()` API does not NUL terminate strings for us and we cannot rely on `initctl` or any other external API user to do so for us. This patch improves error and boundary checking. - Use memcpy() + hard termination instead. - Fix use of strchr() on possibly non-NUL terminated string. Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
ee6d524bc8
commit
70f4d99922
1 file changed
+47
-20
@@ -22,6 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -35,19 +36,47 @@
|
|||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "service.h"
|
#include "service.h"
|
||||||
|
|
||||||
|
#include "libite/lite.h"
|
||||||
#include "libuev/uev.h"
|
#include "libuev/uev.h"
|
||||||
|
|
||||||
uev_t api_watcher;
|
uev_t api_watcher;
|
||||||
|
|
||||||
|
/* Make sure the job id is NUL terminated and on the form SVC:ID. */
|
||||||
|
static char *sanitize_jobid(char *jobid, size_t len)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
static char buf[42];
|
||||||
|
|
||||||
static svc_t *convert_jobid(char *jobid)
|
while (isdigit(jobid[i]) && i < len)
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (jobid[i++] == ':') {
|
||||||
|
while (isdigit(jobid[i]) && i < len)
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i + 1 < sizeof(buf)) {
|
||||||
|
memcpy(buf, jobid, i);
|
||||||
|
buf[i + 1] = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static svc_t *convert_jobid(int noid, char *jobid, size_t len)
|
||||||
{
|
{
|
||||||
int job, id = 1;
|
int job, id = 1;
|
||||||
char *token;
|
char *token, *ptr;
|
||||||
|
|
||||||
|
jobid = sanitize_jobid(jobid, len);
|
||||||
if (!jobid)
|
if (!jobid)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (noid && (ptr = strchr(jobid, ':')))
|
||||||
|
ptr = 0;
|
||||||
|
|
||||||
token = strtok(jobid, ":");
|
token = strtok(jobid, ":");
|
||||||
if (!token) {
|
if (!token) {
|
||||||
job = atoi(jobid);
|
job = atoi(jobid);
|
||||||
@@ -62,35 +91,31 @@ static svc_t *convert_jobid(char *jobid)
|
|||||||
return svc_find_by_jobid(job, id);
|
return svc_find_by_jobid(job, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_start(char *jobid)
|
static int do_start(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
return service_start(convert_jobid(jobid));
|
return service_start(convert_jobid(0, buf, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_stop(char *jobid)
|
static int do_stop(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
return service_stop(convert_jobid(jobid));
|
return service_stop(convert_jobid(0, buf, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_reload(char *jobid)
|
static int do_reload(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
return service_reload(convert_jobid(jobid));
|
return service_reload(convert_jobid(0, buf, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_restart(char *jobid)
|
static int do_restart(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
return service_restart(convert_jobid(jobid));
|
return service_restart(convert_jobid(0, buf, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_query_inetd(char *buf, size_t len)
|
static int do_query_inetd(char *buf, size_t len)
|
||||||
{
|
{
|
||||||
char *ptr = strchr(buf, ':');
|
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
if (ptr)
|
svc = convert_jobid(1, buf, len);
|
||||||
ptr = 0;
|
|
||||||
|
|
||||||
svc = convert_jobid(buf);
|
|
||||||
if (!svc || !svc_is_inetd(svc)) {
|
if (!svc || !svc_is_inetd(svc)) {
|
||||||
_e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", buf);
|
_e("Cannot %s svc %s ...", !svc ? "find" : "query, not an inetd", buf);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -106,8 +131,10 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
ssize_t len = read(sd, &rq, sizeof(rq));
|
ssize_t len;
|
||||||
|
|
||||||
|
memset(&rq, 0, sizeof(rq));
|
||||||
|
len = read(sd, &rq, sizeof(rq));
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
if (-1 == len) {
|
if (-1 == len) {
|
||||||
if (EINTR == errno)
|
if (EINTR == errno)
|
||||||
@@ -169,19 +196,19 @@ static void cb(uev_t *w, void *UNUSED(arg), int UNUSED(events))
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_START_SVC:
|
case INIT_CMD_START_SVC:
|
||||||
result = do_start(rq.data);
|
result = do_start(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_STOP_SVC:
|
case INIT_CMD_STOP_SVC:
|
||||||
result = do_stop(rq.data);
|
result = do_stop(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RELOAD_SVC:
|
case INIT_CMD_RELOAD_SVC:
|
||||||
result = do_reload(rq.data);
|
result = do_reload(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_RESTART_SVC:
|
case INIT_CMD_RESTART_SVC:
|
||||||
result = do_restart(rq.data);
|
result = do_restart(rq.data, sizeof(rq.data));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INIT_CMD_QUERY_INETD:
|
case INIT_CMD_QUERY_INETD:
|
||||||
|
|||||||
Reference in new issue
Block a user