| //===------- CStdLib.h - CStdLib runtime helper functions -----------------===// |
| // |
| // The SAFECode Compiler |
| // |
| // This file was developed by the LLVM research group and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file provides all external functions included by the CStdLib pass. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef _CSTDLIB_H |
| #define _CSTDLIB_H |
| |
| #include "../include/CStdLibSupport.h" |
| #include "../include/CWE.h" |
| #include "../include/strnlen.h" |
| |
| #include "DebugReport.h" |
| #include "PoolAllocator.h" |
| |
| #include <iostream> |
| |
| #define TAG unsigned tag |
| #define SRC_INFO const char *SourceFile, unsigned lineNo |
| |
| // Default versions of arguments to debug functions |
| #define DEFAULT_TAG 0 |
| #define DEFAULT_SRC_INFO "<Unknown>", 0 |
| #define DEFAULTS DEFAULT_TAG, DEFAULT_SRC_INFO |
| #define SRC_INFO_ARGS SourceFile, lineNo |
| |
| using namespace llvm; |
| |
| namespace { |
| |
| // |
| // Various violation types |
| // |
| |
| static inline void |
| OOB_VIOLATION(const void *fault_ptr, |
| DebugPoolTy *handle, |
| const void *start, |
| size_t len, |
| SRC_INFO) { |
| OutOfBoundsViolation v; |
| v.type = ViolationInfo::FAULT_OUT_OF_BOUNDS; |
| v.faultPC = __builtin_return_address(0); |
| v.faultPtr = fault_ptr; |
| v.CWE = CWEBufferOverflow; |
| v.SourceFile = SourceFile; |
| v.lineNo = lineNo; |
| v.PoolHandle = handle; |
| v.objStart = start; |
| v.objLen = len; |
| v.dbgMetaData = NULL; |
| ReportMemoryViolation(&v); |
| } |
| |
| static inline void |
| WRITE_VIOLATION(const void *fault_ptr, |
| DebugPoolTy *handle, |
| size_t dst_sz, |
| size_t src_sz, |
| SRC_INFO) { |
| WriteOOBViolation v; |
| v.type = ViolationInfo::FAULT_WRITE_OUT_OF_BOUNDS; |
| v.faultPC = __builtin_return_address(0); |
| v.faultPtr = fault_ptr; |
| v.CWE = CWEBufferOverflow; |
| v.SourceFile = SourceFile; |
| v.lineNo = lineNo; |
| v.PoolHandle = handle; |
| v.dstSize = dst_sz; |
| v.srcSize = src_sz; |
| v.dbgMetaData = NULL; |
| ReportMemoryViolation(&v); |
| } |
| |
| static inline void |
| LOAD_STORE_VIOLATION(const void *fault_ptr, |
| DebugPoolTy *handle, |
| SRC_INFO) { |
| DebugViolationInfo v; |
| v.faultPC = __builtin_return_address(0); |
| v.faultPtr = fault_ptr; |
| v.CWE = CWEBufferOverflow; |
| v.dbgMetaData = NULL; |
| v.PoolHandle = handle; |
| v.SourceFile = SourceFile; |
| v.lineNo = lineNo; |
| ReportMemoryViolation(&v); |
| } |
| |
| static inline void |
| C_LIBRARY_VIOLATION(const void *fault_ptr, |
| DebugPoolTy *handle, |
| const char *function, |
| SRC_INFO) { |
| CStdLibViolation v; |
| v.type = ViolationInfo::FAULT_CSTDLIB; |
| v.faultPC = __builtin_return_address(0); |
| v.faultPtr = fault_ptr; |
| v.CWE = CWEBufferOverflow; |
| v.SourceFile = SourceFile; |
| v.lineNo = lineNo; |
| v.PoolHandle = handle; |
| v.function = function; |
| v.dbgMetaData = NULL; |
| ReportMemoryViolation(&v); |
| } |
| |
| // |
| // Check for string termination. |
| // |
| // @param start This is a pointer to the start of the string. |
| // @param end The end of the object. String is not scanned farther than here. |
| // @param p Reference to size object. Filled with the length of the string if |
| // string is terminated, otherwised filled with the size of the object. |
| // @return Returns true if the string is terminated within bounds (ie., |
| // if the nul terminator occurs between string and end, inclusive). |
| // Returns false if no nul terminator was found. |
| // |
| // Note that start and end should be valid boundaries for a valid object. |
| // |
| static inline bool |
| isTerminated(const char *start, void *end, size_t &p) { |
| size_t max = 1 + ((char *)end - (const char *)start), len; |
| len = _strnlen((const char *)start, max); |
| p = len; |
| if (len == max) |
| return false; |
| else |
| return true; |
| } |
| |
| // |
| // Check for object overlap. |
| // |
| // @param ptr1Start The start of the first memory object |
| // @param ptr1End The end of the first memory object or the bound that writing |
| // operation actually touch. |
| // @param ptr2Start The start of the second memory object |
| // @param ptr2End The end of the second memory object or the bound that writing |
| // operation actually touch. |
| // |
| // @return Whether these 2 memory object overlaps |
| // |
| static inline bool |
| isOverlapped(const void* ptr1Start, |
| const void* ptr1End, |
| const void* ptr2Start, |
| const void* ptr2End) { |
| if( ((long int)ptr1Start>(long int)ptr2End && (long int)ptr1End>(long int)ptr2Start) || |
| ((long int)ptr1Start<(long int)ptr2End && (long int)ptr1End<(long int)ptr2Start) ) |
| return false; |
| return true; |
| } |
| |
| // |
| // Searches inside the given pool for the memory object associated with the |
| // the given address. If the memory object is found, it sets the poolBegin |
| // and poolEnd pointers to point to the first and last valid positions of |
| // the memory object, and returns true. If the memory object is not found in |
| // the pool, or the pool is NULL, it attemps to find the object in the external |
| // objects pool. When the object is not found in either pool, the function |
| // returns false. |
| // |
| // @param pool The pool handle which is expected to contain the object. |
| // @param address The address for which the bounding object is sought. |
| // @param poolBegin Reference to a pointer to set to the beginning of |
| // the memory object. |
| // @param poolEnd Reference to a pointer to set to the last valid address |
| // the memory object. |
| // @return Returns true if the object was found, false otherwise. |
| // |
| static inline bool |
| pool_find(DebugPoolTy *pool, void *address, void *&poolBegin, void *&poolEnd) { |
| |
| if (address == NULL) |
| return false; |
| |
| // Retrieve memory area's bounds from pool handle. |
| if ((pool && pool->Objects.find(address, poolBegin, poolEnd)) || |
| ExternalObjects->find(address, poolBegin, poolEnd)) |
| return true; |
| |
| return false; |
| } |
| |
| // |
| // Macros for determining the completeness of pointer arguments using the |
| // completeness bitwise vector. |
| // |
| #define ARG1_COMPLETE(c) ((bool) (c & 0x1)) |
| #define ARG2_COMPLETE(c) ((bool) (c & 0x2)) |
| |
| // Return the number of bytes between a and b, inclusive. |
| static inline size_t byte_range(const void *a, const void *b) { |
| return 1 + (char *) b - (char *) a; |
| } |
| |
| // Use this stream for reporting errors. |
| static std::ostream &err = std::cerr; |
| |
| // |
| // This function attempts to verify that given string pointer points to |
| // a valid string that is terminated within its memory object's boundaries. |
| // For strings that are marked complete, if the string is discovered to be |
| // not in its pool, or unterminated within memory object boundaries, |
| // the function reports a violation and returns false. |
| // For strings not marked complete, the function attempts to do the same |
| // checks as for complete pointers, except that it assumes the string was |
| // valid if the string's memory object is not found in the pool. |
| // |
| // The function returns true if no memory violations were discovered, and |
| // false when there was a violation. |
| // |
| // @param string The pointer to the string to be checked. |
| // @param pool The pool that should be searched for the memory object |
| // that contains the string. |
| // @param complete This is a boolean value which is true if the string |
| // pointer was reported complete by DSA, and false if not. |
| // If the string is incomplete, no errors are reported |
| // if it does not exist in the pool and is non-NULL. |
| // @param function The name of the C library function for debug reporting |
| // purposes. |
| // @param SRC_INFO Source and line info debug information. |
| // @return Returns true if no violations were discoverd, and false |
| // if the pointer does not point to a valid string and a |
| // memory violation was reported. |
| // Note that if the function returns true, the pointer may |
| // still not point to a valid string if the pointer was |
| // incomplete. |
| // |
| static inline bool |
| validStringCheck(const char *string, |
| DebugPoolTy *pool, |
| bool complete, |
| const char *function, |
| SRC_INFO) { |
| void *objStart, *objEnd; |
| size_t len; |
| |
| // Check if the string is NULL. If it is, report this as an error. |
| if (string == NULL) { |
| err << "String pointer is NULL!\n"; |
| C_LIBRARY_VIOLATION(string, pool, function, SRC_INFO_ARGS); |
| return false; |
| } |
| |
| // Retrieve the string from the pool. If no string is found and the pointer |
| // is not complete, return true. Otherwise report an error and return false. |
| if (!pool_find(pool, (void *)string, objStart, objEnd)) { |
| if (complete) { |
| err << "String not found in pool!\n"; |
| LOAD_STORE_VIOLATION(string, pool, SRC_INFO_ARGS); |
| return false; |
| } |
| else |
| return true; |
| } |
| |
| // Do a termination check. |
| if (!isTerminated(string, objEnd, len)) { |
| err << "String is not terminated within object bounds!\n"; |
| C_LIBRARY_VIOLATION(string, pool, function, SRC_INFO_ARGS); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // |
| // Check to see if the memory region between the location pointed to by Buf |
| // and the end of the same memory object is of at least the given minimum size. |
| // |
| // This function will look up the buffer object in the pool to determine its |
| // size. If the pointer is complete and not found in the pool the function |
| // will report an error. If the pointer points to a region of size less than |
| // MinSize then this function will report an error. |
| // |
| // Inputs |
| // Pool - The pool handle for the buffer |
| // Buf - The buffer |
| // Complete - A boolean describing if the pointer is complete |
| // MinSize - The minimum expected size of the region pointed to by Buf |
| // SRC_INFO - Source file and line number information for debugging purposes |
| // |
| static inline void |
| minSizeCheck (DebugPoolTy * Pool, |
| void * Buf, |
| bool Complete, |
| size_t MinSize, |
| SRC_INFO) { |
| bool Found; |
| void * BufStart = 0, * BufEnd = 0; |
| |
| // |
| // Retrive the buffer's bound from the pool. If we cannot find the object and |
| // we know everything about what the buffer should be pointing to, then |
| // report an error. |
| // |
| if (!(Found = pool_find (Pool, Buf, BufStart, BufEnd)) && Complete) { |
| LOAD_STORE_VIOLATION (Buf, Pool, SRC_INFO_ARGS); |
| } |
| |
| if (Found) { |
| // |
| // Make sure that the region between the location pointed to by Buf and the |
| // end of the same memory object is of size at least MinSize. |
| // |
| size_t BufSize = byte_range (Buf, BufEnd); |
| |
| if (BufSize < MinSize) { |
| C_LIBRARY_VIOLATION (Buf, Pool, "", SRC_INFO_ARGS); |
| } |
| } |
| |
| return; |
| } |
| |
| } |
| |
| #endif // _CSTDLIB_H |