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

[BUG] cannot run npm scripts as root as long as the directory's owner is a regular user #4095

Closed
2 tasks done
zimtsui opened this issue Nov 26, 2021 · 9 comments
Closed
2 tasks done
Labels
Bug thing that needs fixing Needs Triage needs review for next steps Release 8.x work is associated with a specific npm 8 release

Comments

@zimtsui
Copy link

zimtsui commented Nov 26, 2021

Is there an existing issue for this?

  • I have searched the existing issues

This issue exists in the latest npm version

  • I am using the latest npm

Current Behavior

If a project directory belongs to a linux regular user, all npm scripts in it cannot be run as root.

This problem doesn't exist on npm v6.x

Expected Behavior

When logged in as root, or running npm script with sudo, the scripts should be run as root.

Steps To Reproduce

zim@desktop:~$ mkdir ./haha
zim@desktop:~$ cd ./haha
zim@desktop:~/haha$ emacs ./package.json

~/haha/package.json:

{
  "name": "haha",
  "scripts": {
    "test": "whoami"
  }
}
zim@desktop:~/haha$ sudo npm run test
[sudo] password for zim: 

> test
> whoami

zim

zim is a regular user.

Environment

  • npm: 8.1.3
  • Node: 16.13.0
  • OS: Ubuntu 20.04
  • platform: amd64
  • npm config:
; "user" config from /home/zim/.npmrc

registry = "https://repo.huaweicloud.com/repository/npm/" 

; node bin location = /usr/local/bin/node
; cwd = /home/zim/haha
; HOME = /home/zim
; Run `npm config ls -l` to show all defaults.

My npm and node are installed from n

@zimtsui zimtsui added Bug thing that needs fixing Needs Triage needs review for next steps Release 8.x work is associated with a specific npm 8 release labels Nov 26, 2021
@ljharb
Copy link
Contributor

ljharb commented Nov 26, 2021

sudo doesn’t run as a specific super user, and doesn’t change who’s logged in. It just runs the command as your regular user but with super user privileges.

@zimtsui
Copy link
Author

zimtsui commented Nov 27, 2021

@ljharb So why this problem doesn't exist with npm v6.x.x?

Furthermore, if I log in as root directly, the problem still exists.

$su --login root

@wistnki
Copy link

wistnki commented Dec 2, 2021

This problem seems to exist with npm v 7.0.2 with node v15.0.0 and later.
npm 6.14.15 with node 14.18.2 does not have it.

(My npm and node are also installed from n on Ubuntu 20.04 amd64.)

@ArturDorochowicz
Copy link

I think I'm seeing the same issue. It starts with npm 7.0.0. I don't think node version matters.

@ArturDorochowicz
Copy link

ArturDorochowicz commented Dec 16, 2021

This can be reproduced in Docker.

Create a Dockerfile with:

FROM node:14-bullseye-slim

RUN echo 'Confirm we are root uid=0'; id
RUN echo 'Prints 16.14.15'; npm -v

# switch to user node
USER node
RUN mkdir /home/node/src/
WORKDIR /home/node/src/

RUN echo '{ "scripts": { "test": "node --eval \\"console.log(process.getuid())\\"" } }' > package.json

RUN echo 'Confirm we are user node uid=1000'; id
RUN echo 'Correctly prints 1000'; npm test

# switch to root
USER root
RUN echo 'Confirm we are root uid=0'; id
RUN echo 'Correctly prints 0'; npm test

# install [email protected]
RUN npm install -g [email protected]

RUN echo 'Prints 7.0.0'; npm -v

RUN echo 'Confirm we are root uid=0'; id
RUN echo 'INCORRECTLY prints 1000, BUG???'; npm test

Building produces output as described:

>docker build --progress plain --no-cache .
Sending build context to Docker daemon   2.56kB
Step 1/16 : FROM node:14-bullseye-slim
 ---> 93b578a7072d
Step 2/16 : RUN echo 'Confirm we are root uid=0'; id
 ---> Running in 71aca8fe6102
Confirm we are root uid=0
uid=0(root) gid=0(root) groups=0(root)
Removing intermediate container 71aca8fe6102
 ---> ef2a7f39ad01
