In Computer Systems: a Programmer's Perspective,
Unfortunately, a number of commonly used library functions, including
strcpy
,strcat
, andsprintf
, have the property that they can generate a byte sequence without being given any indication of the size of the destination buffer [97]. Such conditions can lead to vulnerabilities to buffer overflow.
Since strcpy
, strcat
, and sprintf
are dangerous, what shall we use instead of them, or how shall we use them correctly/securely?
In the book, there is an example of implementing a simple shell, which calls strcpy()
. I was wondering what purpose is strcpy(buf, cmdline)
in eval()
? Does it introduce security vulnerability, or does it improve security, by limiting the size of the char array to an known size? Is it a regular way for security coding?
What if we don't know the max limit of a command line length?
Thanks.
#include "csapp.h"
#define MAXARGS 128
/* Function prototypes */
void eval(char *cmdline);
int parseline(char *buf, char **argv);
int builtin_command(char **argv);
int main()
{
char cmdline[MAXLINE]; /* Command line */
while (1) {
/* Read */
printf("> ");
Fgets(cmdline, MAXLINE, stdin);
if (feof(stdin))
exit(0);
/* Evaluate */
eval(cmdline);
}
}
/* eval - Evaluate a command line */
void eval(char *cmdline)
{
char *argv[MAXARGS]; /* Argument list execve() */
char buf[MAXLINE]; /* Holds modified command line */
int bg; /* Should the job run in bg or fg? */
pid_t pid; /* Process id */
strcpy(buf, cmdline);
bg = parseline(buf, argv);
if (argv[0] == NULL)
return; /* Ignore empty lines */
if (!builtin_command(argv)) {
if ((pid = Fork()) == 0) { /* Child runs user job */
if (execve(argv[0], argv, environ) < 0) {
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
/* Parent waits for foreground job to terminate */
if (!bg) {
int status;
if (waitpid(pid, &status, 0) < 0)
unix_error("waitfg: waitpid error");
}
else
printf("%d %s", pid, cmdline);
}
return;
}
/* If first arg is a builtin command, run it and return true */
int builtin_command(char **argv)
{
if (!strcmp(argv[0], "quit")) /* quit command */
exit(0);
if (!strcmp(argv[0], "&")) /* Ignore singleton & */
return 1;
return 0; /* Not a builtin command */
}
/* parseline - Parse the command line and build the argv array */
int parseline(char *buf, char **argv)
{
char *delim; /* Points to first space delimiter */
int argc; /* Number of args */
int bg; /* Background job? */
buf[strlen(buf)-1] = ’ ’; /* Replace trailing ’\n’ with space */
while (*buf && (*buf == ’ ’)) /* Ignore leading spaces */
buf++;
/* Build the argv list */
argc = 0;
while ((delim = strchr(buf, ’ ’))) {
argv[argc++] = buf;
*delim = ’\0’;
buf = delim + 1;
while (*buf && (*buf == ’ ’)) /* Ignore spaces */
buf++;
}
argv[argc] = NULL;
if (argc == 0) /* Ignore blank line */
return 1;
/* Should the job run in the background? */
if ((bg = (*argv[argc-1] == ’&’)) != 0)
argv[--argc] = NULL;
return bg;
}
parseline()
do? The comment forbuf
says it holds the modified command line. Is this perhaps related to variable expansion?strcpy
,sprintf
, and the like.sprintf_s
to replace our code. It's kind of leaving us to the gutters if people just say we shouldn't use something without suggesting an alternative we can actually use without reducing our demographics to just Windows users. Well, I don't really understand the voting patterns on this site. Makes zero sense to me.