From nobody@FreeBSD.org  Sat Nov 13 13:19:52 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 9C4B7106566B
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 13 Nov 2010 13:19:52 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id 6FF128FC0A
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 13 Nov 2010 13:19:52 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id oADDJqEq020133
	for <freebsd-gnats-submit@FreeBSD.org>; Sat, 13 Nov 2010 13:19:52 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id oADDJqjg020132;
	Sat, 13 Nov 2010 13:19:52 GMT
	(envelope-from nobody)
Message-Id: <201011131319.oADDJqjg020132@www.freebsd.org>
Date: Sat, 13 Nov 2010 13:19:52 GMT
From: Andrey Zonov <andrey.zonov@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Overflow in vmspace_swap_count()
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         152200
>Category:       kern
>Synopsis:       [vm] [patch] Overflow in vmspace_swap_count()
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    brucec
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Nov 13 13:20:04 UTC 2010
>Closed-Date:    Fri Mar 04 20:30:52 UTC 2011
>Last-Modified:  Fri Mar  4 20:40:08 UTC 2011
>Originator:     Andrey Zonov
>Release:        8.1-RELEASE
>Organization:
>Environment:
FreeBSD xxx.xxx.ru 8.1-RELEASE FreeBSD 8.1-RELEASE #0 r212732M: Tue Mar 30 03:14:51 MSD 2010     root@xxx.xxx.ru:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
When memory exhasted, [pagedaemon] calls src/sys/vm/vm_pageout.c:vm_pageout_oom(),
this function calls src/sys/vm/swap_pager.c:vmspace_swap_count() for swap usage
calculation of process.

vmspace_swap_count() uses type `int' for address defference and it often leads
to `n' variable overflow and system may kill random swapped processes, not only
with big memory usage.
>How-To-Repeat:
# swapon /dev/something
# fetch http://zonov.pp.ru/tests/swapped_test.tbz
# tar xyf swapped_test.tbz
# cd swapped_test
# make test

Be carefully, that may hang up your system!
>Fix:


Patch attached with submission follows:

Index: /usr/src/sys/vm/vm_map.h
===================================================================
--- /usr/src/sys/vm/vm_map.h	(revision 212732)
+++ /usr/src/sys/vm/vm_map.h	(working copy)
@@ -373,6 +373,6 @@
     int flags);
 int vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end,
     int flags);
-int vmspace_swap_count (struct vmspace *vmspace);
+long vmspace_swap_count (struct vmspace *vmspace);
 #endif				/* _KERNEL */
 #endif				/* _VM_MAP_ */
Index: /usr/src/sys/vm/swap_pager.c
===================================================================
--- /usr/src/sys/vm/swap_pager.c	(revision 212732)
+++ /usr/src/sys/vm/swap_pager.c	(working copy)
@@ -2412,12 +2412,12 @@
  *	if the VM object has any swap use at all the associated map entries
  *	count for at least 1 swap page.
  */
