Issue with getmntent_r with overlay/overlay2 with /proc/mounts entries >=1024 bytes
While investigating an issue with Java and how JNI is using
getMountEntries()
and it’s getmntent JNI
dispatcher
we came across a discrepancy between how getmntent_r()
behaves in musl
and glibc on the following conditions:
- docker storage driver is overlay or overlay2
- there are enough layers so that the
overlay /
entry in proc mounts in longer than 1024 characters
Note that this is separate from the older Alpine bug#5703 that deals with the 256byte fixed limit.
Here are the reproduction steps:
-
Ensure `docker info` reports overlay/overlay2. This is the default, e.g. on Fedora, Docker for Mac and Docker for Windows.
-
Create the following files in your dir:
cat >docker-compose.yml <<EOF version: ‘2’ services: mytester: build: . image: testgetmntent:alpine EOF
cat >Dockerfile <<EOF FROM alpine:latest RUN apk update && apk add bash gcc musl-dev && rm -rf /var/cache/apk/\* RUN echo test 0 >/tmp/test0 RUN echo test 1 >/tmp/test1 RUN echo test 2 >/tmp/test2 RUN echo test 3 >/tmp/test3 RUN echo test 4 >/tmp/test4 RUN echo test 5 >/tmp/test5 RUN echo test 6 >/tmp/test6 RUN echo test 7 >/tmp/test7 RUN echo test 8 >/tmp/test8 RUN echo test 9 >/tmp/test9 RUN echo test 10 >/tmp/test10 RUN echo test 11 >/tmp/test11 EOF
- Build and run the resulting image with:
docker-compose build —pull && docker-compose run mytester /bin/bash
- In the shell, create the following C program to test
getmntent_r
:
cat >getmntent\_r\_tester.c <<EOF \#include <stdio.h> \#include <mntent.h> void print\_mount(const struct mntent \*fs); int main(int argc, char \*\*argv) { FILE \*fp; struct mntent \*fs; struct mntent ent; char buf\[1024\]; int buflen = sizeof(buf); fp = setmntent(“/proc/mounts”, “r”); /\* read only \*/ if (fp == NULL) { printf(“Error calling setmntent\\n”); return(1); } while ((fs = getmntent\_r(fp, &ent, (char\*)&buf, buflen )) != NULL) print\_mount(fs); endmntent(fp); } void print\_mount(const struct mntent \*fs) { printf(“%s %s %s %s %d %d\\n”, fs->mnt\_fsname, fs->mnt\_dir, fs->mnt\_type, fs->mnt\_opts, fs->mnt\_freq, fs->mnt\_passno); } EOF
- Compile and run it. Notice there’s no output.
bash-4.3\# gcc getmntent\_r\_tester.c bash-4.3\# ./a.out
- Notice that
overlay /
entry in/proc/mounts
exceeds 1024bytes:
bash-4.3\# grep overlay /proc/mounts | wc -c 1069
-
Exit the container, run
docker-compose down
. -
Edit the
Dockerfile
and remove the last 2 RUN commands -
Rebuild, rerun the image and recompile and rerun the C program, in steps 3-5:
bash-4.3\# gcc getmntent\_r\_tester.c bash-4.3\# grep overlay /proc/mounts | wc -c 961 bash-4.3\# ./a.out overlay / overlay rw,seclabel,relatime,lowerdir=/var/lib/docker/overlay2/l/LVWNODYSVRXAQW4P5QXNVVXDSS:/var/lib/docker/overlay2/l/RVAZXPKSLDGTV5QXZLI6HZAXXU:/var/lib/docker/overlay2/l/EJIOFNYRMEPTJ4AID2PXUZNJOC:/var/lib/docker/overlay2/l/P4BG3VO46BQDHUXLXPZ3KDXAIR:/var/lib/docker/overlay2/l/G563LG47W5E6A4YPFZCTQ5ORUG:/var/lib/docker/overlay2/l/E2PLIGC66VLBLKENQA2GUKOZXO:/var/lib/docker/overlay2/l/6C5UXCJ4COZVHKHDRDKGW7PKIZ:/var/lib/docker/overlay2/l/GY45BC44L45ZYGQB7XCUU3L4LU:/var/lib/docker/overlay2/l/FF4KRJU7RWCA2GQ6OZV4OHLCXM:/var/lib/docker/overlay2/l/5SZT4SYLCF5LZAZCAJIA6YFB3K:/var/lib/docker/overlay2/l/3SP6Y2WURVZ4L6IZD3WQ2T5ZRG:/var/lib/docker/overlay2/l/LZZGUAD7WB6NZAKG5PSE4K7S6B:/var/lib/docker/overlay2/l/5VA5PMTBPJ4VRPX7HNGUVOYARI,upperdir=/var/lib/docker/overlay2/9ff9f8c3a876cec942dbfa5324894d24d1fe4eb52700320e5e5fa3e7e34a137a/diff,workdir=/var/lib/docker/overlay2/9ff9f8c3a876cec942dbfa5324894d24d1fe4eb52700320e5e5fa3e7e34a137a/work 0 0
- Trying the same process with a different docker image base, based on glibc, (e.g. fedora:latest) works in all cases.
(from redmine: issue id 7093, created on 2017-04-05, closed on 2017-06-01)
- Changesets:
- Revision 189a2712 by Natanael Copa on 2017-05-30T15:58:56Z:
community/openjdk8: increase buffer size for getmntent_r
Java will only use 1024 byte buffer for parsing mounts. Unlike glibc
will musl return error when this is not big enough instead of truncating
it.
We solve it by allocating a much bigger buffer.
fixes #7093
We also build without precompiled headers, which does not work eith PIE.
- Revision d0a7b324 by Natanael Copa on 2018-06-13T21:18:57Z:
community/openjdk8: increase buffer size for getmntent_r
Java will only use 1024 byte buffer for parsing mounts. Unlike glibc
will musl return error when this is not big enough instead of truncating
it.
We solve it by allocating a much bigger buffer.
fixes #7093
We also build without precompiled headers, which does not work eith PIE.