On Tue, Apr 25, 2023 at 09:43:38AM -0500, Jonathon Jongsma wrote:
On 4/25/23 8:11 AM, Erik Skultety wrote:
> On Mon, Apr 24, 2023 at 03:50:48PM -0500, Jonathon Jongsma wrote:
> > When running libvirt from the build directory with the 'run' script,
it
> > will run as unconfined_t. This can result in unexpected behavior when
> > selinux is enforcing due to the fact that the selinux policies are
> > written assuming that libvirt is running with the
> > system_u:system_r:virtd_t context. This patch adds a new --selinux
> > option to the run script. When this option is specified, it will launch
> > the specified binary using the 'runcon' utility to set its selinux
> > context to the one mentioned above. Since this requires root privileges,
> > setting the selinux context is not the default behavior and must be
> > enabled with the command line switch.
>
> A fiddled with writing custom selinux transition rules to achieve the same
> thing a couple years back, but never finished it. No wonder, this is a much
> cleaner approach.
> I will only comment on the Python side of things, leaving the overall approach
> and idea commenting to someone else.
>
> >
> > Signed-off-by: Jonathon Jongsma <jjongsma(a)redhat.com>
> > ---
> > run.in | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------
> > 1 file changed, 50 insertions(+), 6 deletions(-)
> >
> > diff --git a/run.in b/run.in
> > index c6d3411082..4aa458b791 100644
> > --- a/run.in
> > +++ b/run.in
> > @@ -40,6 +40,7 @@
> > #
> > # ----------------------------------------------------------------------
> > +import argparse
> > import os
> > import os.path
> > import random
> > @@ -59,15 +60,20 @@ def prepend(env, varname, extradir):
> > here = "@abs_builddir@"
> > -if len(sys.argv) < 2:
> > - print("syntax: %s BINARY [ARGS...]" % sys.argv[0],
file=sys.stderr)
>
> Since you decided to use argparse (yes please), we can drop ^this if we
> properly set the arguments with argparse, it'll even generate the help for us.
> This way it looks only like a partial solution. Argparse has great
> documentation so you can just take one of the examples they list.
Yeah, I probably should have commented on why I used this 'partial'
approach. I tried a few different ways, including adding a positional
argument to argparse that would capture the target executable and its
arguments like so:
argsparse.add_argument("args",
nargs="+")
and then parsing with parser.parse_args() rather than parse_known_args().
But that prevented me from passing arguments to the target binary without
inserting a '--' in to indicate that the run script should stop parsing:
Fails:
# ./_build/run --selinux ./_build/src/libvirtd --verbose
usage: run [--selinux] args [args ...]
run: error: unrecognized arguments: --verbose
Works:
# ./_build/run --selinux -- ./_build/src/libvirtd --verbose
2023-04-25 14:26:32.175+0000: 1530463: info : libvirt version: 9.3.0
...
That seemed annoying to me.
Maybe we could keep using parse_known_args() with the 'args' argument
defined above, but I have a vague recollection that this caused some other
undesirable behavior so I switched back to the version I submitted. I'll try
to refresh my memory.
>
> > +parser = argparse.ArgumentParser(add_help=False)
>
> Why don't we want the automatic help?
Because then the run script would intercept the --help option and prevent us
from passing it to e.g. libvirt or virsh. Maybe that's not something that we
really care about, but I made the choice to pass as much through to the
executable as possible.
Right, good point. Without trying it myself, could we utilize subparsers for
this? IOW, have:
./run binary <binary> <args>
where 'binary' is a keyword arg for the run script. Since --help is
positional in argparse when you use subparsers, we could have the main parser
with help, but the 'binary' subparser without it - that way we could
theoretically pass --help to whatever binary we actually want the run script to
wrap. Like I said though, I haven't tried ^this so I'm just tossing in whatever
I just made up in my head.
>
> > +parser.add_argument('--selinux',
> > + action='store_true',
> > + help='Run in the appropriate selinux context')
> > +
> > +opts, args = parser.parse_known_args()
>
> If you want to use ^this, then you need to be aware of prefix matching on the
> options recognized by Argparse. IOW if one is to pass <args> to the
<binary>
> then none of the <args> can be a prefix of any of the long options argeparse
> knows about (in this case --selinux), otherwise it'll consume it. Altough
> unlikely, we should stay on the safe side and use:
> argparse.ArgumentParser(..., allow_abbrev=False) [1]
>
> [2]
https://docs.python.org/3.11/library/argparse.html?highlight=argparse#all...
ok, I wasn't aware of that option.
>
> > +
> > +if len(args) < 1:
> > + print("syntax: %s [--selinux] BINARY [ARGS...]" % sys.argv[0],
file=sys.stderr)
> > sys.exit(1)
>
> Same here, with argparse ^this is not needed if the args/options are defined
> correctly.
>
> > -prog = sys.argv[1]
> > -args = sys.argv[1:]
> > +prog = args[0]
>
> argparse's parser obj has a 'prog' attribute [2].
>
> [2]
https://docs.python.org/3/library/argparse.html#prog
I think that's the wrong 'prog' though. That would give me the
'./run'
script, whereas I want the 'libvirtd' program (or whatever) that the user
wants to execute.
Sorry, I completely overlooked the lack of 'sys.' in there, you're absolutely
right.
Erik