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] root permissions do not carry forward into execution #3110

Closed
ReillyBova opened this issue Apr 20, 2021 · 14 comments
Closed

[BUG] root permissions do not carry forward into execution #3110

ReillyBova opened this issue Apr 20, 2021 · 14 comments
Labels
Bug thing that needs fixing Needs Triage needs review for next steps Release 7.x work is associated with a specific npm 7 release

Comments

@ReillyBova
Copy link

Current Behavior:

I am using webpack to bind a dev server to the privileged port 443 on an M1 Macbook Air (Apple Silicon) running the latest version of Big Sur. In order to bind to the privileged port, my npm start script must be run with root permissions, so I execute sudo npm start. Unfortunately, the root permissions do not carry into the execution, and my server fails to bind to port 443 and throws an error that is identical to the error thrown when run without sudo:

✖ 「wds」:  Error: listen EACCES: permission denied 127.0.0.1:443
    at Server.setupListenHandle [as _listen2] (net.js:1301:21)
    at listenInCluster (net.js:1366:12)
    at GetAddrInfoReqWrap.doListen [as callback] (net.js:1503:7)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:69:8) {

Expected Behavior:

I expect sudo npm run to have no issues binding to port 443 because it has root permissions. This is how it behaves when I backdate npm to 6.14.12.

Steps To Reproduce:

  1. Create an npm start script that tries to bind to a privileged port (e.g. 443)
  2. Run npm start with root permissions (e.g. sudo npm start if on a Mac)
  3. You should see an error
  4. Try binding to the same port directly in your terminal using root permissions
  5. You should not see an error
  6. Redo steps 1-3 using npm v6. Confirm no error is thrown.

I'm not sure how broad this issue is. Here are some open questions:

  1. Is this just related to binding to privileged ports?
  2. Is this just an M1 Apple Silicon problem?
  3. Is this just a Mac OS 11 problem?
  4. Is this an issue on all Mac OS versions?
  5. Is this an issue on all devices?
  6. Etc.

Environment:

  • OS macOS Big Sur 11.2.3
  • Node: 14.16.1
  • npm: 7.10.0
@ReillyBova ReillyBova added Bug thing that needs fixing Needs Triage needs review for next steps Release 7.x work is associated with a specific npm 7 release labels Apr 20, 2021
@alienzhou
Copy link

alienzhou commented Apr 26, 2021

Maybe due to the change below:

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.

described in v7.0.0-beta.0 CHANGELOG


Perhaps because now when running script in root, v7.x will use infer-owner to get the uid and gid based on cwd. It may change the original root uid and gid (0).

const st = fs.lstatSync(path)
threw = false
const { uid, gid } = st
cache.set(path, { uid, gid })
return { uid, gid }

Then pass them to the spawn function as options.

const promiseSpawn = (cmd, args, opts, extra = {}) => {
const cwd = opts.cwd || process.cwd()
const isRoot = process.getuid && process.getuid() === 0
const { uid, gid } = isRoot ? inferOwner.sync(cwd) : {}
return promiseSpawnUid(cmd, args, {
...opts,
cwd,
uid,
gid
}, extra)
}

@darcyclarke
Copy link
Contributor

@ReillyBova as @alienzhou noted, this was an intended change in v7 - you can resolve this by running your scripts/npm within a root owned folder

@jcouturier
Copy link

@ReillyBova as @alienzhou noted, this was an intended change in v7 - you can resolve this by running your scripts/npm within a root owned folder

I'm unclear on why this was an intended change in v7. Running local npm as root and chown'ing the project folder to root seems like a rather messy way to deal with this. I wouldn't consider that a resolution, it's just sidestepping the problem and creating new problems. This issue is really wreaking havoc.

@nwalters512
Copy link

This has caused pretty significant problems with us too - we've had to switch away from npm-scripts to Makefiles to avoid this. This violates conventions of other tools (e.g. make) and is just generally confusing. I've yet to actually see an explanation of why this change was introduced - can a maintainer at least help us understand that?

@rashkov
Copy link

rashkov commented Aug 24, 2021

So this is the source of my debugging nightmare... I've lost hours trying to figure out why my node application could not access a file in a privileged location, when I do sudo npm start. It wasn't clear what was going on until until I printed os.userInfo(), and even after that I had to search quite a bit to find this issue.

A warning message for this new behavior would be very appreciated.

To be frank, it's a little irresponsible not to provide more transparency here. This is a deeply non-obvious behavior. If there are good security reasons for this, then please make them known.

@chulkilee
Copy link
Contributor

https://docs.npmjs.com/cli/v7/using-npm/scripts#user

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

Hit this issue in CI

  • jenkins checks out the repo as jenkins user (uid=1000)
  • docker container runs npm run as root

🤦

you can resolve this by running your scripts/npm within a root owned folder

This is not an option as this will break other programs.

@rashkov
Copy link

rashkov commented Jan 31, 2022

If anyone is looking for a workaround, you can use yarn instead.

@robertsLando
Copy link

While someone could agree on the choice to infer uid ang gid from folder there will still be someone who wants to override this, I have two programs in the same folder and I need to start one with root and the other with non-root user and I haven't any workaround here. An option to override this breaking change would be the best IMO

@gnida-rada
Copy link

Does anyone know a viable workaround to this issue? Changing ownership of a directory where source lives in not viable for my project.
Thanks!

@gnida-rada
Copy link

If anyone is looking for a workaround, you can use yarn instead.

Yarn exhibits exactly the same problem.

@wjureczka
Copy link

wjureczka commented Apr 26, 2022

Any updates on that?
I serve my web application on port 443 and I need use sudo for that. This behavior breaks applications' start-up.

Error: listen EACCES: permission denied 127.0.0.1:443
    at Server.setupListenHandle [as _listen2] (net.js:1303:21)
    at listenInCluster (net.js:1368:12)
    at GetAddrInfoReqWrap.doListen [as callback] (net.js:1505:7)
    at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:71:8) {
  code: 'EACCES',
  errno: -13,
  syscall: 'listen',
  address: '127.0.0.1',
  port: 443
}

Same problem is described here: #4589

@robertsLando
Copy link

Does anyone know a viable workaround to this issue? Changing ownership of a directory where source lives in not viable for my project.

The only workaround is to not use npm to start your script. Just use node directly

@rashkov
Copy link

rashkov commented Apr 26, 2022

Yarn does work though...

-> % ls -l
total 12
-rw-r--r-- 1 mike mike  54 Apr 26 12:13 index.js
-rw-r--r-- 1 mike mike 230 Apr 26 12:12 package.json
-rw-r--r-- 1 mike mike 275 Apr 26 12:17 yarn.lock

-> % cat package.json 
{
  "name": "blah",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

-> % cat index.js 
const os = require('os');
console.log(os.userInfo());
-> % yarn --version
3.2.0
-> % yarn start
{
  uid: 1000,
  gid: 1000,
  username: 'mike',
  homedir: '/home/mike',
  shell: '/bin/zsh'
}
-> % sudo yarn start
{
  uid: 0,
  gid: 0,
  username: 'root',
  homedir: '/root',
  shell: '/bin/bash'
}

-> % ls -ld
drwxr-xr-x 3 mike mike 4096 Apr 26 12:17 .

also worked for yarn version 1.22.18 when I tried that.

But yeah maybe @robertsLando is right, using node directly would be the most simple thing. Still, npm scripts can get pretty complicated, so I wonder if this is always possible without a lot of work.

@robertsLando
Copy link

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

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 7.x work is associated with a specific npm 7 release
Projects
None yet
Development

No branches or pull requests

10 participants