Patch Integration Engine
News
Download
Prepatch
Documentation
Contact
Libpie Reference

Libpie is a shared library for the development of prepatches for use with PIE. This document describes in detail the usage of the individual functions that libpie makes available to a C programmer. Prepatches essentially work by making assertions. If these assertions fail, the prepatch will prevent a vulnerable function from being exploited. Libpie allows expressive assertions such as "argument two must be less than 256 bytes in length" to be transformed first into a valid C construct and then into working machine code.

It should be noted that the return values given are not the return values from the prepatch, but the library functions themselves. If one of the libpie functions fails it should be expected that the prepatch would fail too.

Libpie Functions

pie_begin
pie_end
pie_set
pie_string_length
pie_value
pie_match_sub_string
pie_byte_at_offset
pie_byte_count
pie_sub_string_at_offset
pie_sub_string_count
pie_force_return

Name:
pie_begin -- start the prepatch creation process.
Synopsis:
int pie_begin(char *target, char *func_name, int func_count, int options);
Description:
When creating a prepatch this must always be the first libpie function called. The pie_begin() function sets both target binary and function information. The file name specified by target represents the target binary that is to be prepatched. It can be either the full path to the program or simply the binary's file name. The argument func_name points to the name of the vulnerable function that is to be prepatched, while func_count is the number of arguments this function takes. The options are specified by or'ing the following values:

PIE_OPT_USELIBC Use libc functions in the prepatch instead of inline code.
PIE_OPT_LIBREDIR Indicates that the target function is in a library, not the target binary's text section.

If no options are required PIE_NO_OPT should be used. PIE_NO_OPT will be overridden if or'd with any of the above options.
Return values:
Upon successful completion pie_begin() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_end -- finish the prepatch creation process.
Synopsis:
int pie_end(char *patch_name, int do_write);
Description:
When creating a prepatch pie_end() must always be the last libpie function called. The pie_end() function prepares and outputs the prepatch formed by the libpie functions preceeding it. The name of the prepatch is given by patch_name. If patch_name does not contain the correct prepatch suffix of ".pp" it will be appended. If the do_write flag is set to any number other than zero then the prepatch will be written to disk. If do_write is zero, the prepatch will be printed to the standard output.

If the prepatch name is a path and do_write is enabled then the prepatch will be output to that path, otherwise the prepatch will be output to the current directory.
Return values:
Upon successful completion pie_end() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_set -- set internal variable to arg.
Synopsis:
int pie_set(int var, int arg);
Description:
The pie_set() function can be used to set configurable options in the underlying prepatch system. At the time of writing, the only valid variable option is PIE_DEREFERENCE. This variable can be set to a non-negative integer number, or PIE_DEFAULT. The variable controls the depth of pointer derferences by subsequent assertion function calls. The default setting of this variable is PIE_DEFAULT, which indicates that each assertion function call should use the best suited default dereference depth.
Return values:
Upon successful completion pie_set() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_string_length -- assert a string length.
Synopsis:
int pie_string_length(int arg, int action, int value);
Description:
The pie_string_length() function is a string length assertion. It checks to see that the length of a string argument is permissable. The argument that is to be checked is given by arg, a number starting at 1. The action is the comparison operator that is to be used:

    PIE_LESS_THAN
    PIE_LESS_THAN_OR_EQUAL
    PIE_EQUAL
    PIE_NOT_EQUAL
    PIE_GREATER_THAN_OR_EQUAL
    PIE_GREATER_THAN

The final argument is the value that the comparison should apply to the argument given by arg. For example, if one wanted to express the statement "string argument 2 should be less than 256 bytes" with the pie_string_length() function the corresponding arguments should be 2, PIE_LESS_THAN and 256.
Return values:
Upon successful completion pie_string_length() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_value -- assert an argument value.
Synopsis:
int pie_value(int arg, int action, int value);
Description:
The pie_value() function makes an assertion on the value of an argument. It checks to see that the value of an argument is permissable. The argument that is to be checked is given by arg, a number starting at 1. The action is the comparison operator that is to be used:

    PIE_LESS_THAN
    PIE_LESS_THAN_OR_EQUAL
    PIE_EQUAL
    PIE_NOT_EQUAL
    PIE_GREATER_THAN_OR_EQUAL
    PIE_GREATER_THAN

The final argument is the value that the comparison should apply to the argument given by arg. For example, if one wanted to express the statement "argument 1 should equal 4" with the pie_value() function the corresponding arguments should be 1, PIE_EQUAL and 4.
Return values:
Upon successful completion pie_value() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_match_sub_string -- assert the existance of a sub string.
Synopsis:
int pie_match_sub_string(int arg, int action, char *s);
Description:
The pie_match_sub_string() function asserts the existance of a sub string s in a string argument. The argument that is to be checked is given by arg, a number starting at 1. The action is the match operator that is to be used:

    PIE_MUST_MATCH
    PIE_MUST_NOT_MATCH

