Safe functions in programming languages protect memory by defining safe values, operations, and interfaces. For software to be considered memory safe, memory corruption must not be conceivable. Therefore, only computer language constructs that are assured never to cause memory corruption make up the safety functions.
Using Safe Functions
Buffer overruns, which come from improper buffer handling, are a significant source of system security issues. String manipulation procedures are frequently coupled with poor buffer handling. Writing past the end of buffers is not prohibited by the common string manipulation methods provided by the C/C++/D language runtime libraries.
These functions are not inherently “bad,” but the programmer must perform rigorous error checking to be utilized securely. The code will have a security vulnerability if the error checking is omitted, which often happens. A new set of functions are created to address this problem. It is always considered better to create new functions to replace those functions that were prone to security risks with a strong, extensively tested, and detailed set of new ones.
To ensure that your code handles buffers properly, two new sets of string manipulation procedures, which are called safe string functions, provide further processing. The Windows XP SP1, Driver Development Kit, Windows Driver Kit, Windows SDK, and other versions provide these safe string functions. They are meant to replace Windows’ built-in C/C++ counterparts and comparable procedures.
In kernel-mode programs, a single set of safe string functions is accessible. The header file Ntstrsafe.h contains the prototypes for these functions. The WDK includes this header file and a related library. The other collection of safe string methods can be used in user-mode applications. The accompanying header file, Strsafe.h, contains prototypes for these functions. The Windows SDK includes the file and a related library.
Functions of the safe string in kernel mode
The kernel-mode safe string functions provide the following features:
- The output strings from the Unicode and ANSI string functions are always terminated with a NULL character, regardless of whether the action shortens the desired result.
- For each safe string function, the input is the size of the destination buffer. Thus, the function may guarantee that it does not write past the buffer’s end.
- A UNICODE STRING structure may be used as an input parameter, an output parameter, or a combination of these functions.
- All safe string methods provide an NTSTATUS value, with only one possible success code.
- Both a byte-counted and a character-counted version of the majority of safe string functions are provided. For instance, RtlStringCbCata combines two strings with byte counts, while RtlStringCchCata combines strings with character counts.
- Most safe string functions come with an extended, Ex-suffixed version that offers more features. For instance, RtlStringCbCatExa enhances RtlStringCbCata’s capability.
Example
Let’s use the well-known C problem of printing “Hello World.” The following code prints “Hello World” using
printf
, which can print a string of characters:
#include<stdio.h>
int main() {
printf(“hello, world\n”)
return 0;
}
printf variable function in C
The signature of printf is illustrated in the code snippet below, which accepts several different types of inputs. The format string contains an encoded version of these arguments’ properties. printf is a variadic function that agrees with an arbitrary number of arguments.
Int printf (const char * restrict format, ...);
The code below outputs several string and numeric combinations to help us comprehend this notion. printf requires at least one string argument, backed by 0 or more arguments of various types, the specifics of which are encoded in format. The following code demonstrates this:
#include<stdio.h>
int main() {
char myString[ ] = “hello World”;
int myInt = 0;
printf(“This is a string: %s” , myString)
printf(“\nThis is a string: %s and an int: %d”, myString , myInt);
return 0;
}
Why is printf insecure in C?
Here are some explanations for why printf in C is risky:
- The format string and argument list are not matched at the compilation time.
- According to standard C rules, using printf with too few arguments can result in unexplainable behavior but is not always accompanied by a warning.
- Undefined behavior may cause compromised execution or possibly the activation of malicious code.
- The idea of memory safety is broken when using a pointer * format.
- The * format in the preceding example denotes a null-terminated string. The code is not compromised as a result. Therefore, it is the programmer’s obligation to make sure that any pointer points to a genuine piece of data.
Let’s examine a similar safe function in D now:
import std.stdio;
void main()
{
writeln("Hello, World!");
}
What makes writeln safe in D?
Below are a few explanations for why writeln is secure in D:
- It accepts a varying number of arguments of different kinds. Each signature has its own template preserved with the compiler.
- When dealing with a varying argument using tuples, the writeln‘s additional memory safety is guaranteed at compile time using code templates.
- In this case, a one-string type argument is used to call writeln. Strings in D are irreversible char arrays rather than pointers.
Points to remember
Here are some essential points to consider regarding safe functions.
- Undefined behavior is absent from safe functions. It implies that they are unable to access free or recycled memory.
- Safe functions can’t use reference parameters, global variables, or return values to change unsafe values from other program sections.
- Safe functions are examined at compilation time to ensure they don’t contain features like pointer arithmetic and unsafe casts.
- Runtime errors, like uninitialized class objects, can still occur in safe functions. However, they cannot access memory that has not been allocated. Hence they are memory-safe.
Limitations of safe functions
Safe functions have some limitations that make developing useful code exclusively using safe functions challenging. Here are some limitations of safe functions:
- External functions cannot be called by safe functions.
- Safe functions are not allowed to use system calls or execute I/O operations.
- Memory safety does not guarantee portability, sound programming principles, the absence of byte order reliance, or the absence of other issues. It is only concerned with preventing potential memory corruption.
Conclusion
Safe functions are crucial to protecting memory in programming languages. They do this by defining safe values, operations, and interfaces, so that memory corruption is no longer possible. Here, we’ve helped you understand what they are and how they function with examples. In addition to safe string functions, there are many other security tools you can use to ensure the safety of your programming. We’ve discussed many of them in our other articles on application and coding safety, so be sure to check those out.