sodium-friends / sodium-native

Low level bindings for libsodium
MIT License
300 stars 64 forks source link

Segmentation fault using 3.4.1 (musl, x64) #160

Closed SimenB closed 1 year ago

SimenB commented 2 years ago

Given the following Dockerfile

FROM node:16.16.0-alpine3.16

ENTRYPOINT "sh"

RUN apk add --no-cache \
    python3 \
    build-base \
    cmake \
    cairo-dev \
    jpeg-dev \
    pango-dev \
    git

WORKDIR /app

# Adapted from https://github.com/sodium-friends/sodium-native/blob/32ae395ad558ec86680c547b909daf3a13b2dea8/test/crypto_secretbox.js#L4-L32
RUN echo " \
const sodium = require('sodium-native');\
\
const message = Buffer.from('Hej, Verden!');\
const output = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES);\
\
const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES);\
sodium.randombytes_buf(key);\
\
const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES);\
sodium.randombytes_buf(nonce);\
\
const result = Buffer.alloc(output.length - sodium.crypto_secretbox_MACBYTES);\
\
sodium.crypto_secretbox_easy(output, message, nonce, key);\
\
sodium.crypto_secretbox_open_easy(result, output, nonce, key);\
\
console.log({ result, message });\
" > index.js

RUN npm init -y && npm install --save sodium-native@3.4.1

Run docker build -t sodium . && docker run sodium followed by node index.js inside the image to see it segfault.

If you install sodium-native@3.3.0 instead, it runs fine.


Note that I'm not able to reproduce this when built on an M1 mac, only on an x64 one. So this might be instruction set dependent.

mafintosh commented 2 years ago

@SimenB does 3.3.0 work?

mafintosh commented 2 years ago

ah sorry you mention that

mafintosh commented 2 years ago

@SimenB can you see if it triggered recompilation at install on 3.3.0 and not on 3.4.1? afaik since this using musl it would need to be compiled

mafintosh commented 2 years ago

You can check that by seeing if node_modules/sodium-native/build exists

SimenB commented 2 years ago

There's no build folder for either 3.3.0 or 3.4.1. It shows up if I do cd node_modules/sodium-native && npm run dev. Doing so makes it work for 3.4.1. (:tada:)

Should https://github.com/sodium-friends/sodium-native/blob/32ae395ad558ec86680c547b909daf3a13b2dea8/package.json#L17 be postinstall? But even so, it works without build on 3.3.0.

mafintosh commented 2 years ago

ah, mb we are actually using libc now and that's why. this is on a linux host?

SimenB commented 2 years ago

Mac. x64 fails, M1 mac works

jakob11git commented 2 years ago

I experience the same. Now I'm using sodium-native@3.3.0 and then it works fine. But 3.4.0 and 3.4.1 produce a segmentation fault. However, this is not on a Mac, this is happening to me inside Docker container with Alpine Linux running on an Ubuntu host and also on my local machine with the same Docker container running on macOS Intel.

I have to admit I got to this solution mostly by try and error and have no further experience. If I can provide anything or test out anything that might be helpful, I would appreciate a quick explanation of what to do.

shayneczyzewski commented 2 years ago

Same experiences as others here. I am on an M1 Mac, but building our app's Node Alpine Docker images for --platform linux/amd64 since I deploy to Heroku. Reverting back to 3.3.0 works on Heroku, 3.4.1 seg faults. Appreciate everyones' efforts here!

mafintosh commented 2 years ago

Ya, I think we figured it out, a new experimental API is using stuff from libc, so just need to use a helper for that instead, and I'll make a new build. Using 3.3.0 is fine until then, the only change is the addition of the experimental API which you prob do not care about :)

tetchel commented 2 years ago

I am also able to reproduce a segfault on 3.4.1 but not on 3.3.0 in a node:18-alpine container.

shayneczyzewski commented 2 years ago

Hi gang, I was curious if there was a release target in mind for this fix? Thanks so much!

yorch commented 2 years ago

Same problem, only in Docker (Node 16 Alpine image), works fine on Intel Mac. For some reason, reverting back to 3.3.0 doesn't fix it for me and using segfault-handler doesn't give me much clue on what's the reason behind. It happened when I refreshed my yarn.lock file which included bumping sodium-native from 3.3.0 -> 3.4.1. There were a few other dep upgrades, but this package is my main lead so far. Will keep debugging

yorch commented 2 years ago

mmm.. seems like a combination of using the non alpine version of Node and adding cd node_modules/sodium-native && npm run dev as part of my Dockerfile fixes it. Still don't get why just reverting to 3.3.0 would fix it, given that I've been using the same Docker images.

mafintosh commented 2 years ago

Fix coming here https://github.com/sodium-friends/sodium-native/pull/162

mafintosh commented 1 year ago

Turned out to be because we link libc in the prebuild but the alpine musl one doesn't have the full binary compat. Fixed in 4.0.0 (you can most likely just upgrade, see CHANGELOG for breaking changes) as 4.0.0 has official musl prebuilds now.

Also means you can just do

FROM node:16.16.0-alpine3.16

ENTRYPOINT "sh"

WORKDIR /app

# Adapted from https://github.com/sodium-friends/sodium-native/blob/32ae395ad558ec86680c547b909daf3a13b2dea8/test/crypto_secretbox.js#L4-L32
RUN echo " \
const sodium = require('sodium-native');\
\
const message = Buffer.from('Hej, Verden!');\
const output = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES);\
\
const key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES);\
sodium.randombytes_buf(key);\
\
const nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES);\
sodium.randombytes_buf(nonce);\
\
const result = Buffer.alloc(output.length - sodium.crypto_secretbox_MACBYTES);\
\
sodium.crypto_secretbox_easy(output, message, nonce, key);\
\
sodium.crypto_secretbox_open_easy(result, output, nonce, key);\
\
console.log({ result, message });\
" > index.js

RUN npm init -y && npm install --save sodium-native@4

No need for all the build deps

SimenB commented 1 year ago

Awesome, thanks!