setcap-wrapper: Addressing more PR feedback, unifying drvs, and cleaning up a bit
This commit is contained in:
parent
e92b8402b0
commit
3fe7b1a4c9
@ -3,17 +3,27 @@ let
|
|||||||
|
|
||||||
inherit (config.security) wrapperDir;
|
inherit (config.security) wrapperDir;
|
||||||
|
|
||||||
isNotNull = v: if v != null || v != "" then true else false;
|
wrappers = config.security.wrappers;
|
||||||
|
mkWrapper = { program, source ? null, ...}: ''
|
||||||
|
if ! source=${if source != null then source else "$(readlink -f $(PATH=$WRAPPER_PATH type -tP ${program}))"}; then
|
||||||
|
# If we can't find the program, fall back to the
|
||||||
|
# system profile.
|
||||||
|
source=/nix/var/nix/profiles/default/bin/${program}
|
||||||
|
fi
|
||||||
|
|
||||||
cfg = config.security.wrappers;
|
gcc -Wall -O2 -DSOURCE_PROG=\"$source\" -DWRAPPER_DIR=\"${config.security.wrapperDir}\" \
|
||||||
|
-lcap-ng -lcap ${./permissions-wrapper.c} -o $out/bin/${program}.wrapper -L ${pkgs.libcap.lib}/lib -L ${pkgs.libcap_ng}/lib \
|
||||||
|
-I ${pkgs.libcap.dev}/include -I ${pkgs.libcap_ng}/include -I ${pkgs.linuxHeaders}/include
|
||||||
|
'';
|
||||||
|
|
||||||
setcapWrappers = import ./setcap-wrapper-drv.nix {
|
wrappedPrograms = pkgs.stdenv.mkDerivation {
|
||||||
inherit config lib pkgs;
|
name = "permissions-wrapper";
|
||||||
};
|
unpackPhase = "true";
|
||||||
|
installPhase = ''
|
||||||
setuidWrappers = import ./setuid-wrapper-drv.nix {
|
mkdir -p $out/bin
|
||||||
inherit config lib pkgs;
|
${lib.concatMapStrings mkWrapper wrappers}
|
||||||
};
|
'';
|
||||||
|
}
|
||||||
|
|
||||||
###### Activation script for the setcap wrappers
|
###### Activation script for the setcap wrappers
|
||||||
mkSetcapProgram =
|
mkSetcapProgram =
|
||||||
@ -23,8 +33,10 @@ let
|
|||||||
, owner ? "nobody"
|
, owner ? "nobody"
|
||||||
, group ? "nogroup"
|
, group ? "nogroup"
|
||||||
...
|
...
|
||||||
}: ''
|
}:
|
||||||
cp ${setcapWrappers}/bin/${program}.wrapper $wrapperDir/${program}
|
assert (lib.versionAtLeast (lib.getVersion config.boot.kernelPackages.kernel) "4.3");
|
||||||
|
''
|
||||||
|
cp ${wrappedPrograms}/bin/${program}.wrapper $wrapperDir/${program}
|
||||||
|
|
||||||
# Prevent races
|
# Prevent races
|
||||||
chmod 0000 $wrapperDir/${program}
|
chmod 0000 $wrapperDir/${program}
|
||||||
@ -33,9 +45,6 @@ let
|
|||||||
# Set desired capabilities on the file plus cap_setpcap so
|
# Set desired capabilities on the file plus cap_setpcap so
|
||||||
# the wrapper program can elevate the capabilities set on
|
# the wrapper program can elevate the capabilities set on
|
||||||
# its file into the Ambient set.
|
# its file into the Ambient set.
|
||||||
#
|
|
||||||
# Only set the capabilities though if we're being told to
|
|
||||||
# do so.
|
|
||||||
${pkgs.libcap.out}/bin/setcap "cap_setpcap,${capabilities}" $wrapperDir/${program}
|
${pkgs.libcap.out}/bin/setcap "cap_setpcap,${capabilities}" $wrapperDir/${program}
|
||||||
|
|
||||||
# Set the executable bit
|
# Set the executable bit
|
||||||
@ -53,7 +62,7 @@ let
|
|||||||
, permissions ? "u+rx,g+x,o+x"
|
, permissions ? "u+rx,g+x,o+x"
|
||||||
...
|
...
|
||||||
}: ''
|
}: ''
|
||||||
cp ${setuidWrappers}/bin/${program}.wrapper $wrapperDir/${program}
|
cp ${wrappedPrograms}/bin/${program}.wrapper $wrapperDir/${program}
|
||||||
|
|
||||||
# Prevent races
|
# Prevent races
|
||||||
chmod 0000 $wrapperDir/${program}
|
chmod 0000 $wrapperDir/${program}
|
||||||
@ -147,10 +156,10 @@ in
|
|||||||
|
|
||||||
###### implementation
|
###### implementation
|
||||||
config = {
|
config = {
|
||||||
# Make sure our setcap-wrapper dir exports to the PATH env
|
# Make sure our wrapperDir exports to the PATH env variable when
|
||||||
# variable when initializing the shell
|
# initializing the shell
|
||||||
environment.extraInit = ''
|
environment.extraInit = ''
|
||||||
# The permissions wrappers override other bin directories.
|
# Wrappers override other bin directories.
|
||||||
export PATH="${wrapperDir}:$PATH"
|
export PATH="${wrapperDir}:$PATH"
|
||||||
'';
|
'';
|
||||||
|
|
||||||
@ -162,16 +171,17 @@ in
|
|||||||
config.security.setuidPrograms)
|
config.security.setuidPrograms)
|
||||||
++ lib.mapAttrsToList
|
++ lib.mapAttrsToList
|
||||||
(n: v: (if v ? "program" then v else v // {program=n;}))
|
(n: v: (if v ? "program" then v else v // {program=n;}))
|
||||||
cfg.wrappers;
|
wrappers;
|
||||||
|
|
||||||
wrapperPrograms =
|
mkWrappedPrograms =
|
||||||
builtins.map
|
builtins.map
|
||||||
(s: if (s ? "setuid" && s.setuid == true) ||
|
(s: if (s ? "capabilities")
|
||||||
|
then mkSetcapProgram s
|
||||||
|
else if
|
||||||
|
(s ? "setuid" && s.setuid == true) ||
|
||||||
(s ? "setguid" && s.setguid == true) ||
|
(s ? "setguid" && s.setguid == true) ||
|
||||||
(s ? "permissions")
|
(s ? "permissions")
|
||||||
then mkSetuidProgram s
|
then mkSetuidProgram s
|
||||||
else if (s ? "capabilities")
|
|
||||||
then mkSetcapProgram s
|
|
||||||
else ""
|
else ""
|
||||||
) programs;
|
) programs;
|
||||||
|
|
||||||
@ -185,7 +195,7 @@ in
|
|||||||
wrapperDir=$(mktemp --directory --tmpdir=${wrapperDir} wrappers.XXXXXXXXXX)
|
wrapperDir=$(mktemp --directory --tmpdir=${wrapperDir} wrappers.XXXXXXXXXX)
|
||||||
chmod a+rx $wrapperDir
|
chmod a+rx $wrapperDir
|
||||||
|
|
||||||
${lib.concatStringsSep "\n" (builtins.filter isNotNull cfg.wrappers)}
|
${lib.concatStringsSep "\n" mkWrappedPrograms}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -26,16 +26,6 @@ extern char **environ;
|
|||||||
static char * sourceProg = SOURCE_PROG;
|
static char * sourceProg = SOURCE_PROG;
|
||||||
static char * wrapperDir = WRAPPER_DIR;
|
static char * wrapperDir = WRAPPER_DIR;
|
||||||
|
|
||||||
// Make sure we have the WRAPPER_TYPE macro specified at compile
|
|
||||||
// time...
|
|
||||||
#ifdef WRAPPER_SETCAP
|
|
||||||
static char * wrapperType = "setcap";
|
|
||||||
#elif defined WRAPPER_SETUID
|
|
||||||
static char * wrapperType = "setuid";
|
|
||||||
#else
|
|
||||||
#error "Program must be compiled with either the WRAPPER_SETCAP or WRAPPER_SETUID macro"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Update the capabilities of the running process to include the given
|
// Update the capabilities of the running process to include the given
|
||||||
// capability in the Ambient set.
|
// capability in the Ambient set.
|
||||||
static void set_ambient_cap(cap_value_t cap)
|
static void set_ambient_cap(cap_value_t cap)
|
||||||
@ -66,7 +56,7 @@ static int make_caps_ambient(const char *selfPath)
|
|||||||
|
|
||||||
if(!caps)
|
if(!caps)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "could not retreive the capability set for this file\n");
|
fprintf(stderr, "no caps set or could not retrieve the caps for this file, not doing anything...\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +161,16 @@ int main(int argc, char * * argv)
|
|||||||
|
|
||||||
assert(selfPathSize > 0);
|
assert(selfPathSize > 0);
|
||||||
|
|
||||||
|
// Assert we have room for the zero byte, this ensures the path
|
||||||
|
// isn't being truncated because it's too big for the buffer.
|
||||||
|
//
|
||||||
|
// A better way to handle this might be to use something like the
|
||||||
|
// whereami library (https://github.com/gpakosz/whereami) or a
|
||||||
|
// loop that resizes the buffer and re-reads the link if the
|
||||||
|
// contents are being truncated.
|
||||||
|
assert(selfPathSize < sizeof(selfPath));
|
||||||
|
|
||||||
|
// Set the zero byte since readlink doesn't do that for us.
|
||||||
selfPath[selfPathSize] = '\0';
|
selfPath[selfPathSize] = '\0';
|
||||||
|
|
||||||
// Make sure that we are being executed from the right location,
|
// Make sure that we are being executed from the right location,
|
||||||
@ -207,8 +207,7 @@ int main(int argc, char * * argv)
|
|||||||
// Read the capabilities set on the file and raise them in to the
|
// Read the capabilities set on the file and raise them in to the
|
||||||
// Ambient set so the program we're wrapping receives the
|
// Ambient set so the program we're wrapping receives the
|
||||||
// capabilities too!
|
// capabilities too!
|
||||||
if (strcmp(wrapperType, "setcap") == 0)
|
make_caps_ambient(selfPath);
|
||||||
assert(!make_caps_ambient(selfPath));
|
|
||||||
|
|
||||||
execve(sourceProg, argv, environ);
|
execve(sourceProg, argv, environ);
|
||||||
|
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.security.wrappers;
|
|
||||||
|
|
||||||
# Produce a shell-code splice intended to be stitched into one of
|
|
||||||
# the build or install phases within the derivation.
|
|
||||||
mkSetcapWrapper = { program, source ? null, ...}: ''
|
|
||||||
if ! source=${if source != null then source else "$(readlink -f $(PATH=$PERMISSIONS_WRAPPER_PATH type -tP ${program}))"}; then
|
|
||||||
# If we can't find the program, fall back to the
|
|
||||||
# system profile.
|
|
||||||
source=/nix/var/nix/profiles/default/bin/${program}
|
|
||||||
fi
|
|
||||||
|
|
||||||
gcc -Wall -O2 -DWRAPPER_SETCAP=1 -DSOURCE_PROG=\"$source\" -DWRAPPER_DIR=\"${config.security.run-wrapperDir}\" \
|
|
||||||
-lcap-ng -lcap ${./permissions-wrapper.c} -o $out/bin/${program}.wrapper -L ${pkgs.libcap.lib}/lib -L ${pkgs.libcap_ng}/lib \
|
|
||||||
-I ${pkgs.libcap.dev}/include -I ${pkgs.libcap_ng}/include -I ${pkgs.linuxHeaders}/include
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
|
|
||||||
# This is only useful for Linux platforms and a kernel version of
|
|
||||||
# 4.3 or greater
|
|
||||||
assert pkgs.stdenv.isLinux;
|
|
||||||
assert lib.versionAtLeast (lib.getVersion config.boot.kernelPackages.kernel) "4.3";
|
|
||||||
|
|
||||||
pkgs.stdenv.mkDerivation {
|
|
||||||
name = "setcap-wrapper";
|
|
||||||
unpackPhase = "true";
|
|
||||||
buildInputs = [ pkgs.linuxHeaders ];
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
|
|
||||||
# Concat together all of our shell splices to compile
|
|
||||||
# binary wrapper programs for all configured setcap programs.
|
|
||||||
${lib.concatMapStrings mkSetcapWrapper cfg.setcap}
|
|
||||||
'';
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
cfg = config.security.wrappers;
|
|
||||||
|
|
||||||
# Produce a shell-code splice intended to be stitched into one of
|
|
||||||
# the build or install phases within the derivation.
|
|
||||||
mkSetuidWrapper = { program, source ? null, ...}: ''
|
|
||||||
if ! source=${if source != null then source else "$(readlink -f $(PATH=$WRAPPER_PATH type -tP ${program}))"}; then
|
|
||||||
# If we can't find the program, fall back to the
|
|
||||||
# system profile.
|
|
||||||
source=/nix/var/nix/profiles/default/bin/${program}
|
|
||||||
fi
|
|
||||||
|
|
||||||
gcc -Wall -O2 -DWRAPPER_SETUID=1 -DSOURCE_PROG=\"$source\" -DWRAPPER_DIR=\"${config.security.run-wrapperDir}\" \
|
|
||||||
-lcap-ng -lcap ${./permissions-wrapper.c} -o $out/bin/${program}.wrapper -L ${pkgs.libcap.lib}/lib -L ${pkgs.libcap_ng}/lib \
|
|
||||||
-I ${pkgs.libcap.dev}/include -I ${pkgs.libcap_ng}/include -I ${pkgs.linuxHeaders}/include
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
|
|
||||||
# This is only useful for Linux platforms and a kernel version of
|
|
||||||
# 4.3 or greater
|
|
||||||
assert pkgs.stdenv.isLinux;
|
|
||||||
|
|
||||||
pkgs.stdenv.mkDerivation {
|
|
||||||
name = "setuid-wrapper";
|
|
||||||
unpackPhase = "true";
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/bin
|
|
||||||
|
|
||||||
# Concat together all of our shell splices to compile
|
|
||||||
# binary wrapper programs for all configured setcap programs.
|
|
||||||
${lib.concatMapStrings mkSetuidWrapper cfg.setuid}
|
|
||||||
'';
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user