bug-gnu-utils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Possible DoS issues in gettext


From: Bruno Haible
Subject: Re: Possible DoS issues in gettext
Date: Fri, 16 Nov 2007 03:03:19 +0100
User-agent: KMail/1.5.4

Hello,

Ismail Dönmez wrote:
> Multiple DoS issues are reported against PHP's gettext functions [0] but 
> looks 
> like its a gettext problem. Is it possible to fix these problems in gettext 
> itself?
> 
> [0] http://www.securityfocus.com/archive/1/483648/30/30/threaded

Thank you for reporting this. I have forwarded it as a glibc bug at
  <http://sourceware.org/bugzilla/show_bug.cgi?id=5346>

Applying the fix also to GNU gettext as follows.


2007-11-15  Bruno Haible  <address@hidden>

        Avoid crash by stack overflow when msgid is very long.
        * dcigettext.c (struct known_translation_t): Turn msgid into a union.
        (transcmp): Use the appropriate part of s1->msgid and s2->msgid.
        (DCIGETTEXT): Change the allocation of the 'search' variable so that
        it needs only fixed stack space. Delay the initialization of
        msgid_len until it is needed.
        Reported by Laurent Gaffié <address@hidden> via
        Ismail Dönmez <address@hidden>.

*** gettext-runtime/intl/dcigettext.c.bak       21 Oct 2007 18:42:41 -0000      
1.38
--- gettext-runtime/intl/dcigettext.c   16 Nov 2007 00:58:59 -0000
***************
*** 269,275 ****
    size_t translation_length;
  
    /* Pointer to the string in question.  */
!   char msgid[ZERO];
  };
  
  gl_rwlock_define_initialized (static, tree_lock)
--- 269,280 ----
    size_t translation_length;
  
    /* Pointer to the string in question.  */
!   union
!     {
!       char appended[ZERO];  /* used if domain != NULL */
!       const char *ptr;      /* used if domain == NULL */
!     }
!   msgid;
  };
  
  gl_rwlock_define_initialized (static, tree_lock)
***************
*** 288,294 ****
    s1 = (const struct known_translation_t *) p1;
    s2 = (const struct known_translation_t *) p2;
  
!   result = strcmp (s1->msgid, s2->msgid);
    if (result == 0)
      {
        result = strcmp (s1->domainname, s2->domainname);
--- 293,300 ----
    s1 = (const struct known_translation_t *) p1;
    s2 = (const struct known_translation_t *) p2;
  
!   result = strcmp (s1->domain != NULL ? s1->msgid.appended : s1->msgid.ptr,
!                  s2->domain != NULL ? s2->msgid.appended : s2->msgid.ptr);
    if (result == 0)
      {
        result = strcmp (s1->domainname, s2->domainname);
***************
*** 501,509 ****
    char *retval;
    size_t retlen;
    int saved_errno;
!   struct known_translation_t *search;
    struct known_translation_t **foundp = NULL;
-   size_t msgid_len;
  #if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
    const char *localename;
  #endif
--- 507,514 ----
    char *retval;
    size_t retlen;
    int saved_errno;
!   struct known_translation_t search;
    struct known_translation_t **foundp = NULL;
  #if defined HAVE_PER_THREAD_LOCALE && !defined IN_LIBGLOCALE
    const char *localename;
  #endif
***************
*** 539,553 ****
      category = LC_MESSAGES;
  #endif
  
-   msgid_len = strlen (msgid1) + 1;
- 
    /* Try to find the translation among those which we found at
       some time.  */
!   search = (struct known_translation_t *)
!          alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
!   memcpy (search->msgid, msgid1, msgid_len);
!   search->domainname = domainname;
!   search->category = category;
  #ifdef HAVE_PER_THREAD_LOCALE
  # ifndef IN_LIBGLOCALE
  #  ifdef _LIBC
--- 544,555 ----
      category = LC_MESSAGES;
  #endif
  
    /* Try to find the translation among those which we found at
       some time.  */
!   search.domain = NULL;
!   search.msgid.ptr = msgid1;
!   search.domainname = domainname;
!   search.category = category;
  #ifdef HAVE_PER_THREAD_LOCALE
  # ifndef IN_LIBGLOCALE
  #  ifdef _LIBC
***************
*** 571,590 ****
  #   endif
  #  endif
  # endif
!   search->localename = localename;
  # ifdef IN_LIBGLOCALE
!   search->encoding = encoding;
  # endif
  
    /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
       tsearch calls can be fatal.  */
    gl_rwlock_rdlock (tree_lock);
  
!   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
  
    gl_rwlock_unlock (tree_lock);
  
-   freea (search);
    if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
      {
        /* Now deal with plural.  */
--- 573,591 ----
  #   endif
  #  endif
  # endif
!   search.localename = localename;
  # ifdef IN_LIBGLOCALE
!   search.encoding = encoding;
  # endif
  
    /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
       tsearch calls can be fatal.  */
    gl_rwlock_rdlock (tree_lock);
  
!   foundp = (struct known_translation_t **) tfind (&search, &root, transcmp);
  
    gl_rwlock_unlock (tree_lock);
  
    if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
      {
        /* Now deal with plural.  */
***************
*** 773,781 ****
--- 774,784 ----
              if (foundp == NULL)
                {
                  /* Create a new entry and add it to the search tree.  */
+                 size_t msgid_len;
                  size_t size;
                  struct known_translation_t *newp;
  
+                 msgid_len = strlen (msgid1) + 1;
                  size = offsetof (struct known_translation_t, msgid)
                         + msgid_len + domainname_len + 1;
  #ifdef HAVE_PER_THREAD_LOCALE
***************
*** 790,796 ****
  #endif
  
                      new_domainname =
!                       (char *) mempcpy (newp->msgid, msgid1, msgid_len);
                      memcpy (new_domainname, domainname, domainname_len + 1);
  #ifdef HAVE_PER_THREAD_LOCALE
                      new_localename = new_domainname + domainname_len + 1;
--- 793,800 ----
  #endif
  
                      new_domainname =
!                       (char *) mempcpy (newp->msgid.appended, msgid1,
!                                         msgid_len);
                      memcpy (new_domainname, domainname, domainname_len + 1);
  #ifdef HAVE_PER_THREAD_LOCALE
                      new_localename = new_domainname + domainname_len + 1;





reply via email to

[Prev in Thread] Current Thread [Next in Thread]