summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLouis Burda <quent.burda@gmail.com>2023-06-18 17:34:06 +0200
committerLouis Burda <quent.burda@gmail.com>2023-06-18 17:34:06 +0200
commit839d8742c8fe85d6cffd60c4d39853779c5a1e16 (patch)
tree0348aab22e8b71c09bfa50234c3841e03e706c45
parentf1e6447562f8521696af876a0f7c7fe3c0dcd51b (diff)
downloadtmpl-839d8742c8fe85d6cffd60c4d39853779c5a1e16.tar.gz
tmpl-839d8742c8fe85d6cffd60c4d39853779c5a1e16.zip
Read input file-line wise and fix UAF
-rw-r--r--main.c147
-rw-r--r--test10
2 files changed, 69 insertions, 88 deletions
diff --git a/main.c b/main.c
index 73f904b..b5121ab 100644
--- a/main.c
+++ b/main.c
@@ -1,10 +1,10 @@
#define _XOPEN_SOURCE 500
-#include <err.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
#include <stdlib.h>
enum {
@@ -24,9 +24,33 @@ struct var {
struct var *next;
};
-struct var *vars, **vars_end;
+static struct var *vars = NULL;
+static struct var **vars_end = &vars;
-const char *
+static struct block stack[32] = { 0 };
+static int stack_top = 0;
+static size_t lineno = 0;
+
+static void
+die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fputs("tmpl: ", stderr);
+ vfprintf(stderr, fmt, ap);
+ if (*fmt && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ } else {
+ fputc('\n', stderr);
+ }
+ va_end(ap);
+
+ exit(1);
+}
+
+static const char *
getvar(const char *name)
{
struct var *var;
@@ -39,18 +63,18 @@ getvar(const char *name)
return getenv(name);
}
-void
+static void
assign(char *line)
{
char *sep;
struct var *var;
sep = strchr(line, '=');
- if (!sep) err(1, "invalid assign: '%s'", line);
+ if (!sep) die("invalid assign '%s'", line);
*sep = '\0';
var = malloc(sizeof(struct var));
- if (!var) err(1, "malloc");
+ if (!var) die("malloc:");
var->name = line;
var->value = sep + 1;
var->next = NULL;
@@ -59,20 +83,17 @@ assign(char *line)
vars_end = &var->next;
}
-void
+static void
template(char *line)
{
- static struct block stack[32] = { 0 };
- static int stack_top = 0;
- static size_t lineno = 0;
const char *value;
char *open, *close;
- char *sep;
+ char *sep, *dup;
lineno++;
if (!strncmp(line, "#ifdef ", 7)) {
- if (stack_top == 32) errx(1, "too much nesting");
+ if (stack_top == 32) die("too deeply nested");
stack[stack_top].active = 0;
stack[stack_top].type = IFDEF;
if (!stack_top || stack[stack_top-1].active) {
@@ -81,13 +102,13 @@ template(char *line)
}
stack_top++;
} else if (!strncmp(line, "#ifeq ", 6)) {
- if (stack_top == 32) errx(1, "too much nesting");
+ if (stack_top == 32) die("too deeply nested");
stack[stack_top].active = 0;
stack[stack_top].type = IFEQ;
if (!stack_top || stack[stack_top-1].active) {
value = getvar(line + 6);
sep = strchr(line + 6, ' ');
- if (!sep) err(1, "invalid #ifeq: %lu:%s", lineno, line);
+ if (!sep) die("invalid #ifeq\n%lu: %s", lineno, line);
if (!strcmp(value, sep + 1)) {
stack[stack_top].active = 1;
}
@@ -96,31 +117,35 @@ template(char *line)
} else if (!strcmp(line, "#else")) {
if (!stack_top || (stack[stack_top-1].type != IFDEF
&& stack[stack_top-1].type != IFEQ))
- err(1, "invalid #else: %lu:%s", lineno, line);
+ die("invalid #else\n%lu: %s", lineno, line);
stack[stack_top-1].active ^= 1;
stack[stack_top-1].type = ELSE;
} else if (!strcmp(line, "#endif")) {
- if (!stack_top) err(1, "invalid #endif: %lu:%s", lineno, line);
+ if (!stack_top) die("invalid #endif\n%lu: %s", lineno, line);
stack_top--;
} else if (!strncmp(line, "#define ", 8)) {
if (stack_top && !stack[stack_top-1].active)
return;
sep = strchr(line + 8, ' ');
- if (!sep) err(1, "invalid #default: %lu:%s", lineno, line);
+ if (!sep) die("invalid #default\n%lu: %s", lineno, line);
*sep = '=';
- assign(line + 8);
+ dup = strdup(line + 8);
+ if (!dup) die("strdup:");
+ assign(dup);
} else if (!strncmp(line, "#default ", 9)) {
if (stack_top && !stack[stack_top-1].active)
return;
sep = strchr(line + 9, ' ');
- if (!sep) err(1, "invalid #default: %lu:%s", lineno, line);
+ if (!sep) die("invalid #default\n%lu: %s", lineno, line);
*sep = '\0';
value = getvar(line + 9);
if (!value) {
*sep = '=';
- assign(line + 9);
+ dup = strdup(line + 9);
+ if (!dup) die("strdup:");
+ assign(dup);
}
} else if (!strncmp(line, "#-- ", 4)) {
return; /* comment */
@@ -157,76 +182,44 @@ template(char *line)
}
}
-void
-perline(char *contents, int nonempty, void (*process)(char *))
-{
- char *line, *sep, *end;
-
- line = contents;
- do {
- sep = strchr(line, '\n');
- end = sep ? sep : line + strlen(line);
- *end = '\0';
- if (!nonempty || end > line + 1)
- process(line);
- line = end + 1;
- } while (sep);
-}
-
-char *
-readall(const char *path)
+static void
+perline(const char *path, int nonempty, void (*process)(char *))
{
- char buf[BUFSIZ];
- char *contents;
- ssize_t ret;
- size_t len, cap;
- int fd;
-
- fd = open(path, O_RDONLY);
- if (fd < 0) err(1, "open '%s'", path);
-
- cap = BUFSIZ + 1;
- contents = malloc(cap);
- if (!contents) err(1, "malloc");
-
- len = 0;
- while ((ret = read(fd, buf, BUFSIZ)) > 0) {
- if (len + (size_t) ret >= cap) {
- cap *= 2;
- contents = realloc(contents, cap);
- if (!contents) err(1, "realloc");
+ char linebuf[4096];
+ size_t len;
+ FILE *f;
+
+ f = fopen(path, "r");
+ if (!f) die("fopen '%s':", path);
+ while (fgets(linebuf, 4096, f)) {
+ len = strlen(linebuf);
+ if (len && linebuf[len - 1] == '\n') {
+ linebuf[len - 1] = '\0';
+ } else if (len && !feof(f)) {
+ die("fgets '%s': line too long", path);
}
- memcpy(contents + len, buf, (size_t) ret);
- len += (size_t) ret;
+ if (len || !nonempty)
+ process(linebuf);
}
- contents[len] = '\0';
-
- return contents;
+ fclose(f);
}
int
-main(int argc, const char **argv)
+main(int argc, char **argv)
{
- const char **arg;
const char *path;
- char *str, *contents;
-
- vars = NULL;
- vars_end = &vars;
+ char **arg;
if (!argc) return 1;
for (arg = argv + 1; *arg; arg++) {
if (!strcmp(*arg, "-h") || !strcmp(*arg, "--help")) {
- fprintf(stderr, "Usage: tmpl [-c CONFIG].. [-D NAME=VALUE].. FILE..\n");
+ fprintf(stderr, "Usage: tmpl [-c CONFIG].. "
+ "[-D NAME=VALUE].. FILE..\n");
return 1;
} else if (!strcmp(*arg, "-D") || !strcmp(*arg, "--define")) {
- str = strdup(*++arg);
- if (!str) err(1, "strdup");
- assign(str);
+ assign(*++arg);
} else if (!strcmp(*arg, "-c") || !strcmp(*arg, "--config")) {
- contents = readall(*++arg);
- perline(contents, 1, assign);
- free(contents);
+ perline(*++arg, 1, assign);
} else {
break;
}
@@ -234,8 +227,6 @@ main(int argc, const char **argv)
for (; *arg; arg++) {
path = !strcmp(*arg, "-") ? "/dev/stdin" : *arg;
- contents = readall(path);
- perline(contents, 0, template);
- free(contents);
+ perline(path, 0, template);
}
}
diff --git a/test b/test
deleted file mode 100644
index a6b9af5..0000000
--- a/test
+++ /dev/null
@@ -1,10 +0,0 @@
-#default PREFIX /usr/local
-#default BINDIR /bin
-
-#ifdef DEBUG
-yes debug
-#else
-no debug
-#endif
-
-install -m755 "#{TARGET}" -t "#{DESTDIR}#{PREFIX}#{BINDIR}"