Question about inline code / incompatibility between FreeBSD sh and bash

2008-06-21 Thread Garrett Cooper
Hi,
 Sorry for emailing this list, but neither the GNU indexed
homepage nor the actual project page listed any other email address.
 I'm trying to determine whether or not this is an implicit bug or
a feature of BSD bourne shell (in particular FreeBSD's sh):
 When I try and execute `portsnap fetch update' [1], things go
through as the author intended. However, using `bash portsnap fetch
update' I get the following error message:

/usr/sbin/portsnap: portsnap: line 882: syntax error near unexpected
token `newline'
/usr/sbin/portsnap: portsnap: line 882: `   if !'

 The incompatible section of code (at least the one that bash
barfs on -- I say that because there are a few similar sections IIRC)
is:

if !
if ! [ -z "${EXTRACTPATH}" ]; then
grep "^${EXTRACTPATH}" ${WORKDIR}/INDEX
elif ! [ -z "${REFUSE}" ]; then
grep -vE "${REFUSE}" ${WORKDIR}/INDEX
else
cat ${WORKDIR}/INDEX
fi | tr '|' ' ' | while read FILE HASH; do
echo ${PORTSDIR}/${FILE}
if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then
echo "files/${HASH}.gz not found -- snapshot corrupt."
return 1
fi
case ${FILE} in
*/)
rm -rf ${PORTSDIR}/${FILE%/}
mkdir -p ${PORTSDIR}/${FILE}
tar -xzf ${WORKDIR}/files/${HASH}.gz\
-C ${PORTSDIR}/${FILE}
;;
*)
rm -f ${PORTSDIR}/${FILE}
tar -xzf ${WORKDIR}/files/${HASH}.gz\
-C ${PORTSDIR} ${FILE}
;;
esac
done; then

I'm pretty sure that the issue is because the code spans multiple
lines and could be (typically) modularized out into a function in
bash.
So the question is, can anyone verify that either bash or
FreeBSD's sh is correct, and/or verify whether or not there is a
possible incompatibility with the POSIX spec for bourne shells in
either camp?
Thanks,
-Garrett

PS Please CC me as I'm not subscribed to [EMAIL PROTECTED]

[1] A copy of portsnap can be found here:
http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.sbin/portsnap/portsnap/portsnap.sh?rev=1.28;content-type=text%2Fplain




Re: Question about inline code / incompatibility between FreeBSD sh and bash

2008-06-21 Thread Garrett Cooper
On Thu, Jun 19, 2008 at 2:12 AM, Garrett Cooper <[EMAIL PROTECTED]> wrote:
> Hi,
> Sorry for emailing this list, but neither the GNU indexed
> homepage nor the actual project page listed any other email address.
> I'm trying to determine whether or not this is an implicit bug or
> a feature of BSD bourne shell (in particular FreeBSD's sh):
> When I try and execute `portsnap fetch update' [1], things go
> through as the author intended. However, using `bash portsnap fetch
> update' I get the following error message:
>
> /usr/sbin/portsnap: portsnap: line 882: syntax error near unexpected
> token `newline'
> /usr/sbin/portsnap: portsnap: line 882: `   if !'
>
> The incompatible section of code (at least the one that bash
> barfs on -- I say that because there are a few similar sections IIRC)
> is:
>
>if !
>if ! [ -z "${EXTRACTPATH}" ]; then
>grep "^${EXTRACTPATH}" ${WORKDIR}/INDEX
>elif ! [ -z "${REFUSE}" ]; then
>grep -vE "${REFUSE}" ${WORKDIR}/INDEX
>else
>cat ${WORKDIR}/INDEX
>fi | tr '|' ' ' | while read FILE HASH; do
>echo ${PORTSDIR}/${FILE}
>if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then
>echo "files/${HASH}.gz not found -- snapshot corrupt."
>return 1
>fi
>case ${FILE} in
>*/)
>rm -rf ${PORTSDIR}/${FILE%/}
>mkdir -p ${PORTSDIR}/${FILE}
>tar -xzf ${WORKDIR}/files/${HASH}.gz\
>-C ${PORTSDIR}/${FILE}
>;;
>*)
>rm -f ${PORTSDIR}/${FILE}
>tar -xzf ${WORKDIR}/files/${HASH}.gz\
>-C ${PORTSDIR} ${FILE}
>;;
>esac
>done; then
>
>I'm pretty sure that the issue is because the code spans multiple
> lines and could be (typically) modularized out into a function in
> bash.
>So the question is, can anyone verify that either bash or
> FreeBSD's sh is correct, and/or verify whether or not there is a
> possible incompatibility with the POSIX spec for bourne shells in
> either camp?
> Thanks,
> -Garrett
>
> PS Please CC me as I'm not subscribed to [EMAIL PROTECTED]
>
> [1] A copy of portsnap can be found here:
> http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.sbin/portsnap/portsnap/portsnap.sh?rev=1.28;content-type=text%2Fplain