-int
+long
 vmspace_swap_count(struct vmspace *vmspace)
 {
 	vm_map_t map = &vmspace->vm_map;
 	vm_map_entry_t cur;
-	int count = 0;
+	long count = 0;
 
 	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
 		vm_object_t object;
@@ -2427,7 +2427,7 @@
 			VM_OBJECT_LOCK(object);
 			if (object->type == OBJT_SWAP &&
 			    object->un_pager.swp.swp_bcount != 0) {
-				int n = (cur->end - cur->start) / PAGE_SIZE;
+				vm_offset_t n = (cur->end - cur->start) / PAGE_SIZE;
 
 				count += object->un_pager.swp.swp_bcount *
 				    SWAP_META_PAGES * n / object->size + 1;


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->brucec 
Responsible-Changed-By: brucec 
Responsible-Changed-When: Mon Feb 21 10:11:12 UTC 2011 
Responsible-Changed-Why:  
Take. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=152200 
State-Changed-From-To: open->patched 
State-Changed-By: brucec 
State-Changed-When: Wed Feb 23 10:28:51 UTC 2011 
State-Changed-Why:  
Committed to HEAD. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=152200 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/152200: commit references a PR
Date: Wed, 23 Feb 2011 10:28:46 +0000 (UTC)

 Author: brucec
 Date: Wed Feb 23 10:28:37 2011
 New Revision: 218966
 URL: http://svn.freebsd.org/changeset/base/218966
 
 Log:
   Calculate and return the count in vmspace_swap_count as a vm_offset_t
   instead of an int to avoid overflow.
   
   While here, clean up some style(9) issues.
   
   PR:		kern/152200
   Reviewed by:	kib
   MFC after:	2 weeks
 
 Modified:
   head/sys/vm/swap_pager.c
   head/sys/vm/vm_map.h
 
 Modified: head/sys/vm/swap_pager.c
 ==============================================================================
 --- head/sys/vm/swap_pager.c	Wed Feb 23 09:22:33 2011	(r218965)
 +++ head/sys/vm/swap_pager.c	Wed Feb 23 10:28:37 2011	(r218966)
 @@ -2420,23 +2420,24 @@ SYSCTL_NODE(_vm, OID_AUTO, swap_info, CT
   *	if the VM object has any swap use at all the associated map entries
   *	count for at least 1 swap page.
   */
 -int
 +vm_offset_t
  vmspace_swap_count(struct vmspace *vmspace)
  {
 -	vm_map_t map = &vmspace->vm_map;
 +	vm_map_t map;
  	vm_map_entry_t cur;
 -	int count = 0;
 +	vm_object_t object;
 +	vm_offset_t count, n;
  
 -	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
 -		vm_object_t object;
 +	map = &vmspace->vm_map;
 +	count = 0;
  
 +	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
  		if ((cur->eflags & MAP_ENTRY_IS_SUB_MAP) == 0 &&
  		    (object = cur->object.vm_object) != NULL) {
  			VM_OBJECT_LOCK(object);
  			if (object->type == OBJT_SWAP &&
  			    object->un_pager.swp.swp_bcount != 0) {
 -				int n = (cur->end - cur->start) / PAGE_SIZE;
 -
 +				n = (cur->end - cur->start) / PAGE_SIZE;
  				count += object->un_pager.swp.swp_bcount *
  				    SWAP_META_PAGES * n / object->size + 1;
  			}
 
 Modified: head/sys/vm/vm_map.h
 ==============================================================================
 --- head/sys/vm/vm_map.h	Wed Feb 23 09:22:33 2011	(r218965)
 +++ head/sys/vm/vm_map.h	Wed Feb 23 10:28:37 2011	(r218966)
 @@ -380,6 +380,6 @@ int vm_map_unwire(vm_map_t map, vm_offse
      int flags);
  int vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end,
      int flags);
 -int vmspace_swap_count (struct vmspace *vmspace);
 +vm_offset_t vmspace_swap_count(struct vmspace *vmspace);
  #endif				/* _KERNEL */
  #endif				/* _VM_MAP_ */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/152200: commit references a PR
Date: Fri,  4 Mar 2011 20:26:55 +0000 (UTC)

 Author: brucec
 Date: Fri Mar  4 20:26:35 2011
 New Revision: 219273
 URL: http://svn.freebsd.org/changeset/base/219273
 
 Log:
   MFC r218966, r219124:
   
   Change the return type of vmspace_swap_count to a long to match the other
   vmspace_*_count functions.
   
   While here, clean up some style(9) issues.
   
   PR:	kern/152200
 
 Modified:
   stable/8/sys/vm/swap_pager.c
   stable/8/sys/vm/vm_map.h
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/vm/swap_pager.c
 ==============================================================================
 --- stable/8/sys/vm/swap_pager.c	Fri Mar  4 19:53:07 2011	(r219272)
 +++ stable/8/sys/vm/swap_pager.c	Fri Mar  4 20:26:35 2011	(r219273)
 @@ -2408,23 +2408,24 @@ SYSCTL_NODE(_vm, OID_AUTO, swap_info, CT
   *	if the VM object has any swap use at all the associated map entries
   *	count for at least 1 swap page.
   */
 -int
 +long
  vmspace_swap_count(struct vmspace *vmspace)
  {
 -	vm_map_t map = &vmspace->vm_map;
 +	vm_map_t map;
  	vm_map_entry_t cur;
 -	int count = 0;
 +	vm_object_t object;
 +	long count, n;
  
 -	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
 -		vm_object_t object;
 +	map = &vmspace->vm_map;
 +	count = 0;
  
 +	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
  		if ((cur->eflags & MAP_ENTRY_IS_SUB_MAP) == 0 &&
  		    (object = cur->object.vm_object) != NULL) {
  			VM_OBJECT_LOCK(object);
  			if (object->type == OBJT_SWAP &&
  			    object->un_pager.swp.swp_bcount != 0) {
 -				int n = (cur->end - cur->start) / PAGE_SIZE;
 -
 +				n = (cur->end - cur->start) / PAGE_SIZE;
  				count += object->un_pager.swp.swp_bcount *
  				    SWAP_META_PAGES * n / object->size + 1;
  			}
 
 Modified: stable/8/sys/vm/vm_map.h
 ==============================================================================
 --- stable/8/sys/vm/vm_map.h	Fri Mar  4 19:53:07 2011	(r219272)
 +++ stable/8/sys/vm/vm_map.h	Fri Mar  4 20:26:35 2011	(r219273)
 @@ -382,6 +382,6 @@ int vm_map_unwire(vm_map_t map, vm_offse
      int flags);
  int vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end,
      int flags);
 -int vmspace_swap_count (struct vmspace *vmspace);
 +long vmspace_swap_count(struct vmspace *vmspace);
  #endif				/* _KERNEL */
  #endif				/* _VM_MAP_ */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: brucec 
State-Changed-When: Fri Mar 4 20:30:34 UTC 2011 
State-Changed-Why:  
Merged to stable/7 and stable/8. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=152200 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/152200: commit references a PR
Date: Fri,  4 Mar 2011 20:30:38 +0000 (UTC)

 Author: brucec
 Date: Fri Mar  4 20:30:18 2011
 New Revision: 219274
 URL: http://svn.freebsd.org/changeset/base/219274
 
 Log:
   MFC r218966, r219124:
   
   Change the return type of vmspace_swap_count to a long to match the other
   vmspace_*_count functions.
   
   While here, clean up some style(9) issues.
   
   PR:   kern/152200
 
 Modified:
   stable/7/sys/vm/swap_pager.c
   stable/7/sys/vm/vm_map.h
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/vm/swap_pager.c
 ==============================================================================
 --- stable/7/sys/vm/swap_pager.c	Fri Mar  4 20:26:35 2011	(r219273)
 +++ stable/7/sys/vm/swap_pager.c	Fri Mar  4 20:30:18 2011	(r219274)
 @@ -2266,23 +2266,24 @@ SYSCTL_NODE(_vm, OID_AUTO, swap_info, CT
   *	if the VM object has any swap use at all the associated map entries
   *	count for at least 1 swap page.
   */
 -int
 +long
  vmspace_swap_count(struct vmspace *vmspace)
  {
 -	vm_map_t map = &vmspace->vm_map;
 +	vm_map_t map;
  	vm_map_entry_t cur;
 -	int count = 0;
 +	vm_object_t object;
 +	long count, n;
  
 -	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
 -		vm_object_t object;
 +	map = &vmspace->vm_map;
 +	count = 0;
  
 +	for (cur = map->header.next; cur != &map->header; cur = cur->next) {
  		if ((cur->eflags & MAP_ENTRY_IS_SUB_MAP) == 0 &&
  		    (object = cur->object.vm_object) != NULL) {
  			VM_OBJECT_LOCK(object);
  			if (object->type == OBJT_SWAP &&
  			    object->un_pager.swp.swp_bcount != 0) {
 -				int n = (cur->end - cur->start) / PAGE_SIZE;
 -
 +				n = (cur->end - cur->start) / PAGE_SIZE;
  				count += object->un_pager.swp.swp_bcount *
  				    SWAP_META_PAGES * n / object->size + 1;
  			}
 
 Modified: stable/7/sys/vm/vm_map.h
 ==============================================================================
 --- stable/7/sys/vm/vm_map.h	Fri Mar  4 20:26:35 2011	(r219273)
 +++ stable/7/sys/vm/vm_map.h	Fri Mar  4 20:30:18 2011	(r219274)
 @@ -376,6 +376,6 @@ int vm_map_unwire(vm_map_t map, vm_offse
      int flags);
  int vm_map_wire(vm_map_t map, vm_offset_t start, vm_offset_t end,
      int flags);
 -int vmspace_swap_count (struct vmspace *vmspace);
 +long vmspace_swap_count(struct vmspace *vmspace);
  #endif				/* _KERNEL */
  #endif				/* _VM_MAP_ */
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
