Bug 221224

Summary: setlocale.c does not properly detect if locale contains too many slashes
Product: Base System Reporter: Leonard Janis Robert König <ljrk>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Some People CC: emaste, schily
Priority: ---    
Version: CURRENT   
Hardware: Any   
OS: Any   

Description Leonard Janis Robert König 2017-08-04 16:21:06 UTC
Overview
There's a loop at [1] which tries to find the first character after a number of consecutive slashes.  In line 164 i == _LC_LAST is checked which should be always false at this location, since it was set to 1 a few lines before and never changed since.
But even if i was not set in this loop, it'd still wouldn't make any sense, since then i would always have the value _LC_LAST because of the very first loop in the function.

Steps to Reproduce
call setlocale(LC_ALL, "/some////////string/");

Actual Results / Expected results:
Unclear

----

[1] https://svnweb.freebsd.org/base/head/lib/libc/locale/setlocale.c?revision=314436&view=markup#l157
Comment 1 Leonard Janis Robert König 2017-08-05 11:43:17 UTC
i actually does get increased in line 172 so it does actually count the number of sequences of slashes in the locale string (correctly).

But while this works, setting i to 1 within a loop that doesn't use i is very confusing (as is the rest of the code).

But even while i correctly counts the number of slashes it silently assumes that slashes are only used as separators between locales in a compound locale -- leading and trailing slashes are thus also counted which results in eg. "/1/2/3/4/5/6" to be seen as having 6 slashes (correct) but 6+1 locales (incorrect) in line 164 and also the first locale to be set to "/", the second to "1/" and the 6th to "5/".

Ie: setlocale(LC_ALL, "/1/2/3/4/5/6") calls strlcpy(new_categories[i], locale, len+1) with:

 i | locale         | len+1 | (new) categories[i]
---|----------------|-------|---------------------
 1 | "/1/2/3/4/5/6" | 1     | "/"
 2 | "1/2/3/4/5/6"  | 2     | "1/"
 3 | "2/3/4/5/6"    | 2     | "2/"
 4 | "3/4/5/6"      | 2     | "3/"
 5 | "4/5/6"        | 2     | "4/"
 6 | "5/6"          | 2     | "5/"
Comment 2 Leonard Janis Robert König 2017-08-07 13:51:49 UTC
It seems that there's no documentation on how a "composite locale" is built except

> A composite locale is a string beginning with a "/", followed by the locale of each category, separated by a "/".

from [1].
However, FreeBSDs implementation does not allow leading slashes as seen earlier already.

However the implementation allows for more than one '/' separating the locales -- except for the first, ie:

"C/C/////C/C/C/C/" -- allowed
"C/////C/C/C/C/C/" -- not allowed

this at least is inconsistent if not unwanted, I assume (also the documentation on how a composite locale is built is lacking, especially since it's behavior is based on the internal ordering of LC_*).

----

[1] http://docs.oracle.com/cd/E13203_01/tuxedo/tux91/rf3c/rf3c14.htm
Comment 3 Jörg Schilling 2017-08-08 14:24:33 UTC
Note that AIX, HP-UX, (closed) Solaris are based on the same i18n code and 
all use the following ordering:

#define LC_CTYPE        0 
#define LC_NUMERIC      1 
#define LC_TIME         2 
#define LC_COLLATE      3 
#define LC_MONETARY     4 
#define LC_MESSAGES     5 
#define LC_ALL          6 

This ordering is used for composite locales!