When I take the above code, combine remove the newline and make it into ...

if ! if ! [ -z "${EXTRACTPATH}" ]; then

... as well as line 951, the script is parsed properly.

The "problem" is reported at parse.y:3071, but I'm unsure how to trace
back the issue through the yacc code.

-Garrett




Re: Question about inline code / incompatibility between FreeBSD sh and bash

2008-06-21 Thread Garrett Cooper
On Thu, Jun 19, 2008 at 2:29 AM, Garrett Cooper <[EMAIL PROTECTED]> wrote:
> On Thu, Jun 19, 2008 at 2:12 AM, Garrett Cooper <[EMAIL PROTECTED]> wrote:
>>
>> /usr/sbin/portsnap: portsnap: line 882: syntax error near unexpected
>> token `newline'
>> /usr/sbin/portsnap: portsnap: line 882: `   if !'
>>
>> The incompatible section of code (at least the one that bash
>> barfs on -- I say that because there are a few similar sections IIRC)
>> is:
>>
>>if !
>>if ! [ -z "${EXTRACTPATH}" ]; then
>>grep "^${EXTRACTPATH}" ${WORKDIR}/INDEX
>>elif ! [ -z "${REFUSE}" ]; then
>>grep -vE "${REFUSE}" ${WORKDIR}/INDEX
>>else
>>cat ${WORKDIR}/INDEX
>>fi | tr '|' ' ' | while read FILE HASH; do
>>echo ${PORTSDIR}/${FILE}
>>if ! [ -r "${WORKDIR}/files/${HASH}.gz" ]; then
>>echo "files/${HASH}.gz not found -- snapshot corrupt."
>>return 1
>>fi
>>case ${FILE} in
>>*/)
>>rm -rf ${PORTSDIR}/${FILE%/}
>>mkdir -p ${PORTSDIR}/${FILE}
>>tar -xzf ${WORKDIR}/files/${HASH}.gz\
>>-C ${PORTSDIR}/${FILE}
>>;;
>>*)
>>rm -f ${PORTSDIR}/${FILE}
>>tar -xzf ${WORKDIR}/files/${HASH}.gz\
>>-C ${PORTSDIR} ${FILE}
>>;;
>>esac
>>done; then
>>
>
> When I take the above code, combine remove the newline and make it into ...
>
>if ! if ! [ -z "${EXTRACTPATH}" ]; then
>
> ... as well as line 951, the script is parsed properly.
>
> The "problem" is reported at parse.y:3071, but I'm unsure how to trace
> back the issue through the yacc code.

Correction: report_syntax_error in parse.y.
-Garrett




access(2) shouldn't be used with test(1)

2010-07-20 Thread Garrett Cooper
According to the POSIX spec, using access(2) is implementation
dependent when running as superuser [1]. FreeBSD intentionally returns
true whenever euid/uid = 0 [2]. FreeBSD's /bin/sh doesn't have this
`issue' with test(1). Example:

$ ls -l typescript
-rw-r--r--  1 gcooper  gcooper  37875 Jul 12 22:19 typescript
$ sudo sh -c 'test -x typescript; echo $?'
1
$ sudo bash -c 'test -x typescript; echo $?'
0

Code should be added to detect the mode via stat(2), instead of
access(2) (the FreeBSD manpage also notes security issues with race
conditions when using access(2), so access(2) use is discouraged).
If I can get the details for grabbing bash from cvs/svn/whatever,
I'll whip up a patch for this.
Thanks,
-Garrett

[1] http://www.opengroup.org/onlinepubs/95399/functions/access.html
- see RATIONALE.
[2] http://www.freebsd.org/cgi/man.cgi?query=access



Re: access(2) shouldn't be used with test(1)

2010-07-20 Thread Garrett Cooper
On Tue, Jul 20, 2010 at 11:00 AM, Garrett Cooper  wrote:
>    According to the POSIX spec, using access(2) is implementation
> dependent when running as superuser [1]. FreeBSD intentionally returns
> true whenever euid/uid = 0 [2]. FreeBSD's /bin/sh doesn't have this
> `issue' with test(1). Example:
>
> $ ls -l typescript
> -rw-r--r--  1 gcooper  gcooper  37875 Jul 12 22:19 typescript
> $ sudo sh -c 'test -x typescript; echo $?'
> 1
> $ sudo bash -c 'test -x typescript; echo $?'
> 0
>
>    Code should be added to detect the mode via stat(2), instead of
> access(2) (the FreeBSD manpage also notes security issues with race
> conditions when using access(2), so access(2) use is discouraged).
>    If I can get the details for grabbing bash from cvs/svn/whatever,
> I'll whip up a patch for this.
>
> [1] http://www.opengroup.org/onlinepubs/95399/functions/access.html
> - see RATIONALE.
> [2] http://www.freebsd.org/cgi/man.cgi?query=access