For example, if one wanted to express the statement "argument 4 should never contain the word evil" with the pie_match_sub_string() function the corresponding arguments should be 4, PIE_MUST_NOT_MATCH and "evil".
Return values:
Upon successful completion pie_match_sub_string() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_byte_at_offset -- assert a byte value at an offset.
Synopsis:
int pie_byte_at_offset(int arg, off_t offset, int action, char byte);
Description:
The pie_byte_at_offset() function makes an assertion on a byte of data at an offset from the start of an argument. It checks to see that this byte is permissable. The argument that is to be checked is given by arg, a number starting at 1. The offset to the byte that is to be checked is given by offset, where 0 would check the first byte in an argument. The action is the comparison operator that is to be used:

    PIE_LESS_THAN
    PIE_LESS_THAN_OR_EQUAL
    PIE_EQUAL
    PIE_NOT_EQUAL
    PIE_GREATER_THAN_OR_EQUAL
    PIE_GREATER_THAN

The final argument is the byte that the comparison should apply to the argument given by arg. For example, if one wanted to express the statement "the tenth byte of argument 1 should be greater than or equal to 0xcc" with the pie_byte_at_offset() function the corresponding arguments should be 1, 9, PIE_GREATER_THAN_OR_EQUAL and 0xcc. Notice that the offset is 9, not 10, as the first byte is represented by 0.
Return values:
Upon successful completion pie_byte_at_offset() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_byte_count -- assert the total count of a byte in an argument.
Synopsis:
int pie_byte_count(int arg, char byte, int action, int value);
Description:
The pie_byte_count() function counts the number of occurances of a byte in an argument and on this makes an assertion. The argument from which the byte is to be counted is given by arg, a number starting at 1. The byte argument gives the byte that will be counted, while the action is the comparison operator that is to be used:

    PIE_LESS_THAN
    PIE_LESS_THAN_OR_EQUAL
    PIE_EQUAL
    PIE_NOT_EQUAL
    PIE_GREATER_THAN_OR_EQUAL
    PIE_GREATER_THAN

The final argument is the value that the comparison should apply to the total byte count. For example, if one wanted to express the statement "argument 2 should contain the byte 0x86 less than 12 times" with the pie_byte_count() function the corresponding arguments should be 2, 0x86, PIE_LESS_THAN and 12.
Return values:
Upon successful completion pie_byte_count() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_sub_string_at_offset -- assert the existance of a sub string at an offset.
Synopsis:
int pie_sub_string_at_offset(int arg, off_t offset, int action, char *s);
Description:
The pie_sub_string_at_offset() function asserts the existance of a sub string s at an offset from the start of an argument. The argument that is to be checked is given by arg, a number starting at 1. The offset to the start of the sub string that is to be checked is given by offset, where 0 would be the first byte in an argument. The action is the match operator that is to be used:

    PIE_MUST_MATCH
    PIE_MUST_NOT_MATCH

For example, if one wanted to express that statement "the sub string starting at the seventh byte of argument 3 should match the word evil" with the pie_sub_string_at_offset() function the corresponding arguments should be 3, 6, PIE_MUST_MATCH, "evil". Notice that the offset is 6, not 7, as the first byte is represented by 0.
Return values:
Upon successful completion pie_sub_string_at_offset() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_sub_string_count -- assert the number of occurances of a sub string.
Synopsis:
int pie_sub_string_count(int arg, char *s, int action, int value);
Description:
The pie_sub_string_count() function asserts the number of times a sub string s occurs in an argument. The argument that is to be checked is given by arg, a number starting at 1. The action is the comparison operator that is to be used:

    PIE_LESS_THAN
    PIE_LESS_THAN_OR_EQUAL
    PIE_EQUAL
    PIE_NOT_EQUAL
    PIE_GREATER_THAN_OR_EQUAL
    PIE_GREATER_THAN

The final argument is the value that the comparison should apply to the total count of the sub string. For example, if one wanted to express the statement "argument 5 should contain the word evil more than 8 times" with the pie_sub_string_count() function the corresponding arguments should be 5, "evil", PIE_GREATER_THAN, 8.
Return values:
Upon successful completion pie_sub_string_count() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Name:
pie_force_return -- force a return instead of applying an assertion
Synopsis:
int pie_force_return(int ret);
Description:
The pie_force_return() function causes any calls to the target function to return immediately with a value of ret. This is not a prepatch assertion since the return behaviour is guaranteed regardless of the function argumuntes. The pie_force_return() function is intended for use with target functions that cannot be prepatched by the existing methods but can safely return without performing their designed computation.

NOTE: THIS IS A TEMPORARY SOLUTION UNTIL A MORE GENERAL RETURN MECHANISM IS IMPLEMENTED.
Return values:
Upon successful completion pie_force_return() returns 0. Otherwise, -1 is returned and the global variable errno is set to indicate the error.


Copyright (C) 2004, Ben Hawkes
SourceForge.net Logo