Re: Debian bug 561991:

dpkg's commit 353b02acb33224bc2d7e3b0295538d592b9c8bad (by Guillem Jover
<guil...@debian.org> on 2009-09-30) involves comparing two things:

 a) the st_size member of a stat struct (from an lstat() call)

 b) the length of bytes returned by readlink()

When a symlink is an absolute link within the intended chroot,
libfakechroot properly edits (b) by intercepting readlink().

However, libfakechroot's interception of lstat() does not edit/intercept
the length of the returned call, so it returns the raw underlying length.

Try running attached program both within a built-out fakechroot, for
example:

> 0 wt...@pip:~/debirf/rescue/root$ bin/symlength usr/bin/touch
> usr/bin/touch -> /home/wt215/debirf/rescue/root/bin/touch
> readlink size: 40
> stat size: 40
> 0 wt...@pip:~/debirf/rescue/root$ fakechroot /usr/sbin/chroot $(pwd) 
> /bin/symlength usr/bin/touch
> usr/bin/touch -> /bin/touch
> readlink size: 10
> stat size: 40
> 0 wt...@pip:~/debirf/rescue/root$ 

The returned lstat() size differs from the readlink() size for absolute
symlinks anchored within the fakechroot.  It doesn't do this in any
other context (though this launchpad bug shows it affecting ecryptfs
too: https://bugs.launchpad.net/ubuntu/lucid/+source/dpkg/+bug/524919)

I see two possible resolutions:

 0) dpkg shouldn't assume that these values will always be identical

 1) fakechroot should verify and tweak the output of st_size when
lstat'ing a symlink if the symlink is absolute and within the fakechroot.

        --dkg
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

char buf[1024];
struct stat stab;
ssize_t sz;

/* demonstration of fakechroot failure in http://bugs.debian.org/561991

   Usage: symlength /path/to/symlink

*/

int main(int argc, char* argv[]) {
  if (argc != 2) {
    fprintf(stderr, "Usage: %s /path/to/symlink\n", argv[0]);
    return 1;
  }
  if (lstat(argv[1], &stab)) {
    fprintf(stderr, "Could not lstat %s\n", argv[1]);
    return 2;
  }
  if ((stab.st_mode & S_IFMT) != S_IFLNK) {
    fprintf(stderr, "%s is not a symlink\n", argv[1]);
    return 3;
  }
  sz = readlink(argv[1], buf, sizeof(buf));
  
  printf("%s -> %s\n", argv[1], buf);
  printf("readlink size: %d\n", sz);
  printf("stat size: %d\n", (int)stab.st_size);
  return 0;
}

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to