Bug 291870 (CVE-2007-4135) - VUL-0: CVE-2007-4135: bug in nfsidmap 0.12
Summary: VUL-0: CVE-2007-4135: bug in nfsidmap 0.12
Status: RESOLVED FIXED
Alias: CVE-2007-4135
Product: SUSE Security Incidents
Classification: Novell Products
Component: Incidents (show other bugs)
Version: unspecified
Hardware: Other SLES 10
: P5 - None : Major
Target Milestone: ---
Assignee: Marcus Meissner
QA Contact: Security Team bot
URL:
Whiteboard: CVE-2007-4135: CVSS v2 Base Score: 6....
Keywords:
Depends on:
Blocks:
 
Reported: 2007-07-13 16:57 UTC by Tony Ernst
Modified: 2021-09-27 08:48 UTC (History)
7 users (show)

See Also:
Found By: Third Party Developer/Partner
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tony Ernst 2007-07-13 16:57:28 UTC
SuSE ships libnfsidmap based on version 0.12 which has a flaw in it's name-->uid translations.  This as it is causing problems in NFSv4 name lookups.

# rpm -q nfsidmap   
nfsidmap-0.12-16.12

This is a bug in the version of nfsidmap that ships with SLES10 SP1.  idmapd will eventually call nfs4_name_to_uid which will eventually work it's way to this code:

static struct passwd *nss_getpwnam(const char *name, const char *domain, int *err_p)
{
	struct passwd *pw;
	struct pwbuf *buf;
	size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
	char *localname;
	int err = ENOMEM;

	buf = malloc(sizeof(*buf) + buflen);
	if (buf == NULL)
		goto err;

	err = EINVAL;
	localname = strip_domain(name, domain);
	if (localname == NULL)
		goto err_free_buf;
                                 
	err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw);
         ^------will be 0 when name not found                       ^
                        will be NULL when name not found------------|   
	free(localname);
	if (err == 0 && pw != NULL) {  <---notice no handling for err==0 && pw==NULL
		*err_p = 0;
		return pw;
	}
err_free_buf:
	free(buf);
err:
	*err_p = -err;  <---here's the problem, -0 is still 0
	return NULL;
}

So the problem is that this version of getpwnam_r does not return an error code if the requested name does not exist in /etc/passwd, it sets pw to NULL.  This code tries to account for that but obviously forgets that the error code will still be zero in that case.  So the calling routine is this:

static int nss_name_to_uid(char *name, uid_t *uid)
{
	struct passwd *pw = NULL;
	char *domain;
	int err = -EINVAL;

	domain = get_default_domain();
	pw = nss_getpwnam(name, domain, &err);
	if (pw == NULL)  <--correctly detects we didn't get anything back 
                            from getpwnam_r
		goto out; <---oops, this will make us return with the current
                              value of err, which is 0
	*uid = pw->pw_uid;
	free(pw);
	err = 0;
out:
	return err;
}

So all the higher layers think everything went fine and use the bogus data in the pw struct, which happens to be 0 in this case which causes it to be mapped to root.  Please note that this could have security implications.

CITI has fixed this in version 0.17.
Comment 1 Marcus Meissner 2007-07-17 11:19:09 UTC
First, getpwnam_r returns 0 on success. check the manpage.


0.20 has this hunk:

+       } else if (err == 0 && pw == NULL) {
+               err = ENOENT;

additionaly.
Comment 4 Anja Stock 2007-07-17 14:06:05 UTC
SWAMPID is 11215
Comment 5 Brett Grandbois 2007-07-17 21:57:44 UTC
>First, getpwnam_r returns 0 on success. check the manpage.

Yes it does.  And the manpage also points out:
 
"The  formulation  given  above under "RETURN VALUE" is from POSIX.1-2001.  It does not call "not found" an error, and hence does not specify what value errno might  have in this situation. But that makes it impossible to recognize errors. One might argue that according to POSIX errno should be left unchanged if an entry is  not  found.  Experiments  on  various  Unix-like systems show that lots of different values occur in this situation: 0, ENOENT, EBADF, ESRCH, EWOULDBLOCK, EPERM and probably others."

Which experiment shows SP1 returns 0 when it can not find an entry as well
as setting pwbufp to NULL.  So obviously both need to be checked for the case
of an entry not existing, which the 0.12 version does not do correctly.  

The fix mentioned above first went in in version 0.17 but 0.20 is the current
and should be used as the new basis.
Comment 6 Marcus Meissner 2007-07-18 06:17:19 UTC
we usually do not do version updates in between service packs.

I have added the 2 lines shown in comment #c1 to the package.
Comment 7 Marcus Meissner 2007-08-14 13:36:40 UTC
in qa
Comment 8 Andrej Semen 2007-08-14 13:56:15 UTC
could you provide me an bug fix test to this bug? 
To reproduce the bug for qa maintenance reasons.
Comment 10 Marcus Meissner 2007-08-15 14:05:13 UTC
server and client. client is sles10sp1 test target.

"rcidmap start" on both.

On server (setup once):

/etc/exports contains a NFSv4 export:
   /foo   *.suse.de(rw,fsid=0)

A new user was created which does NOT exist on client.
   useradd -m tux2
   touch /foo/foo
   chown tux2:users /foo/foo


On the client:
  mkdir /test
  mount -t nfs4 server:/foo /test

BEFORE (BROKEN):
  ls -l /test
  -rw-r--r-- 1 root users .... foo

AFTER (GOOD):
  -rw-r--r-- 1 nobody users .... fooo

(non existing users should be shown as nobody)


You can use "grape.suse.de" as already setup server so you just need to do
the client testing:

   mkdir /test
   mount -t nfs4 grape.suse.de:/foo /test
   ls -la /test

to check whether its ok.
Comment 11 Marcus Meissner 2007-08-15 15:21:18 UTC
make that:

mkdir /test
mount -t nfs4 grape.suse.de:/ /test
ls -la /test
Comment 12 Andrej Semen 2007-08-15 16:09:55 UTC
thanks that helped a lot.

for start see comment #10 use:

rcidmapd start
Comment 13 Anja Stock 2007-08-20 14:01:57 UTC
released
Comment 14 Marcus Meissner 2007-08-24 08:15:28 UTC
CVE-2007-4135
Comment 15 Thomas Biege 2009-10-13 23:35:32 UTC
CVE-2007-4135: CVSS v2 Base Score: 6.2 (AV:L/AC:H/Au:N/C:C/I:C/A:C)