Bug 528581

Summary: rpc.rquotad calls quotactl with garbage arguments
Product: [Fedora] Fedora Reporter: Deji Akingunola <dakingun>
Component: quotaAssignee: Petr Pisar <ppisar>
Status: CLOSED ERRATA QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: medium    
Version: 12CC: dwalsh, eparis, kdudka, mgrepl, NeoNerd, ovasik
Target Milestone: ---   
Target Release: ---   
Hardware: x86_64   
OS: Linux   
URL: https://sourceforge.net/tracker/?func=detail&aid=2996418&group_id=18136&atid=118136
Whiteboard: setroubleshoot_trace_hash:750852c8561ae99d72b9d077daccdcdef76164bc79e2c2c1d6b551ca0280e2cc
Fixed In Version: quota-3.17-9.fc12 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
: 589478 (view as bug list) Environment:
Last Closed: 2010-05-27 18:33:09 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 589478    
Attachments:
Description Flags
Prevent NULL region corruption
none
Fix prevenemting read and write on zero page none

Description Deji Akingunola 2009-10-12 23:54:54 UTC
Summary:

Your system may be seriously compromised! /usr/sbin/rpc.rquotad attempted to
mmap low kernel memory.

Detailed Description:

[SELinux is in permissive mode. This access was not denied.]

SELinux has denied the rpc.rquotad the ability to mmap low area of the kernel
address space. The ability to mmap a low area of the address space, as
configured by /proc/sys/kernel/mmap_min_addr. Preventing such mappings helps
protect against exploiting null deref bugs in the kernel. All applications that
need this access should have already had policy written for them. If a
compromised application tries modify the kernel this AVC would be generated.
This is a serious issue. Your system may very well be compromised.

Allowing Access:

Contact your security administrator and report this issue.

Additional Information:

Source Context                system_u:system_r:rpcd_t:s0
Target Context                system_u:system_r:rpcd_t:s0
Target Objects                None [ memprotect ]
Source                        rpc.rquotad
Source Path                   /usr/sbin/rpc.rquotad
Port                          <Unknown>
Host                          (removed)
Source RPM Packages           quota-3.17-7.fc12
Target RPM Packages           
Policy RPM                    selinux-policy-3.6.32-24.fc12
Selinux Enabled               True
Policy Type                   targeted
MLS Enabled                   True
Enforcing Mode                Permissive
Plugin Name                   mmap_zero
Host Name                     (removed)
Platform                      Linux (removed) 2.6.31.1-56.fc12.x86_64 #1 SMP Tue Sep
                              29 16:16:22 EDT 2009 x86_64 x86_64
Alert Count                   2
First Seen                    Tue 06 Oct 2009 02:49:39 PM EDT
Last Seen                     Mon 12 Oct 2009 07:43:32 PM EDT
Local ID                      63898359-96cb-46fc-a706-a30e6ba3e31a
Line Numbers                  

Raw Audit Messages            

node=(removed) type=AVC msg=audit(1255391012.132:9): avc:  denied  { mmap_zero } for  pid=1588 comm="rpc.rquotad" scontext=system_u:system_r:rpcd_t:s0 tcontext=system_u:system_r:rpcd_t:s0 tclass=memprotect

node=(removed) type=SYSCALL msg=audit(1255391012.132:9): arch=c000003e syscall=179 success=no exit=-14 a0=580500 a1=0 a2=0 a3=0 items=0 ppid=1587 pid=1588 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="rpc.rquotad" exe="/usr/sbin/rpc.rquotad" subj=system_u:system_r:rpcd_t:s0 key=(null)



Hash String generated from  selinux-policy-3.6.32-24.fc12,mmap_zero,rpc.rquotad,rpcd_t,rpcd_t,memprotect,mmap_zero
audit2allow suggests:

#============= rpcd_t ==============
allow rpcd_t self:memprotect mmap_zero;

Comment 1 Eric Paris 2009-10-13 16:36:35 UTC
reassigning to quota package, that syscall call looks like garbage....  apparently rpc.rquotad called

quotactl(0x580500, 0, 0, 0)

which doesn't seem to be a valid command....

Right shift that by SUBCMDSHIFT you get 0x5805 for the command, which certainly doesn't look like a valid quota command to me.  The selinux complaint is because the kernel (based on this erroneous command) attempted to either read or write to the address at special or addr, both of which are NULL.

the real bug here is that the syscall is being made with garbage.  garbage in garbage out...

Comment 2 Ondrej Vasik 2009-10-13 17:16:01 UTC
Could you please provide package version of quota you are using? Additionally - are some quotas active on your system? If so, could you please briefly describe them? I'd like to have some simple reproducer. TIA.

Comment 3 Deji Akingunola 2009-10-13 18:00:59 UTC
The version is as specified in the original selinux report, quota-3.17-7.fc12.x86_64. 
I don't even have quotas enabled on the system (neither was I using nfs), its just a default rawhide Development installation plus some other development packages.

Comment 4 Eric Paris 2009-11-02 14:25:43 UTC
*** Bug 532342 has been marked as a duplicate of this bug. ***

Comment 5 Bug Zapper 2009-11-16 13:34:28 UTC
This bug appears to have been reported against 'rawhide' during the Fedora 12 development cycle.
Changing version to '12'.

More information and reason for this action is here:
http://fedoraproject.org/wiki/BugZappers/HouseKeeping

Comment 6 Fedora Admin XMLRPC Client 2010-04-29 12:18:12 UTC
This package has changed ownership in the Fedora Package Database.  Reassigning to the new owner of this component.

Comment 7 Petr Pisar 2010-05-03 15:24:38 UTC
First argument of quotactl(2) is constructed using QCMD(cmd, type) macro that is defined as such:

#define SUBCMDMASK  0x00ff
#define SUBCMDSHIFT 8
#define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))

Thus second byte (0x05) from failed quotactl() argument 0x580500 must originate from `cmd' and cannot be influenced by `type'. There is not much occurrences of 0x05 in sources, so I try to search in this area. Of course uninitiated values must be observed.

Other bytes from the argument can come from `type' value.

Comment 8 Petr Pisar 2010-05-03 15:39:56 UTC
I suspect this code:

#define XQM_CMD(cmd)    ( ('X'<<8)+(cmd) )
#define Q_XGETQSTAT  XQM_CMD(0x5)   /* returns fs_quota_stat_t struct */

qcmd = QCMD(Q_XFS_GETQSTAT, 0);
[...]
if (quotactl(qcmd, h->qh_quotadev, 0, (void *)&info) < 0)
        return -1;

And really, 'X' has ASCII value 0x85, thus qcmd == 0x850500 what is our winning number.

Why magic constant 'X'? Beacuse of _X_FS. The code is from quotaio_xfs.{c,h}.

Comment 9 Petr Pisar 2010-05-03 15:41:04 UTC
(In reply to comment #8)
s/85/58/g

Comment 10 Petr Pisar 2010-05-03 16:28:59 UTC
The only problem is the `&info' pointer cannot be NULL because it's local on-stack structure.

Comment 11 Petr Pisar 2010-05-03 16:35:09 UTC
Problem located:

quotasys.c:711:

void init_kernel_interface(void)
{
    struct stat st; 
    struct sigaction sig, oldsig;

    /* This signal handling is needed because old kernels send us SIGSEGV as they try to resolve the device */
    sig.sa_handler = SIG_IGN;
    sig.sa_sigaction = NULL;
    if (sigemptyset(&sig.sa_mask) < 0)
        die(2, _("Cannot create set for sigaction(): %s\n"), strerror(errno));
    sig.sa_flags = 0;
    if (sigaction(SIGSEGV, &sig, &oldsig) < 0)
        die(2, _("Cannot set signal handler: %s\n"), strerror(errno));

    kernel_formats = 0;
    if (!stat("/proc/fs/xfs/stat", &st))
        kernel_formats |= (1 << QF_XFS);
    else
→       if (!quotactl(QCMD(Q_XGETQSTAT, 0), NULL, 0, NULL) || (errno != EINVAL && errno != ENOSYS))
            kernel_formats |= (1 << QF_XFS);

Comment 12 Petr Pisar 2010-05-04 07:43:11 UTC
Regarding comment #1: The quotactl(0x580500, 0, 0, 0) is a valid kernel command (linux-2.6.32/fs/quota/quota.c:319).

The only real problem is NULL argv[3]. quota-tools use this dummy value to detect XFS support on running kernel. However due to ambivalent zeroth page semantics on x86 kernel sometimes returns EFAULT (if the page is unmapped), sometimes 0 if the page is mapped. Therefore mmap_minaddr check has been introduced into later kernels and into SELinux policies.

I propose to use auxiliary struct fs_quota_stat as last quotactl(2) argument to make sure (1) kernel does not overwrite occasionally mapped memory region (as happened in duplicate bug #532342) and (2) too keep in-line with modern approach zeroth page is reserved as promoted by SELinux.

I will discuss this issue with upstream.

Comment 13 Petr Pisar 2010-05-04 11:36:15 UTC
The EFAULT itself is produced earlier in quotactl(2). Kernel tries to copy second argument (name of mounted block device) into kernel space by getname() that produces EFAULT if user space source address (the second quotctl(2) argument) is NULL (if zeroth page unmapped).

We can supply "" instead of NULL. That causes ENOENT and does not trigger page fault.

The only remaining problem is I can not reproduce SELinux deny on unfixed code.

Comment 14 Petr Pisar 2010-05-04 13:07:45 UTC
I'd like to hear from reports whether they can still reproduce the SELinux deny. I'm not able to do so on my Fedora12+testing_updates (kernel-2.6.32.12-114.fc12.x86_64, selinux-policy-3.6.32-113.fc12.noarch):

# strace -equotactl /usr/sbin/rpc.rquotad -F
quotactl(Q_XGETQSTAT|USRQUOTA, NULL, 0, NULL) = -1 EFAULT (Bad address)
^C

This adds no new line into /var/log/audit/audit.log on my system. (You can run the command as non-superuser, because quotactl check is performed before RPC bind.)

I'd like ask Dan Walsh and Eric Paris what they thing about it. Why the same syscall on the same kernel returns different values (compare duplicates of this bug report). Why SELinux does not catch access to NULL. And whether SELinux catches only write attempt or read one too (quotactl(2) exhibits both of them on NULL).

Comment 15 Eric Paris 2010-05-04 14:44:26 UTC
If the lowest mapping in your address space was set with MAP_GROWSDOWN you will get the SELinux denial instead of the EFAULT.  How to get into this spot with quotactl I'm not sure off the top of my head, usually it requires a long running program that has used lots of its address space and ends up putting a stack way down there.

So I could pretty easily write a test program which would cause it by calling that syscall manually with those options.....

Comment 16 Petr Pisar 2010-05-05 12:33:27 UTC
Created attachment 411576 [details]
Prevent NULL region corruption

This is backported patch from upstream CVS tree too prevent write to NULL.

Remaining issues (read from NULL by kernel, zeroth page presence) are in discussion with upstream maintainer.

Comment 17 Petr Pisar 2010-05-10 14:37:06 UTC
Created attachment 412858 [details]
Fix prevenemting read and write on zero page

This patch adds to the previous one NULL pointer read prevention.

The "/dev/root" device could seem silly, but the code itself does not have any meaning on modern kernels. Thus it should not have any impact, but silent SELinux. The "/dev/root" has been selected by upstream (instead of proposed "").

Comment 18 Fedora Update System 2010-05-10 15:43:59 UTC
quota-3.17-10.fc13 has been submitted as an update for Fedora 13.
http://admin.fedoraproject.org/updates/quota-3.17-10.fc13

Comment 19 Fedora Update System 2010-05-10 15:57:18 UTC
quota-3.17-9.fc12 has been submitted as an update for Fedora 12.
http://admin.fedoraproject.org/updates/quota-3.17-9.fc12

Comment 20 Fedora Update System 2010-05-10 16:23:12 UTC
quota-3.17-7.fc11 has been submitted as an update for Fedora 11.
http://admin.fedoraproject.org/updates/quota-3.17-7.fc11

Comment 21 Petr Pisar 2010-05-10 16:28:11 UTC
I have pushed the patch into all Fedoras. As nobody knows how rpc.rquotad could get mapped zero page and the NULL references has been fixed by the patch, I'll close this bug report when new releases hit stable repositories.

Comment 22 Fedora Update System 2010-05-11 19:40:45 UTC
quota-3.17-9.fc12 has been pushed to the Fedora 12 testing repository.  If problems still persist, please make note of it in this bug report.
 If you want to test the update, you can install it with 
 su -c 'yum --enablerepo=updates-testing update quota'.  You can provide feedback for this update here: http://admin.fedoraproject.org/updates/quota-3.17-9.fc12

Comment 23 Fedora Update System 2010-05-26 21:43:45 UTC
quota-3.17-10.fc13 has been pushed to the Fedora 13 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 24 Fedora Update System 2010-05-27 18:33:03 UTC
quota-3.17-9.fc12 has been pushed to the Fedora 12 stable repository.  If problems still persist, please make note of it in this bug report.

Comment 25 Fedora Update System 2010-05-27 18:34:15 UTC
quota-3.17-7.fc11 has been pushed to the Fedora 11 stable repository.  If problems still persist, please make note of it in this bug report.