CS 111 Scribe notes • March 24, 2013

Problem with symbolic links

In Emacs, let's say you're editing /etc/passwd.
While the Emacs buffer contents are not equal to the file contents, Emacs creates a symbolic link:
/etc/.#passwd
with contents: eggert@penguin.z:9371
This acts as a locking mechanism and contains info about Emacs as well as a process ID (9371).

Questions:

What can go wrong?
  1. non-Emacs editors (aside: Emacs stat("/etc/passwd") before rewriting, st_mtime...)
  2. Emacs crashes (workaround: kill(9371, 0)) (failures possible)
  3. Emacs loops while holding the lock (workaround: Emacs can steal the lock)
  4. Suppose /etc/.#passwd already exists for some other reason
    If it is a regular file /etc/.#passwd/, don't lock. (we hope this is the case).
  5. Another application removes the lock file or changes what it points to. (This messes up Emacs)
  6. You haven't changed buffer yet; Someone else locks it. (stat... as in 1.)
  7. File name base (after last slash) ≥ 254 bytes. (workaround: same as 4.)
  8. Different Emacses on different hosts can interoperate. (lnxsrv03.seas.ucla.edu vs. lnxsrv01.seas.ucla.edu)
  9. MS-Windows makes symlinks hard (ie. Programs need "create symbolic links" privileges) (workaround: use regular files)

Alternatives to using symlinks for lock files

  1. fcntl(fc,F_SETLK,...) (POSIX) not in Windows, postdates Emacs, didn't work with NFS until NFSv4.
  2. Use regular files for locks
    -Peformance?
Figure 1
  1. fctl has 3 system calls
    • open(".#file")
    • read(fd,buf,bufsize)
    • close()
  2. Only 1 system call(atomic) for symbolic links: symlink(".#file",buf,bufsize)
Figure 2

$ ln -s 'eggert@27' foo
$ ln foo bar

Symbolic links are directory entries.

Figure 3

Advantages: fewer disk accesses.
Disadvantages: no hard links to symlinks.

Security issues with symbolic links

Attacker (eggert)				Victim
$ ln -s ~eggert/data /tmp/foo			umask 077
$ touch ~eggert/data				sort -o /tmp/foo
$ chmod 777 ~eggert/data			uniq /tmp/foo
$ cat ~eggert/data				rm /tmp/foo

File name resolution

open("a/b/c/foo",O_RDONLY)...

$ ls -l a/b ... a/b->x/y
Suppose a/b goes to x/y Steps: per process working directory
  1. get this process's working directory D from process table
  2. get 1st file name component C
  3. look up C in D (if none, we fail errno==ENOENT)
  4. you now have inode #I
    • is it a directory? errno==ENOTDIR
    • is it a symlink?
      • No: errno==EPERM
      • Yes: substitute symlink contents for name
  5. Set D=I and repeat from step 2
Problems?
  1. If contents start with a / (root directory vs. working directory)
  2. symlink loop (fix: counter of # symlinks traversed. Limit is 20. errno==ELOOP).
System calls Example Code:
main.c

#include <unistd.h>

int main (int argc, char ** argv) {
	chdir(argv[1]);
}
Call
$ gcc main.c -o mcd
$ ./mcd /tmp
$ cat foo

/home/eggert/playpen/usr/bin/passwd
/home/eggert/playpen/etc/passwd
chroot("/home/eggert/playpen");
system("/usr/bin/su");

Link Counts and Hard Links

Figure 4
  1. bug in system:
    • removed link but forgot to decrement link count
    • => file system will leak blocks
  2. bug: decrement link count, without removing directory entry
    • => file system has dangling ptr (undefinded behavior).
  3. link can't overflow
  4. loops of hardlinks no hardlinks to directories
Figure 5

Brief look at other file system problems

GPFS (an example big-machine file system)

120 PetaBytes from about 200,000 hard drives (600 GB hard drives for performance)

magic-gpfs-clone /gpfs /gpfs-feb25
cd /gpfs-Feb25
tar -cf /dev/tape .
↑ Top