#382760 dpkg reports wrong package version and status on failed upgrade of setuid file

Package:
dpkg
Source:
dpkg
Description:
Debian package management system
Submitter:
Corey Wright
Date:
2010-05-25 10:33:03 UTC
Severity:
important
#382760#5
Date:
2006-08-13 07:18:33 UTC
From:
To:
Package: dpkg
Version: 1.10.28
Severity: important
Tags: sarge

when upgrading passwd (and similarly with login) from 4.0.3-31sarge5 to
4.0.3-31sarge8, dpkg aborts with an error ("failed to rmdir/unlink
`//usr/bin/chage.dpkg-tmp': Operation not permitted"), returns an exit
status indicating an error, but dpkg lists the upgraded package as being
installed fine ("ii  passwd         4.0.3-31sarge8 change and administer
password and group dat").

the expected behavior is that dpkg should not list the new version's status
as "installed" when none of the new version's files have been installed due
to a recognized error during installation.

i chose a severity of "important" because the behavior is very misleading,
especially in the case of security updates.  (i now have to go back and
audit all previous security updates that included setuid/gid files to
insure that they truly did get upgraded.)

i set a tag of "sarge" because this behavior was observed on sarge, and
though it might also be present in etch/sid and the problem resolved
there, i want to point out that this bug exists in sarge (and imho should
remain open until fixed there).

dpkg encounters the error because it tries to chmod 600 a setuid/setgid
file before unlinking it, but cannot as the file exists within a vserver
where it is immutable (but unlinkable).  this error does not occur with
other files because dpkg does not try to chmod non-setuid/setgid files, but
instead immediately unlinks them.

please see the attached session log and strace log for more information.

the below "system information" was manually modified to reflect the server
on which the problems occurs and not the workstation on which i ran
reportbug and composed this bug report.

corey

#382760#12
Date:
2010-05-25 10:30:12 UTC
From:
To:
Hi,

The situation has evolved since then. In most cases it fails and should thus
not report the new version as installed. But there's one situation where it
only emits a warning and continues as usual... that's when the setuid file
should be removed during upgrade (i.e. it's no longer present in the newer
version). Effectively this leaves the old file around when the setuid file
should be removed from the package.

For src/processarc.c:

      if (secure_unlink_statted(fnamevb.buf, &oldfs)) {
        warning(_("unable to securely remove old file '%.250s': %s"),
                namenode->name, strerror(errno));
      }

From src/help.c:

int
secure_unlink_statted(const char *pathname, const struct stat *stab)
{
  if (S_ISREG(stab->st_mode) ? (stab->st_mode & 07000) :
      !(S_ISLNK(stab->st_mode) || S_ISDIR(stab->st_mode) ||
        S_ISFIFO(stab->st_mode) || S_ISSOCK(stab->st_mode))) {
    if (chmod(pathname, 0600))
      return -1;
  }
  if (unlink(pathname)) return -1;
  return 0;
}

I'm not sure this is any better than the situation described in this bug
report. Guillem, why not oshite() when the chmod()/unlink() fails with
errno != ENOENT much like is done at the other places where secure_unlink is
used?

Cheers,