Below are some of the common errors that students make while coding

1. Checking the return types of functions

Checking the return types of functions is important for robust programming. Exception cases should be handled to avoid unexpected program behavior. When memory cannot be allocated, it is a good idea to have a consistent recovery plan, even if your solution is to print an error message and exit
with a nonzero exit status. The example below shows a correct usage of malloc().
The return value of malloc() is tested.

int *create_int_array(size_t nelements_wanted){

int *i_ptr = (int *) malloc(sizeof(int) * nelements_wanted);

if(i_ptr != NULL){

  memset(i_ptr,0,sizeof(int) * nelements_wanted);

}

else{

   return NULL;

}

return i_ptr;

}

The above example was taken from page 154 in the second edition of the book, Secure Coding in C and C++, written by Robert Seacord.

2. Avoid race conditions when doing file operations by using the file descriptor

Use the open() function insted of fopen(). open() returns the file descriptor. It opens a file and returns an error if the file already exists when the O_CREAT and O_EXCL options are used. fopen() returns the file pointer. It automatically creates a file if it does not exist. However, fopen() does not return any error if the file exists. Use functions in your program that takes the file descriptor as one of its arguments. For example use fchmod() instead of chmod(), fstat() instead of stat() etc. The file descriptor ensures that while you are working a file, is not being modified someone else.
Following example was been taken from CERT secure coding website. The link is,
https://www.securecoding.cert.org/confluence/display/c/POS38-C.+Beware+of+race+conditions+when+
using+fork+and+file+descriptors
In the below program, the programmer closes the file descriptor in the child after forking and then reopens it.
The file descriptor ensures that the file has not been modified in the meantime.

char c;
pid_t pid;

/* Open file and remember file status */
struct stat orig_st;
if (lstat( filename, &orig_st) != 0) {
   /* handle error */
}
int fd = open(filename, O_RDWR);
if (fd == -1) {
  /* Handle error */
}
struct stat new_st;
if (fstat(fd, &new_st) != 0) {
   /* handle error */
}
if (orig_st.st_dev != new_st.st_dev ||
orig_st.st_ino != new_st.st_ino) {
   /* file was tampered with while opening */
}
/* file is good, operate on fd */
read(fd,&c,1);
printf("root process:%c\n",c);
pid = fork();
if (pid == -1) {
  /* Handle error */
}
if (pid == 0){ /*child*/
close(fd);
/* Reopen file, creating new file descriptor */
fd = open(filename, O_RDONLY);
if (fd == -1) {
   /* Handle error */
}
if (fstat(fd, &new_st) != 0) {
    /* handle error */
}
if (orig_st.st_dev != new_st.st_dev ||
orig_st.st_ino != new_st.st_ino) {
  /* file was tampered with between opens */
}
read(fd, &c, 1);
read(fd, &c, 1);
printf("child:%c\n", c);
close(fd);
}
else { /*parent*/
   read(fd, &c, 1);
   printf("parent:%c\n", c);
   close(fd);

}

3. Use functions that prevent buffer overflow

The function gets() is a common source of buffer overflow vulnerabilities. The function fgets() offers more secure solution. The gets() function reads a line from standard input into a buffer until a terminating newline or EOF is found. It does not check for buffer overrun. It is not possible to tell without knowing the data in advance how many characters gets() will read. This is because gets() continues to store characters past the end of the buffer.

fgets() accepts two additional arguments. They are, the number of characters to read and an input stream. This function reads atmost one less than the number of characters specified from the stream into an array. No additional characters are read after a newline character or end-of-file. A null character is written immediately after the last character is read into the array. Unlike gets(), fgets() function retains the newline character. Hence, fgets() cannot be used as a direct replacement for gets().

gets_s() function is a closer direct replacement of gets() than fgets(), since it reads only from the input stream. gets_s() function accepts an additional argument, rsize_t. This argument specifies the maximum number of characters to input. Object of size type rsize_t, can have size greater than RSIZE_MAX or zero. For either of the values gets_s() returns an error. Objects of large size are an indication that the size of the object was not calculated properly. One such example is when a negative number is presented as large positive number when it was converted from unsigned to size_t. Hence in order to detect vulnerabilities, object size range should be restricted. gets_s() reads at-most one less than the number of character in the input and writes a null character to the end of the array after the last character is read. gets_s() function returns NULL if it does encounter a newline when reading an input. The buffer is set to NULL string and clears the input string to the next newline character.

However, both fgets() and gets_s() can lead to buffer overflow if the specified number of characters to input is greater than the length of the destination buffer.

The above information was obtained from US-CERT website. The link is, https://www.us-cert.gov/bsi/articles/knowledge/coding-practices/fgets-and-gets_s