Oh, and BTW... here's the version of bash I'm using:

$ bash --version
GNU bash, version 4.1.7(0)-release (amd64-portbld-freebsd9.0)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Thanks,
-Garrett



Re: access(2) shouldn't be used with test(1)

2010-07-20 Thread Garrett Cooper
On Tue, Jul 20, 2010 at 11:28 AM, Eric Blake  wrote:
> On 07/20/2010 12:00 PM, Garrett Cooper wrote:
>>     According to the POSIX spec, using access(2) is implementation
>> dependent when running as superuser [1].
>
> But as long as the answer is correct, then the access(2) family of calls
> is the right thing to use.
>
>> FreeBSD intentionally returns
>> true whenever euid/uid = 0 [2].
>
> Remember, POSIX allows an OS where the superuser CAN read/write/execute
> any file it wants, regardless of whether there are explicit permission
> bits set in the stat() results.  If FreeBSD is one of the OS's where the
> superuser can execute a file that doesn't have any x bits set in stat(),
> then that's one of the privileges of being the superuser, and their
> implementation of access(X_OK) always returning true is correct.  On the
> other hand, POSIX suggests that a better implementation is that the
> superuser should only be able to arbitrarily execute files if the stat()
> and ACL bits allow execute permissions to at least one entity (whether
> or not that entity is also the superuser), in which case, blindly
> returning true for access(X_OK) for uid 0 on a file with no other
> execute permissions would be a bug in access().

Yeah, the manpage gives access(2) the `license to lie':

 Even if a process's real or effective user has appropriate privileges and
 indicates success for X_OK, the file may not actually have execute per-
 mission bits set.  Likewise for R_OK and W_OK.

> Also, remember that access(2) takes into account ACLs, but stat() does
> not.  POSIX requires that 'test -x file' succeed for a non-superuser uid
> that does not own a file with 700 stat() bits, but where the file also
> has an ACL granting execute rights to that uid.

Hmmm...

>> FreeBSD's /bin/sh doesn't have this
>> `issue' with test(1). Example:
>
> I argue that either FreeBSD's /bin/sh or their access(2) is buggy; the
> question now is which one.

Technically it's test(1) that's reporting the mode info, and what they
do is use eaccess(2) instead of access(2).

>> $ ls -l typescript
>> -rw-r--r--  1 gcooper  gcooper  37875 Jul 12 22:19 typescript
>> $ sudo sh -c 'test -x typescript; echo $?'
>> 1
>> $ sudo bash -c 'test -x typescript; echo $?'
>> 0
>
> Try:
>
> echo echo hi > foo
> chmod 644 foo
> sudo sh -c './foo'
>
> If it prints hi, then bash is correct as-is, because FreeBSD falls into
> the category of OSs that allow arbitrary superuser execution regardless
> of whether any other entity has execute rights, which is allowed but not
> recommended by POSIX.  On the other hand, if the superuser fails to
> execute ./foo but access(2) says it can, then FreeBSD's access(2) is
> broken, at which point bash should be working around the broken
> access().  But I still argue that bash is correct for using the
> access(2) family (actually, bash should be using faccessat(,AT_EACCESS)
> [required by POSIX 2008] or the non-portable alternatives eaccess() or
> euidaccess() in preference to access(2), because you want to know if the
> file is executable for the effective id).

Yeah, it fails:

$ echo echo hi > foo
$ chmod 644 foo
$ sudo sh -c './foo'
./foo: Permission denied

>>     Code should be added to detect the mode via stat(2), instead of
>> access(2) (the FreeBSD manpage also notes security issues with race
>> conditions when using access(2), so access(2) use is discouraged).
>>     If I can get the details for grabbing bash from cvs/svn/whatever,
>
> Bash (unfortunately) is not available in a public repository.  Provide
> any patch against the 4.1 sources instead; that's the latest publicly
> available source.  But be aware that bash already has fallback code to
> use stat() on systems with known-buggy access(2), and that your solution
> must NOT interfere with correct test behavior on systems with ACLs (that
> is, relying _solely_ on stat() is almost guaranteed to be wrong on any
> platform with alternate access controls).
>
> Meanwhile, if bash ever uses access() instead of faccessat(,AT_EACCESS)
> on a POSIX 2008 platform, then that would be a bug worth fixing.

