File_mmap of /dev/zero is currently blocked

I’ve never managed to get strace on gui apps to work - it complains about needing to be root, and then running gui apps through sudo fails with being unable to access X display. I’ve run the makemkvcon without using the gui intermediary, though, and posted the results to http://paste.ubuntu.com/25171485/

This appears to be this kernel: https://launchpad.net/ubuntu/+source/linux-hwe. I installed this kernel in an amd64 vm (apt-get install linux-generic-hwe-16.04), rebooted and don’t see the denial.

I’ve pulled-out the two mmap lines from the very end of the strace (previous post):

mmap(NULL, 393216, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = -1 EACCES (Permission denied)
mmap(NULL, 393216, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = -1 EACCES (Permission denied)

the difference seems to be that it wants MAP_PRIVATE access

Right, if I use MAP_PRIVATE, I also don’t see the denial. Lets get a full strace. Can you do:

$ strace -D -f -vv -e '!select,_newselect,clock_gettime' -- /path/to/thing/getting/denied

here’s the pastebin. I’m just trawling through it myself: http://paste.ubuntu.com/25171738/

FYI, for those wondering about the -e '!select,_newselect,clock_gettime' arguments, please see Stracing snap commands

I talked about this with AppArmor upstream and was reminded that either PROT_EXEC would need to be specified in the mmap() call on the /dev/zero fd, or the application has the personality bit set which would cause read to also map EXEC.

Looking at the strace, I don’t see anything fishy with the PROT_EXECs and I don’t see a call to personality(). However it seems this trace was perhaps not done under confinement or done on a different binary? The only open on /dev/zero in the last paste doesn’t show an mmap() on the fd so something is different…

it’s definitely the same binary called the same as previously with different strace wrapper - the mmap is line 2118 and 2121

Yes I see now that the open is at 2040 but the two mmaps are at 2118 and 2121.

That leaves personality: I don’t see personality in this trace. Are you using setarch to invoke this program? Is it a program not compiled for Linux?

I’m not using setarch. the program, is closed source and presumably compiled for linux (else?)

this is what file tells about the binary:

/snap/makemkv/x12/usr/bin/makemkvcon: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.24, stripped

The next step would be to add some debugging information to the kernel. Either you can provide me with the snap and how you are invoking it, or we can provide you a debugging kernel to install. I suggest the former. If you would prefer, you can send me the snap privately (jamie at ubuntu dot com).

I’ve emailed you a link to the file. I had to link it rather than attach because gmail (my provider) doesn’t like large attachments. The file is on my Nextcloud instance.

Thanks, I have it and have reproduced the issue.

It looks like this is kernel-specific. If I try the 16.04 4.4 kernel, I don’t see the issue, but the 4.10 hwe kernel does. I’ll continue to work with AppArmor upstream on this.

thanks for looking into it :slight_smile:

Ok, as it turns out the 4.10 kernel is behaving correctly and other kernels should be denying the ‘m’ on /dev/zero. Those kernels will likely get an update to fix this.

The problem stems from the fact that usr/bin/makemkvcon has the READ_IMPLIES_X personality bit set. This can be seen with:

$ readelf -lW usr/bin/makemkvcon|grep GNU_STACK
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RWE 0x10

(notice how ‘E’ is listed). When this bit is set, read access implies execute, and ‘m’ is a special form of execute (from ‘man apparmor.d’: ‘allow PROT_EXEC with mmap(2) calls’) and because we only have ‘/dev/zero rw’, you see the denial. Previously when we looked at the mmap()s in the strace while we only saw PROT_READ and PROT_WRITE, because the personality bit was set, PROT_EXEC was added under mediation. This personality is very problematic on the whole, because it changes the requirements of the permissions and in trying to meet those requirements, it can substantially weaken the policy (eg, normally you ‘read’ or ‘read and exec’ or ‘read and write’, but not ‘read, write and exec’).

In this very particular case, allowing ‘/dev/zero m’ would not be a problem, because ‘man zero’ tells us that writes to /dev/zero are simply discarded by the kernel. However, because the program has an executable stack, there is nothing saying that after we fix /dev/zero something else won’t pop out needing x or m permissions when it shouldn’t. In the future, AppArmor will have language something along the lines of ‘allow read_implies_x’ which, when the personality bit is set, it will add ‘x’ implicitly to any read rules. This is not a solution because it merely makes it easier to allow weakened, workaround policy (it is conceivable it could be in a separate snappy interface though).

I suggest approaching upstream and pointing them at https://wiki.ubuntu.com/SecurityTeam/Roadmap/ExecutableStacks so they can improve their code. Currently their code is vulnerable to stack memory attacks and fixing this will meaningfully improve their code everywhere. It just so happens it would also make the ‘m’ denial go away.

so, for the near-term “get it working” I’ve added a call to execstack -c $binary and we’re getting closer now. it doesn’t die with the m request on /dev/zero. Now I’m onto getting the qt frontend to load, which is complaining about:

Qt: Session management error: None of the authentication protocols specified are supported

replying to myself, the Session management error from qt is a non-error unrelated to the continued failure. The GUI app which is open source calls into the closed-source makemkvcon CLI program which in turn tries to create an entry at /dev/shm/makemkvshm???? where the question marks are random. Because it’s a closed source binary I’m fairly sure it isn’t possible to move the shared memory device easily, so I’m stuck on getting the UI working, but at least the CLI works correctly excepting the shared memory interface which is only triggered when the GUI interacts with it.

I suggest taking a look at the snapcraft preload part: https://github.com/sergiusens/snapcraft-preload