Skip to content

Commit

Permalink
Add vasprintf/asprintf
Browse files Browse the repository at this point in the history
The only hardening being done here is to set the char** parameter to thos
functions to NULL in case of an error, to prevent it from being used should
people forget to check return values. This is already done on some BSD, as well
as in Rocky Linux.
  • Loading branch information
jvoisin committed May 24, 2024
1 parent 92c611a commit 3d33925
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 3 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ At this point, the program will safely crash.

- `FD_CLR`
- `FD_SET`
- `asprintf`
- `bcopy`
- `bzero`
- `calloc`
Expand Down Expand Up @@ -121,6 +122,7 @@ At this point, the program will safely crash.
- `umask`
- `vfprintf`
- `vprintf`
- `vasprintf`
- `vsnprintf`
- `vsprintf`
- `wcrtomb`
Expand Down
40 changes: 40 additions & 0 deletions include/stdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,26 @@ _FORTIFY_FN(vprintf) int vprintf(const char *__f, __builtin_va_list __v)
return __orig_vprintf(__f, __v);
#endif
}

#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#if __has_builtin(__builtin_vasprintf)
__diagnose_as_builtin(__builtin_vasprintf, 1, 2, 3)
#endif
_FORTIFY_FN(vasprintf) int vasprintf(char **restrict strp, const char *restrict fmt, __builtin_va_list ap)
{
#if __has_builtin(__builtin___vasprintf_chk) && USE_NATIVE_CHK
return __builtin___vasprintf_chk(_FORTIFY_SOURCE, strp, fmt, ap);
#else
int ret = __orig_vasprintf(strp, fmt, ap);
if (ret < 0)
*strp = NULL;
return ret;
#endif
}


#endif // defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
//
#endif // __clang__


Expand Down Expand Up @@ -312,6 +332,26 @@ _FORTIFY_FN(fprintf) int fprintf(FILE *__s, const char *__f, ...)
#endif
}

#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
#undef asprintf
__fh_access(read_only, 2)
__fh_format(printf, 2, 0)
#if __has_builtin(__builtin_asprintf)
__diagnose_as_builtin(__builtin_asprintf, 2, 3)
#endif
_FORTIFY_FN(asprintf) int asprintf(char **restrict strp, const char *restrict fmt, ...)
{
#if __has_builtin(__builtin___asprintf_chk) && USE_NATIVE_CHK
return __builtin___asprintf_chk(_FORTIFY_SOURCE, strp, fmt, __builtin_va_arg_pack());
#else
int ret = __orig_asprintf(strp, fmt, __builtin_va_arg_pack());
if (ret<0)
*strp = NULL;
return ret;
#endif
}
#endif

#pragma GCC diagnostic pop
#endif /* __has_builtin(__builtin_va_arg_pack) */

Expand Down
8 changes: 5 additions & 3 deletions tests/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
CFLAGS+=-I../include/ -D_FORTIFY_SOURCE=3 -static -O2 -DPEDANTIC_CHECKS
CFLAGS+=-I../include/ -D_FORTIFY_SOURCE=3 -static -O2 -DPEDANTIC_CHECKS -Wno-format

COMPTIME_TARGETS= \
test_memcpy_overwrite_under \
Expand All @@ -12,6 +12,7 @@ RUNTIME_TARGETS= \
test_FD_SET_negative \
test_FD_ISSET_SETSIZE \
test_FD_ISSET_negative \
test_asprintf \
test_bcopy_dynamic_read \
test_bcopy_dynamic_write \
test_bcopy_static_read \
Expand Down Expand Up @@ -126,11 +127,12 @@ RUNTIME_TARGETS= \
test_ttyname_r_dynamic \
test_ttyname_r_static \
test_umask \
test_vasprintf \
test_vfprintf \
test_vprintf \
test_vsnprintf_dynamic \
test_vsnprintf_static \
test_vsprintf \
test_vfprintf \
test_vprintf \
test_wcscat_static_write \
test_wcscpy_static_write \
test_wcsncat_static_write \
Expand Down
20 changes: 20 additions & 0 deletions tests/test_asprintf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#define _GNU_SOURCE
#include "common.h"

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char** argv) {
char* buf;
asprintf(&buf, "total: %d+%d=%d", 1, 2, 3);
puts(buf);
free(buf);

#ifndef __clang__
asprintf(&buf, "total: %", 1);
assert(buf == NULL);
#endif

return 0;
}
36 changes: 36 additions & 0 deletions tests/test_vasprintf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#define _GNU_SOURCE
#include "common.h"

#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>

void test(const char *fmt, ...)
{
char* buf;
va_list args;
va_start(args, fmt);
vasprintf(&buf, fmt, args);
va_end(args);
puts(buf);
free(buf);
}

void test2(const char *fmt, ...)
{
char* buf;
va_list args;
va_start(args, fmt);
vasprintf(&buf, fmt, args);
va_end(args);
assert(buf == NULL);
}

int main(int argc, char** argv) {
test("Total: %d+%d=%d", 1, 2, 3);
#ifndef __clang__
test2("Total: %", 1, 2, 3);
#endif
return 0;
}

0 comments on commit 3d33925

Please sign in to comment.