OpenOSC
Open Object Size Checking: Library to detect buffer overflows in C/C++ code
Install / Use
/learn @cisco/OpenOSCREADME
OpenOSC Library - README
Table of Contents
- Licensing
- Overview
- Design Considerations
- Relationship to FORTIFY_SOURCE
- Metric-only Mode for FORTIFY_SOURCE
- How to Build OpenOSC Library
- How to Build Packages with OpenOSC Library
- Tested Platforms
- Known Issues
- Bibliography
Licensing
This project's licensing restrictions are documented in the file 'LICENSE' under the root directory of this release. Basically it's ASL 2.0 licensed.
Overview
OpenOSC is an open-source object size check library written in C. It has been developed in order to promote the use of compiler builtin object size check capability for enhanced security. It provides robust support for detecting buffer overflows in various functions that perform operations on memory and strings. Not all types of buffer overflows can be detected with this library, but it does provide an extra level of validation for some functions that are potentially a source of buffer overflow flaws. It protects both C and C++ code.
Design Considerations
The OpenOSC library is a standalone library with the following features:
- Metrics to understand buffer overflow detection effectiveness
- Ability to detect source buffer overread as well as buffer overflow
- Truncate overflow past the end of buffer in running process
- Abort behavior configurable
- Extensible to additional data movement routines
- Extension for SafeC bounds checking library available
OpenOSC contains two parts: the mapping header files and the runtime library.
The runtime library libopenosc.so contains the code to do runtime buffer overflow checks. This library is required to be linked by all packages.
The mapping header files contain the code to perform compile-time buffer overflow checks and map various memory routines to the runtime check routines in the runtime library.
The mapping header files are only required in the package build environment, while the runtime library is required in both the deployment environment and the package build environment.
Two OSC function mapping methods are supported in OpenOSC:
#define OPENOSC_ASM_LABEL_REDIRECT_METHOD 1
#define OPENOSC_FUNC_MACRO_REDEFINE_METHOD 2
They are two different mapping methods. The ASM_LABEL_REDIRECT method uses
__asm__ label to redirect an alias function to the real function at assembly
language level, while keeping them as different functions at C language level.
The FUNC_MACRO_REDEFINE method uses macro redefining mechanism to directly
redefine a foo function as a new openosc_foo function at C language level.
The two methods both have advantages and disadvantages.
Note that if your compiler is clang, the ASM_LABEL_REDIRECT method requires that your clang version must be >= 5.0 version.
The default mapping method is 1, the ASM_LABEL_REDIRECT method. User can choose the FUNC_MACRO_REDEFINE method by adding the below define to CFLAGS:
CFLAGS += "-DOPENOSC_MM=2"
New mapping method can be added as needed in future.
- Built-in OSC-METRICS feature
The built-in OSC-METRICS feature can be enabled by the below flag to CFLAGS:
CFLAGS += "-DOPENOSC_METRIC_FEATURE_ENABLED"
Additionally, the objsize-METRICS feature can be enabled by the below:
CFLAGS += "-DOPENOSC_METRIC_OBJSIZE_ENABLED"
Two OSC-watermarking methods are supported in OpenOSC:
#define RTD_ASM_BYTE_METHOD 1
#define RTD_ASM_LOC_METHOD 2
The default method is RTD_ASM_LOC_METHOD. This method uses DWARF debugging info,
so it requires the -g CFLAGS to take effect. And the OSC-METRICS info can be
stripped via the strip command, just like other debugging info. The other method
RTD_ASM_BYTE_METHOD directly inserts MAGIC words into the code, so it occupies
code memory, and does not require -g CFLAGS to take effect, also OSC-METRICS
info cannot be stripped. You can add "-DOPENOSC_METRIC_METHOD=1" to CFLAGS to
force using the RTD_ASM_BYTE_METHOD.
After building your binaries with the above CFLAGS, You can run the oscmetrics tool to collect the OSC-METRICS:
$ tools/oscmetrics.py -bmwv -d your-dir > metrics-report.txt
If the non-default RTD_ASM_BYTE_METHOD is used to generate OSC-METRICs info,
then you need to add the -t option to specify the type:
$ tools/oscmetrics.py -bmwv -d your-dir -t byte_inline > metrics-report.txt
It can generate a WatermarkPC decoding table as below:
###################################################
OSC-METRIC WatermarkPC summary for all binary files
## Note: DSTSIZE is format of: (dstsize, srcsize, copylen), (dstsize, copylen), or (dstsize).
## Copy-length of -9 means that the copy-length parameter
## for memcpy is unknown (non-constant) at compile-time.
###################################################
FileIndex: 3 ./test/openosc_test_cpp
Idx PC OSCFUNC CASE# DSTSIZE SRCFUNC SRCLINE
---------------------------------------------------------------------------------------
0 0x400ce5 memcpy CASE7 5,20,4 openosc_test_memcpy() openosc_test_cpp.cpp:23
1 0x400de4 memcpy CASE2 5,20,7 openosc_test_memcpy() openosc_test_cpp.cpp:28
2 0x400e31 memcpy CASE2 5,20,8 openosc_test_memcpy() openosc_test_cpp.cpp:30
3 0x400ea3 memcpy CASE3 5,20,-9 openosc_test_memcpy() openosc_test_cpp.cpp:33
4 0x400f15 memcpy CASE3 5,20,-9 openosc_test_memcpy() openosc_test_cpp.cpp:34
5 0x400f8b memcpy CASE3 5,20,-9 openosc_test_memcpy() openosc_test_cpp.cpp:36
6 0x400fdd memcpy CASE2 0,20,1 openosc_test_memcpy() openosc_test_cpp.cpp:38
7 0x401049 memcpy CASEa -1,20,2 openosc_test_memcpy() openosc_test_cpp.cpp:40
One trick: To generate the binary even when buffer overflow errors exist, add
-DOPENOSC_OVERFLOW_ERROR_OUT_DISABLE to CFLAGS. This will just print warnings
instead of errors at compile-time so that binary can be generated. If you use
-DOPENOSC_MM=2 CFLAGS, then you can add -DOPENOSC_METRIC_ONLY_MODE to CFLAGS
to collect OSC metrics only.
Trick #2: the oscmetrics.py tool ignores intermediate relocatable *.o files by
default. You can add --scan_all_elf_files option to force the tool to scan the
*.o files too.
Trick #3: for cross-compilation binaries, you may need to specify the location
of cross-compilation tools: objdump, addr2line, etc. in a configfile, then run
oscmetrics.py with -c configfile option to get correct results.
Relationship to FORTIFY_SOURCE
Most compilers (gcc/clang/icc) provide the FORTIFY_SOURCE feature.
It is enabled by adding -D_FORTIFY_SOURCE=2 option to CFLAGS.
CFLAGS += "-D_FORTIFY_SOURCE=2"
OpenOSC and compiler's FORTIFY_SOURCE are both built upon the compiler's builtin object size check capability, thus are equivalent in providing memory overflow detection/protection. As a result, a package can only be compiled with one of them: either OpenOSC or FORTIFY_SOURCE, but not both. FORTIFY_SOURCE and OpenOSC are mutually exclusive. OpenOSC will automatically detect the existence of _FORTIFY_SOURCE flag, and disable OpenOSC if detected.
OpenOSC can co-exist with FORTIFY_SOURCE. That is, some packages or binaries can be compiled with OpenOSC, and some other packages/binaries can be compiled with FORTIFY_SOURCE. They can co-exist on the same Linux system, and will be protected by different runtime libraries.
Here is a comparison summary table:
| Feature/Behavior | FORTIFY_SOURCE | OpenOSC | | ----------------- | -------------- | ------------------- | | OSC Metrics | No support | Supported | | Source Overread | No support | Supported | | Traceback | No traceback | Print traceback | | Abort behavior | Always abort | Configurable | | Copy truncation | No truncate | Yes/Configurable | | Logging | No syslog | Syslog/Configurable | | Cover new routine | Not easy | Easy |
Metric-only Mode for FORTIFY_SOURCE
The OpenOSC OSC-METRICS feature has been enhanced to work with FORTIFY_SOURCE feature enabled.
It is enabled by adding -DOPENOSC_METRIC_ONLY_MODE option to CFLAGS.
CFLAGS += "-include openosc.h -DOPENOSC_METRIC_ONLY_MODE -D_FORTIFY_SOURCE=2"
This does not turn on OSC-METRICS for objsize/copylen. If you want it, add the OPENOSC_METRIC_OBJSIZE_ENABLED flag.
CFLAGS += "-include openosc.h -DOPENOSC_METRIC_ONLY_MODE -DOPENOSC_METRIC_OBJSIZE_ENABLED -D_FORTIFY_SOURCE=2"
This will generate the same OSC-METRICS watermarks for the compiled binary file with the OPENOSC_METRIC_FEATURE_ENABLED flag. And you can use the same tools/oscmetrics.py script to decode the OSC-METRICS watermarks.
With this OPENOSC_METRIC_ONLY_MODE flag, the memory/string functions will always be mapped to itself, except for the addition of OSC-METRICS. The generated assembly/binary code should also be the same as before, except for the addition of OSC-METRICS. Of course, out-of-order generation of some assembly instructions are expected, and still considered the same code.
The nice thing about this metric-only mode is that you don't need to build the libopenosc.so library. You don't need to change your linking LDFLAGS, since you don't link with any additional library. The only change required is CFLAGS.
Note this Metric-only mode also works without FORTIFY_SOURCE feature. It will map all functions to themselves, except for the addition of OS
Related Skills
node-connect
340.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
84.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
340.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
84.1kCommit, push, and open a PR
