Bug 910500 - (CVE-2014-5220) VUL-0: CVE-2014-5220: mdadm: mdcheck doesn't validate the input of mdadm --detail --export, possible command injection
(CVE-2014-5220)
VUL-0: CVE-2014-5220: mdadm: mdcheck doesn't validate the input of mdadm --de...
Status: RESOLVED FIXED
Classification: Novell Products
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents
unspecified
Other All
: P3 - Medium : Minor
: ---
Assigned To: Neil Brown
Security Team bot
maint:running:60549:low
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2014-12-17 14:20 UTC by ml1 noc
Modified: 2015-04-22 11:36 UTC (History)
7 users (show)

See Also:
Found By: Community User
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description ml1 noc 2014-12-17 14:20:42 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"
Comment 1 Neil Brown 2014-12-17 23:48:05 UTC
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 ??
Comment 2 ml1 noc 2014-12-17 23:55:22 UTC
(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
Comment 3 ml1 noc 2014-12-18 14:34:54 UTC
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 ...
Comment 4 tosiara tosiara 2015-01-05 06:02:09 UTC
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
Comment 5 Shad Sterling 2015-01-27 13:32:56 UTC
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)
Comment 6 ml1 noc 2015-01-29 15:41:00 UTC
> 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
Comment 7 Shad Sterling 2015-02-01 21:29:15 UTC
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?
Comment 8 Neil Brown 2015-02-01 22:17:05 UTC
>  Is there a way to change the MD_NAME?

Stop the array (if it is running), then assemble with
   --update=name --name=NewName
Comment 9 Bernhard Wiedemann 2015-02-04 00:00:08 UTC
This is an autogenerated message for OBS integration:
This bug (910500) was mentioned in
https://build.opensuse.org/request/show/283972 Factory / mdadm
Comment 10 Neil Brown 2015-02-04 00:04:43 UTC
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?
Comment 11 Johannes Segitz 2015-02-04 15:20:23 UTC
(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.
Comment 12 Marcus Meissner 2015-02-04 15:23:59 UTC
Is this USB attack vector valid? Can this really happen on just plugging in a prepared USB stick?
Comment 13 Neil Brown 2015-02-04 23:49:18 UTC
(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.
Comment 14 Neil Brown 2015-02-04 23:55:12 UTC
(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.
Comment 15 Johannes Segitz 2015-02-05 10:15:45 UTC
We will treat this as a security issue. I will assign a CVE shortly and start an update.
Comment 16 Johannes Segitz 2015-02-05 10:24:15 UTC
This is CVE-2014-5220
Comment 17 Swamp Workflow Management 2015-02-05 10:24:59 UTC
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
Comment 18 Shad Sterling 2015-02-05 13:02:58 UTC
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.
Comment 19 Johannes Segitz 2015-02-05 13:20:19 UTC
(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.
Comment 20 Johannes Segitz 2015-02-05 13:22:01 UTC
(In reply to Johannes Segitz from comment #19)
well, I just learned who the upstream maintainer is ... ;) Neil, what do you think?
Comment 21 Neil Brown 2015-02-05 20:44:05 UTC
(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.
Comment 22 Neil Brown 2015-02-06 05:17:37 UTC
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.
Comment 23 Bernhard Wiedemann 2015-02-06 06:00:07 UTC
This is an autogenerated message for OBS integration:
This bug (910500) was mentioned in
https://build.opensuse.org/request/show/284268 13.2 / mdadm
Comment 24 Johannes Segitz 2015-02-06 08:52:15 UTC
(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.
Comment 26 Bernhard Wiedemann 2015-02-06 23:00:08 UTC
This is an autogenerated message for OBS integration:
This bug (910500) was mentioned in
https://build.opensuse.org/request/show/284578 13.2 / mdadm
Comment 27 Neil Brown 2015-02-18 03:57:27 UTC
Update has been accepted, so closing bug.
Comment 28 Swamp Workflow Management 2015-02-18 10:04:57 UTC
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
Comment 29 tosiara tosiara 2015-03-09 05:59:52 UTC
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).
Comment 30 tosiara tosiara 2015-03-09 06:34:45 UTC
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
Comment 31 Swamp Workflow Management 2015-03-09 23:00:13 UTC
bugbot adjusting priority
Comment 32 Neil Brown 2015-03-23 06:47:23 UTC
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.