Make sure GDB uses a valid shell when starting the inferior and to perform the "shell" command
Commit Message
It is known that GDB needs a valid shell to start the inferior and to
offer the "shell" command to the user. This has recently been the
cause of a problem on the MIPS buildslave, because $SHELL was set to
/sbin/nologin and several tests were failing. The thread is here:
<https://sourceware.org/ml/gdb-patches/2015-07/msg00535.html>
However, I think we can do better than that. If 'startup-with-shell'
is on, which is the default, we blindly trust that the user will
provide a valid shell for us, and this may not be true all the time.
So I am proposing a patch to increment the tests made by GDB before
running the inferior to decide whether it will use $SHELL or not.
Particularly, I created a new function, called "valid_shell", which
defines the concept of a valid shell for GDB:
- A file that exists and is executable by the user
- A file that is not /sbin/nologin
For now, I think this is enough to cover most cases. The default
action when an invalid shell is found is to use /bin/sh instead (we
already do that when $SHELL is not defined, for example), and also
issue a warning to the user. This applies for when we are starting
the inferior and when we are executing the "shell" command.
To make things more robust, I made the code also check /bin/sh and
make sure it is also valid. If it is not, and if we are starting the
inferior, then GDB will use fork+exec instead. If we are executing
the "shell" command and we cannot find a valid shell, GDB will error
out.
I updated the documentation to reflect the new behavior, and created a
testcase to exercise the code. This patch has been regression-tested
on Fedora 22 x86_64.
OK to apply?
gdb/ChangeLog:
2015-07-24 Sergio Durigan Junior <sergiodj@redhat.com>
* cli/cli-cmds.c (shell_escape): Check if the selected shell is
valid.
* fork-child.c (check_startup_with_shell): New function.
(fork_inferior): Move code to the new function above. Call it.
* utils.c (valid_shell): New function.
* utils.h (valid_shell): New prototype.
gdb/doc/ChangeLog:
2015-07-24 Sergio Durigan Junior <sergiodj@redhat.com>
* gdb.texinfo (Shell Commands): Mention that the shell needs to be
valid; point to "Valid Shell" subsection.
(Valid Shell): New subsection.
(Starting your Program): Mention that the shell needs to be valid;
point to "Valid Shell" subsection.
(Your Program's Arguments): Likewise.
(Your Program's Environment): Likewise.
gdb/testsuite/ChangeLog:
2015-07-24 Sergio Durigan Junior <sergiodj@redhat.com>
* gdb.base/invalid-shell.exp: New file.
---
gdb/cli/cli-cmds.c | 9 +++-
gdb/doc/gdb.texinfo | 51 +++++++++++++-------
gdb/fork-child.c | 82 +++++++++++++++++++++++++++-----
gdb/testsuite/gdb.base/invalid-shell.exp | 38 +++++++++++++++
gdb/utils.c | 10 ++++
gdb/utils.h | 11 +++++
6 files changed, 170 insertions(+), 31 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/invalid-shell.exp
Comments
On 15-07-24 02:19 PM, Sergio Durigan Junior wrote:
> It is known that GDB needs a valid shell to start the inferior and to
> offer the "shell" command to the user. This has recently been the
> cause of a problem on the MIPS buildslave, because $SHELL was set to
> /sbin/nologin and several tests were failing. The thread is here:
>
> <https://sourceware.org/ml/gdb-patches/2015-07/msg00535.html>
>
> However, I think we can do better than that. If 'startup-with-shell'
> is on, which is the default, we blindly trust that the user will
> provide a valid shell for us, and this may not be true all the time.
> So I am proposing a patch to increment the tests made by GDB before
> running the inferior to decide whether it will use $SHELL or not.
> Particularly, I created a new function, called "valid_shell", which
> defines the concept of a valid shell for GDB:
>
> - A file that exists and is executable by the user
>
> - A file that is not /sbin/nologin
Note that on my Ubuntu 14.04:
$ which nologin
/usr/sbin/nologin
I think that /bin/false is also commonly specified as the default shell
for system users (at least according to my /etc/passwd).
Thanks,
Simon
On 07/24/2015 03:19 PM, Sergio Durigan Junior wrote:
> diff --git a/gdb/testsuite/gdb.base/invalid-shell.exp b/gdb/testsuite/gdb.base/invalid-shell.exp
> new file mode 100644
> index 0000000..252ef13
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/invalid-shell.exp
> @@ -0,0 +1,38 @@
> +# Copyright 2015 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see<http://www.gnu.org/licenses/>.
> +
> +standard_testfile normal.c
> +
> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
> + untested "could not compile test program"
> + return -1
> +}
> +
> +gdb_exit
> +
> +# Set the $SHELL to an invalid file. This will cause GDB to use
> +# /bin/sh instead.
> +set oldshell $env(SHELL)
> +set env(SHELL) "/invalid/path/to/file"
> +
> +clean_restart $binfile
> +
> +# Running the inferior must work.
> +gdb_test "run" "Starting program: .*\r\nwarning: Invalid shell \\\'/invalid/path/to/file\\\'; using \\\'/bin/sh\\\' instead.\r\n\\\[Inferior $decimal \\\(process $decimal\\\) exited normally\\\]" "starting with /bin/sh instead of invalid shell"
> +
> +# Invoking a shell command must also work.
> +gdb_test "shell echo hi" "hi" "invoking shell command from prompt"
> +
> +set env(SHELL) $oldshell
I think this test, as is, will not be meaningful for non-linux targets
or, in general, for remote targets.
Also, the assumption of a path like "/invalid/path/to/file" may not work
for mingw32.
"run" will also not work for remote targets unless they are running in
extended-remote mode.
We should either make tests more general or restrict them appropriately
so they don't cause spurious failures for targets for which these should
not be executed.
On Friday, July 24 2015, Luis Machado wrote:
> On 07/24/2015 03:19 PM, Sergio Durigan Junior wrote:
>> diff --git a/gdb/testsuite/gdb.base/invalid-shell.exp b/gdb/testsuite/gdb.base/invalid-shell.exp
>> new file mode 100644
>> index 0000000..252ef13
>> --- /dev/null
>> +++ b/gdb/testsuite/gdb.base/invalid-shell.exp
>> @@ -0,0 +1,38 @@
>> +# Copyright 2015 Free Software Foundation, Inc.
>> +
>> +# This program is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU General Public License as published by
>> +# the Free Software Foundation; either version 3 of the License, or
>> +# (at your option) any later version.
>> +#
>> +# This program is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> +# GNU General Public License for more details.
>> +#
>> +# You should have received a copy of the GNU General Public License
>> +# along with this program. If not, see<http://www.gnu.org/licenses/>.
>> +
>> +standard_testfile normal.c
>> +
>> +if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
>> + untested "could not compile test program"
>> + return -1
>> +}
>> +
>> +gdb_exit
>> +
>> +# Set the $SHELL to an invalid file. This will cause GDB to use
>> +# /bin/sh instead.
>> +set oldshell $env(SHELL)
>> +set env(SHELL) "/invalid/path/to/file"
>> +
>> +clean_restart $binfile
>> +
>> +# Running the inferior must work.
>> +gdb_test "run" "Starting program: .*\r\nwarning: Invalid shell
>> \\\'/invalid/path/to/file\\\'; using \\\'/bin/sh\\\'
>> instead.\r\n\\\[Inferior $decimal \\\(process $decimal\\\) exited
>> normally\\\]" "starting with /bin/sh instead of invalid shell"
>> +
>> +# Invoking a shell command must also work.
>> +gdb_test "shell echo hi" "hi" "invoking shell command from prompt"
>> +
>> +set env(SHELL) $oldshell
>
> I think this test, as is, will not be meaningful for non-linux targets
> or, in general, for remote targets.
>
> Also, the assumption of a path like "/invalid/path/to/file" may not
> work for mingw32.
>
> "run" will also not work for remote targets unless they are running in
> extended-remote mode.
>
> We should either make tests more general or restrict them
> appropriately so they don't cause spurious failures for targets for
> which these should not be executed.
You're right, I was going to disable this test for remote targets and I
forgot, thanks for letting me know.
I'll disable the test for unsupported targets.
On Friday, July 24 2015, Simon Marchi wrote:
> On 15-07-24 02:19 PM, Sergio Durigan Junior wrote:
>> It is known that GDB needs a valid shell to start the inferior and to
>> offer the "shell" command to the user. This has recently been the
>> cause of a problem on the MIPS buildslave, because $SHELL was set to
>> /sbin/nologin and several tests were failing. The thread is here:
>>
>> <https://sourceware.org/ml/gdb-patches/2015-07/msg00535.html>
>>
>> However, I think we can do better than that. If 'startup-with-shell'
>> is on, which is the default, we blindly trust that the user will
>> provide a valid shell for us, and this may not be true all the time.
>> So I am proposing a patch to increment the tests made by GDB before
>> running the inferior to decide whether it will use $SHELL or not.
>> Particularly, I created a new function, called "valid_shell", which
>> defines the concept of a valid shell for GDB:
>>
>> - A file that exists and is executable by the user
>>
>> - A file that is not /sbin/nologin
>
> Note that on my Ubuntu 14.04:
>
> $ which nologin
> /usr/sbin/nologin
/sbin/nologin is probably a symlink to this file, isn't it? But yeah,
the check could include /usr/sbin/nologin as well.
> I think that /bin/false is also commonly specified as the default shell
> for system users (at least according to my /etc/passwd).
Indeed. I will include /bin/false as well.
Thanks,
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Sergio Durigan Junior <sergiodj@redhat.com>
> Date: Fri, 24 Jul 2015 14:19:53 -0400
>
> It is known that GDB needs a valid shell to start the inferior and to
> offer the "shell" command to the user. This has recently been the
> cause of a problem on the MIPS buildslave, because $SHELL was set to
> /sbin/nologin and several tests were failing. The thread is here:
>
> <https://sourceware.org/ml/gdb-patches/2015-07/msg00535.html>
>
> However, I think we can do better than that. If 'startup-with-shell'
> is on, which is the default, we blindly trust that the user will
> provide a valid shell for us, and this may not be true all the time.
> So I am proposing a patch to increment the tests made by GDB before
> running the inferior to decide whether it will use $SHELL or not.
> Particularly, I created a new function, called "valid_shell", which
> defines the concept of a valid shell for GDB:
>
> - A file that exists and is executable by the user
>
> - A file that is not /sbin/nologin
>
> For now, I think this is enough to cover most cases. The default
> action when an invalid shell is found is to use /bin/sh instead (we
> already do that when $SHELL is not defined, for example), and also
> issue a warning to the user. This applies for when we are starting
> the inferior and when we are executing the "shell" command.
>
> To make things more robust, I made the code also check /bin/sh and
> make sure it is also valid. If it is not, and if we are starting the
> inferior, then GDB will use fork+exec instead. If we are executing
> the "shell" command and we cannot find a valid shell, GDB will error
> out.
>
> I updated the documentation to reflect the new behavior, and created a
> testcase to exercise the code. This patch has been regression-tested
> on Fedora 22 x86_64.
>
> OK to apply?
The documentation part is OK, but please use @pxref instead of "see
@ref" for cross-references in parentheses.
Thanks.
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: GDB Patches <gdb-patches@sourceware.org>
> Date: Fri, 24 Jul 2015 15:10:27 -0400
>
> > Note that on my Ubuntu 14.04:
> >
> > $ which nologin
> > /usr/sbin/nologin
>
> /sbin/nologin is probably a symlink to this file, isn't it? But yeah,
> the check could include /usr/sbin/nologin as well.
>
> > I think that /bin/false is also commonly specified as the default shell
> > for system users (at least according to my /etc/passwd).
>
> Indeed. I will include /bin/false as well.
Since the number of valid shells is much smaller than the number of
non-shell programs, isn't it better to have a database of known shells
than to have a database of non-shells people could be expected to set
SHELL to?
On Friday, July 24 2015, Eli Zaretskii wrote:
>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: GDB Patches <gdb-patches@sourceware.org>
>> Date: Fri, 24 Jul 2015 15:10:27 -0400
>>
>> > Note that on my Ubuntu 14.04:
>> >
>> > $ which nologin
>> > /usr/sbin/nologin
>>
>> /sbin/nologin is probably a symlink to this file, isn't it? But yeah,
>> the check could include /usr/sbin/nologin as well.
>>
>> > I think that /bin/false is also commonly specified as the default shell
>> > for system users (at least according to my /etc/passwd).
>>
>> Indeed. I will include /bin/false as well.
>
> Since the number of valid shells is much smaller than the number of
> non-shell programs, isn't it better to have a database of known shells
> than to have a database of non-shells people could be expected to set
> SHELL to?
My intention is not to catch all the invalid shells that can be set, but
rather make sure that the shell is at least an executable, and is not
something that is commonly used as a "non-shell", like /sbin/nologin or
/bin/false. Other than these two I cannot think of many more options to
cover in the check.
Another good thing about doing this type of check is that every known
and unknown shell will still work. When we explicitly check for certain
shell's as you suggest, it means that if we forget any of them its users
will be negatively impacted.
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: simon.marchi@ericsson.com, gdb-patches@sourceware.org
> Date: Fri, 24 Jul 2015 15:28:58 -0400
>
> Another good thing about doing this type of check is that every known
> and unknown shell will still work. When we explicitly check for certain
> shell's as you suggest, it means that if we forget any of them its users
> will be negatively impacted.
I don't think there are so many shells out there that we run a real
risk of forgetting them. And even if we do, there's plenty of time
till the next release to hear from those who might be negatively
impacted.
On 15-07-24 03:10 PM, Sergio Durigan Junior wrote:
> On Friday, July 24 2015, Simon Marchi wrote:
>
>> On 15-07-24 02:19 PM, Sergio Durigan Junior wrote:
>>> It is known that GDB needs a valid shell to start the inferior and to
>>> offer the "shell" command to the user. This has recently been the
>>> cause of a problem on the MIPS buildslave, because $SHELL was set to
>>> /sbin/nologin and several tests were failing. The thread is here:
>>>
>>> <https://sourceware.org/ml/gdb-patches/2015-07/msg00535.html>
>>>
>>> However, I think we can do better than that. If 'startup-with-shell'
>>> is on, which is the default, we blindly trust that the user will
>>> provide a valid shell for us, and this may not be true all the time.
>>> So I am proposing a patch to increment the tests made by GDB before
>>> running the inferior to decide whether it will use $SHELL or not.
>>> Particularly, I created a new function, called "valid_shell", which
>>> defines the concept of a valid shell for GDB:
>>>
>>> - A file that exists and is executable by the user
>>>
>>> - A file that is not /sbin/nologin
>>
>> Note that on my Ubuntu 14.04:
>>
>> $ which nologin
>> /usr/sbin/nologin
>
> /sbin/nologin is probably a symlink to this file, isn't it? But yeah,
> the check could include /usr/sbin/nologin as well.
No it isn't:
$ ls -l /sbin/nologin
ls: cannot access /sbin/nologin: No such file or directory
On 15-07-24 03:53 PM, Eli Zaretskii wrote:
> I don't think there are so many shells out there that we run a real
> risk of forgetting them.
Even though you can try to list all known shells, they won't necessarily
be in the same location. For example, the servers I work on at work have
an old version of everything, so I use my own version of bash. SHELL won't
be /bin/bash but /home/<user>/local/bin/bash. gdb wouldn't recognize it as
a valid shell.
> And even if we do, there's plenty of time
> till the next release to hear from those who might be negatively
> impacted.
I don't think that's true. The number of users who go build and use gdb
from the master branch is probably negligible. If this affects some users,
it will most likely be when it gets released in distros (months or years
after the actual release, depending on the distro).
Eli Zaretskii <eliz@gnu.org> writes:
> Since the number of valid shells is much smaller than the number of
> non-shell programs, isn't it better to have a database of known shells
> than to have a database of non-shells people could be expected to set
> SHELL to?
This database will be of infinite size. Why should it be invalid to set
SHELL=/foo/bar if that's my self-compiled super-duper shell?
Andreas.
On Friday, July 24 2015, Simon Marchi wrote:
> On 15-07-24 03:53 PM, Eli Zaretskii wrote:
>> I don't think there are so many shells out there that we run a real
>> risk of forgetting them.
>
> Even though you can try to list all known shells, they won't necessarily
> be in the same location. For example, the servers I work on at work have
> an old version of everything, so I use my own version of bash. SHELL won't
> be /bin/bash but /home/<user>/local/bin/bash. gdb wouldn't recognize it as
> a valid shell.
>
>> And even if we do, there's plenty of time
>> till the next release to hear from those who might be negatively
>> impacted.
>
> I don't think that's true. The number of users who go build and use gdb
> from the master branch is probably negligible. If this affects some users,
> it will most likely be when it gets released in distros (months or years
> after the actual release, depending on the distro).
Yeah, I don't agree with this proposal as well. I will submit a v2
soon, without Eli's proposal, and see what others say. If others also
prefer Eli's idea, we can discuss the details.
> On Jul 24, 2015, at 3:53 PM, Eli Zaretskii <eliz@gnu.org> wrote:
>
>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: simon.marchi@ericsson.com, gdb-patches@sourceware.org
>> Date: Fri, 24 Jul 2015 15:28:58 -0400
>>
>> Another good thing about doing this type of check is that every known
>> and unknown shell will still work. When we explicitly check for certain
>> shell's as you suggest, it means that if we forget any of them its users
>> will be negatively impacted.
>
> I don't think there are so many shells out there that we run a real
> risk of forgetting them. And even if we do, there's plenty of time
> till the next release to hear from those who might be negatively
> impacted.
But if you omit a shell, is the user of that shell blocked from using gdb? That’s not a good failure mode. It seems to me that omitting a non-shell is much more forgiving: all that happens is that you don’t get the friendly error message.
So that says the explicit list should be of non-shells.
paul
On Friday, July 24 2015, Paul Koning wrote:
> But if you omit a shell, is the user of that shell blocked from using
> gdb? That’s not a good failure mode. It seems to me that omitting a
> non-shell is much more forgiving: all that happens is that you don’t
> get the friendly error message.
As I said before, I agree with this rationale. However, I just would
like to make it clear that if the shell is invalid, the user will still
be able to start inferiors because GDB will default to /bin/sh.
On 15-07-24 04:25 PM, Paul_Koning@Dell.com wrote:
> But if you omit a shell, is the user of that shell blocked from using gdb? That’s not a good failure mode. It seems to me that omitting a non-shell is much more forgiving: all that happens is that you don’t get the friendly error message.
>
> So that says the explicit list should be of non-shells.
>
> paul
With Eli's suggestion, if SHELL is valid but gdb doesn't know about it (e.g.
SHELL=/my/super/duper/shell), it will fall back to using /bin/sh. So no,
the user wouldn't be blocked.
> On Jul 24, 2015, at 4:38 PM, Simon Marchi <simon.marchi@ericsson.com> wrote:
>
> On 15-07-24 04:25 PM, Paul_Koning@Dell.com wrote:
>> But if you omit a shell, is the user of that shell blocked from using gdb? That’s not a good failure mode. It seems to me that omitting a non-shell is much more forgiving: all that happens is that you don’t get the friendly error message.
>>
>> So that says the explicit list should be of non-shells.
>>
>> paul
>
> With Eli's suggestion, if SHELL is valid but gdb doesn't know about it (e.g.
> SHELL=/my/super/duper/shell), it will fall back to using /bin/sh. So no,
> the user wouldn't be blocked.
>
>
Not unless the features in that unknown shell are needed for the application to function correctly.
paul
On Fri, Jul 24, 2015 at 1:42 PM, <Paul_Koning@dell.com> wrote:
>
>> On Jul 24, 2015, at 4:38 PM, Simon Marchi <simon.marchi@ericsson.com> wrote:
>>
>> On 15-07-24 04:25 PM, Paul_Koning@Dell.com wrote:
>>> But if you omit a shell, is the user of that shell blocked from using gdb? That’s not a good failure mode. It seems to me that omitting a non-shell is much more forgiving: all that happens is that you don’t get the friendly error message.
>>>
>>> So that says the explicit list should be of non-shells.
>>>
>>> paul
>>
>> With Eli's suggestion, if SHELL is valid but gdb doesn't know about it (e.g.
>> SHELL=/my/super/duper/shell), it will fall back to using /bin/sh. So no,
>> the user wouldn't be blocked.
>>
>>
> Not unless the features in that unknown shell are needed for the application to function correctly.
another case of this is shells which actively restrict the application to some
subset of available functionality
http://plash.beasts.org/index.html#section1
i'm not sure about the following being unfamiliar with it, but it
seems a likely candidate for this as well.
https://github.com/trombonehero/capsh
an unrecognised shell in this case could lead to increased authority
of the inferior process, as the general effort here is to restrict
processes to those file descriptors that the shell passes to it and
remove the ability to obtain new file descriptors the shell has not
blessed..
> Date: Fri, 24 Jul 2015 16:09:40 -0400
> From: Simon Marchi <simon.marchi@ericsson.com>
> CC: <gdb-patches@sourceware.org>
>
> On 15-07-24 03:53 PM, Eli Zaretskii wrote:
> > I don't think there are so many shells out there that we run a real
> > risk of forgetting them.
>
> Even though you can try to list all known shells, they won't necessarily
> be in the same location. For example, the servers I work on at work have
> an old version of everything, so I use my own version of bash. SHELL won't
> be /bin/bash but /home/<user>/local/bin/bash. gdb wouldn't recognize it as
> a valid shell.
I didn't say that, but meant to suggest testing only the basename of
the shell.
> > And even if we do, there's plenty of time
> > till the next release to hear from those who might be negatively
> > impacted.
>
> I don't think that's true. The number of users who go build and use gdb
> from the master branch is probably negligible. If this affects some users,
> it will most likely be when it gets released in distros (months or years
> after the actual release, depending on the distro).
Fine, have it your way, and let's see if that flies. I thought the
fact that we've got 2 additional candidates in less than 1 day is
evidence that more will follow, but I guess we will see.
> From: Andreas Schwab <schwab@linux-m68k.org>
> Cc: Sergio Durigan Junior <sergiodj@redhat.com>, simon.marchi@ericsson.com, gdb-patches@sourceware.org
> Date: Fri, 24 Jul 2015 22:18:08 +0200
>
> Eli Zaretskii <eliz@gnu.org> writes:
>
> > Since the number of valid shells is much smaller than the number of
> > non-shell programs, isn't it better to have a database of known shells
> > than to have a database of non-shells people could be expected to set
> > SHELL to?
>
> This database will be of infinite size. Why should it be invalid to set
> SHELL=/foo/bar if that's my self-compiled super-duper shell?
The same goes for non-shells as well.
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: <eliz@gnu.org>, <simon.marchi@ericsson.com>, <gdb-patches@sourceware.org>
> Date: Fri, 24 Jul 2015 16:35:19 -0400
>
> On Friday, July 24 2015, Paul Koning wrote:
>
> > But if you omit a shell, is the user of that shell blocked from using
> > gdb? That’s not a good failure mode. It seems to me that omitting a
> > non-shell is much more forgiving: all that happens is that you don’t
> > get the friendly error message.
>
> As I said before, I agree with this rationale. However, I just would
> like to make it clear that if the shell is invalid, the user will still
> be able to start inferiors because GDB will default to /bin/sh.
As would happen if we don't recognize the shell.
> Date: Fri, 24 Jul 2015 14:36:38 -0700
> From: Matt Rice <ratmice@gmail.com>
> Cc: simon.marchi@ericsson.com, Eli Zaretskii <eliz@gnu.org>, Sergio Durigan Junior <sergiodj@redhat.com>, "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
>
> On Fri, Jul 24, 2015 at 1:42 PM, <Paul_Koning@dell.com> wrote:
> >
> >> On Jul 24, 2015, at 4:38 PM, Simon Marchi <simon.marchi@ericsson.com> wrote:
> >>
> >> On 15-07-24 04:25 PM, Paul_Koning@Dell.com wrote:
> >>> But if you omit a shell, is the user of that shell blocked from using gdb? That’s not a good failure mode. It seems to me that omitting a non-shell is much more forgiving: all that happens is that you don’t get the friendly error message.
> >>>
> >>> So that says the explicit list should be of non-shells.
> >>>
> >>> paul
> >>
> >> With Eli's suggestion, if SHELL is valid but gdb doesn't know about it (e.g.
> >> SHELL=/my/super/duper/shell), it will fall back to using /bin/sh. So no,
> >> the user wouldn't be blocked.
> >>
> >>
> > Not unless the features in that unknown shell are needed for the application to function correctly.
>
> another case of this is shells which actively restrict the application to some
> subset of available functionality
They should be included in the list of the shells we know about.
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Andreas Schwab <schwab@linux-m68k.org>
>> Cc: Sergio Durigan Junior <sergiodj@redhat.com>, simon.marchi@ericsson.com, gdb-patches@sourceware.org
>> Date: Fri, 24 Jul 2015 22:18:08 +0200
>>
>> Eli Zaretskii <eliz@gnu.org> writes:
>>
>> > Since the number of valid shells is much smaller than the number of
>> > non-shell programs, isn't it better to have a database of known shells
>> > than to have a database of non-shells people could be expected to set
>> > SHELL to?
>>
>> This database will be of infinite size. Why should it be invalid to set
>> SHELL=/foo/bar if that's my self-compiled super-duper shell?
>
> The same goes for non-shells as well.
No, the set of non-shells is finite, because they will match a line in
/etc/shells.
Andreas.
> From: Andreas Schwab <schwab@linux-m68k.org>
> Cc: sergiodj@redhat.com, simon.marchi@ericsson.com, gdb-patches@sourceware.org
> the set of non-shells is finite, because they will match a line in
> /etc/shells.
I'm okay with looking up non-shells in /etc/shells, but that's not
what the proposed patch does. It just compares the shell's file name
with a list of known "invalid" shells. It doesn't even mention
/etc/shells, in fact, not even in the documentation parts of the
patch.
On Saturday, July 25 2015, Eli Zaretskii wrote:
>> > And even if we do, there's plenty of time
>> > till the next release to hear from those who might be negatively
>> > impacted.
>>
>> I don't think that's true. The number of users who go build and use gdb
>> from the master branch is probably negligible. If this affects some users,
>> it will most likely be when it gets released in distros (months or years
>> after the actual release, depending on the distro).
>
> Fine, have it your way, and let's see if that flies. I thought the
> fact that we've got 2 additional candidates in less than 1 day is
> evidence that more will follow, but I guess we will see.
Maybe I should have been more clear about what I want to achieve with
this patch.
My goal was not to match every possible invalid shell out there, nor to
make sure that the specified shell is a known and valid shell. My goal
was to make sure that the shell exists, is an executable, and is not
something that is commonly used to disable logins (/sbin/nologin or
/bin/false are the obvious candidates here).
The 2 additional candidates that have been mentioned were actually just
1: I did not remember to include /bin/false in the list before, but
/usr/sbin/nologin is nologin (and I could even just check for the
basename as you proposed in another message, eliminating the need to
include checks for {,/usr}).
I don't think we will see the list of non-shells expanding much more.
One can always say "Hey, but /bin/ls is a not a shell!", and we will say
"Right, and it is not commonly used as shell anyway".
Finally, I don't want to forbid the user to specify her own shell to run
the inferior, and to name her shell as she wants.
Thanks,
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: Simon Marchi <simon.marchi@ericsson.com>, gdb-patches@sourceware.org
> Date: Sat, 25 Jul 2015 12:29:56 -0400
>
> My goal was not to match every possible invalid shell out there, nor to
> make sure that the specified shell is a known and valid shell. My goal
> was to make sure that the shell exists, is an executable, and is not
> something that is commonly used to disable logins (/sbin/nologin or
> /bin/false are the obvious candidates here).
>
> The 2 additional candidates that have been mentioned were actually just
> 1: I did not remember to include /bin/false in the list before, but
> /usr/sbin/nologin is nologin (and I could even just check for the
> basename as you proposed in another message, eliminating the need to
> include checks for {,/usr}).
>
> I don't think we will see the list of non-shells expanding much more.
> One can always say "Hey, but /bin/ls is a not a shell!", and we will say
> "Right, and it is not commonly used as shell anyway".
Just reading the section you proposed for the manual seems to imply
the goals are much wider than you say above. If we only want to avoid
these 2 non-shells, why do we even need to document that obscure
detail?
> Finally, I don't want to forbid the user to specify her own shell to run
> the inferior, and to name her shell as she wants.
Her shell could be named /sbin/nologin, no?
On Saturday, July 25 2015, Eli Zaretskii wrote:
>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: Simon Marchi <simon.marchi@ericsson.com>, gdb-patches@sourceware.org
>> Date: Sat, 25 Jul 2015 12:29:56 -0400
>>
>> My goal was not to match every possible invalid shell out there, nor to
>> make sure that the specified shell is a known and valid shell. My goal
>> was to make sure that the shell exists, is an executable, and is not
>> something that is commonly used to disable logins (/sbin/nologin or
>> /bin/false are the obvious candidates here).
>>
>> The 2 additional candidates that have been mentioned were actually just
>> 1: I did not remember to include /bin/false in the list before, but
>> /usr/sbin/nologin is nologin (and I could even just check for the
>> basename as you proposed in another message, eliminating the need to
>> include checks for {,/usr}).
>>
>> I don't think we will see the list of non-shells expanding much more.
>> One can always say "Hey, but /bin/ls is a not a shell!", and we will say
>> "Right, and it is not commonly used as shell anyway".
>
> Just reading the section you proposed for the manual seems to imply
> the goals are much wider than you say above. If we only want to avoid
> these 2 non-shells, why do we even need to document that obscure
> detail?
Because I think it is worth documenting this to the user; the more
information we give about how GDB behaves, the better (IMHO).
The new section says:
@node Valid Shell
@subsection Valid Shell
@value{GDBN} considers a @emph{valid shell} a file that:
@enumerate
@item
Exists and can be executed by the user.
@item
Is not the @file{/sbin/nologin} (or @file{/usr/sbin/nologin}) program.
@item
Is not the @file{/bin/false} program.
@end enumerate
If any of those conditions are not met, the specified shell is not
used by @value{GDBN}.
I do not see any difference from what I said above, but if you think
this text can be improved, or that this text is not needed at all, then
by all means feel free to ask this.
>> Finally, I don't want to forbid the user to specify her own shell to run
>> the inferior, and to name her shell as she wants.
>
> Her shell could be named /sbin/nologin, no?
Yes... I should have said:
Finally, I don't want to forbid the user to specify her own shell to
run the inferior, and to name her shell as she wants, as long as it is
not named {,/usr}/sbin/nologin and /bin/false, and as long as it is an
existing file, and as long as this file can be executed by her.
Thanks,
> From: Sergio Durigan Junior <sergiodj@redhat.com>
> Cc: simon.marchi@ericsson.com, gdb-patches@sourceware.org
> Date: Sat, 25 Jul 2015 13:03:12 -0400
>
> The new section says:
>
> @node Valid Shell
> @subsection Valid Shell
>
> @value{GDBN} considers a @emph{valid shell} a file that:
>
> @enumerate
> @item
> Exists and can be executed by the user.
>
> @item
> Is not the @file{/sbin/nologin} (or @file{/usr/sbin/nologin}) program.
>
> @item
> Is not the @file{/bin/false} program.
> @end enumerate
>
> If any of those conditions are not met, the specified shell is not
> used by @value{GDBN}.
>
> I do not see any difference from what I said above, but if you think
> this text can be improved, or that this text is not needed at all, then
> by all means feel free to ask this.
The use of "valid" seems to imply much broader goals. Your
description seems to say that "pseudo-shells used to disable logins"
is a better (though longer) terminology.
Also, I suggest to say "such as the following", so as not to imply
that this is necessarily an exhaustive list.
Finally, is it really OK to lump here the "cannot be executed by the
user" case? Maybe we should error out in that case.
On Saturday, July 25 2015, Eli Zaretskii wrote:
>> From: Sergio Durigan Junior <sergiodj@redhat.com>
>> Cc: simon.marchi@ericsson.com, gdb-patches@sourceware.org
>> Date: Sat, 25 Jul 2015 13:03:12 -0400
>>
>> The new section says:
>>
>> @node Valid Shell
>> @subsection Valid Shell
>>
>> @value{GDBN} considers a @emph{valid shell} a file that:
>>
>> @enumerate
>> @item
>> Exists and can be executed by the user.
>>
>> @item
>> Is not the @file{/sbin/nologin} (or @file{/usr/sbin/nologin}) program.
>>
>> @item
>> Is not the @file{/bin/false} program.
>> @end enumerate
>>
>> If any of those conditions are not met, the specified shell is not
>> used by @value{GDBN}.
>>
>> I do not see any difference from what I said above, but if you think
>> this text can be improved, or that this text is not needed at all, then
>> by all means feel free to ask this.
>
> The use of "valid" seems to imply much broader goals. Your
> description seems to say that "pseudo-shells used to disable logins"
> is a better (though longer) terminology.
>
> Also, I suggest to say "such as the following", so as not to imply
> that this is necessarily an exhaustive list.
OK, I will make these changes and send a v3.
> Finally, is it really OK to lump here the "cannot be executed by the
> user" case? Maybe we should error out in that case.
I don't think we should error out in this case, since we can fallback to
/bin/sh and display a warning (which is what the patch does). Erroring
out seems too much for me.
@@ -752,8 +752,13 @@ shell_escape (char *arg, int from_tty)
close_most_fds ();
- if ((user_shell = (char *) getenv ("SHELL")) == NULL)
- user_shell = "/bin/sh";
+ if ((user_shell = (char *) getenv ("SHELL")) == NULL
+ || !valid_shell (user_shell))
+ {
+ user_shell = "/bin/sh";
+ if (!valid_shell (user_shell))
+ error (_("Cannot use '%s' as a shell."), user_shell);
+ }
/* Get the name of the shell for arg0. */
p = lbasename (user_shell);
@@ -1409,11 +1409,12 @@ just use the @code{shell} command.
@cindex shell escape
@item shell @var{command-string}
@itemx !@var{command-string}
-Invoke a standard shell to execute @var{command-string}.
-Note that no space is needed between @code{!} and @var{command-string}.
-If it exists, the environment variable @code{SHELL} determines which
-shell to run. Otherwise @value{GDBN} uses the default shell
-(@file{/bin/sh} on Unix systems, @file{COMMAND.COM} on MS-DOS, etc.).
+Invoke a standard shell to execute @var{command-string}. Note that no
+space is needed between @code{!} and @var{command-string}. If it
+exists and points to a valid shell (see @ref{Valid Shell,,}), the
+environment variable @code{SHELL} determines which shell to run.
+Otherwise @value{GDBN} uses the default shell (@file{/bin/sh} on Unix
+systems, @file{COMMAND.COM} on MS-DOS, etc.).
@end table
The utility @code{make} is often needed in development environments.
@@ -1428,6 +1429,22 @@ Execute the @code{make} program with the specified
arguments. This is equivalent to @samp{shell make @var{make-args}}.
@end table
+@node Valid Shell
+@subsection Valid Shell
+
+@value{GDBN} considers a @emph{valid shell} a file that:
+
+@enumerate
+@item
+Exists and can be executed by the user.
+
+@item
+Is not the @file{/sbin/nologin} program.
+@end enumerate
+
+If any of those conditions are not met, the specified shell is not
+used by @value{GDBN}.
+
@node Logging Output
@section Logging Output
@cindex logging @value{GDBN} output
@@ -2041,6 +2058,7 @@ is used to pass the arguments, so that you may use normal conventions
the arguments.
In Unix systems, you can control which shell is used with the
@code{SHELL} environment variable. If you do not define @code{SHELL},
+or if you define it to an invalid shell (see @ref{Valid Shell,,}),
@value{GDBN} uses the default shell (@file{/bin/sh}). You can disable
use of any shell with the @code{set startup-with-shell} command (see
below for details).
@@ -2286,9 +2304,10 @@ The arguments to your program can be specified by the arguments of the
@code{run} command.
They are passed to a shell, which expands wildcard characters and
performs redirection of I/O, and thence to your program. Your
-@code{SHELL} environment variable (if it exists) specifies what shell
-@value{GDBN} uses. If you do not define @code{SHELL}, @value{GDBN} uses
-the default shell (@file{/bin/sh} on Unix).
+@code{SHELL} environment variable (if it exists and if it contains a
+valid shell---see @ref{Valid Shell,,}) specifies what shell
+@value{GDBN} uses. If you do not define @code{SHELL}, @value{GDBN}
+uses the default shell (@file{/bin/sh} on Unix).
On non-Unix systems, the program is usually invoked directly by
@value{GDBN}, which emulates I/O redirection via the appropriate system
@@ -2395,14 +2414,14 @@ rather than assigning it an empty value.
@emph{Warning:} On Unix systems, @value{GDBN} runs your program using
the shell indicated by your @code{SHELL} environment variable if it
-exists (or @code{/bin/sh} if not). If your @code{SHELL} variable
-names a shell that runs an initialization file when started
-non-interactively---such as @file{.cshrc} for C-shell, $@file{.zshenv}
-for the Z shell, or the file specified in the @samp{BASH_ENV}
-environment variable for BASH---any variables you set in that file
-affect your program. You may wish to move setting of environment
-variables to files that are only run when you sign on, such as
-@file{.login} or @file{.profile}.
+exists and points to a valid shell (see @ref{Valid Shell,,}), or
+@code{/bin/sh} if not. If your @code{SHELL} variable names a shell
+that runs an initialization file when started non-interactively---such
+as @file{.cshrc} for C-shell, $@file{.zshenv} for the Z shell, or the
+file specified in the @samp{BASH_ENV} environment variable for
+BASH---any variables you set in that file affect your program. You
+may wish to move setting of environment variables to files that are
+only run when you sign on, such as @file{.login} or @file{.profile}.
@node Working Directory
@section Your Program's Working Directory
@@ -108,6 +108,73 @@ escape_bang_in_quoted_argument (const char *shell_file)
return 0;
}
+/* Check if the user has specified any shell to start the inferior,
+ and if the specified shell is valid (i.e., it exists and can be
+ executed by the user).
+
+ The shell specified by the user, if any, is
+ SHELL_FILE_ARG.
+
+ DEFAULT_SHELL_FILE is the default shell that will be used by GDB if
+ the user said she wants to start the inferior using a shell (i.e.,
+ STARTUP_WITH_SHELL is 1), but:
+
+ - No shell has been specified by the user (i.e., the $SHELL
+ environment variable is NULL), or;
+
+ - The shell specified by the user (through the $SHELL environment
+ variable) is invalid. An invalid shell is defined as being
+ either a non-existing file, a file the user cannot execute, or
+ the /sbin/nologin shell.
+
+ This function will return 1 when the user wants to start the
+ inferior using a shell and the shell is valid; it will return 0
+ otherwise. */
+
+static int
+check_startup_with_shell (char **shell_file, char *shell_file_arg,
+ char *default_shell_file)
+{
+ /* 'startup_with_shell' is declared in inferior.h and bound to the
+ "set startup-with-shell" option. If 0, we'll just do a
+ fork/exec, no shell, so don't bother figuring out what shell. */
+ if (startup_with_shell)
+ {
+ gdb_assert (shell_file != NULL);
+ gdb_assert (default_shell_file != NULL);
+ *shell_file = shell_file_arg;
+
+ /* Figure out what shell to start up the user program under. */
+ if (*shell_file == NULL)
+ *shell_file = getenv ("SHELL");
+ if (*shell_file == NULL
+ || !valid_shell (*shell_file))
+ {
+ if (*shell_file != NULL)
+ warning (_("Invalid shell '%s'; using '%s' instead."),
+ *shell_file, default_shell_file);
+ /* Being overzealous here. */
+ if (valid_shell (default_shell_file))
+ *shell_file = default_shell_file;
+ else
+ {
+ warning (_("Cannot use '%s' as the shell, using 'exec' "
+ "to start inferior."),
+ default_shell_file);
+ *shell_file = NULL;
+ }
+ }
+
+ if (*shell_file != NULL)
+ return 1;
+ }
+
+ /* We set startup_with_shell to zero here because if the specified
+ shell is invalid then no shell will be used. */
+ startup_with_shell = 0;
+ return 0;
+}
+
/* Start an inferior Unix child process and sets inferior_ptid to its
pid. EXEC_FILE is the file to run. ALLARGS is a string containing
the arguments to the program. ENV is the environment vector to
@@ -148,19 +215,8 @@ fork_inferior (char *exec_file_arg, char *allargs, char **env,
if (exec_file == 0)
exec_file = get_exec_file (1);
- /* 'startup_with_shell' is declared in inferior.h and bound to the
- "set startup-with-shell" option. If 0, we'll just do a
- fork/exec, no shell, so don't bother figuring out what shell. */
- shell_file = shell_file_arg;
- if (startup_with_shell)
- {
- /* Figure out what shell to start up the user program under. */
- if (shell_file == NULL)
- shell_file = getenv ("SHELL");
- if (shell_file == NULL)
- shell_file = default_shell_file;
- shell = 1;
- }
+ shell = check_startup_with_shell (&shell_file, shell_file_arg,
+ default_shell_file);
if (!shell)
{
new file mode 100644
@@ -0,0 +1,38 @@
+# Copyright 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+standard_testfile normal.c
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+ untested "could not compile test program"
+ return -1
+}
+
+gdb_exit
+
+# Set the $SHELL to an invalid file. This will cause GDB to use
+# /bin/sh instead.
+set oldshell $env(SHELL)
+set env(SHELL) "/invalid/path/to/file"
+
+clean_restart $binfile
+
+# Running the inferior must work.
+gdb_test "run" "Starting program: .*\r\nwarning: Invalid shell \\\'/invalid/path/to/file\\\'; using \\\'/bin/sh\\\' instead.\r\n\\\[Inferior $decimal \\\(process $decimal\\\) exited normally\\\]" "starting with /bin/sh instead of invalid shell"
+
+# Invoking a shell command must also work.
+gdb_test "shell echo hi" "hi" "invoking shell command from prompt"
+
+set env(SHELL) $oldshell
@@ -3364,6 +3364,16 @@ gdb_filename_fnmatch (const char *pattern, const char *string, int flags)
return fnmatch (pattern, string, flags);
}
+/* See utils.h. */
+
+int
+valid_shell (const char *shell)
+{
+ return (shell != NULL
+ && strcmp (shell, "/sbin/nologin") != 0
+ && access (shell, X_OK) == 0);
+}
+
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_utils;
@@ -369,4 +369,15 @@ extern void dump_core (void);
extern char *make_hex_string (const gdb_byte *data, size_t length);
+/* Return 1 if SHELL is a valid shell to execute a command, zero
+ otherwise.
+
+ A valid shell is defined a file that is:
+
+ - Not /sbin/nologin;
+
+ - Executable by the user. */
+
+extern int valid_shell (const char *shell);
+
#endif /* UTILS_H */