Step 3/16 : RUN echo 'Prints 16.14.15'; npm -v
 ---> Running in 2939303072a9
Prints 16.14.15
6.14.15
Removing intermediate container 2939303072a9
 ---> f3af3b983003
Step 4/16 : USER node
 ---> Running in 73d3184233f1
Removing intermediate container 73d3184233f1
 ---> 2c4508865511
Step 5/16 : RUN mkdir /home/node/src/
 ---> Running in 87749f5bb748
Removing intermediate container 87749f5bb748
 ---> ab665e3bb5a6
Step 6/16 : WORKDIR /home/node/src/
 ---> Running in db5c4cf569e8
Removing intermediate container db5c4cf569e8
 ---> e90635fc7f68
Step 7/16 : RUN echo '{ "scripts": { "test": "node --eval \\"console.log(process.getuid())\\"" } }' > package.json
 ---> Running in 0d038f78018e
Removing intermediate container 0d038f78018e
 ---> a93de13a1446
Step 8/16 : RUN echo 'Confirm we are user node uid=1000'; id
 ---> Running in 40f6f43facbe
Confirm we are user node uid=1000
uid=1000(node) gid=1000(node) groups=1000(node)
Removing intermediate container 40f6f43facbe
 ---> 54ce8de539ca
Step 9/16 : RUN echo 'Correctly prints 1000'; npm test
 ---> Running in b5580147c191
Correctly prints 1000

> @ test /home/node/src
> node --eval "console.log(process.getuid())"

1000
Removing intermediate container b5580147c191
 ---> 382a2f7740be
Step 10/16 : USER root
 ---> Running in 4b66c3c1197b
Removing intermediate container 4b66c3c1197b
 ---> cc2e79fd1e20
Step 11/16 : RUN echo 'Confirm we are root uid=0'; id
 ---> Running in 655dee3d6fa4
Confirm we are root uid=0
uid=0(root) gid=0(root) groups=0(root)
Removing intermediate container 655dee3d6fa4
 ---> 345f5f8df1e2
Step 12/16 : RUN echo 'Correctly prints 0'; npm test
 ---> Running in 0fbada6850ec
Correctly prints 0

> @ test /home/node/src
> node --eval "console.log(process.getuid())"

0
Removing intermediate container 0fbada6850ec
 ---> 0927a16f1a53
Step 13/16 : RUN npm install -g [email protected]
 ---> Running in b4c3cede2713
/usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js
/usr/local/bin/npx -> /usr/local/lib/node_modules/npm/bin/npx-cli.js
+ [email protected]
added 59 packages from 23 contributors, removed 239 packages and updated 198 packages in 13.96s
Removing intermediate container b4c3cede2713
 ---> b03a1504a663
Step 14/16 : RUN echo 'Prints 7.0.0'; npm -v
 ---> Running in 80439ebd651a
Prints 7.0.0
7.0.0
Removing intermediate container 80439ebd651a
 ---> 9911c19d01ef
Step 15/16 : RUN echo 'Confirm we are root uid=0'; id
 ---> Running in bc5aa59209d2
Confirm we are root uid=0
uid=0(root) gid=0(root) groups=0(root)
Removing intermediate container bc5aa59209d2
 ---> 6998796881d4
Step 16/16 : RUN echo 'INCORRECTLY prints 1000, BUG???'; npm test
 ---> Running in 6eccdb5835d8
INCORRECTLY prints 1000, BUG???

> test
> node --eval "console.log(process.getuid())"

1000
npm notice 
npm notice New major version of npm available! 7.0.0 -> 8.3.0
npm notice Changelog: <https://github.com/npm/cli/releases/tag/v8.3.0>
npm notice Run `npm install -g [email protected]` to update!
npm notice 
Removing intermediate container 6eccdb5835d8
 ---> 2538d32cfc1a
Successfully built 2538d32cfc1a 

This can just as well be reproduced with newest npm (8.3.0). I'm only showing 7.0.0, because it's the earliest version where it occurs.

