Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
__gconv_translit_find: Disable function [BZ #17187]
This functionality has never worked correctly, and the implementation
contained a security vulnerability (CVE-2014-5119).
  • Loading branch information
Florian Weimer committed Aug 26, 2014
1 parent e4e7cfd commit a1a6a40
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 174 deletions.
7 changes: 7 additions & 0 deletions ChangeLog
@@ -1,3 +1,10 @@
2014-08-26 Florian Weimer <fweimer@redhat.com>

[BZ #17187]
* iconv/gconv_trans.c (struct known_trans, search_tree, lock,
trans_compare, open_translit, __gconv_translit_find):
Remove module loading code.

2014-08-26 Allan McRae <allan@archlinux.org>

* po/vi.po: Update Vietnamese translation from translation project.
Expand Down
9 changes: 8 additions & 1 deletion NEWS
Expand Up @@ -23,7 +23,7 @@ Version 2.20
16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009, 17022, 17031,
17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075, 17078, 17079,
17084, 17086, 17088, 17092, 17097, 17125, 17135, 17137, 17150, 17153,
17213, 17259, 17261, 17262, 17263.
17187, 17213, 17259, 17261, 17262, 17263.

* Reverted change of ABI data structures for s390 and s390x:
On s390 and s390x the size of struct ucontext and jmp_buf was increased in
Expand Down Expand Up @@ -108,6 +108,13 @@ Version 2.20
handle the new instruction encodings. This is known to affect Valgrind
versions up through 3.9 (but will be fixed in the forthcoming 3.10
release), and might affect other tools that do instruction emulation.

* Support for loadable gconv transliteration modules has been removed.
The support for transliteration modules has been non-functional for
over a decade, and the removal is prompted by security defects. The
normal gconv conversion modules are still supported. Transliteration
with //TRANSLIT is still possible, and the //IGNORE specifier
continues to be supported. (CVE-2014-5519)

Version 2.19

Expand Down
177 changes: 4 additions & 173 deletions iconv/gconv_trans.c
Expand Up @@ -238,181 +238,12 @@ __gconv_transliterate (struct __gconv_step *step,
return __GCONV_ILLEGAL_INPUT;
}


/* Structure to represent results of found (or not) transliteration
modules. */
struct known_trans
{
/* This structure must remain the first member. */
struct trans_struct info;

char *fname;
void *handle;
int open_count;
};


/* Tree with results of previous calls to __gconv_translit_find. */
static void *search_tree;

/* We modify global data. */
__libc_lock_define_initialized (static, lock);


/* Compare two transliteration entries. */
static int
trans_compare (const void *p1, const void *p2)
{
const struct known_trans *s1 = (const struct known_trans *) p1;
const struct known_trans *s2 = (const struct known_trans *) p2;

return strcmp (s1->info.name, s2->info.name);
}


/* Open (maybe reopen) the module named in the struct. Get the function
and data structure pointers we need. */
static int
open_translit (struct known_trans *trans)
{
__gconv_trans_query_fct queryfct;

trans->handle = __libc_dlopen (trans->fname);
if (trans->handle == NULL)
/* Not available. */
return 1;

/* Find the required symbol. */
queryfct = __libc_dlsym (trans->handle, "gconv_trans_context");
if (queryfct == NULL)
{
/* We cannot live with that. */
close_and_out:
__libc_dlclose (trans->handle);
trans->handle = NULL;
return 1;
}

/* Get the context. */
if (queryfct (trans->info.name, &trans->info.csnames, &trans->info.ncsnames)
!= 0)
goto close_and_out;

/* Of course we also have to have the actual function. */
trans->info.trans_fct = __libc_dlsym (trans->handle, "gconv_trans");
if (trans->info.trans_fct == NULL)
goto close_and_out;

/* Now the optional functions. */
trans->info.trans_init_fct =
__libc_dlsym (trans->handle, "gconv_trans_init");
trans->info.trans_context_fct =
__libc_dlsym (trans->handle, "gconv_trans_context");
trans->info.trans_end_fct =
__libc_dlsym (trans->handle, "gconv_trans_end");

trans->open_count = 1;

return 0;
}


int
internal_function
__gconv_translit_find (struct trans_struct *trans)
{
struct known_trans **found;
const struct path_elem *runp;
int res = 1;

/* We have to have a name. */
assert (trans->name != NULL);

/* Acquire the lock. */
__libc_lock_lock (lock);

/* See whether we know this module already. */
found = __tfind (trans, &search_tree, trans_compare);
if (found != NULL)
{
/* Is this module available? */
if ((*found)->handle != NULL)
{
/* Maybe we have to reopen the file. */
if ((*found)->handle != (void *) -1)
/* The object is not unloaded. */
res = 0;
else if (open_translit (*found) == 0)
{
/* Copy the data. */
*trans = (*found)->info;
(*found)->open_count++;
res = 0;
}
}
}
else
{
size_t name_len = strlen (trans->name) + 1;
int need_so = 0;
struct known_trans *newp;

/* We have to continue looking for the module. */
if (__gconv_path_elem == NULL)
__gconv_get_path ();

/* See whether we have to append .so. */
if (name_len <= 4 || memcmp (&trans->name[name_len - 4], ".so", 3) != 0)
need_so = 1;

/* Create a new entry. */
newp = (struct known_trans *) malloc (sizeof (struct known_trans)
+ (__gconv_max_path_elem_len
+ name_len + 3)
+ name_len);
if (newp != NULL)
{
char *cp;

/* Clear the struct. */
memset (newp, '\0', sizeof (struct known_trans));

/* Store a copy of the module name. */
newp->info.name = cp = (char *) (newp + 1);
cp = __mempcpy (cp, trans->name, name_len);

newp->fname = cp;

/* Search in all the directories. */
for (runp = __gconv_path_elem; runp->name != NULL; ++runp)
{
cp = __mempcpy (__stpcpy ((char *) newp->fname, runp->name),
trans->name, name_len);
if (need_so)
memcpy (cp, ".so", sizeof (".so"));

if (open_translit (newp) == 0)
{
/* We found a module. */
res = 0;
break;
}
}

if (res)
newp->fname = NULL;

/* In any case we'll add the entry to our search tree. */
if (__tsearch (newp, &search_tree, trans_compare) == NULL)
{
/* Yickes, this should not happen. Unload the object. */
res = 1;
/* XXX unload here. */
}
}
}

__libc_lock_unlock (lock);

return res;
/* Transliteration module loading has been removed because it never
worked as intended and suffered from a security vulnerability.
Consequently, this function always fails. */
return 1;
}

0 comments on commit a1a6a40

Please sign in to comment.