[net.bugs.usg] Bug in who

jrw@hropus.UUCP (Jim Webb) (01/24/86)

> I discovered something MIGHTY INTERESTING the other day while logged-in as
> root on a 3B2/300 running Sys5r2.  I tried and repeated it on a 3B2/400
> running the same.
> 
> # pwd
> /usr/foobar
> # ls
> file1
> file2
> file3
> # who -b .
> # ls
> . not found
> # cd ..
> ..: bad directory
> # cd /usr
> # ls | grep foobar
> #
> 
> I cannot repeat this as an ordinary user even on a directory which I own
> and which I own the parent of and have write permission on both.  It looks
> much like an unlink() is somehow getting done on the argument of the
> "who -b" but since I don't have source for the 3B2 "who," I don't know
> for sure.  Could someone check this out for me?  When this happened,
> even fsck could not retrieve the lost files (arrrrgh!!!!), it just complained
> about "bad free list".  The '.' was a typo (shaky hands) but it sure caused
> me a lot of headaches from a command that SURELY must be nondestructive :-).
> 
> Thanks of course, well in advance.
> -- 
>  -------------------------------    Disclaimer:  The views contained herein are
> |       dan levy | yvel nad      |  my own and are not at all those of my em-
> |         an engihacker @        |  ployer or the administrator of any computer
> | at&t computer systems division |  upon which I may hack.
> |        skokie, illinois        |
>  --------------------------------   Path: ..!ihnp4!ttrdc!levy

HMM, intriguing little bug you found.  I tried this on all of my SVR2 machines,
not only 3B2's, and had SIMILAR findings.  The problem lies in the utmp library
routines.  This is what is going on:  

	1)  who calls utmpname with argument "." to change it from /etc/utmp
	2)  getutent does a check on this "." and sees that it is NOT
	    a file filled with utmp-structures, SO...
	3)  it unlinks it and then links it again, thus creating a new one.

		!!! NOT GOOD IF YOU ARE ROOT !!!


Anyway, all is not lost, and you CAN get all of your files back, so
sorry about the following long narrative, but here we go...

# cd /tmp
# mkdir foobar
# cd foobar 
# >file1
# >file2
# >file3
# ls -lai
total 10
   57 drwxr-xr-x   2 root     sys           80 Jan 24 12:54 .
    2 drwxrwxrwx   7 root     root        4480 Jan 24 12:54 ..
   83 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file1
   12 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file2
   69 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file3
# cd ..
# ls -lai foobar
total 10
   57 drwxr-xr-x   2 root     sys           80 Jan 24 12:54 .
    2 drwxrwxrwx   7 root     root        4480 Jan 24 12:54 ..
   83 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file1
   12 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file2
   69 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file3
# od -c foobar
0000000   9  \0   .  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020 002  \0   .   .  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040   S  \0   f   i   l   e   1  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000060  \f  \0   f   i   l   e   2  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000100   E  \0   f   i   l   e   3  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000120
# cd foobar


****  THE FUN STARTS HERE ****


# who -b .



****  who -b . just created a file with the name . in the current directory ****


# ls -la
-rw-r--r--   1 root     sys            0 Jan 24 12:55 .

# od -c .
0000000
# cd ..
# od -c foobar
0000000   ^  \0   .  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  ** YUK ! **
0000020 002  \0   .   .  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040   S  \0   f   i   l   e   1  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000060  \f  \0   f   i   l   e   2  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000100   E  \0   f   i   l   e   3  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000120
# ls -l foobar
total 0
-rw-r--r--   1 root     sys            0 Jan 24 12:54 file1
-rw-r--r--   1 root     sys            0 Jan 24 12:54 file2
-rw-r--r--   1 root     sys            0 Jan 24 12:54 file3
# cd foobar

**** WHEN NOT GIVEN AN ARGUMENT, ls LISTS . WHICH IS NORMALLY A DIRECTORY ****

# ls -la
-rw-r--r--   1 root     sys            0 Jan 24 12:55 .
# cd ..

**** link and unlink are in /etc.  ONLY root can run them, as ALL error checking
**** is removed ...

# unlink foobar/.
# link foobar foobar/.
# ls -lai foobar
total 10
   57 drwxr-xr-x   2 root     sys           80 Jan 24 12:56 .
    2 drwxrwxrwx   7 root     root        4480 Jan 24 12:56 ..
   83 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file1
   12 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file2
   69 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file3
# cd foobar
# ls -lai
total 10
   57 drwxr-xr-x   2 root     sys           80 Jan 24 12:56 .
    2 drwxrwxrwx   7 root     root        4480 Jan 24 12:56 ..
   83 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file1
   12 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file2
   69 -rw-r--r--   1 root     sys            0 Jan 24 12:54 file3
# od -c .
0000000   9  \0   .  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000020 002  \0   .   .  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000040   S  \0   f   i   l   e   1  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000060  \f  \0   f   i   l   e   2  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000100   E  \0   f   i   l   e   3  \0  \0  \0  \0  \0  \0  \0  \0  \0
0000120


The reason fsck came back with normal results was because the files were in
fact still there.  The reason I was able to cd about was because I was running
ksh, which does not look at . and .. too often (it looks at $PWD).  If you
just do the links and unlinks as above, you will be able to get to your files.
In fact, you can still get to them now if you want, but then you won't be able
to do much with that pesky .-less directory.
-- 
Jim Webb                                        ihnp4!houxm!hropus!jrw

doug@ides.UUCP (Douglas J. Wait) (01/29/86)

If a file parameter is passed to who(1) and the file is not a multiple of
sizeof(struct utmp) the file will be unlinked.  An empty file of the same
name will be created.  This will also happen using the getut(3C) functions.

The reason you can not repeat the problem with a directory under a non-root
user is that only root can remove a directory.

The other options, such as -b, have nothing to do with the file truncation.

Hope this helps!
-- 

			Doug Wait
			AT&T Information Systems
			200 Lincon
			Maitland, FL 32751
			(305)660-6460

			..!{akgua,ihnp4,abcom}!abfli!doug

			"Is anyBODY OUT there..."