xorl %eax, %eax

CVE-2009-0887: Linux-PAM Singedness Issue

leave a comment »

Linux PAM is a popular authentication mechanism which you almost certainly already know. It can be used in a variety of applications and it is included in the Linux OS. On March 2009, Marcus Granado reported a vulnerability on libpam. It affects libpam up to 1.0.3 release, the code presented herein is from this library’s release. Here is the buggy routine:

47 char *_pam_StrTok(char *from, const char *format, char **next)
48 /*
49  * this function is a variant of the standard strtok, it differs in that
50  * it takes an additional argument and doesn't nul terminate tokens until
51  * they are actually reached.
52  */
53 {
54      char table[256], *end;
55      int i;

This function is located at libpam/pam_misc.c and its comment is pretty descriptive. This is used mainly on parsing of configuration files and this is why this isn’t such a big issue since only superuser can (ab)use it. The first signedness issue appears at line 62, here is the code:

60      /* initialize table */
61      for (i=1; i<256; table[i++] = '');
62      for (i=0; format[i] ; table[(int)format[i++]] = 'y');

As you can see, it casts the format array which is a signed constant character pointer to a signed integer. This may result on a negative integer if for example format[i++] contains some Unicode character, and consequently, this will lead to writing ‘y‘ out of bounds, before the actual table[] array. This was simply fixed like this:

      /* initialize table */
      for (i=1; i<256; table[i++] = '');
-     for (i=0; format[i] ; table[(int)format[i++]] = 'y');
+     for (i=0; format[i] ;
+      table[(unsigned char)format[i++]] = 'y');

Now it can only contain values between 0-255 since it uses unsigned character to cast it. The next signdness issue was at line 65. Here it is:

64      /* look for first non-format char */
65      while (*from && table[(int)*from]) {
66           ++from;
67      }

Again, variable from which is a signed character pointer and used as index of table[] is now translated into a signed integer allowing it to have negative values and read out of bounds of the table[] array. Again, the fix was this:

      /* look for first non-format char */
-     while (*from && table[(int)*from]) {
+     while (*from && table[(unsigned char)*from]) {

The final signedness issue of this function was at line 95. The vulnerability is more or less the same as the previously discussed ones.

91          /* note, this string is stripped of its edges: "..." is what
92             remains */
93      } else if (*from) {
94          /* simply look for next blank char */
95          for (end=from; *end && !table[(int)*end]; ++end);
96      } else {
97          return (*next = NULL);                    /* no tokens left */
98      }

When it attempts to search for blank characters at line 95, it once again casts end (which is a signed character pointer) into a signed integer leaving the same bug of reading out of bounds of table[] buffer. Here is the patch for this one too:

      /* simply look for next blank char */
-     for (end=from; *end && !table[(int)*end]; ++end);
+     for (end=from; *end && !table[(unsigned char)*end]; ++end);
      } else {
      return (*next = NULL);                    /* no tokens left */

This is nothing to really worry about since it can be triggered only by superuser since the above routine is called only by the following two functions:

static int _pam_parse_conf_file(pam_handle_t *pamh, FILE *f
                                , const char *known_service /* specific file */
                                , int requested_module_type /* specific type */
                                , int stack_level /* level of substack */
                                , int not_other
#endif /* PAM_READ_BOTH_CONFS */

/* Generate argv, argc from s */
/* caller must free(argv)     */
int _pam_mkargv(char *s, char ***argv, int *argc)

Written by xorl

March 26, 2009 at 14:12

Posted in bugs, linux

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s