This is an LLVM pass for inter-procedural whole program analysis of Linux program
capabilities. Currently it requires that your programs properly instrumented with
privilege library calls in PrivLibrary
directory.
See here for Linux capabilities.
This pass is able to infer from your instrumentations where certain capabilities
are live in the program, and ergo where in the program you can savely remove
capabilities. Based on this information, it could automatically insert calls
from PrivLibrary
to remove capabilities, enforcing the Principle of Minimal
Capabilities.
So far compiling requires putting code inside the LLVM source tree. Standalone compilation coming on the way.
-
Go to
${LLVM_SRC_DIR}/lib/Transform/
, backup yourLLVMBuild.txt
,CMakeLists.txt
andMakefile
files. -
Clone this repo.
-
Copy all its contents to the
lib/Transform
directory of the LLVM source tree. Use the following script to finish the whole process. Before that, make sure you have all your Makefile related files backed up.git clone https://github.com/hxy9243/priv_analysis.git -b printGlobal cp -R priv_analysis/* .
-
In your build directory of LLVM, go to
${LLVM_BUILD_DIR}/lib/Transform/
, edit the Makefile, add the following to the Makefile fieldPARALLEL_DIRS:
PrivAnalysis ExternFunCall
. -
Type
make
to make them all. -
The library shall now be compiled and moved in your
${LLVM_BUILD_DIR}/${Release_Or_Debug}/lib/
directory.${Release_Or_Debug}
could beRelease
,Debug
,Release+Asserts
orDebug+Asserts
, depending on your LLVM compile options.Right now you should to able to see the
LLVMPrivAnalysis.so
andLLVMExternFunCall.so
shared libraries in the lib folder.
To use the pass, your code needs to be properly instrumented with privilege bracketing. That is, all privileged external function calls need to be bracketed. Privilege will be raised in the EFFECTIVE set right before the call, and lowered right after the call.
This repo provides with a simple interface to Linux capability library for privilege bracketing.
The related functions are:
-
int priv_lowerall()
: Lower all privilges in the EFFECTIVE set. -
int priv_raise(int count, ...)
: Raise one to a few capabilities in the EFFECTIVE set.parameter count -- the number of capabilities to operate on,
parameter ... -- the name of the capabilities.
See here for more on capabilities.
-
int priv_lower(int count, ...)
: Lower one to a few capabilites in the EFFECTIVE set. parameter same aspriv_raise
. -
int priv_remove(int count, ...)
: Remove one to a few capabilities from the PERMITTED set, making them never usable in the same process. Parameter same aspriv_raise
. This is to be inserted automatically by the pass transformation.
The shared library pass presumes the following for the pass to be properly working:
-
All external function calls are properly bracketed with
priv_raise
andpriv_lower
.For example:
priv_raise(1, CAP_SETUID); setuid(some_other_uid_that_requires_capability_to_change_into); priv_lower(1, CAP_SETUID); .... priv_raise(1, CAP_CHROOT); chroot("some_path"); priv_lower(1, CAP_CHROOT);
-
Paired
priv_raise
andpriv_lower
must be in the same Basic Block. There are no control flow related instructions inside the bracketing.Therefore the following code:
if (setuid(id)) { ... }
needs to be transformed into the following for correct and fine-grained bracketing.
priv_raise(1, CAP_SETUID); int setuid\_return = setuid(id); priv\_lower(1, CAP\_SETUID); if (setuid\_return) { ... }
Use opt inside the build directory to use the shared library. (Known issue: using opt built from other sources, e.g. system-wise installed opt from package manager, may result in errors.)
Use the compiled library with opt:
${LLVM_BUILD_DIR}/${Release_Or_Debug}/bin/opt -load ${LLVM_BUILD_DIR}/${Release_Or_Debug}/lib/${SHARED_LIBRARY} -${PASS_NAME} ${OPTION} bitcode.bc > bitcode.opt.bc
SHARED_LIBRARY
is the shared library we obtained, which is
LLVMPrivAnalysis.so
or LLVMExternFunCall.so
,
PASS_NAME
is the name of the pass inside each shared library, explained in detail below.
So for example, if you want to insert remove capability instructions, run with the following command, and get transformed bitcode in bitcode.opt.bc:
${LLVM_BUILD_DIR}/Release+Asserts/bin/opt -load ${LLVM_BUILD_DIR}/Release+Asserts/lib/LLVMPrivAnalysis.so -PrivRemoveInsert bitcode.bc > bitcode.opt.bc
-
ExternFunCall pass: Print the external function calls from the input bitcode source, e.g. the standard C library, or external library whose source is not in the bitcode file.
Run with:
--analyze
option to see the output.This is an assist pass for figuring out which function calls needs privilege bracketing.
-
SplitBB pass: Internal pass for splitting the Basic Blocks for easier analysis.
-
LocalAnalysis pass: Internal pass for inferring bracketed privileged calls. Depends on SplitBB pass.
-
PropagateAnalysis pass: Propagate information along in Call Graph. Depends on LocalAnalysis pass.
-
GlobalLiveAnalysis pass: Infer live information depending on Call Graph and Control Flow Graphs from all functions. Depends on Propagate Analysis pass and UnifyExitNode pass (built pass in LLVM).
Run with
--analyze
to see the unique set of capabilities for the whole source program. -
PrivRemoveInsert pass: Insert
priv_remove
calls to proper locations where capabilities are no more live. Depends on GlobalLiveAnalysis.
The GNU General Public License is a free, copyleft license for software and other kinds of works.