[1438] in linux-security and linux-alert archive
[linux-security] Re: Re: GNU tar vulnerability
daemon@ATHENA.MIT.EDU (Dave Kinchlea)
Thu Feb 6 07:34:29 1997
Date: Wed, 5 Feb 1997 13:48:41 -0800 (PST)
From: Dave Kinchlea <security@kinch.ark.com>
To: "linux-security@redhat.com" <linux-security@redhat.com>
cc: "bugtraq@netspace.org" <bugtraq@netspace.org>,
bug-gnu-utils@prep.ai.mit.edu
In-Reply-To: <199702031750.LAA30637@pop2a.mail.mci.com>
Resent-From: linux-security@redhat.com
Reply-To: linux-security@redhat.com
There is some debate as to whether this is a bug or not, in my view it
is and so I supply a patch for those that want to fix it.
Discussion:
GNU tar extends the standard tar format to include names for
owner and group AS WELL AS UID/GID values in the header. The intent is
to be able to restore files under the correct user name when run by
root. The problem is that the names take precedence over the uid/gid
EVEN IF they are nonexistent on the system extracting the files. So,
when root goes to extract a file with names used in the header and those
names are not found, those files get owned by root and not by the
uid/gid of the underlying file. This problem is compounded when the file
in the archive is setuid, the extracted file becomes a setuid(root) file
which is surely not what is expected.
Rather than try to determine when to remove the setuid bit and
when not to, I decided that the Right Answer is to honour the UID/GID
pair in the header if the names used in the header is a nonexistent
user/group.
[mod: about 5 people reported the same without taking the trouble to
write the patch. Good work Dave! -- REW]
--- tar-1.11.8/src/list.c.orig 1997/02/05 21:10:10 1.1
+++ tar-1.11.8/src/list.c 1997/02/05 21:43:51
@@ -414,6 +414,9 @@
decode_header (register union record *header, register struct stat *st,
int *stdp, int wantug)
{
+ int saveuid;
+ int savegid;
+
st->st_mode = from_oct (8, header->header.mode);
st->st_mode &= 07777;
st->st_mtime = from_oct (1 + 12, header->header.mtime);
@@ -435,13 +438,22 @@
st->st_uid = from_oct (8, header->header.uid);
st->st_gid = from_oct (8, header->header.gid);
#else
+ /*
+ * if there is a name saved and it produces a non-root uid from
+ * finduid(), use that value otherwise fall back to using the
+ * uid from the header. This saves tar from making inappropriate
+ * setuid(root) files from nonexistent users
+ */
+
st->st_uid =
(*header->header.uname
- ? finduid (header->header.uname)
+ ? saveuid=finduid (header->header.uname)
+ ? saveuid : from_oct (8, header->header.uid)
: from_oct (8, header->header.uid));
st->st_gid =
(*header->header.gname
- ? findgid (header->header.gname)
+ ? savegid=findgid (header->header.gname)
+ ? savegid : from_oct (8, header->header.gid)
: from_oct (8, header->header.gid));
#endif
}