Subject: Re: CVS commit: basesrc/lib/libc/locale
To: None <tshiozak@netbsd.org>
From: enami tsugutomo <enami@sm.sony.co.jp>
List: source-changes
Date: 08/06/2002 17:13:57
Takuya SHIOZAKI <tshiozak@netbsd.org> writes:

> Module Name:	basesrc
> Committed By:	tshiozak
> Date:		Fri Aug  2 07:12:52 UTC 2002
> 
> Modified Files:
> 	basesrc/lib/libc/locale: setlocale.c
> 
> Log Message:
> fix a bug of setlocale when changing locales with LC_ALL for the first
> argunemt and with a string containing many slashes for the second argument.
> This bug may cause setlocale() to destroy static datas.

From reading the source, there may be still/more bugs.

1) If the first category is followed by multiple slash, it may be
   copied into new_categories[1].  I guess further load may fail tho.

2) If multiple slash appears later, the `locale' may goes beyond the
   `r', and `len' become negative.

I've confirmed the latter actually.

enami.

Index: setlocale.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libc/locale/setlocale.c,v
retrieving revision 1.41
diff -c -r1.41 setlocale.c
*** setlocale.c	2002/08/03 06:12:30	1.41
--- setlocale.c	2002/08/06 07:48:13
***************
*** 153,188 ****
  		(void)strlcpy(new_categories[category], locale,
  		    sizeof(new_categories[category]));
  	} else {
! 		if ((r = strchr(locale, '/')) == 0) {
! 			for (i = 1; i < _LC_LAST; ++i) {
! 				(void)strlcpy(new_categories[i], locale,
! 				    sizeof(new_categories[i]));
  			}
! 		} else {
! 			for (i = 1; r[1] == '/'; ++r)
! 				;
! 			if (!r[1])
! 				return (NULL);	/* Hmm, just slashes... */
! 			do {
! 				if (i == _LC_LAST)
! 					return (NULL);	/* too many slashes. */
! 				len = r - locale;
! 				if (len + 1 > sizeof(new_categories[i]))
! 					return (NULL);	/* too long */
! 				(void)memcpy(new_categories[i], locale, len);
! 				new_categories[i][len] = '\0';
! 				i++;
! 				locale = r;
! 				while (*locale == '/')
! 					++locale;
! 				while (*++r && *r != '/');
! 			} while (*locale);
! 			while (i < _LC_LAST) {
! 				(void)strlcpy(new_categories[i],
! 				    new_categories[i - 1],
! 				    sizeof(new_categories[i]));
! 				i++;
! 			}
  		}
  	}
  
--- 153,180 ----
  		(void)strlcpy(new_categories[category], locale,
  		    sizeof(new_categories[category]));
  	} else {
! 		for (i = 1;; i++, locale = r) {
! 			while (*locale == '/')
! 				locale++;
! 			for (r = locale; *r && *r != '/';)
! 				r++;
! 			len = r - locale;
! 			if (len == 0) {
! 				if (i == 1)
! 					return (NULL); /* Hmm, just
! 							  slashes... */
! 				break;		/* The end of string */
  			}
! 			if (len + 1 > sizeof(new_categories[i]))
! 				return (NULL);	/* too long */
! 			(void)memcpy(new_categories[i], locale, len);
! 			new_categories[i][len] = '\0';
! 		}
! 		while (i < _LC_LAST) {
! 			(void)strlcpy(new_categories[i],
! 			    new_categories[i - 1],
! 			    sizeof(new_categories[i]));
! 			i++;
  		}
  	}