Some examples of buffer overflow can be found here http://spc.cs.ucdavis.edu/index.php/situations/buffer-overflow

4. Use functions that allow to run a subprocess in a pristine environment

An example of a function that allows you to run a subprocess in a pristine environment is execve(). This function takes in three arguments. The signature of the function execve() is,
int execve(const char *filename, char *const argv[], char *const envp[]);

The argument envp is an array of strings. It is of the form key, value pairs. Both argv and envp should be NULL terminated. The values of the elements of envp cleans the environment. An example of the elements of envp array is as follows.

envp[0] = "PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin";
envp[1] = "IFS= \t\n";
envp[2] = "SHELL=/bin/bash";
envp[3] = "HOME=/home/xyz";
envp[4] = NULL;

5. Check validity of input parameters

Always check the value of input parameters. For example, in case of a function that expects a positive integer as an input, check should be made if the input value is less than zero. If such a check is not made, a negative input will lead to unexpected program behavior which is a security vulnerability.

6. Avoid double-free vulnerabilities

A double-free vulnerability arises when the same chunk memory is freed twice without it being reallocated between two free operations.
The following example taken from the Chapter "Dynamic Memory Management", page 159 from Robert C. Seacord's book, "Secure Coding in C and C++", shows the occurrence of a double-free vulnerability.

char *p2;
chap *p = malloc(100)
...
if((p2 = realloc(p,nsize))== NULL){
   if (p){

     free (p);

       }
   p = NULL;
   return NULL;
}
p = p2

The concern here is what happens when the size of n is 0 and what happens to the memory referenced by p. For library implementations where realloc() frees the memory but returns a null pointer, execution of the above code results in a double-free vulnerability.
On POSIX system, a safe alternative should be to check the value of errno.

errno = 0
p2 = realloc(p,size)
if(p2 == NULL){
   if(errno == ENOMEM){
     free(p)
   }
   return;
}

However, the above solution will not work on AIX and glibc, where errno is unchanged.

One obvious solution is to never allocate 0 bytes. Check the size of nsize.

char *p2;
char *p = malloac(100);
...
if((nsize == 0) || (p2 == realloc(p,size) == NULL){
   free(p);
   p = NULL;
   return NULL;
}
p = p2;

7. Avoid storing plaintext password

Storing passwords in plaintext in an application's properties or configuration file may result in a system compromise. Anyone can gain access to the file will have access to the password.
The below code in Java shows that the password is stored in the properties file. Anyone who has access to the properties file will have access to the password.

...

Properties prop = new Properties();

prop.load(new FileInputStream("config.properties"));

String password = prop.getProperty("password");

DriverManager.getConnection(url, usr, password);

...

A mitigation of this vulnerability is to avoid storing passwords in easily accessible locations. Ensure that the file is protected from being accessed users other than the owners of that file.

This vulnerability is mentioned in Common Weakness Enumeration (CWE) list of security flaws. The ID is 256. The link to the details of this vulnerability is https://cwe.mitre.org/data/definitions/256.html .


8. Avoid calling malloc(size_t size) with the value of the size parameter as 0
 
Calling malloc with a value of the size parameter, 0 return a NULL pointer or a unique pointer that can be passed to free( ). Calling free(NULL) or free(address) (any address received by malloc( )) should not cause any problem.
 
When using malloc( ) always check whether the memory returned by malloc( ) is NULL.
 
What you should not do 
 
char *ptr = (char*) malloc(10); //initialise a buffer of size 10

ptr[10]='c';

What you should do

char *ptr = (char*) malloc(10); //initialise a buffer of size 10

if (ptr != NULL){
   ptr[10]='c';
}

Concept Map

The above example maps to F and Assumptions in the Concept Map.

9. Minimise the scope of variables and functions

What you should not do

In the code below, count is a non-static variable, global variable. The function returns when the value of count exceeds a maximum value. If this variable count is to be accessed within the function, it should be defined within the function counter() (within the minimum possible scope).

unsigned int count = 0;

void counter() {
   if (count++ > MAX_COUNT) return;
    /* ... */

}

What you should do

In the code below, count is defined within the function counter(). Re-initialization of this variable is prevented be declaring it as a static variable. The value of count persists as long as the persists.

void counter() {
static unsigned int count = 0;
if (count++ > MAX_COUNT) return;
   /* ... */

}

Concept Map

This maps to iv in the Concept Map.

This example was taken from the CERT Secure Coding website, https://www.securecoding.cert.org/confluence/display/c/DCL19-C.+Minimize+the+scope+of+variables+and+functions .

 

JSN Teki template designed by JoomlaShine.com