From: "Luka Marčetić" <paxcoder@gmail.com>
To: musl@lists.openwall.com
Subject: Re: New daily reports - nothing
Date: Wed, 10 Aug 2011 13:47:17 +0200 [thread overview]
Message-ID: <4E426FC5.7020303@gmail.com> (raw)
In-Reply-To: <20110810013839.GU132@brightrain.aerifal.cx>
[-- Attachment #1: Type: text/plain, Size: 1170 bytes --]
On 08/10/2011 03:38 AM, Rich Felker wrote:
(Thanks for explaining mprotect first of all)
> Especially as you're nearing the deadline, I'd like to ask you to
> please listen when I make recommendations like this. Sure learning
> about mprotect is educational, but in terms of getting stuff done, if
> you'd taken my advice several days (a week now?) back about how to
> check for writes past the end of the buffer, you would have been able
> to spend your time today getting something done rather than wondering
> why mprotect wasn't doing what you wanted....
>
> Rich
The worst thing is, I already do check that: I write '\r' in the last
byte of the buffer, and then call the function saying the buffer is
size-1 long (so it shows if it gets overwritten). It doesn't even make
sense to test for reading/writing beyond size+1, except to test for
implementation lunacy. I have no idea why I did that anymore. I
should've just removed sigset altogether. I didn't need mprotect, nor
wrappers... :-(
P.S. Final buf.c thus won't look like the attached file. In it,
alloc_bounded() is the broken one - a fixed version may appear somewhere
else in the future though.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: buf.c --]
[-- Type: text/x-csrc; name="buf.c", Size: 20092 bytes --]
#include <errno.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "common/common.h"
#include <string.h> //strerror_r
#include <limits.h> //PATH_MAX
#include <stdlib.h> //mbstowcs
#include <stdio.h> //getdelim, snprintf
#include <unistd.h> //confstr, getcwd, gethostname, readlink
#include <iconv.h> //iconv
#include <time.h> //time, gmtime
#include <monetary.h> //strfmon
/*
* Copyright (c) 2011 Luka Marčetić<paxcoder@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*/
/**
** \file
** Tests functions for writing beyond string lenght and errno's they set
** tests: confstr, getcwd, getdelim, gethostname, iconv, mbstowcs, snprintf,
** readlink, strfmon, strftime, wcstombs, ttyname_r, strerror_r
** depends: malloc, sigaction, strlen, mkstemp, fdopen,fclose,fileno, strptime
** iconv_open,iconv_close, free, setjmp, longjmp, open,close,
** mmap,mprotect,munmap
**/
jmp_buf env;
struct sigaction act, oldact[2]; //set by main, used in wrappers:
void bridge_sig_jmp(int sig);
static void* malloc_bounded(size_t size);
static int free_bounded(void* vp);
static int wrap_confstr(int name, char *buf, size_t len);
static int wrap_getcwd(char *buf, size_t size);
static int wrap_getdelim(char **lineptr, size_t *n, int delimiter,FILE *stream);
static int wrap_gethostname(char *name, size_t namelen);
static int wrap_mbstowcs(wchar_t *pwcs, char *s, size_t n);
static int wrap_snprintf(char *s, size_t n, char *format/*, ...*/);
static int wrap_readlink(char *path, char *buf, size_t bufsize);
static int wrap_strfmon(char *s, size_t maxsize, char *format/*,...*/, float F);
static int wrap_strftime(char *s,size_t maxsize,char *format,struct tm *timeptr);
static int wrap_wcstombs(char *s, wchar_t *pwcs, size_t n);
static int wrap_strerror_r(int errnum, char *strerrbuf, size_t buflen);
static int wrap_ttyname_r(int fildes, char *name, size_t namesize);
static int wrap_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
//još malloc wrapper thingy----
int main()
{
iconv_t cd;
wchar_t *ws;
size_t size;
struct tm tm;
FILE *stream = NULL;
char *s, *fun, *tmp, filename[] = "/tmp/clutsXXXXXX";
int fd, sig, function, wrong, failed, err, err_expected;
int ffun[] = {2, 3,8}; //functions that depend on the temporary file(two do)
//GLOBAL:
act=(struct sigaction){.sa_handler=bridge_sig_jmp, .sa_flags=SA_NODEFER};
failed = 0;
function = 1;
do {
err = wrong = 0;
s = fun = tmp = NULL;
ws = NULL;
stream = NULL;
if (seq_has(function, ffun) && (fd=mkstemp(filename)) != -1) {
if ((stream=fdopen(fd, "w+b")) == NULL)
wrong = -1;
}
switch(function) {
case 1:
fun = sreturnf("confstr(_CS_PATH, s, sizeof(s)-1)");
size = confstr(_CS_PATH, NULL, 0);
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err=wrap_confstr(_CS_PATH, s, size-1)) == -1)
wrong = 1;
else
/*if ((err))
wrong = 5;
else */if (s[size-1] != '\r')
wrong = 2;
break;
case 2:
fun = sreturnf("getcwd(s, sizeof(s)-1)");
s = malloc(PATH_MAX);
size = strlen(getcwd(s, PATH_MAX))+1;
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err=wrap_getcwd(s, size-1)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
else if (err != (err_expected = ERANGE))
wrong = 3;
break;
case 3:
//same for getline
fun = sreturnf("getdelim(&s, &<strlen(s)>, '\\n', stream)");
if (stream == NULL)
break;
fwrite("123\n", (size = 4), 1, stream);
s = malloc_bounded(size);
s[size-1] = '\r';
if((err=wrap_getdelim(&s,(size_t[]){size-1},'\n',stream)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
break;
case 4:
fun = sreturnf("gethostname(s, sizeof(s)-1)");
s = malloc(HOST_NAME_MAX);
gethostname(s, HOST_NAME_MAX);
size = strlen(s) + 1;
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err=wrap_gethostname(s, size-1)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
else if (err != (err_expected = ERANGE))
wrong = 3;
break;
case 5:
fun = sreturnf("iconv(&<\"abcd\">, &<4>, &s, &<3>)");
s = malloc_bounded((size = 4));
s[size-1] = '\r';
cd = iconv_open("", "");
err = wrap_iconv(
cd,
(char **)(char *[]){"abcd"},
(size_t *)(size_t []){size},
(char **)(char *[]){s},
(size_t *)(size_t []){size-1}
);
iconv_close(cd);
if (err == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
else if (err != (err_expected = E2BIG))
wrong = 3;
break;
case 6:
fun = sreturnf("mbstowcs(ws, \"abc\", 3)");
size = 4;
ws = malloc_bounded(size * sizeof(wchar_t));
ws[size-1] = L'\r';
if ((err=wrap_mbstowcs(ws, "abcd", size-1)) == -1)
wrong = 1;
else if (ws[size-1] != L'\r')
wrong = 2;
else if (err != (err_expected = E2BIG))
wrong = 3;
break;
case 7:
fun = sreturnf("snprintf(s, 3, \"abc\")");
s = malloc_bounded((size = 4));
s[size-1] = '\r';
if ((err=wrap_snprintf(s, size-1, "abc")) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
break;
case 8:
fun=sreturnf("readlink(\"%s.sym\", s, sizeof(s)-1)", filename);
tmp = sreturnf("%s.sym", filename);
if (stream == NULL)
break;
else if (symlink(filename, tmp)) {
wrong = 4;
break;
}
s = malloc(PATH_MAX);
size = readlink(tmp, s, PATH_MAX);
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err=wrap_readlink(tmp, s, size-1)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
break;
case 9:
fun = sreturnf("strerror_r(1, s, sizeof(s)-1)");
s = malloc(80);
strerror_r(1, s, 80);
size = strlen(s);
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err = wrap_strerror_r(1, s, size-1)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
else if (err != (err_expected = ERANGE))
wrong = 3;
break;
case 10:
fun = sreturnf("strfmon(s, sizeof(s)-1, \"%%!i\", 123.0)");
s = malloc(80);
size = strfmon(s, 80, "%!i", 123.0) + 1;
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err=wrap_strfmon(s, size-1, "%!i", 123.0)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
else if (err != (err_expected = E2BIG))
wrong = 3;
break;
case 11:
fun = sreturnf("strftime(s, sizeof(s)-1, \"%Y\", tm)");
s = malloc(80);
tm = *gmtime((time_t []){time(NULL)});
strftime(s, 80, "%Y", &tm);
size = strlen(s) + 1;
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err=wrap_strftime(s, size-1, "%Y", &tm)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
break;
case 12:
fun = sreturnf("ttyname_r(STDERR_FILENO, s, sizeof(s)-1)");
s = malloc(TTY_NAME_MAX);
err = ttyname_r(STDERR_FILENO, s, TTY_NAME_MAX);
size = strlen(s) + 1;
free(s); s = NULL;
if (size < 2) {
wrong = -2;
break;
}
s = malloc_bounded(size);
s[size-1] = '\r';
if ((err = wrap_ttyname_r(STDERR_FILENO, s, size-1)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
else if (err != (err_expected = ERANGE))
wrong = 3;
break;
case 13:
fun = sreturnf("wcstombs(s, L\"abc\" 3)");
s = malloc_bounded((size = 4));
s[size-1] = '\r';
if ((err=wrap_wcstombs(s, L"abcd", size-1)) == -1)
wrong = 1;
else if (s[size-1] != '\r')
wrong = 2;
break;
default:
function = 0; //exit while
break;
}
if(((sig=free_bounded(ws)) || (sig=free_bounded(s))) && !wrong)
wrong = 6;
if (wrong) {
++failed;
if (wrong == -2)
fprintf(
stderr,
"%s could not be tested, because a preceeding call to the"
" same function returned length (of s) lesser than 2\n",
fun
);
else if (wrong == -1)
fprintf(stderr, "%s is unable to run, opening \"%s\" failed\n",
fun, filename);
else if (wrong == 1)
fprintf(stderr, "%s caused a SIGSEGV!\n", fun);
else if (wrong == 2)
fprintf(stderr, "%s wrote too many bytes to the buffer\n",fun);
else if (wrong == 3) {
free(tmp);
fprintf(stderr, "%s failed to set errno=%s",
fun, (tmp = e_name(err_expected)));
free(tmp);
fprintf(stderr, " (it is %s)\n", (tmp = e_name(err)));
}
else if (wrong == 4)
fprintf(stderr,
"%s was not called,"
" symlink(\"%s\", \"%s.sym\") failed\n",
fun, filename, filename);
else if (wrong == 5) {
free(tmp);
fprintf(stderr, "%s set errno = %s\n", fun, (tmp=e_name(err)));
}
else if (wrong == 6)
fprintf(
stderr,
"%s caused a signal %d to be received. A pointer passed to"
" the function might be errorneously redirected\n",
fun, sig
);
}
free(fun);
free(tmp);
if (stream != NULL && seq_has(function, ffun))
fclose(stream);
} while(function++);
return failed;
}
///A bridge function for sigaction(), jumps via longjmp() back to a setjmp()
void bridge_sig_jmp(int sig)
{
longjmp(env, sig);
return;
}
/**
** A quasi-implementation of malloc(), which allocates 2 additional words, one
** before the memory segment of the requested size, one after. It protects
** those words against reading/writing, so accessing them raises a SIGSEGV.
** \param size length of the memory segment to be allocated for reading/writing
** \returns a pointer to the allocated memory, NULL on failure
** \warning Needs to be freed by free_bounded(), not the regular free()
**/
static void* malloc_bounded(size_t size) {
int fd = open("/dev/zero", O_RDWR);
size_t *stp = NULL;
if (fd != -1) {
size += 2 * sizeof(size_t); //+boundry words
stp = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
if (stp != MAP_FAILED) {
*stp = size; //write metadata to the first word
//seal both ends:
mprotect(stp, sizeof(size_t), PROT_NONE);
mprotect((((char*)stp)+size)-sizeof(size_t), sizeof(size_t), PROT_NONE);
++stp;
}
else
stp = NULL;
close(fd);
}
return (void *)stp;
}
/**
** A quasi-implementation of free, which uses the metadata hidden in boundry
** words (allocated by malloc_bounded()) to unmap space.
** \param vp the pointer returned by malloc_bounded()
** \returns a caught signal on failure
**/
static int free_bounded(void* vp) {
size_t *stp = ((size_t *)vp)-1;
int sig = 0;
if(vp != NULL) {
sigaction(SIGABRT, &act, &oldact[0]);
sigaction(SIGSEGV, &act, &oldact[0]);
if(!(sig = setjmp(env))) {
mprotect(stp, sizeof(size_t), PROT_READ);
munmap(stp, *stp);
}
sigaction(SIGSEGV, &oldact[0], NULL);
sigaction(SIGABRT, &oldact[0], NULL);
}
return sig;
}
///< Wrappers start here: They take the same~ arguments as the functions that
///< they call, but catch SIGSEGVs, and return error codes on failure
static int wrap_confstr(int name, char *buf, size_t len)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (confstr(name, buf, len) == 0)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_getcwd(char *buf, size_t size)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (getcwd(buf, size) == NULL)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_getdelim(char **lineptr, size_t *n, int delimiter, FILE *stream)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (getdelim(lineptr, n, delimiter, stream) == -1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_gethostname(char *name, size_t namelen)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (gethostname(name, namelen) == -1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft)==(size_t)-1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_mbstowcs(wchar_t *pwcs, char *s, size_t n)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (mbstowcs(pwcs, s, n) == (size_t)-1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_snprintf(char *s, size_t n, char *format/*, ...*/)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (snprintf(s, n, format) < 0)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_readlink(char *path, char *buf, size_t bufsize)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (readlink(path, buf, bufsize) == -1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_strfmon(char *s, size_t maxsize, char *format/*, ...*/, float F)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (strfmon(s, maxsize, format, F) == -1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_strftime(char *s,size_t maxsize,char *format,struct tm *timeptr)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (strftime(s, maxsize, format, timeptr) == 0)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_wcstombs(char *s, wchar_t *pwcs, size_t n)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env)) {
if (wcstombs(s, pwcs, n) == (size_t)-1)
err = errno;
}else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_strerror_r(int errnum, char *strerrbuf, size_t buflen)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env))
err = strerror_r(errnum, strerrbuf, buflen);
else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
static int wrap_ttyname_r(int fildes, char *name, size_t namesize)
{
int err = 0;
sigaction(SIGSEGV, &act, &oldact[0]);
if(!setjmp(env))
err = ttyname_r(fildes, name, namesize);
else
err = -1;
sigaction(SIGSEGV, &oldact[0], NULL);
return err;
}
next prev parent reply other threads:[~2011-08-10 11:47 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-08-03 22:14 New daily reports Luka Marčetić
2011-08-03 22:46 ` Solar Designer
2011-08-04 10:51 ` Luka Marčetić
2011-08-04 11:54 ` Solar Designer
2011-08-04 12:01 ` Luka Marčetić
2011-08-04 12:12 ` Solar Designer
2011-08-05 0:02 ` New daily reports - started pthread_eintr.c Luka Marčetić
2011-08-05 0:10 ` Solar Designer
2011-08-06 4:40 ` New daily reports - debugging alloc.c et al Luka Marčetić
2011-08-06 11:15 ` Szabolcs Nagy
2011-08-06 11:50 ` Szabolcs Nagy
2011-08-06 14:34 ` Szabolcs Nagy
2011-08-06 15:38 ` Szabolcs Nagy
2011-08-07 2:41 ` New daily reports - debugging alloc.c still Luka Marčetić
2011-08-07 2:50 ` Solar Designer
2011-08-07 7:32 ` Rich Felker
2011-08-07 22:25 ` Luka Marčetić
2011-08-09 3:02 ` New daily reports - buf.c Luka Marčetić
2011-08-10 1:34 ` New daily reports - nothing Luka Marčetić
2011-08-10 1:38 ` Rich Felker
2011-08-10 11:47 ` Luka Marčetić [this message]
2011-08-10 2:02 ` Solar Designer
2011-08-10 11:23 ` Luka Marčetić
2011-08-10 11:56 ` Solar Designer
2011-08-10 12:13 ` Luka Marčetić
2011-08-10 2:07 ` Solar Designer
2011-08-10 2:12 ` Rich Felker
2011-08-10 4:59 ` Rich Felker
2011-08-10 12:09 ` Luka Marčetić
2011-08-10 12:44 ` Luka Marčetić
2011-08-10 14:25 ` Rich Felker
2011-08-10 17:21 ` Luka Marčetić
2011-08-10 17:33 ` Rich Felker
2011-08-10 18:23 ` Luka Marčetić
2011-08-10 18:21 ` Rich Felker
2011-08-10 18:34 ` Luka Marčetić
2011-08-10 18:33 ` Rich Felker
2011-08-14 20:00 ` Rich Felker
2011-08-15 14:14 ` Luka Marčetić
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4E426FC5.7020303@gmail.com \
--to=paxcoder@gmail.com \
--cc=musl@lists.openwall.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).