This project is under Development, most functionalities are not implemented yet.
LDFL (LD File Liar) is a powerful LD_PRELOAD library that intercepts and modify libc file system operations. It allows you to:
- Log Filesystem Interactions: File & Directory manipulation can be logged to syslog or stderr
- Remap File Paths: Redirect file access to different locations
- Control File Access: Restrict or allow access to specific files/directories
- Modify File Permissions: Change ownership and permissions on-the-fly
- Memory-based Files: Serve files directly from memory
- Static Content: Serve predefined static content
- Executable Redirection: Redirect executable paths
This tool can be used on existing binaries or can be included with a static configuration header inside your projects.
You can also view the latest documentation online at GitHub Pages.
The following dependencies are required to build ldfl:
- CMake (version 3.12 or higher)
- PCRE2 library
- Jansson library
- CUnit (optional, for tests)
- Doxygen (optional, for documentation)
On Ubuntu/Debian, you can install these dependencies with:
sudo apt update
sudo apt install -y cmake libpcre2-dev libjansson-dev libcunit1-dev doxygen- Clone the repository:
git clone https://github.com/kakwa/ldfl.git
cd ldfl- Create a build directory and configure CMake:
cmake .- Build the project:
makeOptional build options:
-DBUILD_TESTS=ON: Enable building tests-DBUILD_DOC=ON: Enable building documentation-DCOVERAGE=ON: Enable code coverage (requires-DBUILD_TESTS=ON)-DDEBUG=ON: Build with debug symbols-DSTATIC=ON: Build static library
To run the tests & coverage
cmake . -DBUILD_TESTS=ON -DCOVERAGE=ON
make
make coverage
$BROWSER coverage/index.htmlTo build the documentation:
# Configure CMake
cmake -DBUILD_DOC=ON .
# Get Doxygen awesome CSS
./misc/setup_doxycss.sh
# Build Doc
make
# open the doc
$BROWSER ./docs/html/index.htmlAfter building, you can install the library system-wide:
sudo make installThis will install:
- The library (
libldfl.so) to/usr/local/lib/ - The wrapper executable (
ldfl-cli) to/usr/local/bin/
- Create a configuration file (e.g.,
config.json) with your rule rules:
ldfl-cli -c config.json -- your-application [args...]To enable debug output, use the -d flag:
ldfl-cli -d -c config.json -- your-application [args...]If you need to specify a custom library path:
ldfl-cli -l /path/to/libldfl.so -c config.json -- your-application [args...]You can use LDFL directly with LD_PRELOAD without the wrapper:
# Set the configuration file
export LDFL_CONFIG=/path/to/config.json
# Preload the library
LD_PRELOAD=/path/to/libldfl.so your-application [args...]The configuration file is a JSON file with two main sections: settings and rules.
The settings section controls the logging behavior:
{
"settings": {
"log_mask": [
"rule_found",
"fn_call",
"init",
"rule_apply",
"rule_search",
"fn_call_err"
],
"log_level": "warning",
"logger": "syslog"
}
}Available log masks:
rule_found: Log when a rule rule is foundfn_call: Log LibC function callsinit: Log initialization operationsrule_apply: Log when a rule rule is appliedrule_search: Log rule search operationsfn_call_err: Log LibC function call errors
Log levels:
debuginfowarningerror
Loggers:
syslog: System loggerstderr: Standard error outputdummy: No logging
The rules section defines the file path rerule rules. Each rule has the following properties:
{
"rules": [
{
"name": "<descriptive/name>",
"search_pattern": "<regex pattern>",
"operation": "<operation type>",
"target": "<target path>",
"path_transform": "<absolute|original>",
"extra_options": "<operation specific options>",
"final": false
}
]
}- File Redirection (
path_redir):
{
"name": "temp files redirect",
"search_pattern": ".*/temp/([^/]*)$",
"operation": "path_redir",
"target": "/tmp/$1",
"path_transform": "absolute",
"final": false
}- Executable Redirection (
exec_redir):
{
"name": "executable redirect",
"search_pattern": ".*/.bin/\\([^/]*\\)$",
"operation": "exec_redir",
"target": "/opt/ldfl/bin/\\1",
"path_transform": "absolute",
"final": false
}- Memory File (
mem_open):
{
"name": "memory open",
"search_pattern": ".*/file[0-9].txt",
"operation": "mem_open",
"target": null,
"path_transform": "absolute",
"final": false
}- Static File (
mem_data):
{
"name": "static file",
"search_pattern": ".*/static.bin",
"operation": "mem_data",
"target": "default_blob",
"path_transform": "absolute",
"final": false
}- Permission Change (
perm):
{
"name": "change data perm",
"search_pattern": ".*/data/.*",
"operation": "perm",
"target": null,
"path_transform": "absolute",
"final": false,
"extra_options": "user:group|dir_mode|file_mode"
}- Access Control:
- Allow (
noop):
- Allow (
{
"name": "allow /dev",
"search_pattern": "^/dev/.*",
"operation": "noop",
"target": null,
"path_transform": "absolute",
"final": false
}- Deny (
deny):
{
"name": "default & deny",
"search_pattern": ".*",
"operation": "deny",
"target": null,
"path_transform": "absolute",
"final": false
}- Read-Only (
ro):
{
"name": "read only files",
"search_pattern": ".*/readonly/.*",
"operation": "ro",
"target": null,
"path_transform": "absolute",
"final": false
}For embedding LDFL in your project, copy over lib/ldfl.c in your project.
Create a header file (e.g., ldfl-config.h) with your configuration:
static const unsigned char ldf_default_blob[] = "hello from ldfl";
ldfl_rule_t ldfl_rule[] = {
/* name search_pattern operation target path_transform, final, extra_options */
{ "temp files redirect", ".*/temp/([^/]*)$", LDFL_OP_PATH_REDIR, "/tmp/$1", LDFL_PATH_ABS, false, NULL },
{ "inc redirect", "(.*)/inc/(.*)", LDFL_OP_PATH_REDIR, "$1/lib/$2", LDFL_PATH_ABS, false, NULL },
{ "executable redirect", ".*/.bin/\\([^/]*\\)$", LDFL_OP_EXEC_REDIR, "/opt/ldfl/bin/\\1", LDFL_PATH_ABS, false, NULL },
{ "memory open", ".*/file[0-9].txt", LDFL_OP_MEM_OPEN, NULL, LDFL_PATH_ABS, false, NULL },
{ "static file", ".*/static.bin", LDFL_OP_MEM_DATA, ldf_default_blob, LDFL_PATH_ABS, false, NULL },
{ "change data perm", ".*/data/.*", LDFL_OP_PERM, NULL, LDFL_PATH_ABS, false, "kakwa:kakwa|0700|0600"},
{ "allow /dev", "^/dev/.*", LDFL_OP_NOOP, NULL, LDFL_PATH_ABS, false, NULL },
{ "default & deny", ".*", LDFL_OP_DENY, NULL, LDFL_PATH_ABS, false, NULL },
{ NULL, NULL, LDFL_OP_END, NULL, LDFL_PATH_ABS, false, NULL } // keep this last value
};
ldfl_setting_t ldfl_setting = {
.log_mask = LDFL_LOG_MAPPING_RULE_FOUND | LDFL_LOG_FN_CALL | LDFL_LOG_INIT | LDFL_LOG_MAPPING_RULE_APPLY | LDFL_LOG_FN_CALL_ERR,
.log_level = LOG_WARNING,
.logger = ldfl_syslog_logger,
};In your code, add:
#define LDFL_CONFIG "ldfl-config.h"
#include "ldfl.c"Link against libpcre2 (-lpcre2-8) if necessary.
And finally, build your project.