apple / swift-corelibs-foundation

The Foundation Project, providing core utilities, internationalization, and OS independence
swift.org
Apache License 2.0
5.27k stars 1.13k forks source link

[SR-437] fatalError - could not get correct login name #4184

Closed drewcrawford closed 8 years ago

drewcrawford commented 8 years ago
Previous ID SR-437
Radar None
Original Reporter @drewcrawford
Type Bug
Status Closed
Resolution Done
Environment Linux x86_64 (glibc) swift-2.2-SNAPSHOT-2015-12-31-a
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Foundation | |Labels | Bug | |Assignee | Eugene Gubin (JIRA) | |Priority | Medium | md5: e1a9699af115cfcb14b4871015c130ae

Issue Description:

This is a bug in swift-corelibs-foundation; it's a regression new in the dec-31 snapshot. You cannot run buildbot_linux without a TTY attached (for example, in a Docker container).

The root cause is the implementation of NSUserName, which is exercised in a test suite and will crash without a TTY.

The actual root cause is that getlogin(_r) does not work without a TTY due to a glibc bug.
According to the the manpage, getlogin_r call can fail if:

Standard input didn't refer to a terminal. (See BUGS.)

It goes on to explain:

Unfortunately, it is often rather easy to fool getlogin(). Sometimes it does not work at all, because some program messed up the utmp file. Often, it gives only the first 8 characters of the login name. The user currently logged in on the controlling terminal of our program need not be the user who started it. Avoid getlogin() for security-related purposes.

Note that glibc does not follow the POSIX specification and uses stdin instead of /dev/tty. A bug. (Other recent systems, like SunOS 5.8 and HP-UX 11.11 and FreeBSD 4.8 all return the login name also when stdin is redirected.)

This glibc bug occurs in real-world scenarios:

1. This call is exercised in a test that runs under buildbot_linux

  1. I build buildbot_linux inside a Docker container
  2. Docker containers have no attached tty during a build
  3. The swift-2.2-SNAPSHOT-2015-12-31-a can no longer be built for Docker.

The bug can be reproduced (although it takes awhile) on any system with Docker installed by creating a file called 'Dockerfile' with the following contents and then running "docker build ."

    FROM debian:latest

    ENV SWIFT_TAG="swift-2.2-SNAPSHOT-2015-12-31-a" RUNTIME_PACKAGES="clang libedit2 libpython2.7 libxml2 libicu52" BUILDTIME_PACKAGES="git ca-certificates python ninja-build cmake uuid-dev libbsd-dev libicu-dev pkg-config libedit-dev file libxml2-dev python-dev libncurses5-dev libsqlite3-dev libreadline6-dev rsync"

    RUN \
    # Create a directory to work in \
    mkdir swift-dev && \
    cd swift-dev && \
    # Install the runtime and build-time dependencies \
    apt-get update && \
    apt-get install $RUNTIME_PACKAGES $BUILDTIME_PACKAGES -y --no-install-recommends && \
    \
    git clone https://github.com/apple/swift.git && \
    cd swift && \
    # submodules?  Where we're going, we don't need submodules! \
    ./utils/update-checkout --clone && \
    \
    # The silly update-checkout script does not understand matching the swift checkout ref \
    # In practice what you're supposed to do (I think!  It's not documented!) is check out the same snapshot tag  \
    # Not all the folders have them (where do some of them come from??) but we'll just try them all \
    find ../ -maxdepth 1 -type d  -exec bash -c '(cd {} && echo checking out in `pwd` && git checkout $SWIFT_TAG)' \; && \
    \
    # And now we build, like a good little linuxen. \
    # I believe this is what the linux build script does.  In practice, this builds a system into /tmp/install and then tars it up. \
    ./utils/build-script --preset=buildbot_linux install_destdir="/tmp/install" installable_package="/tmp/swift.tar.gz" && \
    \
    # Install our tarball to /usr/local \
    tar xf /tmp/swift.tar.gz -C /usr/local --strip-components 1 && \
    \
    # Clean up \
    cd / && \
    rm -rf /tmp/swift.tar.gz /swift-dev && \
    apt-get remove --purge -y $BUILDTIME_PACKAGES && \
    apt-get autoremove --purge -y && \
    apt-get clean -y && \
    apt-get autoclean -y && \
    rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

    ENTRYPOINT ["bash"]

This produces a "fatalError - could not get login name" with errno ENOTTY.

It's not immediately clear how to fix this so I'm pinging the implementor of NSUserName.

drewcrawford commented 8 years ago

I currently work around with this patch.

It's obviously not a proper solution but it does let me build again with Docker.

phausler commented 8 years ago

Hmm "Jeff" might not be a good default return value here; perhaps "" or "unknown" etc might be a bit more appropriate and less confusing. We may want to also consider reducing the unit test scope for non TTY enabled sessions and skip certain tests when that is the case

swift-ci commented 8 years ago

Comment by Eugene Gubin (JIRA)

https://github.com/apple/swift-corelibs-foundation/pull/206 I made some improvements. Mentioned workaround in place. I think PR should be tested with and without it.

drewcrawford commented 8 years ago

I think this is resolved in PR #206, now merged. Thanks Eugene Gubin (JIRA User)!

drewcrawford commented 8 years ago

Tested by me