J
jacob navia
The main complaints about the version of a C script I presented in this
forum were:
(1) Limited buffers could overflow
(2) Security issues concerning specially crafted file names
Those issues were not at all any problem in the environment where this
script was used but from a more general perspective they could be an
issue.
Here is a version that uses ggets() from Chuck Falconer to avoid problem
number (1) and solves also problem number two. I use snprintf instead of
sprintf to avoid any buffer overflow problems
-------------------------------------------------------cut here
#include <stdio.h>
#include <stdlib.h>
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)
enum {
OK = 0, NOMEM};
int fggets(char* *ln, FILE *f) {
int cursize, ch, ix=0;
char *buffer, *temp;
*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}
buffer[ix] = '\0';
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
*ln = buffer; /* without reducing it */
}
else *ln = temp;
return OK;
}
#define MAXTESTS 2000
#include <stdio.h>
#include <string.h>
void ShowFailures(char *,char *tab[],int);
int main(int argc,char *argv[]){
FILE *f;
char *buf,*p,char cmd[1024];
int r,tests=0, CompilationFailures=0, LinkFailures=0, RunFailures=0;
char *CFailures[MAXTESTS];
char *LFailures[MAXTESTS];
char *RFailures[MAXTESTS];
f = popen("ls *.c","r");
if (f == NULL) { fprintf(stderr,"Impossible to list files.\n");
return -1;
}
while (0==fggets(&buf,f)) {
if (++tests >= MAXTESTS) {
printf("More than %d files. No more space"
"available\n",MAXTESTS);
break;
}
snprintf(cmd,sizeof(cmd),"../lcc -g2 -nw ./%s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
}
else {
p = strchr(buf,'.');
if (p) *p = 0;
snprintf(cmd,sizeof(cmd),"gcc ./%s.o lcclibc_asm.s -lm");
r = system(cmd);
if (r) {
printf("Link of %s.o failed\n",buf);
LFailures[LinkFailures++] = strdup(buf);
}
else {
r = system("./a.out");
if (r) {
printf("Execution of %s failed\n",buf);
RFailures[RunFailures++] = strdup(buf);
}
}
}
}
pclose(f);
printf("\n********************************\n%d"
"tests\n********************************\n",tests);
ShowFailures("Compilation",CFailures,CompilationFailures);
ShowFailures("Link",LFailures,LinkFailures);
ShowFailures("Run",RFailures,RunFailures);
}
void ShowFailures(char *name,char *tab[],int n){
int i;
if (n <= 0) return;
printf("%s failures (%d)\n",name,n);
for (i=0; i<n; i++) {
printf("%s ",tab);
}
printf("\n");
}
---------------------------------------------------------------------------
Note that this is only slightly more complicated than the original and
it has no obvious security problems. Yes, it doesn't handle file names
with new lines in them, and if you create a file name with just the
backspace character in it, it will probably not display it correctly.
This script (I repeat) is not going to be run in an hostile environment.
But now it is more robust. This just confirms that C can be used without
any trouble as a language to create small scripts that organize the work
of other software.
forum were:
(1) Limited buffers could overflow
(2) Security issues concerning specially crafted file names
Those issues were not at all any problem in the environment where this
script was used but from a more general perspective they could be an
issue.
Here is a version that uses ggets() from Chuck Falconer to avoid problem
number (1) and solves also problem number two. I use snprintf instead of
sprintf to avoid any buffer overflow problems
-------------------------------------------------------cut here
#include <stdio.h>
#include <stdlib.h>
#define INITSIZE 112 /* power of 2 minus 16, helps malloc */
#define DELTASIZE (INITSIZE + 16)
enum {
OK = 0, NOMEM};
int fggets(char* *ln, FILE *f) {
int cursize, ch, ix=0;
char *buffer, *temp;
*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}
buffer[ix] = '\0';
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
*ln = buffer; /* without reducing it */
}
else *ln = temp;
return OK;
}
#define MAXTESTS 2000
#include <stdio.h>
#include <string.h>
void ShowFailures(char *,char *tab[],int);
int main(int argc,char *argv[]){
FILE *f;
char *buf,*p,char cmd[1024];
int r,tests=0, CompilationFailures=0, LinkFailures=0, RunFailures=0;
char *CFailures[MAXTESTS];
char *LFailures[MAXTESTS];
char *RFailures[MAXTESTS];
f = popen("ls *.c","r");
if (f == NULL) { fprintf(stderr,"Impossible to list files.\n");
return -1;
}
while (0==fggets(&buf,f)) {
if (++tests >= MAXTESTS) {
printf("More than %d files. No more space"
"available\n",MAXTESTS);
break;
}
snprintf(cmd,sizeof(cmd),"../lcc -g2 -nw ./%s",buf);
p = strchr(buf,'.');
if (p) *p=0;
r = system(cmd);
if (r) {
printf("Compilation of %s.c failed\n",buf);
CFailures[CompilationFailures++] = strdup(buf);
}
else {
p = strchr(buf,'.');
if (p) *p = 0;
snprintf(cmd,sizeof(cmd),"gcc ./%s.o lcclibc_asm.s -lm");
r = system(cmd);
if (r) {
printf("Link of %s.o failed\n",buf);
LFailures[LinkFailures++] = strdup(buf);
}
else {
r = system("./a.out");
if (r) {
printf("Execution of %s failed\n",buf);
RFailures[RunFailures++] = strdup(buf);
}
}
}
}
pclose(f);
printf("\n********************************\n%d"
"tests\n********************************\n",tests);
ShowFailures("Compilation",CFailures,CompilationFailures);
ShowFailures("Link",LFailures,LinkFailures);
ShowFailures("Run",RFailures,RunFailures);
}
void ShowFailures(char *name,char *tab[],int n){
int i;
if (n <= 0) return;
printf("%s failures (%d)\n",name,n);
for (i=0; i<n; i++) {
printf("%s ",tab);
}
printf("\n");
}
---------------------------------------------------------------------------
Note that this is only slightly more complicated than the original and
it has no obvious security problems. Yes, it doesn't handle file names
with new lines in them, and if you create a file name with just the
backspace character in it, it will probably not display it correctly.
This script (I repeat) is not going to be run in an hostile environment.
But now it is more robust. This just confirms that C can be used without
any trouble as a language to create small scripts that organize the work
of other software.