node-red / linux-installers

Node-RED install scripts for various flavours of Linux
Apache License 2.0
94 stars 63 forks source link

setcap in deb installer #33

Closed OrionTheGiant closed 1 year ago

OrionTheGiant commented 2 years ago

I've been hunting down a problem using the NODE_PATH environment variable to find globally installed modules on some systems.

Which led me to this StackOverflow post which pointed to the problem potentially being related to a capability being set on the node binary. As it turned out, all of the systems that were having issues with NODE_PATH had the cap_net_raw+eip capability and some more searching led me to the node-red scripted installer https://github.com/node-red/linux-installers/blob/7f1dfd3de54317000bce6f5f6372c8aa86e27f0e/deb/update-nodejs-and-nodered#L646

Can you explain what the purpose this capability serves as far as node-red and node-red-contrib modules are concerned?

To silently break a piece of Node.js is less than ideal especially when the installer script is the strongly recommended way to get node-red on a Raspberry Pi (and from the looks of it, any Debian-based system that has a Broadcom CPU).

I understand that it probably isn't realistic to remove this from the installer at this point since some nodes will expect that capability but having an option to not set the capability and a note on this page mentioning it for future revisions of the installer would be great.

Thanks!

dceejay commented 2 years ago

Can't recall exactly - was way back before 2019 :-)... but I think it is to do with permissions to access ports below 1024. Without having extended capabilities nodes can't access any port below 1024 unless the system is run as root which we don't really want. This would affect many nodes like email, tcp, http etc so I don't think we would want to change the default right now unless we make it part of a major version bump.

I suppose we could add a flag to the installer (--no-low-ports or something ?) to install without it but not sure how useful that would be.

OrionTheGiant commented 2 years ago

Thanks for the quick response! I totally understand that you can't fully recall why it was added. Whatever the original purpose, it seems odd that it's only needed on Broadcom CPUs.

You're right that it may not be a broad enough issue to need a flag on the installer but mentioning on the Raspberry Pi getting started page that it breaks the NODE_PATH and HOME environment variables in scripts run under node may be enough to help people that it would impact and set them on the right debugging path.

dceejay commented 2 years ago

Hmm good point re broadcom/Pi... hmm now really scratching my brain as to why/if it's still needed... as we haven't had too many issues/complaints about port access on generic ubuntu installs etc.

dceejay commented 2 years ago

Meanwhile back to the original issue - are you able to supply a small example flow that shows this inconsistency ? If I just echo $HOME or $NODE_PATH in an exec node (ie running under node env) I get /home/pi for $HOME and "" for NODE_PATH and likewise on my Mac I get /home/dcj and "" ...

OrionTheGiant commented 2 years ago

Looking up the capabilities here says that CAP_NET_RAW is for transparent proxying and using RAW and PACKET sockets while CAP_NET_BIND_SERVICE is for binding to the lower 1024 ports anyhow. For better or worse, there are plenty of people who run into permission issues and the first thing they try is running it as root so maybe that's part of why there aren't many reported issues?

Printing the environment variables directly turned out not to be enough because the problem is from the module loader only allowing the use of "safe" environment variables. If you print out module.paths without the capability it will include the paths in NODE_PATH and HOME but with the capability set it won't.

Here's an example running from the node REPL

cl-admin@latitude:~$ echo $HOME $NODE_PATH
/home/cl-admin /usr/local/lib/npm/lib/node_modules:
cl-admin@latitude:~$ /sbin/getcap /usr/bin/node
cl-admin@latitude:~$ node
Welcome to Node.js v12.22.2.
> console.log(module.paths)
[
  '/home/cl-admin/repl/node_modules',
  '/home/cl-admin/node_modules',
  '/home/node_modules',
  '/node_modules',
  '/usr/local/lib/npm/lib/node_modules',
  '/home/cl-admin/.node_modules',
  '/home/cl-admin/.node_libraries',
  '/usr/lib/node'
]
> 
cl-admin@latitude:~$ sudo /sbin/setcap cap_net_raw+eip /usr/bin/node
cl-admin@latitude:~$ /sbin/getcap /usr/bin/node
/usr/bin/node = cap_net_raw+eip
cl-admin@latitude:~$ node
Welcome to Node.js v12.22.2.
> console.log(module.paths)
[
  '/home/cl-admin/repl/node_modules',
  '/home/cl-admin/node_modules',
  '/home/node_modules',
  '/node_modules',
  '/usr/lib/node'
]
dceejay commented 2 years ago

Hi @OrionTheGiant
ok I think we have worked out why it was set in the first place... It was because at the time the physical web and BLE was on trend and Pi was great for beacons... so things like noble and this https://www.npmjs.com/package/node-red-node-physical-web - needed raw sockets.

So - how do we back out of this position... ? I think we could maybe just drop it... as any existing installs will continue as they are (we aren't removing the permission). That node (above) in particular does explain the prereq and how to set it, so the fix is "discoverable".

I think we could also add a --allow-low-ports optional flag to enable cap_net_bind_service (across all platforms not just Pi) but default that to no not do anything. (or does the raw permission give access to port <1024 as well ? Thoughts ?

OrionTheGiant commented 2 years ago

Thanks for digging into this!

Dropping the capability from the installer and adding the --allow-low-ports flag sound like good ways forward to me.

That node setting the capability as one of the prerequisites seems like it should cover most cases where no longer automatically setting the capability could potentially cause problems for people.

I would maybe also include a note referring to this issue or mention NODE_PATH wherever the --allow-low-ports flag is documented so people running the script can find their way back here if it turns out to cause problems for them.