About *printf %n fortifications
Gwenole Beauchesne
gbeauchesne@mandriva.com
Fri Feb 24 18:01:00 GMT 2006
Hi,
Why a printf() with %n in the format string would require this string to
be non-writable? (debug/tst-chk1.c, stdio-common/vfprintf.c)
See the attached test case (-O2 -D_FORTIFY_SOURCE=2)
char fmt[] = "%s%n\n";
printf(fmt, "bar", &count);
looks valid to me, but causes an abort() with
*** %n in writable segment detected ***
The check probably meant to be against the %n argument itself.
The following patch fixes this but I have not updated tst-chk1.c yet.
WDYT?
2006-02-24 Gwenole Beauchesne <gbeauchesne@mandriva.com>
* stdio-common/vfprintf.c (vfprintf): Fix fortify checks for %n
specifier.
--- glibc-2.3.6/stdio-common/vfprintf.c.vfprintf-fortify-form-number 2004-11-25 17:40:23.000000000 +0100
+++ glibc-2.3.6/stdio-common/vfprintf.c 2006-02-24 16:46:57.000000000 +0100
@@ -882,44 +882,46 @@ vfprintf (FILE *s, const CHAR_T *format,
/* NOTREACHED */ \
\
LABEL (form_number): \
- if (s->_flags2 & _IO_FLAGS2_FORTIFY) \
- { \
- if (! readonly_format) \
- { \
- extern int __readonly_area (const void *, size_t) \
- attribute_hidden; \
- readonly_format \
- = __readonly_area (format, ((STR_LEN (format) + 1) \
- * sizeof (CHAR_T))); \
- } \
- if (readonly_format < 0) \
- __libc_fatal ("*** %n in writable segment detected ***\n"); \
- } \
- /* Answer the count of characters written. */ \
- if (fspec == NULL) \
- { \
- if (is_longlong) \
- *(long long int *) va_arg (ap, void *) = done; \
- else if (is_long_num) \
- *(long int *) va_arg (ap, void *) = done; \
- else if (is_char) \
- *(char *) va_arg (ap, void *) = done; \
- else if (!is_short) \
- *(int *) va_arg (ap, void *) = done; \
- else \
- *(short int *) va_arg (ap, void *) = done; \
- } \
- else \
+ /* Pointer to signed integer. */ \
+ { \
+ const void *ptr; \
+ if (fspec == NULL) \
+ ptr = va_arg (ap, void *); \
+ else \
+ ptr = args_value[fspec->data_arg].pa_pointer; \
+ \
+ if (s->_flags2 & _IO_FLAGS2_FORTIFY) \
+ { \
+ extern int __readonly_area (const void *, size_t) \
+ attribute_hidden; \
+ \
+ int objsize; \
+ if (is_longlong) \
+ objsize = sizeof(long long int); \
+ else if (is_long_num) \
+ objsize = sizeof(long int); \
+ else if (is_char) \
+ objsize = 1; \
+ else if (!is_short) \
+ objsize = sizeof(int); \
+ else \
+ objsize = sizeof(short); \
+ if (__readonly_area (ptr, objsize) > 0) \
+ __libc_fatal ("*** %n into read-only segment detected ***\n"); \
+ } \
+ \
+ /* Answer the count of characters written. */ \
if (is_longlong) \
- *(long long int *) args_value[fspec->data_arg].pa_pointer = done; \
+ *(long long int *) ptr = done; \
else if (is_long_num) \
- *(long int *) args_value[fspec->data_arg].pa_pointer = done; \
+ *(long int *) ptr = done; \
else if (is_char) \
- *(char *) args_value[fspec->data_arg].pa_pointer = done; \
+ *(char *) ptr = done; \
else if (!is_short) \
- *(int *) args_value[fspec->data_arg].pa_pointer = done; \
+ *(int *) ptr = done; \
else \
- *(short int *) args_value[fspec->data_arg].pa_pointer = done; \
+ *(short int *) ptr = done; \
+ } \
break; \
\
LABEL (form_strerror): \
-------------- next part --------------
#include <stdio.h>
static const int const_count = 0;
int main(void)
{
char buf[10];
char fmt[] = "%s%n\n";
int count;
printf("%s%n\n", "foo", &count);
if (count != 3)
return 1;
printf(fmt, "bar", &count);
if (count != 3)
return 2;
printf("%s%n\n", "dog", &const_count);
if (const_count != 0)
return 3;
return 0;
}
More information about the Libc-alpha
mailing list