class: center, middle # Building a distro with musl libc #### Why and how Alpine Linux did it FOSDEM 2017 Natanael Copa (@n_copa) --- ![Alpline Logo](alpinelinux-logo.svg)
Small. Simple. Secure.
#### Original design goal - to run diskless - install from scratch to ram-disk (tmpfs) at bootup. #### Usecases - router, firewall, vpn, proxy, voip #### Later also - containers (Docker FTW!), servers, desktop? --- ### 2006 - started with Gentoo embedded (uClibc) - busybox - grsecurity kernel - apk-tools ### 2008 - start with aports (selfhosting - drop Gentoo) ### 2013 - v2.7.0 (uClibc based) - 2800 ports - more a general purpose distro --- ## Problems with uClibc - code based on old GNU libc - requried som effort to get patches upstream (39 patches) - non-solvable issues with threading implementation (VLC) - ugly codebase - no stable ABI (silently broke ABI) - seldom releases --- ## musl libc > a new standard library . . . > musl is _lightweight, fast, simple, free_, and strives to be _correct_ in the > sense of standards-conformance and safety. - https://www.musl-libc.org/ - active development - clean, modern codease - stable ABI - libc6 compatible ABI (sort of) - supports UTF-8 --- ## The worries - very few others had tried (sabotage linux) - a lot software assumes GNU libc - how much do we need to patch? - how often do we need to add `-D_GNU_SOURCE` - would upstream support musl? - not as mature as glibc. unknown bugs? --- ## How did it go? Surprisingly well! ### 2014 - v3.0.0 relased - 2916 ports - 131 musl specific patches (at least) ### 2017 - v3.5.0 released (end of 2016) - 3800 ports - 179 musl specific patchs (at least) --- ## The good things with musl - clean and nice code - nice community - musl tries to be (annoyingly) correct - when patch is needed, code gets better - almost every upstream project has welcomed patches for POSIX compatibility (2 exceptions) --- ## Things to watch out for - no `__MUSL__` define - 80k stack size for threads - extensions in *printf/strftime/strptime format strings - RTLD_LAZY (lazy binding) - strerror_r (nasty!) - DNS resolver --- ### No `__MUSL__` define ````diff diff --git a/src/mesa/main/querymatrix.c b/src/mesa/main/querymatrix.c index eb36c76..ef85175 100644 --- a/src/mesa/main/querymatrix.c +++ b/src/mesa/main/querymatrix.c @@ -37,8 +37,12 @@ ... @@ -71,16 +75,8 @@ fpclassify(double x) return FP_NAN; } } -#endif /* _MSC_VER < 1800 */ - -#elif defined(__APPLE__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \ - defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ - (defined(__sun) && defined(__C99FEATURES__)) || defined(__MINGW32__) || \ - (defined(__sun) && defined(__GNUC__)) || defined(ANDROID) || defined(__HAIKU__) - -/* fpclassify is available. */ -#elif !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600 +#else enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL} fpclassify(double x) -- ```` --- ### default thread stack size: 80k --- ### default thread stack size: 80k ````diff diff --git a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp --- a/netwerk/streamconv/converters/nsHTTPCompressConv.cpp +++ b/netwerk/streamconv/converters/nsHTTPCompressConv.cpp @@ -160,31 +160,36 @@ nsHTTPCompressConv::OnStopRequest(nsIReq NS_METHOD nsHTTPCompressConv::BrotliHandler(nsIInputStream *stream, void *closure, const char *dataIn, uint32_t, uint32_t aAvail, uint32_t *countRead) { MOZ_ASSERT(stream); nsHTTPCompressConv *self = static_cast
(closure); *countRead = 0; - const uint32_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop - unsigned char outBuffer[kOutSize]; - unsigned char *outPtr; + const size_t kOutSize = 128 * 1024; // just a chunk size, we call in a loop + uint8_t *outPtr; size_t outSize; size_t avail = aAvail; BrotliResult res; if (!self->mBrotli) { *countRead = aAvail; return NS_OK; } + auto outBuffer = MakeUniqueFallible
(kOutSize); + if (outBuffer == nullptr) { + self->mBrotli->mStatus = NS_ERROR_OUT_OF_MEMORY; + return self->mBrotli->mStatus; + } + do { outSize = kOutSize; - outPtr = outBuffer; + outPtr = outBuffer.get(); // brotli api is documented in brotli/dec/decode.h and brotli/dec/decode.c LOG(("nsHttpCompresssConv %p brotlihandler decompress %d\n", self, avail)); res = ::BrotliDecompressStream( &avail, reinterpret_cast
(&dataIn), &outSize, &outPtr, &self->mBrotli->mTotalOut, &self->mBrotli->mState); outSize = kOutSize - outSize; LOG(("nsHttpCompresssConv %p brotlihandler decompress rv=%x out=%d\n", @@ -205,17 +210,17 @@ nsHTTPCompressConv::BrotliHandler(nsIInp self->mBrotli->mStatus = NS_ERROR_UNEXPECTED; return self->mBrotli->mStatus; } } if (outSize > 0) { nsresult rv = self->do_OnDataAvailable(self->mBrotli->mRequest, self->mBrotli->mContext, self->mBrotli->mSourceOffset, - reinterpret_cast
(outBuffer), + reinterpret_cast
(outBuffer.get()), outSize); LOG(("nsHttpCompressConv %p BrotliHandler ODA rv=%x", self, rv)); if (NS_FAILED(rv)) { self->mBrotli->mStatus = rv; return self->mBrotli->mStatus; } } ```` --- ### Extensions in format strings printf / snprintf / strptime / strftime Read man page! --- ### Extensions in format strings printf / snprintf / strptime / strftime Read man page! #### `man strftime(3)` ```` Glibc notes Glibc provides some extensions for conversion specifications. (These extensions are not specified in POSIX.1-2001, but a few other systems provide similar features.) Between the '%' character and the conversion specifier character, an optional flag and field width may be specified. (These precede the E or O modifiers, if present.) The following flag characters are permitted: _ (underscore) Pad a numeric result string with spaces. - (dash) Do not pad a numeric result string. 0 Pad a numeric result string with zeros even if the conversion specifier character uses space-padding by default. ^ Convert alphabetic characters in result string to uppercase. # Swap the case of the result string. (This flag works only with certain conversion specifier characters, and of these, it is only really useful with %Z.) An optional decimal width specifier may follow the (possibly absent) flag. If the natural size of the field is smaller than this width, then the result string is padded (on the left) to the specified width. ```` ### RTLD_LAZY (lazy binding) not supported. - affects Xorg driver loading - affects openjdk? --- ### `man strerror_r(3)` ```` SYNOPSIS ... int strerror_r(int errnum, char *buf, size_t buflen); /* XSI-compliant */ char *strerror_r(int errnum, char *buf, size_t buflen); /* GNU-specific */ ... RETURN VALUE The strerror(), strerror_l(), and the GNU-specific strerror_r() functions return the appropriate error description string, or an "Unknown error nnn" message if the error number is unknown. The XSI-compliant strerror_r() function returns 0 on success. On error, a (positive) error number is returned (since glibc 2.13), or -1 is returned and errno is set to indicate the error (glibc versions before 2.13). ... CONFORMING TO ... strerror_r() is specified by POSIX.1-2001 and POSIX.1-2008. ... The GNU-specific strerror_r() function is a nonstandard extension. ```` --- ### Example patch for strerror_r ````diff diff --git a/open-vm-tools/lib/err/errPosix.c b/open-vm-tools/lib/err/errPosix.c index 37b45237..63ca9dd7 100644 --- a/open-vm-tools/lib/err/errPosix.c +++ b/open-vm-tools/lib/err/errPosix.c @@ -63,11 +63,13 @@ ErrErrno2String(Err_Number errorNumber, // IN { char *p; -#if defined(linux) && !defined(N_PLAT_NLM) && !defined(__ANDROID__) +#if defined(__GLIBC__) p = strerror_r(errorNumber, buf, bufSize); #else - p = strerror(errorNumber); -#endif + if (strerror_r(errorNumber, buf, bufSize) != 0) + snprintf(buf, bufSize, "unknown error %i", errorNumber); + p = buf; +#endif /* defined __GLIBC__ */ ASSERT(p != NULL); return p; } -- ```` --- ### DNS resolver Does not work as man `resolv.conf` says ````sh $ cat /etc/resolv.conf search example.com nameserver 192.168.0.1 nameserver 8.8.8.8 $ ping foo.bar # foo.bar.example.com? ```` --- ## Conclusions - musl libc is ready for mainline - it works surprisingly well to build a distro with musl libc - fixing software to work with musl improves the quality - musl libc is awesome! --- class: center, middle ## Questions?