Bugzilla – Bug 910500
VUL-0: CVE-2014-5220: mdadm: mdcheck doesn't validate the input of mdadm --detail --export, possible command injection
Last modified: 2015-04-22 11:36:25 UTC
on uname -a Linux lab010.DOMAIN.net 3.18.0-2.g99a9f76-xen #1 SMP Sun Dec 14 10:25:49 UTC 2014 (99a9f76) x86_64 x86_64 x86_64 GNU/Linux lsb_release -rd Description: openSUSE 13.2 (Harlequin) (x86_64) Release: 13.2 mdadm --version mdadm - v3.3.1 - 5th June 2014 i am getting these email notices from system cron every couple of days ... From: "(Cron Daemon)" <cron-admin=lab010.DOMAIN.net@DOMAIN.net> To: cron-admin=lab010.DOMAIN.net@DOMAIN.net Subject: Cron <root@server> source /etc/sysconfig/mdadm; [ -n "$MDADM_CHECK_DURATION" -a -x /usr/share/mdadm/mdcheck ] && /usr/share/mdadm/mdcheck --continue --duration "$MDADM_CHECK_DURATION" Content-Type: text/plain; charset=UTF-8 Auto-Submitted: auto-generated Precedence: bulk X-Cron-Env: <XDG_SESSION_ID=569> X-Cron-Env: <XDG_RUNTIME_DIR=/run/user/0> X-Cron-Env: <LANG=POSIX> X-Cron-Env: <LC_CTYPE=en_US.UTF-8> X-Cron-Env: <PATH=/sbin:/usr/sbin:/bin:/usr/bin> X-Cron-Env: <SHELL=/bin/sh> X-Cron-Env: <HOME=/root> X-Cron-Env: <LOGNAME=root> X-Cron-Env: <USER=root> ... /var/lib/mdcheck/.md-check-8965: line 5: none: No such file or directory /var/lib/mdcheck/.md-check-8965: line 5: none: No such file or directory /usr/share/mdadm/mdcheck: line 109: echo: write error: Invalid argument they originate from grep -rlni mdcheck /etc/cron* /etc/cron.d/mdadm cat /etc/cron.d/mdadm # # cron.d/mdadm - regular redundancy checks # # Start checking each month early in the morning. # Continue each day until all done PATH=/sbin:/usr/sbin:/bin:/usr/bin 0 1 * * 0 root source /etc/sysconfig/mdadm; [ -n "$MDADM_CHECK_DURATION" -a -x /usr/share/mdadm/mdcheck -a $(date +\%d) -le 7 ] && /usr/share/mdadm/mdcheck --duration "$MDADM_CHECK_DURATION" 0 1 * * 1-6 root source /etc/sysconfig/mdadm; [ -n "$MDADM_CHECK_DURATION" -a -x /usr/share/mdadm/mdcheck ] && /usr/share/mdadm/mdcheck --continue --duration "$MDADM_CHECK_DURATION" checking cat /usr/share/mdadm/mdcheck ... # To support '--continue', arrays are identified by UUID and the 'sync_completed' # value is stored in /var/lib/mdcheck/$UUID ... sysname() { set `ls -lLd $1` maj=${5%,} min=$6 readlink -f /sys/dev/block/$maj:$min } .. for dev in /dev/md?* do [ -e "$dev" ] || continue sys=`sysname $dev` ... echo $start > $fl 109 echo $start > $sys/md/sync_min echo check > $sys/md/sync_action ... on my system ls -al /var/lib/mdcheck/ total 16K drwxr-xr-x 2 root root 4.0K Dec 17 01:56 ./ drwxr-xr-x 78 root root 4.0K Dec 15 13:59 ../ -rw-r--r-- 1 root root 319 Dec 13 01:00 .md-check-13566 -rw-r--r-- 1 root root 319 Dec 15 01:00 .md-check-17179 and cat /proc/mdstat | grep md md0 : active raid1 sdb1[1] sda1[0] md1 : active raid1 sda2[0] sdb2[2] md2 : active raid10 sdd1[1] sde1[4] sdc1[0] sdf1[3] ls -al /sys/dev/block/ | egrep "md0|md1|md2" lrwxrwxrwx 1 root root 0 Dec 17 05:56 9:0 -> ../../devices/virtual/block/md0/ lrwxrwxrwx 1 root root 0 Dec 17 05:56 9:1 -> ../../devices/virtual/block/md1/ lrwxrwxrwx 1 root root 0 Dec 17 05:56 9:2 -> ../../devices/virtual/block/md2/ ls -al /sys/dev/block/9:{0,1,2}/md/sync_min -rw-r--r-- 1 root root 4.0K Dec 17 06:00 /sys/dev/block/9:0/md/sync_min -rw-r--r-- 1 root root 4.0K Dec 17 06:00 /sys/dev/block/9:1/md/sync_min -rw-r--r-- 1 root root 4.0K Dec 17 01:00 /sys/dev/block/9:2/md/sync_min cat /etc/sysconfig/mdadm MDADM_DELAY=60 MDADM_MAIL="gk@DOMAIN.com" MDADM_PROGRAM="" MDADM_RAIDDEVICES="/dev/md0 /dev/md1 /dev/md2" MDADM_SCAN=yes MDADM_CONFIG="/etc/mdadm.conf" MDADM_SEND_MAIL_ON_START=yes BOOT_MD_USE_MDADM_CONFIG=yes MDADM_DEVICE_TIMEOUT="60" MDADM_CHECK_DURATION="12 hours"
Hi What version of the mdadm package do you have installed? rpm -q mdadm what is the content of the .md-check files in /var/lib/mdcheck ??
(In reply to Neil Brown from comment #1) > Hi > > What version of the mdadm package do you have installed? > > rpm -q mdadm rpm -q mdadm mdadm-3.3.1-5.10.1.x86_64 > what is the content of the .md-check files in /var/lib/mdcheck ?? cat /var/lib/mdcheck/.md-check-13566 MD_LEVEL=raid10 MD_DEVICES=4 MD_METADATA=1.2 MD_UUID=b1c263cd:1c42565b:f3f1926d:db1811d3 MD_NAME=<none>:nas03 MD_DEVICE_sdc1_ROLE=0 MD_DEVICE_sdc1_DEV=/dev/sdc1 MD_DEVICE_sdd1_ROLE=1 MD_DEVICE_sdd1_DEV=/dev/sdd1 MD_DEVICE_sde1_ROLE=2 MD_DEVICE_sde1_DEV=/dev/sde1 MD_DEVICE_sdf1_ROLE=3 MD_DEVICE_sdf1_DEV=/dev/sdf1 cat /var/lib/mdcheck/.md-check-17179 MD_LEVEL=raid10 MD_DEVICES=4 MD_METADATA=1.2 MD_UUID=b1c263cd:1c42565b:f3f1926d:db1811d3 MD_NAME=<none>:nas03 MD_DEVICE_sdc1_ROLE=0 MD_DEVICE_sdc1_DEV=/dev/sdc1 MD_DEVICE_sdd1_ROLE=1 MD_DEVICE_sdd1_DEV=/dev/sdd1 MD_DEVICE_sde1_ROLE=2 MD_DEVICE_sde1_DEV=/dev/sde1 MD_DEVICE_sdf1_ROLE=3 MD_DEVICE_sdf1_DEV=/dev/sdf1
this morning, it's: /var/lib/mdcheck/.md-check-22591: line 5: none: No such file or directory /var/lib/mdcheck/.md-check-22591: line 5: none: No such file or directory where, still ls -al /var/lib/mdcheck/ total 16K drwxr-xr-x 2 root root 4.0K Dec 18 01:00 ./ drwxr-xr-x 78 root root 4.0K Dec 15 13:59 ../ -rw-r--r-- 1 root root 319 Dec 13 01:00 .md-check-13566 -rw-r--r-- 1 root root 319 Dec 15 01:00 .md-check-17179 those 'old' files, I suspect, are not involved ...
I also got 3 emails since I have upgraded to 13.2 Cron <root@server> source /etc/sysconfig/mdadm; [ -n "$MDADM_CHECK_DURATION" -a -x /usr/share/mdadm/mdcheck ] && /usr/share/mdadm/mdcheck --continue --duration "$MDADM_CHECK_DURATION" /usr/share/mdadm/mdcheck: line 109: echo: write error: Invalid argument
I think I'm having the same problem, with a different error message: /var/lib/mdcheck/.md-check-29228: line 5: syntax error near unexpected token `(' /var/lib/mdcheck/.md-check-29228: line 5: `MD_NAME=adumbrate:Backups (mirror set)' In my case, the problem is that mdadm --detail --export does not shell-escape its output. The error is triggered by lines 90 and 91 of /usr/share/mdadm/mdcheck : mdadm --detail --export "$dev" > $tmp || continue source $tmp Where "$tmp" in this case was set to "/var/lib/mdcheck/.md-check-29228" on line 68. The value of MD_NAME includes characters that must be escaped to appear in a string. In my case, it syntax errors on the parenthesis; in grant's case it tries to redirect stdin from a nonexistent file (it may also have created a file named ":nas03"). It looks like this bug makes it possible to execute arbitrary shell commands as root by including them in an MD_NAME, for example MD_NAME=; rm -rf / tosiara's error looks like a different problem. I have mdadm-3.3.1-5.3.1.x86_64 on openSUSE 13.2 (Harlequin) (x86_64)
> It looks like this bug makes it possible to execute arbitrary shell commands as > root by including them in an MD_NAME, for example > > MD_NAME=; rm -rf / if true, cc'ing security-team
As a temporary workaround to get the cronjob to work until mdadm is patched, it should be enough to change the MD_NAME to something that doesn't need escaping. Unfortunately, searching for ways to rename an md device only turns up ways to change the device node /dev/mdXXX. Is there a way to change the MD_NAME?
> Is there a way to change the MD_NAME? Stop the array (if it is running), then assemble with --update=name --name=NewName
This is an autogenerated message for OBS integration: This bug (910500) was mentioned in https://build.opensuse.org/request/show/283972 Factory / mdadm
Thanks for the report. I have submitted an update for 13.2 and Factory which makes this change: +- mdadm --detail --export "$dev" > $tmp || continue ++ mdadm --detail --export "$dev" | grep '^MD_UUID=' > $tmp || continue to the mdcheck script. You could easily do that by hand rather than wait for the update. Comment #6 is correct that this could be a security issue. If a USB device with carefully crafted metadata were plugged into an openSUSE host, the array would be automatically assembled. If it was still there at 1am when the mdcheck script is run by cron, then shell code from the array name would be executed. Security-team: is there anything else I should do w.r.t. the security aspect?
(In reply to Neil F Brown from comment #10) We probably will assign a CVE for that issue. If you just need MD_UUID, why do you use this > $tmp, source approach? Your changed version should be safe but I don't see the need for that.
Is this USB attack vector valid? Can this really happen on just plugging in a prepared USB stick?
(In reply to Johannes Segitz from comment #11) > If you just need MD_UUID, why do you use this > $tmp, source approach? Well, one has to use some approach... The "--export" flag is intended to make it easy to extra detail for use by some other program, originally udev. It works, so I use it.
(In reply to Marcus Meissner from comment #12) > Is this USB attack vector valid? Can this really happen on just plugging in > a prepared USB stick? Yes. If you plug in a USB which has been configured as the working device in a degraded RAID1, then udev will run "mdadm -I devicename" and the array will be activated. This is not unlike the way a FAT filesystem will automatically be mounted. Once the array has been assembled, /usr/share/mdadm/mdcheck will (at 1am) find it as a "/dev/md*" and will try to extra the UUID to decide what is to be done.
We will treat this as a security issue. I will assign a CVE shortly and start an update.
This is CVE-2014-5220
An update workflow for this issue was started. This issue was rated as low. Please submit fixed packages until 2015-03-05. When done, reassign the bug to security-team@suse.de. https://swamp.suse.de/webswamp/wf/60549
Why is the problem that mdcheck doesn't validate input, rather than that mdadm doesn't escape its output? The output sure looks like it's intended to be parsed by the shell; the man page says "output will be formatted as key=value pairs for easy import into the environment." Does that refer to something other than the shell environment? If the output from mdadm isn't changed, I would expect the same vulnerability to be recreated in future scripts, even if only site-specific scripts.
(In reply to Shad Sterling from comment #18) It's not either or. One is a problem in a software we ship that could potentially be exploited. Because of that we assigned a CVE for that. Having mdadm properly quoting the output is certainly a good idea but could be considered a hardening (which wouldn't receive a CVE). I will file a bug to suggest that.
(In reply to Johannes Segitz from comment #19) well, I just learned who the upstream maintainer is ... ;) Neil, what do you think?
(In reply to Johannes Segitz from comment #20) > well, I just learned who the upstream maintainer is ... ;) Neil, what do you > think? It is already on my list of things I should think about fixing in mdadm. In answer to: > Does that refer to something other than the shell environment? It originally referred to the udev environment. I would like it to work for shell too.
I'm not sure how best to reply to a 'swamp' email... so I'll reply here. This bug is only relevant to openSUSE-13.2, and openSUSE:Factory. No other release containst mdcheck. In particularly, no SLES release contains this. The 'swamp' issue identifies two other bugs that should be address. Neither of these are relevant to either of the affected releases - they already contain the fix. These two are only relevant to SLES11-SP3, and possibly -SP2. So there is only one bug that needs to be fixed for openSUSE. The maint request for 13.2 is 284268. The request for Factory is 283972.
This is an autogenerated message for OBS integration: This bug (910500) was mentioned in https://build.opensuse.org/request/show/284268 13.2 / mdadm
(In reply to Neil F Brown from comment #22) Sorry, didn't know that. You can ignore the SWAMP, I'll handle the openSUSE submit today.
This is an autogenerated message for OBS integration: This bug (910500) was mentioned in https://build.opensuse.org/request/show/284578 13.2 / mdadm
Update has been accepted, so closing bug.
openSUSE-SU-2015:0308-1: An update that fixes one vulnerability is now available. Category: security (low) Bug References: 910500 CVE References: CVE-2014-5220 Sources used: openSUSE 13.2 (src): mdadm-3.3.1-5.14.1
Installed all latest updates, but still receive emails from cron: Cron <root@server> source /etc/sysconfig/mdadm; [ -n "$MDADM_CHECK_DURATION" -a -x /usr/share/mdadm/mdcheck ] && /usr/share/mdadm/mdcheck --continue --duration "$MDADM_CHECK_DURATION" Mon, Mar 9, 2015 at 1:00 AM /usr/share/mdadm/mdcheck: line 109: echo: write error: Invalid argument mdadm version: # rpm -qa | grep mdadm mdadm-3.3.1-5.14.1.x86_64 kernel: # uname -a Linux server 3.18.1-1.g5f2f35e-desktop #1 SMP PREEMPT Wed Dec 17 18:20:30 UTC 2014 (5f2f35e) x86_64 x86_64 x86_64 GNU/Linux # cat /etc/issue Welcome to openSUSE 13.2 "Harlequin" - Kernel \r (\l).
The faulty line of "/usr/share/mdadm/mdcheck" is this one: echo $start > $sys/md/sync_min I think the issue here is that "$start" contains invalid number, probably not aligned to chunk size
bugbot adjusting priority
Hmm... on reflection I cannot think of a good reason for sync_min to need to be chunk-aligned. I have submitted a patch to openSUSE13.2 to remove that restriction and have queued it to go upstream. So it should be fixed in next maintenance kernel, or the kernel-of-the-day in a couple of days. Thanks for the report.