I see the quandary now (thanks for the clarification). FreeBSD
supports POSIX ACLs and MAC, so yes, it does appear that access(2) (or
rather the underlying callers for it) should be fixed. I'll have to
check faccessat(2) to see whether or not it's buggy by writing
unittests for it (*sigh*). At least I'll integrate them into the
open_posix_testsuite in ltp, which means they'll be available for
Linux as well...

Thanks,
-Garrett



Re: access(2) shouldn't be used with test(1)

2010-07-20 Thread Garrett Cooper
On Tue, Jul 20, 2010 at 2:18 PM, Linda Walsh  wrote:
> What are you saying it should return, because I get correct results
> on linux:
>
> sudo sh -c 'test -x start_trans; echo $?'
> 1
> sudo bash -c 'test -x start_trans; echo $?'  1
>
> Are you saying that access on BSD, when
> passed (filename "X_OK") returns "true" for superuser even
> when the file isn't executable?

Correct.

> Sounds like a bug to me   if a file isn't executable, I don't care
> how "super" you are -- permission won't make a text file executable!
> ;-)

Yes, but POSIX says that it's allowed to be broken based on past
behavior, and FreeBSD just says "don't use access, act on the file",
which means that access on FreeBSD is only really useful for F_OK, but
I can get that from open/fstat/whatever.

Not having correct data via test(1) renders the utility useless in
many scenarios, which isn't desirable... I've found other issues with
other implementations of access that need to be resolved as well. This
is just one of the problem applications / languages that I'm
addressing that I care about.

Thanks,
-Garrett

> Garrett Cooper wrote:
>>
>>    According to the POSIX spec, using access(2) is implementation
>> dependent when running as superuser [1]. FreeBSD intentionally returns
>> true whenever euid/uid = 0 [2]. FreeBSD's /bin/sh doesn't have this
>> `issue' with test(1). Example:
>>
>> $ ls -l typescript
>> -rw-r--r--  1 gcooper  gcooper  37875 Jul 12 22:19 typescript
>> $ sudo sh -c 'test -x typescript; echo $?'
>> 1
>> $ sudo bash -c 'test -x typescript; echo $?'
>> 0
>>
>>    Code should be added to detect the mode via stat(2), instead of
>> access(2) (the FreeBSD manpage also notes security issues with race
>> conditions when using access(2), so access(2) use is discouraged).
>>    If I can get the details for grabbing bash from cvs/svn/whatever,
>> I'll whip up a patch for this.
>> Thanks,
>> -Garrett
>>
>> [1] http://www.opengroup.org/onlinepubs/95399/functions/access.html
>> - see RATIONALE.
>> [2] http://www.freebsd.org/cgi/man.cgi?query=access
>>
>



Re: access(2) shouldn't be used with test(1)

2010-07-20 Thread Garrett Cooper
On Tue, Jul 20, 2010 at 5:16 PM, Chet Ramey  wrote:
> On 7/20/10 2:00 PM, Garrett Cooper wrote:
>>     According to the POSIX spec, using access(2) is implementation
>> dependent when running as superuser [1]. FreeBSD intentionally returns
>> true whenever euid/uid = 0 [2]. FreeBSD's /bin/sh doesn't have this
>> `issue' with test(1). Example:
>
> Bash-4.1 doesn't use access for `test -x' (or -e, -r, or -w, for that
> matter) on FreeBSD.  If eaccess is available and configure detects its
> presence, bash uses that, otherwise it either uses access or checks the
> permissions returned by stat.
>
> Bash-4.2 will prefer the use of faccessat if available, falling back to
> eaccess and then access/stat.  On FreeBSD, bash-4.2 will use stat to
> verify X_OK when euid == 0 even if eaccess returns true, since eaccess
> lies also (the FreeBSD test does the same thing).
>
> The relevant code is in lib/sh/eaccess.c:sh_eaccess().  This was
> discussed extensively back in March.

I see what you mean.. I need to do more digging because according to
the config logs, eaccess(2) is used, and when I put an #error in the
relevant block, it pops up with:

findcmd.c:98:2: error: #error "!eaccess!"
*** Error code 1

Stop in /usr/ports/shells/bash/work/bash-4.1.
*** Error code 1

:(...

Thanks,
-Garrett