Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Process PATH search prefers current directory #37101

Closed
sortie opened this issue May 28, 2019 · 3 comments
Closed

Process PATH search prefers current directory #37101

sortie opened this issue May 28, 2019 · 3 comments
Assignees
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@sortie
Copy link
Contributor

sortie commented May 28, 2019

The Dart process execute search prefers the current directory over a PATH search. This behavior violates the rule of least surprise and doesn't appear to be documented. It should instead simply do a path search.

This example program demonstrates the issue:

import 'dart:io';
main() {
  print(Process.runSync("tar", ["--version"]).stdout);
}

This normally works if the system tar is first in the PATH, but if the current directory contains an executable file named tar, then that is preferred even when the current directory is not in the PATH.

#!/bin/sh
echo Preferred the current directory

If that file exists, the test instead prints Preferred the current directory because it preferred the current directory even though it was not in the PATH.

This seems related to the dart --namespace option. The issue seems to be in runtime/bin/process_linux.cc and runtime/bin/process_android.cc in ProcessStarter::ExecProcess and ProcessStarter::ExecDetachedProcess

    char realpath[PATH_MAX];
    if (!FindPathInNamespace(realpath, PATH_MAX)) {
      ReportChildError();
    }
    // TODO(dart:io) Test for the existence of execveat, and use it instead.
    VOID_TEMP_FAILURE_RETRY(
        execvp(realpath, const_cast<char* const*>(program_arguments_)));

The intention of the namespace feature seems to be to emulate a different root directory and working directory, possibly per isolate. The PATH search in the namespace case doesn't seem to be implemented at all, where only absolute paths work. I'll understand what the code is trying to do a bit closer and then come up with a proper fix.

cc @jonasfj

@sortie sortie added area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io P2 A bug or feature request we're likely to work on type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) labels May 28, 2019
@sortie sortie self-assigned this May 28, 2019
@ghost ghost added P1 A high priority bug; for example, a single project is unusable or has many test failures and removed P2 A bug or feature request we're likely to work on labels May 28, 2019
@sigurdm
Copy link
Contributor

sigurdm commented Jun 3, 2019

Also the documentation could use an update
Examples like:

  Process.start('ls', ['-l']).then((process) {...

Encourages creating programs using the ls from $PATH (previously from working directory).
My guess is that usually one should prefer to use the system commands whenever possible: /bin/ls etc.

dart-bot pushed a commit that referenced this issue Jun 11, 2019
This is a security improvement.

On Linux and Android, starting a process with Process.run, Process.runSync
or Process.start would first search the current directory before searching
PATH (Issue [37101][]). Operating systems other than Linux and Android
didn't have this behavior and aren't affected by this vulnerability.

Effectively this puts the current working directory in the front of PATH,
even if it wasn't in the PATH.

This change fixes that vulnerability and only searches the directories in
the PATH environment variable.

Fixes #37101

Change-Id: I05f3137753237f9b3ba4be4eba63ad07a75d865e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/105582
Reviewed-by: William Hesse <whesse@google.com>
@sortie
Copy link
Contributor Author

sortie commented Jun 11, 2019

This was a security vulnerability that has been fixed in Dart 2.3.2 and Dart 2.3.3-dev.0.0.

Here is the text from the CHANGELOG:

Security improvement: On Linux and Android, starting a process with Process.run, Process.runSync, or Process.start would first search the current directory before searching PATH. This behavior effectively put the current working directory in the front of PATH, even if it wasn't in the PATH. This release changes that behavior to only searching the directories in the PATH environment variable. Operating systems other than Linux and Android didn't have this behavior and aren't affected by this vulnerability.

This vulnerability could result in execution of untrusted code if a command without a slash in its name was run inside an untrusted directory containing an executable file with that name:

Process.run("ls", workingDirectory: "/untrusted/directory")

This would attempt to run /untrusted/directory/ls if it existed, even though it is not in the PATH. It was always safe to instead use an absolute path or a path containing a slash.

This vulnerability was introduced in Dart 2.0.0.

@natebosch
Copy link
Member

This was also reported in #34246

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-core-library SDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries. library-io P1 A high priority bug; for example, a single project is unusable or has many test failures type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

3 participants