Also, Node version does not matter. Same thing happens with Node 12 (12-bullseye-slim). In case of Node 16, all image versions already start with npm 7+, so we are in a broken state from the get go.

Update: Actually the earliest version with the issue is 7.0.0-beta.6 (unfortunately, the diff is still quite substantial: v6.14.15...v7.0.0-beta.6). On the other hand all earlier betas (0-5) crash when running that last npm test with something similar to:

 ---> Running in 75810645e3b9
INCORRECTLY prints 1000, BUG???
Error: bad marker
    at ConfigChain.add (/usr/local/lib/node_modules/npm/node_modules/config-chain/index.js:252:33)
    at Conf.add (/usr/local/lib/node_modules/npm/lib/config/core.js:264:27)
    at ConfigChain.addString (/usr/local/lib/node_modules/npm/node_modules/config-chain/index.js:244:8)
    at Conf.<anonymous> (/usr/local/lib/node_modules/npm/lib/config/core.js:242:10)
    at /usr/local/lib/node_modules/npm/node_modules/graceful-fs/graceful-fs.js:123:16
    at FSReqCallback.readFileAfterClose [as oncomplete] (internal/fs/read_file_context.js:63:3)
/usr/local/lib/node_modules/npm/lib/npm.js:18
    throw new Error('npm.load() required')
    ^

Error: npm.load() required
    at Object.get (/usr/local/lib/node_modules/npm/lib/npm.js:18:11)
    at process.errorHandler (/usr/local/lib/node_modules/npm/lib/utils/error-handler.js:177:32)
    at process.emit (events.js:314:20)
    at process._fatalException (internal/process/execution.js:165:25)
The command '/bin/sh -c echo 'INCORRECTLY prints 1000, BUG???'; npm test' returned a non-zero code: 7

@ArturDorochowicz
Copy link

ArturDorochowicz commented Dec 16, 2021

Changelog for 7.0.0-beta.0 says:

The user, group, uid, gid, and unsafe-perms configurations are no longer relevant. When npm is run as root, scripts are always run with the effective uid and gid of the working directory owner.

And in docs:

When npm is run as root, scripts are always run with the effective uid and gid of the working directory owner.

So this is a feature?!

@zimtsui
Copy link
Author

zimtsui commented Feb 8, 2022

This issue is closed because it is an expected behavior as @ArturDorochowicz said.

@robertsLando
Copy link

I have created #4811 please go to upvote it so maybe it get noticed by maintainers

@papb
Copy link

papb commented Aug 4, 2022

See npm/rfcs#546

jonathanhefner added a commit to jonathanhefner/railbarge that referenced this issue Mar 8, 2023
With NPM v7 and v8, when running as root, NPM uses the UID and GID of
the current working directory owner to execute scripts (see
[npm/cli#4095][]).

This can cause a problem if `npm install` is run as root in a directory
owned by another user because module installation scripts will instead
use that user's UID and GID but may still try to write to root's home
directory.  For example, Puppeteer will try to download Chromium to
`/root/.cache/puppeteer/chrome`, raising "EACCES: permission denied".

Similarly, this can cause a problem if `npm install` is run as root in a
directory owned by root, and then that directory is later `chown`ed to
another user.  Subsequent NPM commands (e.g. `npm run build`) run as
root will instead use that user's UID and GID, and will raise "EACCES:
permission denied" when touching anything in the root-owned
`node_modules` directory (e.g. `node_modules/.cache`).

NPM v9 removed this behavior (see [npm/rfcs#546][]), but v9 was first
released on 2022-10-24, and v8 is still widespread.

Therefore, as a workaround, instead of `chown`ing the application
directory to a non-root user, this commit `chmod`s the application
directory to grant owner-equivalent permissions to non-root users.
Additionally, this commit `chown`s and `chmod`s the `PACKAGE_JSON_DIR`
directory in the same way.

[npm/cli#4095]: npm/cli#4095
[npm/rfcs#546]: npm/rfcs#546
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug thing that needs fixing Needs Triage needs review for next steps Release 8.x work is associated with a specific npm 8 release
Projects
None yet
Development

No branches or pull requests

6 participants