What / Why
It might so happen that root installs packages into a directory owned by another user. Consider a case where you launch an app with docker-compose and bind mount the host directory with source code (.) into the container (/app) for changes to source code to automatically propagate into the container. Under this circumstances we get root user and /app owned by uid 1000. During fetch-package-metadata phase it succeeds, since nothing says it has to impersonate:
pacote@9.5.5 started to run commands under cwd's owner. But some files are to be created in ~/.npm/_cacache/tmp (e.g. cloning repositories when installing from github). When a process (npm) user doesn't match the cwd user, process user's cache is still used. So git clone is executed under cwd user to clone to the process user's tmp dir, which apparently fails. That can happen under docker when a non-root's directory is bind-mounted into a container. It's not owned by root in the container either, but the processes in the container are running under root (unless explicitly started as another user).
The issue doesn't reveal itself on the fetch-package-metadata phase:
https://github.com/npm/cli/blob/v6.12.1/lib/fetch-package-metadata.js#L59-L65
https://github.com/npm/pacote/blob/v9.5.8/manifest.js#L25
https://github.com/npm/pacote/blob/v9.5.8/lib/finalize-manifest.js#L49
https://github.com/npm/pacote/blob/v9.5.8/lib/finalize-manifest.js#L154
https://github.com/npm/pacote/blob/v9.5.8/lib/fetch.js#L33
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L71-L73
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L176
But on the extract phase it switches to non-root and fails:
https://github.com/npm/cli/blob/v6.12.1/lib/install/action/extract.js#L90
https://github.com/npm/pacote/blob/v9.5.8/extract.js#L42
https://github.com/npm/pacote/blob/v9.5.8/lib/with-tarball-stream.js#L96
https://github.com/npm/pacote/blob/v9.5.8/lib/fetch.js#L28
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L44
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L71-L73
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L176
When
- When installing packages from GitHub.
Where
How
Current Behavior
npm ERR! code 128
npm ERR! Command failed: git clone --mirror -q git://github.com/kevva/is-positive.git /root/.npm/_cacache/tmp/git-clone-d80b8730/.git
npm ERR! fatal: could not create leading directories of '/root/.npm/_cacache/tmp/git-clone-d80b8730/.git'
Steps to Reproduce
Under non-root user:
1.sh:
#!/bin/sh
set -eux
npm --version
apk add git
npm i kevva/is-positive || cat /root/.npm/_logs/*.log
$ docker run --rm -itv $PWD:/app -w /app node:10.17.0-alpine3.10 ./1.sh
+ npm --version
6.11.3
...
+ npm i kevva/is-positive
...
npm ERR! Command failed: git clone --mirror -q git://github.com/kevva/is-positive.git /root/.npm/_cac
ache/tmp/git-clone-87fa5e82/.git
npm ERR! fatal: could not create leading directories of '/root/.npm/_cacache/tmp/git-clone-87fa5e82/.
git'
...
Or under root in a non-root dir:
$ npm i kevva/is-positive
Expected Behavior
- It either succeeds in both cases (
extract, fetch-package-metadata), or fails. Preferably the former.
Who
References
More info
Introduced in npm-6.11.0, pacote-9.5.5. Fixed in npm-6.13.6, pacote-9.5.12.
Affects node@^10.17.0 (npm-6.11.3), node >= 12.11.0 (npm-6.11.3), node < 13.7.0 (npm-6.13.6). More on it here.
Old steps to reproduce
Create files based on the following gist and do docker-compose up:
docker-compose.yml:
version: '3'
services:
app:
build: .
# entrypoint: sleep 10000000
# ports:
# - 9229:9229
volumes:
- ./:/app
Dockerfile:
FROM node:12.13.0-alpine
RUN apk add git vim
WORKDIR /app
ENTRYPOINT ["./entrypoint.sh"]
entrypoint.sh:
#!/bin/sh
set -eu
npm i || true
cat /root/.npm/_logs/*.log
$ chmod u+x entrypoint.sh
$ docker-compose up
As you might guess the issue was discovered in a docker container. Alternatively,
# useradd -m u1
# cd /home/u1
# echo '{"dependencies": {"is-positive": "kevva/is-positive"}}' > package.json
# npm i
What / Why
It might so happen thatrootinstalls packages into a directory owned by another user. Consider a case where you launch an app withdocker-composeand bind mount the host directory with source code (.) into the container (/app) for changes to source code to automatically propagate into the container. Under this circumstances we getrootuser and/appowned by uid1000. Duringfetch-package-metadataphase it succeeds, since nothing says it has to impersonate:pacote@9.5.5started to run commands under cwd's owner. But some files are to be created in~/.npm/_cacache/tmp(e.g. cloning repositories when installing from github). When a process (npm) user doesn't match the cwd user, process user's cache is still used. Sogit cloneis executed under cwd user to clone to the process user's tmp dir, which apparently fails. That can happen underdockerwhen a non-root's directory is bind-mounted into a container. It's not owned by root in the container either, but the processes in the container are running under root (unless explicitly started as another user).The issue doesn't reveal itself on the
fetch-package-metadataphase:https://github.com/npm/cli/blob/v6.12.1/lib/fetch-package-metadata.js#L59-L65
https://github.com/npm/pacote/blob/v9.5.8/manifest.js#L25
https://github.com/npm/pacote/blob/v9.5.8/lib/finalize-manifest.js#L49
https://github.com/npm/pacote/blob/v9.5.8/lib/finalize-manifest.js#L154
https://github.com/npm/pacote/blob/v9.5.8/lib/fetch.js#L33
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L71-L73
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L176
But on the
extractphase it switches to non-root and fails:https://github.com/npm/cli/blob/v6.12.1/lib/install/action/extract.js#L90
https://github.com/npm/pacote/blob/v9.5.8/extract.js#L42
https://github.com/npm/pacote/blob/v9.5.8/lib/with-tarball-stream.js#L96
https://github.com/npm/pacote/blob/v9.5.8/lib/fetch.js#L28
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L44
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L71-L73
https://github.com/npm/pacote/blob/v9.5.8/lib/fetchers/git.js#L176
When
Where
How
Current Behavior
Steps to Reproduce
Under non-root user:
1.sh:Or under root in a non-root dir:
Expected Behavior
extract,fetch-package-metadata), or fails. Preferably the former.Who
References
More info
Introduced in
npm-6.11.0,pacote-9.5.5. Fixed innpm-6.13.6,pacote-9.5.12.Affects
node@^10.17.0(npm-6.11.3),node >= 12.11.0(npm-6.11.3),node < 13.7.0(npm-6.13.6). More on it here.Old steps to reproduce
Create files based on the following gist and do
docker-compose up:docker-compose.yml:Dockerfile:entrypoint.sh:As you might guess the issue was discovered in a
dockercontainer. Alternatively,