[2021] in SIPB_Linux_Development
patch for i_count vulnerability
daemon@ATHENA.MIT.EDU (mhpower@MIT.EDU)
Fri May 22 19:27:26 1998
From: mhpower@MIT.EDU
Date: Fri, 22 May 1998 19:27:13 -0400
To: linux-dev@MIT.EDU
Cc: yert@MIT.EDU
As far as I can tell, RedHat still hasn't issued any fix for the
i_count overflow security hole that was found in mid-January
(http://www.mit.edu:8008/menelaus/bt/5960). According to
http://www.mit.edu:8008/menelaus/bt/6554, the problem is fixed
in the 2.0.34 kernel; however, many people are not yet using 2.0.34
for various reasons, perhaps including lack of a release on
ftp.kernel.org, and lack of a version of afs built with
the i_count field of struct inode changed to type unsigned long.
Presumably there are some environments in which it's desirable to
prevent some local accounts from obtaining root access by exploiting
the i_count problem. I've attached a patch below that keeps the
traditional data type (unsigned short) for the i_count field, but
changes the memory manager to check for overflows of the type that
occur in attempts to exploit the problem. The approach is to force
a kernel panic rather than allow the i_count field to overflow.
Obviously this provides another way for local accounts to cause
denial of service, but there are many cases in which that's a much
more acceptable risk than root access by arbitrary local users.
Matt
*** linux-2.0.32/mm/filemap.c.old Fri May 22 18:22:24 1998
--- linux-2.0.32/mm/filemap.c Fri May 22 18:25:23 1998
***************
*** 1183,1184 ****
--- 1183,1185 ----
vma->vm_inode = inode;
+ if (inode->i_count == 65535) panic("generic_file_mmap i_count 65535");
inode->i_count++;
*** linux-2.0.32/mm/mlock.c.old Fri May 22 18:22:24 1998
--- linux-2.0.32/mm/mlock.c Fri May 22 18:28:00 1998
***************
*** 38,41 ****
n->vm_flags = newflags;
! if (n->vm_inode)
n->vm_inode->i_count++;
if (n->vm_ops && n->vm_ops->open)
--- 38,43 ----
n->vm_flags = newflags;
! if (n->vm_inode) {
! if (n->vm_inode->i_count == 65535) panic("mlock_fixup_start i_count 65535");
n->vm_inode->i_count++;
+ }
if (n->vm_ops && n->vm_ops->open)
***************
*** 59,62 ****
n->vm_flags = newflags;
! if (n->vm_inode)
n->vm_inode->i_count++;
if (n->vm_ops && n->vm_ops->open)
--- 61,66 ----
n->vm_flags = newflags;
! if (n->vm_inode) {
! if (n->vm_inode->i_count == 65535) panic("mlock_fixup_end i_count 65535");
n->vm_inode->i_count++;
+ }
if (n->vm_ops && n->vm_ops->open)
***************
*** 89,92 ****
vma->vm_flags = newflags;
! if (vma->vm_inode)
vma->vm_inode->i_count += 2;
if (vma->vm_ops && vma->vm_ops->open) {
--- 93,98 ----
vma->vm_flags = newflags;
! if (vma->vm_inode) {
! if (vma->vm_inode->i_count >= 65534) panic("mlock_fixup_middle i_count 65534");
vma->vm_inode->i_count += 2;
+ }
if (vma->vm_ops && vma->vm_ops->open) {
*** linux-2.0.32/mm/mmap.c.old Fri May 22 18:22:24 1998
--- linux-2.0.32/mm/mmap.c Fri May 22 18:29:00 1998
***************
*** 759,762 ****
mpnt->vm_start = end;
! if (mpnt->vm_inode)
mpnt->vm_inode->i_count++;
if (mpnt->vm_ops && mpnt->vm_ops->open)
--- 759,764 ----
mpnt->vm_start = end;
! if (mpnt->vm_inode) {
! if (mpnt->vm_inode->i_count == 65535) panic("unmap_fixup i_count 65535");
mpnt->vm_inode->i_count++;
+ }
if (mpnt->vm_ops && mpnt->vm_ops->open)
*** linux-2.0.32/mm/mprotect.c.old Fri May 22 18:22:24 1998
--- linux-2.0.32/mm/mprotect.c Fri May 22 18:30:44 1998
***************
*** 110,113 ****
n->vm_page_prot = prot;
! if (n->vm_inode)
n->vm_inode->i_count++;
if (n->vm_ops && n->vm_ops->open)
--- 110,115 ----
n->vm_page_prot = prot;
! if (n->vm_inode) {
! if (n->vm_inode->i_count == 65535) panic("mprotect_fixup_start i_count 65535");
n->vm_inode->i_count++;
+ }
if (n->vm_ops && n->vm_ops->open)
***************
*** 133,136 ****
n->vm_page_prot = prot;
! if (n->vm_inode)
n->vm_inode->i_count++;
if (n->vm_ops && n->vm_ops->open)
--- 135,140 ----
n->vm_page_prot = prot;
! if (n->vm_inode) {
! if (n->vm_inode->i_count == 65535) panic("mprotect_fixup_end i_count 65535");
n->vm_inode->i_count++;
+ }
if (n->vm_ops && n->vm_ops->open)
***************
*** 165,168 ****
vma->vm_page_prot = prot;
! if (vma->vm_inode)
vma->vm_inode->i_count += 2;
if (vma->vm_ops && vma->vm_ops->open) {
--- 169,174 ----
vma->vm_page_prot = prot;
! if (vma->vm_inode) {
! if (vma->vm_inode->i_count >= 65534) panic("mprotect_fixup_middle i_count 65534");
vma->vm_inode->i_count += 2;
+ }
if (vma->vm_ops && vma->vm_ops->open) {
*** linux-2.0.32/mm/mremap.c.old Fri May 22 18:22:24 1998
--- linux-2.0.32/mm/mremap.c Fri May 22 18:31:38 1998
***************
*** 141,144 ****
new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
! if (new_vma->vm_inode)
new_vma->vm_inode->i_count++;
if (new_vma->vm_ops && new_vma->vm_ops->open)
--- 141,146 ----
new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
! if (new_vma->vm_inode) {
! if (new_vma->vm_inode->i_count == 65535) panic("move_vma i_count 65535");
new_vma->vm_inode->i_count++;
+ }
if (new_vma->vm_ops && new_vma->vm_ops->open)