[debhelper-devel] "Rules-Requires-Root: no" vs ExtUtils::Install + dh_strip_nondeterminism

Axel Beckert abe at debian.org
Sat Oct 28 01:37:52 UTC 2017


Hi,

I just tried to build systray-mdstat (a Perl-written application which
uses Dist::Zilla as build-system) with "Rules-Requires-Root: no" and
it FTBFS as follows:

>    dh_strip_nondeterminism
> dh_strip_nondeterminism: debian/systray-mdstat/usr/share/perl5/auto/share/dist/systray-mdstat/harddrivespare.png: debian/systray-mdstat/usr/share/perl5/auto/share/dist/systray-mdstat/harddrivespare.png: open: Permission denied at /usr/share/perl5/File/StripNondeterminism/handlers/png.pm line 60.
>
> debian/rules:5: recipe for target 'binary' failed
> make: *** [binary] Error 13
> dpkg-buildpackage: error: debian/rules binary subprocess returned exit status 2

The file in question is read-only, but belongs to the user trying to
build the package:

-r--r--r-- 1 abe abe 1749 Oct 27 22:48 debian/systray-mdstat/usr/share/perl5/auto/share/dist/systray-mdstat/harddrivespare.png

But these read-only permissions are not coming from the source file,
because in the source package it has "normal" permissions:

-rw-r--r-- 1 abe abe 1749 Feb 15  2017 share/harddrivespare.png

The file is installed using a Makefile generated by Perl's
ExtUtils::MakeMaker module (whose Makefile.PL again is generated by
Dist::Zilla). So the "strange" read-only permissions must come from
that installation routine.

Then again, if I build the package again without "Rules-Requires-Root:
no", the file is no more read-only, but has the expected 644
permissions:

-rw-r--r-- 1 abe abe 1749 Oct 27 23:20 debian/systray-mdstat/usr/share/perl5/auto/share/dist/systray-mdstat/harddrivespare.png

So on a first glance it seemed as if ExtUtils::MakeMaker uses
different permissions in the install target depending on the executing
user: If root is running the install target, the permissions are 644,
otherwise the permissions are 444.

The same strange behaviour with permissions seem to happen for scripts
I install into /usr/bin/.

So IMHO it's not dh_strip_nondeterminism's fault, also because it
perl's open() which indeed does bail out on trying to write to files
with 444 (i.e. read-only) permissions (at least as unprivileged user).

I suspect that this fact will more or less affect most perl-based
packages (as ExtUtils::MakeMaker is the most common build-system for
Perl modules and applications) and we can't move them easily to
"Rules-Requires-Root: no" without fixes inside debhelper or
per-package workarounds.

The culprit seems to be in ExtUtils::Install (part of
ExtUtils::MakeMaker) in the pm_to_blib() around line 1215 when the
files are copied to build directory blib:

   1215         my($mode,$atime,$mtime) = (stat $from)[2,8,9];
   1216         utime($atime,$mtime+$Is_VMS,$to);
   1217         _chmod(0444 | ( $mode & 0111 ? 0111 : 0 ),$to);

Also involved seems ExtUtils::MakeMaker's install() subroutine which
later copies files from blib/ to $DESTDIR/$PREFIX/ which again has
similar code which looks like a hardcoded 0444 plus executable bit
where necessary:

    812                 $mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
    813                 $mode = $mode | 0222
    814                     if $realtarget ne $targetfile;
    815                 _chmod( $mode, $targetfile, $verbose );

So this issue very likely affects a big percentage of all Perl
packages (if we want to switch them to "Rules-Requires-Root: no", too)
as ExtUtils::MakeMaker is one of the most popular if not the most
popular build system in the Perl world.

But that again neither does explain why it has the expected settings
when running under root or fakeroot as in both cases the only possible
modes seem either 0444 or 0555.

After quite some debugging I noticed that calling the chmod syscall
under fakeroot doesn't have an effect even if chmod's actions wouldn't
have needed root permissions. And hence all chmod calls made by "make
install" are moot. Accordingly under fakeroot the resulting files have
0644 (as after copying the files) instead of 0444 (when the chmod
calls had an effect). This also implies that the permissions running
under real root might be different that under fakeroot. But I suspect,
dh_fixperms fixes this later.

So one possibility to fix this would be to run dh_fixperms before
dh_strip_nondeterminism, but if I look at the current sequence, I
think there's not much of a chance to change it:

   dh_strip_nondeterminism
   dh_compress
   dh_fixperms

It seems obvious to me that dh_compress needs to come after
dh_strip_nondeterminism as well as that dh_fixperms needs to come
after dh_compress.

So a better but not so efficient way to fix this would be calling
dh_fixperms twice: Once before dh_strip_nondeterminism and once after
dh_compress.

And indeed, systray-mdstat with "Rules-Requires-Root: no" builds fine
if I add this override to debian/rules:

> override_dh_strip_nondeterminism:
>  	dh_fixperms
> 	dh_strip_nondeterminism

Anyone another idea how to fix this in general and (more efficient)
inside debhelper?

		Regards, Axel
-- 
 ,''`.  |  Axel Beckert <abe at debian.org>, https://people.debian.org/~abe/
: :' :  |  Debian Developer, ftp.ch.debian.org Admin
`. `'   |  4096R: 2517 B724 C5F6 CA99 5329  6E61 2FF9 CD59 6126 16B5
  `-    |  1024D: F067 EA27 26B9 C3FC 1486  202E C09E 1D89 9593 0EDE



More information about the debhelper-devel mailing list