node-argon2
node-argon2 copied to clipboard
[0.28.1] Node16 on Alpine suffers SIGSEGV error when using argon2 verify
Steps to reproduce
- Call the argon2.verify function on Node v16.X.X on alpine linux using argon2 v0.28.1
Click here for reproduction repository
Expected behaviour
Verify function returns either true or false.
Actual behaviour
Node exits with SIGSEGV signal.
Environment
Operating system: Alpine linux (official node docker container)
Node version: 16.X.X
I'm using Typescript v4.3.2
Issue is specific to Node16 & argon2 v0.28.1. Node14 works fine as well as argon2 v0.27.2 (even on Node16). I'm not sure whether the verify function is the actual or only culprit, but I've seen in my own application that Node definitely crashes while using this function.
Hello, any update on this ? Got the same problem today on node 16 running on alpine linux with the 0.28.3 package version.
Can confirm the issue. Downgrading to v0.27.2 solves it temporarily.
I can reproduce it, but I could not isolate the root cause yet
Edit: just found it. Seems to be related to Blake2 secure memory wipe from Argon2. Will try to work around that.
Backtrace for anyone interested:
#0 0x00000000000020d6 in ?? ()
#1 0x00007f49b017c99a in secure_wipe_memory () from /home/node/node_modules/argon2/lib/binding/napi-v3/argon2.node
#2 0x00007f49b017e2fd in blake2b_final () from /home/node/node_modules/argon2/lib/binding/napi-v3/argon2.node
#3 0x00007f49b017d458 in initialize () from /home/node/node_modules/argon2/lib/binding/napi-v3/argon2.node
#4 0x00007f49b017c656 in argon2_ctx () from /home/node/node_modules/argon2/lib/binding/napi-v3/argon2.node
#5 0x00007f49b017bfd7 in Napi::AsyncWorker::OnAsyncWorkExecute(napi_env__*, void*) () from /home/node/node_modules/argon2/lib/binding/napi-v3/argon2.node
#6 0x0000558df991f29d in worker (arg=0x0) at ../deps/uv/src/threadpool.c:122
#7 0x00007f49b3059160 in ?? () from /lib/ld-musl-x86_64.so.1
#8 0x0000000000000000 in ?? ()
This seems to be a problem that occurs when the version of Node.js is different between build and runtime.
Alpine Linux is built with Node 14, so the error occurs with Node 16. https://github.com/ranisalt/node-argon2/blob/master/.github/workflows/release.yml#L71
The solution is to run the build in source with the npm_config_build_from_source
flag set to true.
ARG NODE_VERSION=16.2.0
###
# 1. Dependencies
###
# Build with alpine linux
FROM node:${NODE_VERSION}-alpine as dependencies
WORKDIR /home/node/
ENV NODE_ENV development
# Add `build from source` flag
ENV npm_config_build_from_source true
# Install the tools needed for the build
RUN apk add make g++ python3 git
RUN npm i -g node-pre-gyp
COPY tsconfig.json package.json *package-lock.json ./
RUN npm ci
COPY ts ./ts
# "prod-build" on production
RUN npm run setup && \
npm prune --production
###
# 2. Application
###
FROM node:${NODE_VERSION}-alpine
WORKDIR /home/node/
COPY --from=dependencies /home/node/node_modules node_modules
COPY --from=dependencies /home/node/built built
COPY package.json ./
ENV PATH="$PATH:/home/node/node_modules/.bin"
RUN chown -R node:node /home/node
USER node
ENV NODE_ENV production
# "start" on production
CMD ["npm", "run", "start"]
This seems to be a problem that occurs when the version of Node.js is different between build and runtime.
Interestingly, this seems to be only happening with Alpine. I can understand why it happens, but I was expecting node-addon-api
to get around those differences in versions. In this case, it may be related to musl in a corner case that NAA didn't expect.
Getting same error...tried everything I could think of...alpine image fails...node image fails...version 0.27.2 fails...anyone knows why it fails?
Error: /home/node/api/node_modules/argon2/lib/binding/napi-v3/argon2.node: invalid ELF header
at Object.Module._extensions..node (node:internal/modules/cjs/loader:1239:18)
at Module.load (node:internal/modules/cjs/loader:1033:32)
at Function.Module._load (node:internal/modules/cjs/loader:868:12)
at Module.require (node:internal/modules/cjs/loader:1057:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/home/node/api/node_modules/argon2/argon2.js:6:25)
at Module._compile (node:internal/modules/cjs/loader:1155:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1209:10)
at Module.load (node:internal/modules/cjs/loader:1033:32)
at Function.Module._load (node:internal/modules/cjs/loader:868:12)
at Module.require (node:internal/modules/cjs/loader:1057:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/home/node/api/src/app.module.ts:8:1)
at Module._compile (node:internal/modules/cjs/loader:1155:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1209:10)
at Module.load (node:internal/modules/cjs/loader:1033:32)
ARG NODE_VERSION=16
###########
# INSTALL #
###########
FROM node:${NODE_VERSION} As install
# 👉 Security: do not use the `root` user.
ENV USER=node
# You can not use `${USER}` here, but reference `/home/node`.
ENV PATH="/home/node/.npm-global/bin:${PATH}"
# 👉 The `--global` install dir
ENV NPM_CONFIG_PREFIX="/home/node/.npm-global"
# All subsequent commands are run as the `node` user.
USER "${USER}"
# Pre-create the target dir for global install.
RUN mkdir -p "${NPM_CONFIG_PREFIX}/lib"
WORKDIR /home/node/api
COPY ./tsconfig*.json ./package*.json ./
# RUN chown -R node:node /home/node
# Install python/pip
# ENV PYTHONUNBUFFERED=1
# RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python
# RUN python3 -m ensurepip
# RUN pip3 install --no-cache --upgrade pip setuptools
# 👉 Configure NPM, so pkg get installed with correct credentials.
# Avoids `chmod u+x $DIR` and other workarounds.
RUN npm --global --quiet --no-progress install \
&& npm cache clean --force
#########
# BUILD #
#########
FROM node:${NODE_VERSION} As build
WORKDIR /home/node/api
COPY ./tsconfig*.json ./package*.json ./
COPY --from=install /home/node/api/node_modules ./node_modules
COPY . .
ENV NODE_ENV=production
RUN npm ci --only=production && npm cache clean --force
RUN npm run setup && npm prune --production
RUN npm run build
##############
# PRODUCTION #
##############
FROM node:${NODE_VERSION} As production
WORKDIR /home/node
COPY --from=build /home/node/api/node_modules ./node_modules
COPY --from=build /home/node/api/dist ./dist
ENV PATH="$PATH:/home/node/api/node_modules/.bin"
RUN chown -R node:node /home/node/api
USER node
ENV NODE_ENV production
CMD [ "node", "dist/src/main.js" ]
version: '3.8'
services:
db:
# image: mongo # container image to be used
# restart: always
# ports: # expose ports in “host:container” format
# - 27017:27017
# environment: #env variables to pass into the container
# MONGODB_DATABASE: zombies
image: postgres
restart: always
ports:
- "${DATABASE_PORT}:5432"
environment:
POSTGRES_DB: ${DATABASE_NAME}
POSTGRES_USER: ${DATABASE_USERNAME}
POSTGRES_PASSWORD: ${DATABASE_PASSWORD}
volumes:
- ./pgdata:/var/lib/postgresql/data
dev:
container_name: zombies_dev
image: zombies-dev:1.0.0
build:
context: .
target: install
dockerfile: ./Dockerfile
working_dir: /home/node/api
command: npm run start:dev #:debug
ports:
- 3000:3000
# - 9229:9229
networks:
- zombies-network
volumes:
- .:/home/node/api
# - /home/node/api/node_modules
restart: unless-stopped
prod:
container_name: zombies_prod
image: zombies-prod:1.0.0
build:
context: .
target: production
dockerfile: ./Dockerfile
working_dir: /home/node/api
command: npm run start:prod
ports:
- 3000:3000
- 9229:9229
networks:
- zombies-network
volumes:
- .:/home/node
- /home/node/api/node_modules
restart: unless-stopped
networks:
zombies-network:
project url https://github.com/testtestingtester/zombies-angular-nestjs
@testtestingtester the project you sent does not seem to use this library. Additionally, you are not using Alpine, you are using node:16
which uses Debian Buster. There have been reports in the past of people building in an arch and running in another, so check that you are not mixing Debian with Alpine later on.
With that said, can you check the latest version (0.30.2)?
node:16 in the code I pasted but I tried with alpine different versions also, you want me to copy paste those configs? i think not...I'll try 0.30.2 but I'm thinking it's hopeless and probably won't work like the rest I tried...works on mac though
same error even with 0.30.2, i tried downgrading actually because I saw that was the fix others were saying...the project doesn't have the configs in the repo yet but if you try to add them and run docker-compose up -d
you'll see it fails with the same error in docker, works on mac without docker just fine
using bcryptjs
instead fixes my issue
Possibly getting the same error here:
/home/runner/work/code-server/code-server/node_modules/argon2/lib/binding/napi-v3/argon2.node: invalid ELF header
at Runtime._loadModule (test/node_modules/jest-runtime/build/index.js:1180:29)
at Object.<anonymous> (node_modules/argon2/argon2.js:6:25)
Using ubuntu-20.04
in CI with GitHub Actions and 0.30.2
Hi,
Do you know if we have any updates here? I have the same problem with the latest version of argon2 @ 0.30.3
with alpine.3.17
I just saw this for the first time I can ever recall using 0.30.3
, but we also just upgraded Electron so it could be that? But I wouldn't expect this error from upgrading Electron.
Regrettably my scrollback is too small and the error is already gone so I can't see if it was identical to @jsjoeio.
We're running Ubuntu 22.10.
Just hit it again. We're downgrading to 0.29.x
.
If I don't report the issue anymore, it's probably safe to assume the issue is 0.30.x
and not the Electron upgrade - although I'll try to loop back more explicitly. @ranisalt
@Slapbox I believe you have a different problem than the one in this issue. This one is caused by/within musl so unless it's happening in Alpine or Void it's not the same thing :P
It's been some time since I reported this issue and unfortunately it's still a valid issue. Compared to 2021, we're currently using:
- node:18.17.1-alpine (Alpine 3.18.3)
- argon2:0.27.2 (Anything newer crashes the Alpine container as described in the original description)
- typescript:4.9.5
The only reason I'm bumping this issue is because of the security update introduced through 0.31.0 which we cannot update to without changing to another underlying linux distro or replacing argon2 entirely (which I'd really want to avoid if possible).
Is there anything I can do to help resolve this issue in the near future?
@Tallyrald it would be good if you can get the Alpine developers' attention on this issue, it's super hard to debug and when I traced the exception, it happens inside musl, so it's not something we can change from node-argon2
A bug report on their tracker should be enough to get the ball rolling.
this happens because the argon2.node
plugin is precompiled. you cannot expect to run it on a non-glibc system (where it was originally compiled) and work. that it happened to sometimes work is just a fluke.
there is nothing alpine (or musl) can do to fix this. it works if you rebuild it:
> [email protected] start
> node ./built/index.js
[...]
npm ERR! signal SIGSEGV
[...]
$ npx @mapbox/node-pre-gyp rebuild -C node_modules/argon2
$ npm run start
> [email protected] start
> node ./built/index.js
$argon2id$v=19$m=65536,t=8,p=2$4ZxaYfo3wi4uQQcG5Iu+Jg$E/XmpSxdshGcocvDa/DHdcSpHiqvH7o4ckjY1GTUj2+qmPAxjJVIrsh/rWjEB2WAdn8
true
there is nothing alpine (or musl) can do to fix this.
the reason it sometimes happens to work is because musl has some degree of compatibility with glibc (ABI-wise), but it is neither complete nor guaranteed to work (so the older versions just so happened to only use the C api in such a way as to be compatible with either). and when it doesn't match up, having a different ABI than what you compiled against just crashes. there is nothing to do about that (in either alpine, musl, or this repository; though one could argue npm should better handle precompiled binary files and have easy ways to forbid ones that wouldn't work, like how python wheels only install on matching platforms and require building otherwise).
this happens because the
argon2.node
plugin is precompiled
The precompiled binary will be linked against musl if you are running Alpine.
The problem with the Dockerfile provided in this issue is that it installs dependencies under Debian, but then copies to Alpine and does not perform the install step again to refetch the precompiled binary.
The precompiled binary will be linked against musl if you are running Alpine.
in that case it would work fine, indeed this specific way of installing it would be broken :)
yeah, can confirm changing FROM node:${NODE_VERSION}
to FROM node:${NODE_VERSION}-alpine
alone works as expected
Thank you @nekopsykose and @ranisalt for your help. For my specific needs the final solution is to run a 2-step pre-build process before copying everything over to the final image.
- The first step builds most dependencies of the project that need the Debian-based Node image.
- The second step installs argon2 on an Alpine Node image.
- The final step is to copy over all dependencies into the target (Alpine-based) image that is used to run the finalized and prepared application.
For me, the problem is resolved now. If this is satisfactory for others too, please close this issue. Thank you again for your help.
Just for reference, I asked for help in the Alpine issues board HERE which helped the issue move forward and be solved.
@Tallyrald why do you need to run it on Debian? Doesn't Alpine provide the tools you need to build this project?
We have at least one 3rd party library that doesn't support building on Alpine. Heck it didn't even use to run on Alpine, but that got solved some years ago. I wish I knew why this is, but I'm in no position to make a change in regards to this. Best I can do is to trigger a re-verification if we still need to be so specific with this library. If people are able to run the build(install)-phase on Alpine, that is the most straightforward solution.
Alright, since the original problem has been solved, I'm closing the issue