Main Content

CERT C: Rule POS30-C

Use the readlink() function properly

Description

Rule Definition

Use the readlink() function properly.1

Polyspace Implementation

The rule checker checks for Misuse of readlink().

Examples

expand all

Issue

Misuse of readlink() occurs when you pass a buffer size argument to readlink() that does not leave space for a null terminator in the buffer.

For instance:

size_t len = readlink("/usr/bin/perl", buf, sizeof(buf));
The third argument is exactly equal to the size of the second argument. For large enough symbolic links, this use of readlink() does not leave space to enter a null terminator.

Risk

The readlink() function copies the content of a symbolic link (first argument) to a buffer (second argument). However, the function does not append a null terminator to the copied content. After using readlink(), you must explicitly add a null terminator to the buffer.

If you fill the entire buffer when using readlink, you do not leave space for this null terminator.

Fix

When using the readlink() function, make sure that the third argument is one less than the buffer size.

Then, append a null terminator to the buffer. To determine where to add the null terminator, check the return value of readlink(). If the return value is -1, an error has occurred. Otherwise, the return value is the number of characters (bytes) copied.

Example - Incorrect Size Argument of readlink
#include <unistd.h>

#define SIZE1024 1024

extern void display_path(const char *);

void func() {
    char buf[SIZE1024];
    ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf)); //Noncompliant
    if (len > 0) {
        buf[len - 1] = '\0';
    }
    display_path(buf);
}

In this example, the third argument of readlink is exactly the size of the buffer (second argument). If the first argument is long enough, this use of readlink does not leave space for the null terminator.

Also, if no characters are copied, the return value of readlink is 0. The following statement leads to a buffer underflow when len is 0.

buf[len - 1] = '\0';

Correction — Make Sure Size Argument is One Less Than Buffer Size

One possible correction is to make sure that the third argument of readlink is one less than size of the second argument.

The following corrected code also accounts for readlink returning 0.

#include <stdlib.h>
#include <unistd.h>

#define fatal_error() abort()
#define SIZE1024 1024

extern void display_path(const char *);

void func() {
    char buf[SIZE1024];
    ssize_t len = readlink("/usr/bin/perl", buf, sizeof(buf) - 1); 
    if (len != -1) {
        buf[len] = '\0';
        display_path(buf);
    }
    else {
        /* Handle error */
        fatal_error();
    }
}

Check Information

Group: Rule 50. POSIX (POS)

Version History

Introduced in R2019a

expand all


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.