Bug#891477: udev: MemoryDenyWriteExecute breaks gzip on i386
Pascal Hambourg
pascal at plouf.fr.eu.org
Sun Feb 25 22:22:06 GMT 2018
Package: udev
Version: 232-25+deb9u1
This a follow-up to bug #855798 "udev: MemoryDenyWriteExecute=yes should
not be applied to udev plugins" which was closed because the affected
program was not part of Debian. Now it seems that gzip is also affected
by MemoryDenyWriteExecute=yes when run by udev on i386.
Context:
VT console events trigger a rule in
/lib/udev/rules.d/90-console-setup.rules which runs
/etc/console-setup/cached_setup_font.sh. This script runs setfont to set
the configured console font. setfont calls gzip to uncompress the
.psf.gz (cached_Lat15-Fixed16.psf.gz in my case) font file but gzip
fails. So the console font is not set at boot time.
The following command triggers the error on i386:
systemd-run -t -p MemoryDenyWriteExecute=yes gzip -h
Error message:
error while loading shared libraries: cannot restore segment prot after
reloc: Operation not permitted
strace:
======================================
execve("/bin/gzip", ["gzip", "-h"], [/* 4 vars */]) = 0
brk(NULL) = 0x9ac000
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or
directory)
mmap2(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1,
0) = 0xb7703000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or
directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=14043, ...}) = 0
mmap2(NULL, 14043, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76ff000
close(3) = 0
access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or
directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3,
"\177ELF\1\1\1\3\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\360\203\1\0004\0\0\0\334L\33\0\0\0\0\0004\0
\0\n\0(\0E\0D\0\6\0\0\0004\0\0\0004\0\0\0004\0\0\0@\1\0\0@\1\0\0\5\0\0\0"...,
512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1791908, ...}) = 0
mmap2(NULL, 1800732, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3,
0) = 0xb7547000
mprotect(0xb76f8000, 4096, PROT_NONE) = 0
mmap2(0xb76f9000, 12288, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b1000) = 0xb76f9000
mmap2(0xb76fc000, 10780, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76fc000
close(3) = 0
set_thread_area({entry_number:-1, base_addr:0xb7705840, limit:1048575,
seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1,
seg_not_present:0, useable:1}) = 0 (entry_number:6)
mprotect(0xb76f9000, 8192, PROT_READ) = 0
mprotect(0x405000, 98304, PROT_READ|PROT_WRITE) = 0
mprotect(0x405000, 98304, PROT_READ|PROT_EXEC) = -1 EPERM (Operation not
permitted)
writev(2, [{iov_base="gzip", iov_len=4}, {iov_base=": ", iov_len=2},
{iov_base="error while loading shared libraries", iov_len=36},
{iov_base=": ", iov_len=2}, {iov_base="", iov_len=0}, {iov_base="",
iov_len=0}, {iov_base="cannot restore segment prot after reloc",
iov_len=39}, {iov_base=": ", iov_len=2}, {iov_base="Operation not
permitted", iov_len=23}, {iov_base="\n", iov_len=1}], 10) = 109
exit_group(127) = ?
+++ exited with 127 +++
======================================
One can see that mprotect is called with PROT_EXEC, which is prohibited
by MemoryDenyWriteExecute and returns an error. The error message text
is from /lib/ld-linux.so.2.
setfont/gzip works on i386 when run outside udev or when run from udev
without MemoryDenyWriteExecute=yes in
/lib/systemd/system/systemd-udevd.service.
It works on amd64 in any case.
Actually I am not sure whether this bug should be filed against udev or
gzip. There might be other affected programs still unnoticed in Debian.
More information about the Pkg-systemd-maintainers
mailing list