Bug#850869: git-buildpackage: command-line arguments not quoted correctly

2017-01-11 Thread Guido Günther
Hi Simon,
On Tue, Jan 10, 2017 at 07:53:48PM +, Simon McVittie wrote:
> I'm currently using git-buildpackage with a custom --builder command
> (vectis, https://github.com/smcv/vectis) that among other things accepts
> a command-line option of the form:
> 
> --extra-repository='deb [trusted=yes] http://localhost/path suite 
> component'
> 
> With git-buildpackage, I have to backslash-escape the spaces:
> 
> --extra-repository='deb\ [trusted=yes]\ ...'
> 
> or it will treat "--extra-repository=deb", "[trusted=yes]", etc. as
> separate command-line arguments for vectis. This is because
> gbp.command_wrappers.Command(..., shell=True) just joins the command
> to the arguments with " ".join() rather than doing proper shell quoting.
> That's correct for the --builder as currently documented, but not for
> its arguments.
> 
> It would be easy to run into this with debuild if you're using something
> like gbp buildpackage --set-envvar=DEBFULLNAME="Simon McVittie"
> (a debuild option) or gbp buildpackage --check-command="lintian -Ii"
> (a dpkg-buildpackage option).

Thanks for the detailed description. Interesting that this went
unnoticed for so long. I've added a test so we hopefully don't regress
there.

> 
> Doing proper shell quoting in Python 3 is trival (shlex.quote, which
> I use a lot in vectis) but Python 2 doesn't have that function. However,
> there is another way to get the --builder interpreted as a shell
> one-liner and still pass it arguments: you can invoke
> 
> ["sh", "-c", ('%s "$@"' % builder), "sh"] + arguments

I went for using pipes.quote which is python2's equivalent of
shlex.quote and fixed up buildpackage-rpm as well so we're consistent.

Decided to leave quoting to the caller rather than doing it in Command
itself to be consistent between shell=True and cases where command
itself is already a script with arguments from e.g. gbp.conf like
hooks.

Cheers,
 -- Guido

> 
> with shell=False, and it will do the right thing. The first "sh" in
> that monster is argv[0] for the subprocess, and the second is $0 for
> the shell one-liner.
> 
> I attach a possible patch.
> 
> S

> From a088aef91ffa9de60c6d7ac3278360ce0ee571e1 Mon Sep 17 00:00:00 2001
> From: Simon McVittie 
> Date: Tue, 10 Jan 2017 19:49:08 +
> Subject: [PATCH] buildpackage: don't treat dpkg arguments as shell input
> 
> If one of gbp buildpackage's command-line arguments (after processing
> by the calling shell if applicable) includes spaces or shell
> metacharacters, it's unexpected to subject it to a layer of shell
> interpretation. Conversely, the builder option is documented to be
> a shell command and so must go through one layer of shell
> interpretation.
> 
> This makes an invocation like
> 
> gbp buildpackage --check-command="lintian -Ii"
> 
> work the way it was presumably intended.
> ---
>  gbp/scripts/buildpackage.py | 6 +-
>  1 file changed, 5 insertions(+), 1 deletion(-)
> 
> diff --git a/gbp/scripts/buildpackage.py b/gbp/scripts/buildpackage.py
> index 6524f01..c7ad903 100755
> --- a/gbp/scripts/buildpackage.py
> +++ b/gbp/scripts/buildpackage.py
> @@ -727,7 +727,11 @@ def main(argv):
>   )(dir=build_dir)
>  
>  # Finally build the package:
> -RunAtCommand(options.builder, dpkg_args, shell=True,
> +RunAtCommand('sh',
> + ['-c', options.builder + ' "$@"',
> +  'sh'] +   # $0 for the shell one-liner
> + dpkg_args, # $@ for the shell one-liner
> + shell=False,   # we start the shell explicitly
>   extra_env=Hook.md(build_env,
> {'GBP_BUILD_DIR': build_dir})
>   )(dir=build_dir)
> -- 
> 2.11.0
> 



Bug#850869: git-buildpackage: command-line arguments not quoted correctly

2017-01-10 Thread Simon McVittie
Package: git-buildpackage
Version: 0.8.9
Severity: normal
Tags: patch

I'm currently using git-buildpackage with a custom --builder command
(vectis, https://github.com/smcv/vectis) that among other things accepts
a command-line option of the form:

--extra-repository='deb [trusted=yes] http://localhost/path suite component'

With git-buildpackage, I have to backslash-escape the spaces:

--extra-repository='deb\ [trusted=yes]\ ...'

or it will treat "--extra-repository=deb", "[trusted=yes]", etc. as
separate command-line arguments for vectis. This is because
gbp.command_wrappers.Command(..., shell=True) just joins the command
to the arguments with " ".join() rather than doing proper shell quoting.
That's correct for the --builder as currently documented, but not for
its arguments.

It would be easy to run into this with debuild if you're using something
like gbp buildpackage --set-envvar=DEBFULLNAME="Simon McVittie"
(a debuild option) or gbp buildpackage --check-command="lintian -Ii"
(a dpkg-buildpackage option).

Doing proper shell quoting in Python 3 is trival (shlex.quote, which
I use a lot in vectis) but Python 2 doesn't have that function. However,
there is another way to get the --builder interpreted as a shell
one-liner and still pass it arguments: you can invoke

["sh", "-c", ('%s "$@"' % builder), "sh"] + arguments

with shell=False, and it will do the right thing. The first "sh" in
that monster is argv[0] for the subprocess, and the second is $0 for
the shell one-liner.

I attach a possible patch.

S
>From a088aef91ffa9de60c6d7ac3278360ce0ee571e1 Mon Sep 17 00:00:00 2001
From: Simon McVittie 
Date: Tue, 10 Jan 2017 19:49:08 +
Subject: [PATCH] buildpackage: don't treat dpkg arguments as shell input

If one of gbp buildpackage's command-line arguments (after processing
by the calling shell if applicable) includes spaces or shell
metacharacters, it's unexpected to subject it to a layer of shell
interpretation. Conversely, the builder option is documented to be
a shell command and so must go through one layer of shell
interpretation.

This makes an invocation like

gbp buildpackage --check-command="lintian -Ii"

work the way it was presumably intended.
---
 gbp/scripts/buildpackage.py | 6 +-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/gbp/scripts/buildpackage.py b/gbp/scripts/buildpackage.py
index 6524f01..c7ad903 100755
--- a/gbp/scripts/buildpackage.py
+++ b/gbp/scripts/buildpackage.py
@@ -727,7 +727,11 @@ def main(argv):
  )(dir=build_dir)
 
 # Finally build the package:
-RunAtCommand(options.builder, dpkg_args, shell=True,
+RunAtCommand('sh',
+ ['-c', options.builder + ' "$@"',
+  'sh'] +   # $0 for the shell one-liner
+ dpkg_args, # $@ for the shell one-liner
+ shell=False,   # we start the shell explicitly
  extra_env=Hook.md(build_env,
{'GBP_BUILD_DIR': build_dir})
  )(dir=build_dir)
-- 
2.11.0