summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Roche <xroche@users.noreply.github.com>2014-05-28 18:58:59 +0000
committerXavier Roche <xroche@users.noreply.github.com>2014-05-28 18:58:59 +0000
commit5e248cc4e37a388aed8b14c88be92c2805de0256 (patch)
tree1b1e86802f4456188b688102735e3cd9cd256683
parent473baf7f954e8599a024c35f223e355bfee7a3a0 (diff)
Rewrite string template formatting to be format-injection proof.
-rw-r--r--src/htstools.c68
-rw-r--r--src/htstools.h2
2 files changed, 61 insertions, 9 deletions
diff --git a/src/htstools.c b/src/htstools.c
index ae68e60..dc538ef 100644
--- a/src/htstools.c
+++ b/src/htstools.c
@@ -757,10 +757,42 @@ static int sortTopIndexFnc(const void *a_, const void *b_) {
return cmp;
}
+typedef struct hts_template_format_buf {
+ FILE *fp;
+ char *buffer;
+ size_t size;
+ size_t offset;
+} hts_template_format_buf;
+
// note: upstream arg list MUST be NULL-terminated for safety
// returns a negative value upon error
-static int hts_template_formatv(FILE *const fp, const char *format, va_list args) {
- if (fp != NULL && format != NULL) {
+static int hts_template_formatv(hts_template_format_buf *buf,
+ const char *format, va_list args) {
+#undef FPUTC
+#undef FPUTS
+#define FPUTC(C) do { \
+ if (buf->fp != NULL) { \
+ if (fputc(C, buf->fp) < 0) { \
+ return -1; \
+ } \
+ } else { \
+ assertf(buf->buffer != NULL); \
+ if (buf->offset + 1 < buf->size) { \
+ buf->buffer[buf->offset++] = (C); \
+ } else { \
+ return -1; \
+ } \
+ } \
+} while(0)
+#define FPUTS(S) do { \
+ size_t i; \
+ const char *const str_ = (S); \
+ for(i = 0 ; str_[i] != '\0' ; i++) { \
+ FPUTC(str_[i]); \
+ } \
+} while(0)
+
+ if (buf != NULL && format != NULL) {
const char *arg_expanded[32];
size_t i, nbArgs, posArgs;
/* Expand internal code args. */
@@ -776,39 +808,57 @@ static int hts_template_formatv(FILE *const fp, const char *format, va_list args
const unsigned char cFormat = format[++i];
switch(cFormat) {
case '%':
- fputc('%', fp);
+ FPUTC('%');
break;
case 's':
if (posArgs < nbArgs) {
assertf(arg_expanded[posArgs] != NULL);
- fputs(arg_expanded[posArgs], fp);
+ FPUTS(arg_expanded[posArgs]);
posArgs++;
} else {
- fputs("???", fp); /* error (args overflow) */
+ FPUTS("???"); /* error (args overflow) */
}
break;
default: /* ignored */
- fputc('%', fp);
- fputc(cFormat, fp);
+ FPUTC('%');
+ FPUTC(cFormat);
break;
}
} else {
- fputc(c, fp);
+ FPUTC(c);
}
}
return 1;
} else {
return -1;
}
+#undef FPUTC
+#undef FPUTS
}
// note: upstream arg list MUST be NULL-terminated for safety
// returns a negative value upon error
int hts_template_format(FILE *const out, const char *format, ...) {
int success;
+ hts_template_format_buf buf = { NULL, NULL, 0, 0 };
+ va_list args;
+ buf.fp = out;
+ va_start(args, format);
+ success = hts_template_formatv(&buf, format, args);
+ va_end(args);
+ return success;
+}
+
+// note: upstream arg list MUST be NULL-terminated for safety
+// returns a negative value upon error
+int hts_template_format_str(char *buffer, size_t size, const char *format, ...) {
+ int success;
+ hts_template_format_buf buf = { NULL, NULL, 0, 0 };
va_list args;
+ buf.buffer = buffer;
+ buf.size = size;
va_start(args, format);
- success = hts_template_formatv(out, format, args);
+ success = hts_template_formatv(&buf, format, args);
va_end(args);
return success;
}
diff --git a/src/htstools.h b/src/htstools.h
index 5542682..7198fef 100644
--- a/src/htstools.h
+++ b/src/htstools.h
@@ -60,7 +60,9 @@ void longfile_to_83(int mode, char *n83, char *save);
HTS_INLINE int __rech_tageq(const char *adr, const char *s);
HTS_INLINE int __rech_tageqbegdigits(const char *adr, const char *s);
HTS_INLINE int rech_tageq_all(const char *adr, const char *s);
+
int hts_template_format(FILE *const out, const char *format, ...);
+int hts_template_format_str(char *buffer, size_t size, const char *format, ...);
#define rech_tageq(adr,s) \
( \