Ex Debian dev Michael Stapelberg discusses package install hooks and triggers and how they complicate the package manager and potentially slow down the install process. An exciting development he mentions is “hermetic packages” which is discussed briefly under the heading “Implemented in an interpreted language”. This seems to be a framework for defining wrappers in a compiled language instead of bash. Worth reaching out and discussing his views and work which can help with the stacked wrappers proposal.
He had an excellent talk on the subject of package manager speed. German language. Not sure automated translation will be good enough.
GPN19 - Linux package manager sind zu langsam! - YouTube
Contacted.
stackable wrapper, .d configuration drop-in folders
:
https://www.whonix.org/pipermail/whonix-devel/2019-August/001423.html
Could you please provide feedback for this stackable wrappers proposal?
There wasn’t much feedback on stackable wrappers from Michael Stapelberg.
- inquiry: [Whonix-devel] stackable wrapper, .d configuration drop-in folders
- reply: [Whonix-devel] stackable wrapper, .d configuration drop-in folders
Other stackable wrappers resources:
Some suggestions for the config language you can potentially use. I am not technically apt in this space so excuse any simplistic suggestions.
- How the wrappers would be specified in the config language is yet to be invented, which will be done if this implementation path looks favorable.
-
You would invoke the master wrapper script by specifying “–mwrap” in a program’s cli command. mwrap is short for mega wrapper.
-
Somehow preserve the use of mwrap with software across their updates.
-
mwrap would assume a default “wrapper.d” dir is present in the programs “etc” subfolder. This can be extended however to add other arbitrary dirs for it to look into and to chain wrappers contained therein in lexical order as you suggested.
-
The default wrapper.d location should be overridable in case it is a portable program or one installed in the home folder like TBB or /opt.
-
The order of custom wrapper folders should be interpreted according to how they are fed to the command.
-
If a duplicate wrapper script is found in two different folders, mwrap should exit with an error telling the user to change the file name before it can be applied.
-
It should be designed to run different instances per each program that uses it to avoid situations of privilege escalation. Think a malicious program in home folder can feed the mwrap instance running under sudo with arbitrary scripts if it is already used by a binary with folders in /etc/
Can’t we implement this ourselves without requiring upstream?
Create a wrapper that reads from /etc/wrapper.d/
and have wrapper_pre
(for commands to be added before the actual program) and wrapper_post
(for commands to be added after) variables based on the contents of the files there so you have:
${wrapper_pre}${program_name}${wrapper_post}
Create symlinks to run the program with our stackable wrapper by default and configure the program via wrapper.d
.
So the program has one, configurable wrapper that wraps the program with other wrappers.
An implementation of what I said above would be the following.
Create a file called /usr/bin/stackable-wrapper
and add:
#!/bin/bash
sw_dir="/etc/wrapper.d"
program_name="$(basename $0)"
if [ -f "${sw_dir}/${program_name}.conf" ]; then
. "${sw_dir}/${program_name}.conf"
else
echo "ERROR: File ${sw_dir}/${program_name}.conf doesn't exist!"
exit 1
fi
# So we don't execute ourselves.
PATH="$(echo ${PATH} | sed -e 's/\/usr\/local\/bin\://g')"
${wrapper_pre} ${program_name} ${wrapper_post}
Then create the config file e.g. /etc/wrapper.d/gpg.conf
:
wrapper_pre="torsocks firejail"
wrapper_post="--example"
Then symlink it:
ln -s /usr/bin/stackable-wrapper /usr/local/bin/gpg
Should work fine.
We don’t have to use /usr/local/bin/. We can create our own directory for this and modify $PATH to check it first.
For sure possible but then more likely not a solid, sustainable, long term maintainable solution. By asking upstream(s) for input we can avoid running into later one hard to fix issues. Also if we’d manage to make others use this too, then they won’t be inventing their own custom wrappers which then would be incompatible with other wrappers / our wrappers.
proposals/634-stackable-wrappers.txt at master · Kicksecure/proposals · GitHub on subject of $PATH currently mentions:
- amend PATH environment variable …
** …
** Does not work for services started by init / systemd.
It’s not easy to change environment variables (PATH) globally in all cases. Such cases include login in virtual console, X, run by systemd services (root), run by systemd services (user), run by cron, and whatnot. Though, that may be possible.
Changing PATH may also cause AppArmor issues? Dunno yet. Needs investigation. “Ideally” stackable wrappers won’t break existing MAC confinements.
Related:
Needs more than a single ${wrapper_pre}
. Needs to be stackable.
Here are some examples of commands to prepend:
- firejail firefox
- torsocks gpg
- LD_PRELOAD=“$LD_PRELOAD”:libeatmydata.so rsync [ld preload hardened malloc]
- bindp, timeprivacy and probably a lot more
- probably quite some dpkg diversions used for that purpose
Newer examples:
- hardend kernel apt (hkapt)
- rapt (restricted apt)
Here are some examples of commands to append:
- for ZeroNet it would be useful to always automatically append for example --tor always
I don’t understand.
For now, the idea was the wrappers to be transparent. Adding functionality (such as stream isolation, MAC confinement, etc.) but not requiring laymen user to be aware of it.
For sure. Wrappers absolutely must survive upgrades of applications these are wrapping. Needs to be added to proposal or maybe separate discussion summary document as a defined goal.
Could use the same folders as systemd config usually uses.
A config option to expand which folders will be parsed? That’s extra complexity. Not sure what would that be useful for?
/opt (and other uncommon PATHs) is a good point. If we go for PATH variable modification to implement this then all folders should be covered. It however will probably not be possible to wrap direct calls to /opt/pkg-name/binary-name. But that should be OK. Wrappers will probably only be shipped for select applications where we know where these are installed.
Duplicate detection is hard. Two different config files that both want to prepend torsocks or something? Very few applications guard against messed up configs. The ones who ship wrapper configs need to know what they are doing.
Not sure I fully understood that threat model.
However, yes, binaries in /home are another interesting question.
I guess stackable wrappers could parse $HOME/.stackable-wrappers.d
or something if that exists.
- if run with sudo: then all bets of off anyhow. A compromised home folder would mean having failed already anyhow.
- if not without sudo: then there’s no privilege escalation.
$HOME/.stackable-wrappers.d
would not execute anything that the user could not execute manually anyhow. - if run by root: it would parse
/root/.stackable-wrappers.d
(if exists) which would be safe too - if run by systemd / cron: there’s probably in most cases no
$HOME
and if there was it should not be writeable by those system users having no business there
Well, “malicious program in home folder” + sudo = fail anyhow?
I don’t see why it would cause apparmor issues.
No, you can stack commands with a single ${wrapper_pre}
. See the example above in which torsocks
and firejail
are both used for gpg
.
If you want multiple drop-in config files, we can modify the script to source ${sw_dir}/${program_name}_*.conf
. So for example, to stack torsocks
and firejail
using multiple config files you can create /etc/wrapper.d/gpg_torsocks.conf
and add:
wrapper_pre+="torsocks"
then create /etc/wrapper.d/gpg_firejail.conf
and add
wrapper_pre+="firejail"
The modified PATH would also need to apply for invocations through sudo
. Fortunately sudo
has a setting secure_path
.
madaidan via Whonix Forum:
I don’t see why it would cause apparmor issues.
Suppose git internally used gpg. Using standard PATH search to find the gpg binary. git simply calling “gpg” not “/usr/bin/gpg”. Then later an apparmor profile is added for git. By modifying the PATH variable and having gpg in any other path then the default “/usr/bin/gpg” could result in an apparmor violation.
Or perhaps Tor Browser or Firefox would call other binaries. Dunno yet any specific examples.
Perhaps an AppArmor /etc/apparmor.d/tunables/...
or so drop-in configuration snippet could solve that.
No, you can stack commands with a single
${wrapper_pre}
. See the example above in whichtorsocks
andfirejail
are both used forgpg
.If you want multiple drop-in config files,
Yes. For sure.
Each application that provides a wrapper would provide a configuration snippet. Otherwise it would be very inflexible - not using any component (for testing, Kicksecure, alternatives, whatever) no longer possible - at least not without separate user changes to wrapper configs which is bad usability.
we can modify the script to source
${sw_dir}/${program_name}_{0..9}.conf
. So for example, to stacktorsocks
andfirejail
using multiple config files you can create/etc/wrapper.d/gpg_0.conf
and add:wrapper_pre+="torsocks"
Maybe needs to add a space before or behind.
This might be good enough for an initial implementation but would break on more complex inputs perhaps including single quotes, double quotes or command line parameters that contain spaces.
Instead of setting variables directly with wrapper_pre+=
perhaps better to use a shell function because then constructing the actual variable could be done in a shell function (later fixes for white spaces etc) and wouldn’t require later config file changes.
/usr/lib/pbuilder/pdebuild-checkparams
uses
DEBBUILDOPTS=“${2:+$DEBBUILDOPTS $2}”;
EXTRA_CONFIGFILE[${#EXTRA_CONFIGFILE[@]}]=“$2”;
/usr/lib/pbuilder/pbuilder-modules
function get_source_options() {
local source_options
local arg
# Split and de-escape DEBBUILDOPTS. Can't iterate over it before
# de-escaping, as word splitting does not take quotes in the variable into
# account. Need eval as $(echo $DEBBUILDOPTS) on its own doesn't perform
# quote expansion, since quote expansion operates on the *original* word.
eval local args=($DEBBUILDOPTS)
for arg in "${args[@]}"; do
Not sure yet but proper handling for quotes, any special characters and white spaces will probably require a bash array. I don’t know any bash scripts as role models from top of my head.
then create
/etc/wrapper.d/gpg_1.conf
and add
I am not sure yet if the name of the program to be wrapped should be part of the configuration file name. Might work. What is the advantage of this? What would be the disadvantage of having the name or path of the to be wrapped application defined in the config file?
What do you think about uwt (/etc/uwt.d/30_uwt_default.conf
) syntax
uwtwrapper["/usr/bin/git"]="1"
?
/etc/wrapper.d/gpg_1.conf
would mean the first thing that would be run if someone used Debian standard PATH and would execute gpg
? Dunno if /path/to/uncommon/location should be supported.
There’s no specific reason. Having the file path in the config file does sound like a better approach.
Looks better.
How would both the pre and post wrappers be parsed correctly? Seems more complicated.
Information
ID: 634
PHID: PHID-TASK-wusarvu2cuj63v67kpy4
Author: Patrick
Status at Migration Time: open
Priority at Migration Time: Normal
Description
Subject:
stackable wrappers
Draft:
https://github.com/Whonix/proposals/blob/master/634-stackable-wrappers.txt
TODO:
- improve draft
- send to debian-devel mailing list
- discuss on debian-devel
Comments
Patrick
2017-02-16 18:31:03 UTC
HulaHoop
2017-02-17 23:55:33 UTC
Patrick
2017-02-18 17:08:49 UTC
HulaHoop
2017-02-20 02:00:51 UTC
Patrick
2017-02-20 14:25:12 UTC
dau
2017-03-20 02:21:21 UTC
Patrick
2017-03-20 13:35:50 UTC
dau
2017-03-21 01:26:37 UTC
Patrick
2017-03-21 12:53:34 UTC
dau
2017-03-21 20:22:34 UTC
Patrick
2017-03-21 22:10:29 UTC
Patrick
2019-08-17 06:56:43 UTC
dau
2017-03-21 23:36:37 UTC
dau
2017-04-08 23:28:30 UTC
Patrick
2020-02-29 11:09:45 UTC
Improved wording and formatting: