Bug 65318 (CVE-2005-0532)

Summary: VUL-0: CVE-2005-0532: kernel: sign handling issues in 2.6
Product: [Novell Products] SUSE Security Incidents Reporter: Thomas Biege <thomas>
Component: IncidentsAssignee: Marcus Meissner <meissner>
Status: RESOLVED FIXED QA Contact: Security Team bot <security-team>
Severity: Major    
Priority: P3 - Medium CC: ihno, mfrueh, patch-request, security-team
Version: unspecified   
Target Milestone: ---   
Hardware: All   
OS: Linux   
Whiteboard: CVE-2005-0532: CVSS v2 Base Score: 2.1 (AV:L/AC:L/Au:N/C:N/I:N/A:P)
Found By: Other Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---
Attachments: reiserfs-signed.patch
proc-read-signedness.patch
copyfromreadbuf-signedness.patch
proc-read-signedness.patch
reiserfs-signed.patch
fs-readwrite-signedness.patch
always-accessok-checks.patch
verify-area-rename.patch
f-maxcount.patch
2.4-fsmaxcount-rwverifylock.patch
CAN-2005-0136_ia64-kernel.diff

Description Thomas Biege 2005-01-31 17:35:32 UTC
Hello, 
we got this via vendor-sec. 
 
From: Marcelo Tosatti <marcelo.tosatti@cyclades.com> 
To: vendor-sec@lst.de 
Cc: torvalds@osdl.org, Alan Cox <alan@lxorguk.ukuu.org.uk>, 
        Chris Wright <chrisw@osdl.org>, 
        viro@parcelfarce.linux.theplanet.co.uk 
User-Agent: Mutt/1.5.5.1i 
Subject: [vendor-sec] Sign handling issues on v2.6 
Errors-To: vendor-sec-admin@lst.de 
Date: Sun, 30 Jan 2005 12:30:42 -0200 
 
Hi folks,rc.theaimsgroup.com/?l=linux-netdev&m=110608318200957&w=2 
 
Georgi Guninski has discovered three important sign comparison problems 
in v2.6 
kernels. 
- Ð ÐœÐµÐŒÐ°Ð»ÐŸÐ²Ð°Ð¶ÐœÐ°Ñ ÐŸÑПбеММПÑÑÑ - 
ПÑлОÑМÑй ЎОзайМ. 
The collection of vulnerabilities has led Linus to add appropriate range 
checking 
at higher VFS levels (ie sys_read{v}/sys_write{v}): 
 
        ChangeSet@1.1966.1.68, 2005-01-25 20:29:47-08:00, 
torvalds@ppc970.osdl.org 
          Add 'f_maxcount' to allow filesystems to set a per-file maximum IO 
size. 
 
        ChangeSet@1.1966.1.67, 2005-01-25 15:00:33-08:00, 
torvalds@ppc970.osdl.org 
          Rename "locks_verify_area()" to "rw_verify_area()" and clean up the 
          arguments. 
 
With such range checking in place those bugs will be protected (can't be 
be triggered) by the higher levels - they should be fixed nevertheless. 
 
The following fixes are going into Linus's tree Wednesday, so this date 
(February 2) can 
be though of as the release date. 
 
There are for sure more sign handling bugs lying in drivers/fs'es. 
Kudos again to Georgi for his bright auditing! 
 
1) drivers/char/n_tty.c::copy_from_read_buf() 
 
"nr" is user passed parameter, so if its value is higher than MAX_INT, the 
signed "min" will 
happily return "nr", causing unexpected results. 
 
Note that "n" is used afterwards as lenght parameter of copy_to_user: 
 
retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); 
 
This fixes it as suggested by Linus: 
 
--- drivers/char/n_tty.c.orig   2005-01-20 13:33:30.000000000 -0200 
+++ drivers/char/n_tty.c        2005-01-30 13:56:05.038069640 -0200 
@@ -1143,13 +1143,13 @@ 
 
 { 
        int retval; 
-       ssize_t n; 
+       size_t n; 
        unsigned long flags; 
 
        retval = 0; 
        spin_lock_irqsave(&tty->read_lock, flags); 
        n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); 
-       n = min((ssize_t)*nr, n); 
+       n = min(*nr, n); 
        spin_unlock_irqrestore(&tty->read_lock, flags); 
        if (n) { 
                mb(); 
 
2) fs/proc/generic.c::proc_file_read() 
 
