fakesnprintf.h
上传用户:lukesailor
上传日期:2007-01-04
资源大小:27k
文件大小:3k
- /* $Id: fakesnprintf.h,v 1.1 1997/09/09 18:52:32 agulbra Exp $ */
- /*
- * Not sure why the vendors supposedly selling robust Unix versions
- * have yet to implement the size-restricted variants of the stdio
- * formatting routines. Their lack is the single biggest cause of
- * buffer-overrun security problems.
- *
- * This code implements a secure replacement if your O/S:
- *
- * a. Doesn't have a real [v]snprintf()
- * b. Does have an mprotect(2) call that can be pointed
- * at arbitrary pages.
- *
- * It doesn't implement full [v]snprintf() semantics, just
- * sufficient to keep troll-ftpd happy. For example, if
- * an overrun occurs, the function will just return -1.
- *
- * The code is known to work on:
- *
- * Solaris 2.4
- * Irix 5.3
- * Ultrix 4.4 (with -DHAVE_GETPAGESIZE)
- *
- * The code is known NOT to work on:
- *
- * HP/UX 9.01
- * AIX 3.2.5
- */
- #ifndef FAKESNPRINTF_H
- #define FAKESNPRINTF_H
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <malloc.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/mman.h>
- #include <unistd.h>
- #include <signal.h>
- #include <errno.h>
- /*
- ** Insist on at least this much space for the format area.
- */
- #define SPRINTF_MINAREA 1024
- static int sys_pagesize(void)
- {
- #if defined(_SC_PAGESIZE)
- return (int)sysconf(_SC_PAGESIZE);
- #else
- #if defined(_SC_PAGE_SIZE)
- return (int)sysconf(_SC_PAGE_SIZE);
- #else
- #if defined(HAVE_GETPAGESIZE)
- return getpagesize();
- #else
- #error Need to configure ftpd_getpagesize() in fake-snprintf.c
- #endif
- #endif
- #endif
- }
- static char *snprintf_area = 0;
- static int snprintf_areasize = 0;
- static void snprintf_init(void)
- {
- int pagesize, allocsize;
- char *area;
- unsigned long addr;
- snprintf_areasize = pagesize = sys_pagesize();
- if(snprintf_areasize < SPRINTF_MINAREA)
- {
- if(SPRINTF_MINAREA % pagesize)
- snprintf_areasize = pagesize *
- (SPRINTF_MINAREA/pagesize + 1);
- else
- snprintf_areasize = SPRINTF_MINAREA;
- }
- allocsize = snprintf_areasize + pagesize*2;
- area = malloc(allocsize);
- if(!area)
- {
- printf("421 Out of memory in vsnprintfrn");
- fflush(stdout);
- exit(6);
- }
- addr = (unsigned long)area;
- if(addr % pagesize)
- {
- int offset = pagesize - (addr % pagesize);
- addr += offset;
- area = (char *)addr;
- }
- if(mprotect((caddr_t)area + snprintf_areasize, pagesize, PROT_READ) < 0)
- {
- printf("421 Mprotect() failed -- %srn", strerror(errno));
- exit(6);
- }
- snprintf_area = area;
- }
- static void snprintf_catch(int sig)
- {
- printf("421 Buffer overrun detectedrn");
- exit(sig);
- }
- int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
- {
- int len, lim;
- void (*disp)(int);
- if(size <= 0)
- return -1;
- buf[0] = 0;
- /*
- ** Minor optimization saves setting up signal handling
- */
- if(!strchr(fmt, '%') && (len = strlen(fmt)) < (int)size-1)
- {
- strcpy(buf, fmt);
- return len;
- }
- if(!snprintf_area)
- snprintf_init();
- disp = signal(SIGSEGV, snprintf_catch);
- len = vsprintf(snprintf_area, fmt, ap);
- signal(SIGSEGV, disp);
- if(len < 0)
- return len;
- lim = len;
- if(lim > (int)size - 1)
- lim = size - 1;
-
- snprintf_area[lim] = 0;
- strcpy(buf, snprintf_area);
- return len;
- }
- int snprintf(char *buf, size_t size, const char *fmt, ...)
- {
- int len;
- va_list ap;
- va_start(ap, fmt);
- len = vsnprintf(buf, size, fmt, ap);
- va_end(ap);
- return len;
- }
- #endif /* FAKESNPRINTF_H */