"nbytes" is user passed parameter, so if its value is higher than MAX_INT, 
the signed 
"min" comparison returns "nbytes". 
 
Several proc handling functions do not expect huge values. 
get_locks_status() for example 
(handler for /proc/locks) can be exploited to read kernel memory. 
 
--- fs/proc/generic.c.orig      2005-01-20 12:39:42.000000000 -0200 
+++ fs/proc/generic.c   2005-01-30 13:58:00.420528840 -0200 
@@ -60,7 +60,7 @@ 
                return -ENOMEM; 
 
        while ((nbytes > 0) && !eof) { 
-               count = min_t(ssize_t, PROC_BLOCK_SIZE, nbytes); 
+               count = min_t(size_t, PROC_BLOCK_SIZE, nbytes); 
 
                start = NULL; 
                if (dp->get_info) { 
 
3) reiserfs: 
 
NOTE: The fix is incomplete, reiserfs_copy_from_user_to_file_region() also 
suffers 
from similar issue but is not fixed in the following patch. The reiserfs people 
should provide a more appropriate fix. 
 
reiserfs_file_write() casts its (size_t) count parameter to int, which can 
become 
a problem on 64-bit architectures because the following range check will fail 
if for eg count is "0x1ffffffff": 
 
       if ( unlikely((ssize_t) count < 0)) 
              return -EINVAL; 
 
Which will later be casted to "int" here: 
 
        int write_bytes; /* amount of bytes to write during this iteration */ 
 
        if ( !num_pages ) { /* If we do not have enough space even for */ 
            res = -ENOSPC;  /* single page, return -ENOSPC */ 
            if ( pos > (inode->i_size & (inode->i_sb->s_blocksize-1))) 
                break; // In case we are writing past the file end, break. 
            // Otherwise we are possibly overwriting the file, so 
            // let's set write size to be equal or less than blocksize. 
            // This way we get it correctly for file holes. 
            // But overwriting files on absolutelly full volumes would not 
            // be very efficient. Well, people are not supposed to fill 
            // 100% of disk space anyway. 
            write_bytes = min_t(int, count, inode->i_sb->s_blocksize - (pos & 
(inode->i_sb->s_blocksize - 1))); 
 
Making "write_bytes" negative, which potentially causes unexpected results. 
 
The following patch is an attempt to fix this by changing the variables 
dealing 
with count and offset and the "min_t" comparisons to unsigned "size_t". 
 
--- file.c.orig 2005-01-25 16:01:13.000000000 -0200 
+++ file.c      2005-01-26 13:28:11.819375848 -0200 
@@ -588,7 +588,7 @@ error_exit: 
 
 /* Unlock pages prepared by reiserfs_prepare_file_region_for_write */ 
 static void reiserfs_unprepare_pages(struct page **prepared_pages, /* list 
of locked pages */ 
-                             int num_pages /* amount of pages */) { 
+                             size_t num_pages /* amount of pages */) { 
     int i; // loop counter 
 
     for (i=0; i < num_pages ; i++) { 
@@ -619,7 +619,7 @@ static int reiserfs_copy_from_user_to_fi 
     int offset; // offset in page 
 
     for ( i = 0, offset = (pos & (PAGE_CACHE_SIZE-1)); i < num_pages ; 
i++,offset=0) { 
-       int count = min_t(int,PAGE_CACHE_SIZE-offset,write_bytes); // How 
much of bytes to write to this page 
+       size_t count = 
min_t(size_t,PAGE_CACHE_SIZE-offset,write_bytes); // How much of 
bytes to write to this page 
        struct page *page=prepared_pages[i]; // Current page we process. 
 
        fault_in_pages_readable( buf, count); 
@@ -718,8 +718,8 @@ static int reiserfs_submit_file_region_f 
                                struct reiserfs_transaction_handle *th, 
                                struct inode *inode, 
                                loff_t pos, /* Writing position offset */ 
-                               int num_pages, /* Number of pages to write */ 
-                               int write_bytes, /* number of bytes to write */ 
+                               size_t num_pages, /* Number of pages to write */ 
+                               size_t write_bytes, /* number of bytes to write */ 
                                struct page **prepared_pages /* list of pages */ 
                                ) 
 { 
@@ -854,9 +854,9 @@ static int reiserfs_check_for_tail_and_c 
 static int reiserfs_prepare_file_region_for_write( 
                                struct inode *inode /* Inode of the file */, 
                                loff_t pos, /* position in the file */ 
-                               int num_pages, /* number of pages to 
+                               size_t num_pages, /* number of pages to 
                                                  prepare */ 
-                               int write_bytes, /* Amount of bytes to be 
+                               size_t write_bytes, /* Amount of bytes to be 
                                                    overwritten from 
                                                    @pos */ 
                                struct page **prepared_pages /* pointer to array 
@@ -1252,10 +1252,9 @@ static ssize_t reiserfs_file_write( stru 
     while ( count > 0) { 
        /* This is the main loop in which we running until some error occures 
           or until we write all of the data. */ 
-       int num_pages;/* amount of pages we are going to write this iteration 
*/ 
-       int write_bytes; /* amount of bytes to write during this iteration */ 
-       int blocks_to_allocate; /* how much blocks we need to allocate for 
-                                  this iteration */ 
+       size_t num_pages;/* amount of pages we are going to write this 
iteration */ 
+       size_t write_bytes; /* amount of bytes to write during this iteration */ 
+       size_t blocks_to_allocate; /* how much blocks we need to allocate for 
this iteration */ 
 
         /*  (pos & (PAGE_CACHE_SIZE-1)) is an idiom for offset into a page 
of pos*/ 
        num_pages = !!((pos+count) & (PAGE_CACHE_SIZE - 1)) + /* round 
up partial 
@@ -1269,7 +1268,7 @@ static ssize_t reiserfs_file_write( stru 
            /* If we were asked to write more data than we want to or if there 
               is not that much space, then we shorten amount of data to write 
               for this iteration. */ 
-           num_pages = min_t(int, REISERFS_WRITE_PAGES_AT_A_TIME, 
reiserfs_can_fit_pages(inode->i_sb)); 
+           num_pages = min_t(size_t, 
REISERFS_WRITE_PAGES_AT_A_TIME, 
reiserfs_can_fit_pages(inode->i_sb)); 
            /* Also we should not forget to set size in bytes accordingly */ 
            write_bytes = (num_pages << PAGE_CACHE_SHIFT) - 
                            (pos & (PAGE_CACHE_SIZE-1)); 
@@ -1295,7 +1294,7 @@ static ssize_t reiserfs_file_write( stru 
            // But overwriting files on absolutelly full volumes would not 
            // be very efficient. Well, people are not supposed to fill 
            // 100% of disk space anyway. 
-           write_bytes = min_t(int, count, inode->i_sb->s_blocksize - (pos & 
(inode->i_sb->s_blocksize - 1))); 
+           write_bytes = min_t(size_t, count, inode->i_sb->s_blocksize - (pos 
& (inode->i_sb->s_blocksize - 1))); 
            num_pages = 1; 
            // No blocks were claimed before, so do it now. 
            reiserfs_claim_blocks_to_be_allocated(inode->i_sb, 1 << 
(PAGE_CACHE_SHIFT - inode->i_blkbits));
Comment 1 Thomas Biege 2005-01-31 17:35:33 UTC
<!-- SBZ_reproduce  -->
-
Comment 3 Marcus Meissner 2005-02-04 05:37:51 UTC
Created attachment 28196 [details]
reiserfs-signed.patch

from last bk chset
Comment 6 Marcus Meissner 2005-02-04 05:41:05 UTC
Created attachment 28199 [details]
proc-read-signedness.patch
Comment 7 Marcus Meissner 2005-02-04 05:41:46 UTC
Created attachment 28200 [details]
reiserfs-signed.patch
Comment 10 Marcus Meissner 2005-02-04 05:59:48 UTC
Created attachment 28203 [details]
verify-area-rename.patch

http://linux.bkbits.net:8080/linux-2.6/cset@41f6cf91c1R7rbuggBVQLxBuD7m6Aw?nav=index.html|ChangeSet@-10d

required before always-accessok-checks patch i think
Comment 11 Marcus Meissner 2005-02-04 06:03:18 UTC
Created attachment 28204 [details]
f-maxcount.patch

http://linux.bkbits.net:8080/linux-2.6/cset@41f71cbbbAqnp67z79i7SSVQGtmQzg?nav=index.html|ChangeSet@-10d



WILL BREAK BINARY COMPATIBILITY.
Comment 12 Chris L Mason 2005-02-05 02:01:51 UTC
We clearly can't take f-maxcount.patch, but if I'm reading things correctly, the other patches     
should be sufficient to fix the known bugs.     
    
I don't think we can take the verify-area-rename.patch (comment #10) without keeping   
locks_verify_area for compatibility.    
   
fs-readwrite-signedness.patch needs modification since we can't take the f-maxcount patch.  
 
The reiserfs change looks correct to me. 
Comment 13 Marcus Meissner 2005-02-08 21:56:17 UTC
Created attachment 28290 [details]
2.4-fsmaxcount-rwverifylock.patch

backport of f-maxcount and verify-area-rename patch to 2.4... just for the
record.
Comment 14 Marcus Meissner 2005-02-15 20:13:25 UTC
is public now. 
Comment 16 Marcus Meissner 2005-02-17 16:29:56 UTC
Summary was misleading I think. 
 
These issues are triggerable from userspace without the additional VFS 
protections which we cannot apply. 
Comment 17 Thomas Biege 2005-02-21 15:06:16 UTC
Created attachment 28647 [details]
CAN-2005-0136_ia64-kernel.diff
Comment 18 Thomas Biege 2005-02-21 15:06:53 UTC
Date: Mon, 21 Feb 2005 12:38:20 +0100
From: Thomas Biege <thomas@suse.de>
To: Thomas Biege <thomas@suse.de>
Subject: [joey@infodrom.org: [vendor-sec] Re: ia64 ptrace corner cases]
User-Agent: Mutt/1.5.6i

----- Forwarded message from Martin Schulze <joey@infodrom.org> -----

From: Martin Schulze <joey@infodrom.org>
To: Free Software Distribution Vendors <vendor-sec@lst.de>
User-Agent: Mutt/1.5.6+20040907i
Subject: [vendor-sec] Re: ia64 ptrace corner cases
Errors-To: vendor-sec-admin@lst.de
Date: Mon, 21 Feb 2005 09:33:07 +0100

I'm a bit confused about the status of these vulnerabilities in the
IA-64 kernels:

CVE Id           type         2.4/patch       2.6/patch      public?
-------------------------------------------------------------------------
CAN-2005-0135  ia64/unwind       ???             ???       CVE invisible
CAN-2005-0136  ia64/ptrace    vendor-sec      vuln, [1]    CVE invisible
CAN-2005-0137  ia64/syscall   vendor-sec      non-vuln     CVE invisible

[1] 
http://lia64.bkbits.net:8080/linux-ia64-release-2.6.11/cset@41f2d1eePludGYyb1yOmGaW6Iois8Q

Are all three treated as invisible even though the fix for
CAN-2005-0136 is publically available?

Regards,

        Joey
Comment 19 Marcus Meissner 2005-02-21 15:09:23 UTC
the last comment should be somewhere else.... in 
https://bugzilla.innerweb.novell.com/show_bug.cgi?id=65236 
Comment 20 Thomas Biege 2005-02-21 15:16:32 UTC
yes. the patch too.
Comment 21 Marcus Meissner 2005-02-25 16:06:48 UTC
======================================================                            
Candidate: CAN-2005-0529                                                          
URL: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0529                  
Reference: FULLDISC:20050215 linux kernel 2.6 fun. windoze is a joke              
Reference:                                                                       
URL:http://marc.theaimsgroup.com/?l=full-disclosure&m=110846727602817&w=2         
Reference:                                                                       
MISC:http://www.guninski.com/where_do_you_want_billg_to_go_today_3.html           
Reference:                                                                       
CONFIRM:http://linux.bkbits.net:8080/linux-2.6/cset@4201818eC6aMn0x3GY_9rw3ueb2ZW 
+Q                                                                                                                                                                 
Linux kernel 2.6.10 and 2.6.11rc1-bk6 uses different size types for               
offset arguments to the proc_file_read and locks_read_proc, which                 
leads to a heap-based buffer overflow when a signed comparison causes             
negative integers to be used in a positive context.                               
                                                                                                                                                                   
======================================================                            
Candidate: CAN-2005-0530                                                          
URL: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0530                  
Reference: FULLDISC:20050215 linux kernel 2.6 fun. windoze is a joke              
Reference:                                                                       
URL:http://marc.theaimsgroup.com/?l=full-disclosure&m=110846727602817&w=2         
Reference:                                                                        
MISC:http://www.guninski.com/where_do_you_want_billg_to_go_today_3.html          
Reference:                                                                        
CONFIRM:http://linux.bkbits.net:8080/linux-2.6/cset@420181322LZmhPTewcCOLkubGwOL3+w                                                                                
                                                                                  
Signedness error in the copy_from_read_buf function in n_tty.c for                
Linux kernel 2.6.10 and 2.6.11rc1 allows local users to read kernel               
memory via a negative argument.                                                   
                                                                                  
                                                                                  
======================================================                            
Candidate: CAN-2005-0531                                                          
URL: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0531                  
Reference: FULLDISC:20050215 linux kernel 2.6 fun. windoze is a joke              
Reference:                                                                        
URL:http://marc.theaimsgroup.com/?l=full-disclosure&m=110846727602817&w=2         
Reference:                                                                        
MISC:http://www.guninski.com/where_do_you_want_billg_to_go_today_3.html           
Reference:                                                                        
CONFIRM:http://linux.bkbits.net:8080/linux-2.6/gnupatch@4208e1fcfccuD-eH2OGM5mBhi 
+hmQ3A                                                                            
                                                                                  
The atm_get_addr function in addr.c for Linux kernel 2.6.10 and 2.6.11            
before 2.6.11-rc4 may allow local users to trigger a buffer overflow              
via negative arguments.                                                           
                               
 
======================================================                            
Candidate: CAN-2005-0532                                   
      URL: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2005-0532                  
Reference: FULLDISC:20050215 linux kernel 2.6 fun. windoze is a joke             
Reference:                                                                        
URL:http://marc.theaimsgroup.com/?l=full-disclosure&m=110846727602817&w=2         
Reference:                                                                        
MISC:http://www.guninski.com/where_do_you_want_billg_to_go_today_3.html           
Reference:                                                                        
CONFIRM:http://linux.bkbits.net:8080/linux-2.6/cset@42018227TkNpHlX6BefnItV_GqMmz 
+Q                                                                                
                                                                                  
The reiserfs_copy_from_user_to_file_region function in reiserfs/file.c            
for Linux kernel 2.6.10 and 2.6.11 before 2.6.11-rc4, when running on             
64-bit architectures, may allow local users to trigger a buffer                   
overflow as a result of casting discrepancies between size_t and int              
data types.                                                                                                                                           
Comment 22 Marcus Meissner 2005-03-08 16:49:09 UTC
olaf to apply the first 2 patches, chris mason to apply the reiserfs patch. 
 
the infrastructure patvches will not be applied to older versions 
Comment 23 Olaf Kirch 2005-03-15 11:26:49 UTC
Added patches to SLES9 SP1, SP2, and SL_92 branches. HEAD is unaffected 
as these patches are in 2.6.11: 
 
- patches.fixes/n-tty-signedness: Fix sign checks in 
  copy_from_read_buf() (65318). 
- patches.fixes/proc-read-signedness: Fix signed compare in 
  fs/proc/generic.c::proc_file_read() (65318). 
 
Passing this bug to Chris for reiserfs 
Comment 24 Chris L Mason 2005-03-17 13:40:02 UTC
reiserfs patches in SLES9 SP[12], and SL_92.  Patches for HEAD were in 2.6.11. 
Comment 25 Marcus Meissner 2005-03-17 13:43:28 UTC
reopen foir tracking 
Comment 26 Marcus Meissner 2005-03-22 12:54:40 UTC
drivers/char/n_tty.c and fs/proc/generic.c are not affected in 2.4. 
(funny enough that this fault was introduced by introduction of the generic 
min() / min_t() macros in 2.6, instead of adding casts the people should 
have *THOUGHT* instead.) 
 
reiserfs does not have the function mentioned in 2.4, so not affected too. 
 
the others were new feature additions. 
Comment 27 Marcus Meissner 2005-03-24 17:22:17 UTC
updates and advisory released 
Comment 28 Thomas Biege 2009-10-13 21:01:12 UTC
CVE-2005-0532: CVSS v2 Base Score: 2.1 (AV:L/AC:L/Au:N/C:N/I:N/A:P)