our
$VERSION
=
'0.01'
;
sub
run_hook {
my
(
$self
,
$hook
,
@params
) =
@_
;
if
(
$hook
eq
'package-keyrings'
) {
return
(
'/usr/share/keyrings/debian-keyring.gpg'
,
'/usr/share/keyrings/debian-nonupload.gpg'
,
'/usr/share/keyrings/debian-maintainers.gpg'
);
}
elsif
(
$hook
eq
'archive-keyrings'
) {
return
(
'/usr/share/keyrings/debian-archive-keyring.gpg'
);
}
elsif
(
$hook
eq
'archive-keyrings-historic'
) {
return
(
'/usr/share/keyrings/debian-archive-removed-keys.gpg'
);
}
elsif
(
$hook
eq
'builtin-build-depends'
) {
return
qw(build-essential:native)
;
}
elsif
(
$hook
eq
'builtin-build-conflicts'
) {
return
();
}
elsif
(
$hook
eq
'register-custom-fields'
) {
}
elsif
(
$hook
eq
'extend-patch-header'
) {
my
(
$textref
,
$ch_info
) =
@params
;
if
(
$ch_info
->{
'Closes'
}) {
foreach
my
$bug
(
split
(/\s+/,
$ch_info
->{
'Closes'
})) {
}
}
my
$b
= Dpkg::Vendor::Ubuntu::find_launchpad_closes(
$ch_info
->{
'Changes'
});
foreach
my
$bug
(
@$b
) {
}
}
elsif
(
$hook
eq
'update-buildflags'
) {
$self
->_add_build_flags(
@params
);
}
elsif
(
$hook
eq
'builtin-system-build-paths'
) {
return
qw(/build/)
;
}
elsif
(
$hook
eq
'build-tainted-by'
) {
return
$self
->_build_tainted_by();
}
elsif
(
$hook
eq
'sanitize-environment'
) {
umask
0022;
$ENV
{LC_COLLATE} =
'C.UTF-8'
;
}
else
{
return
$self
->SUPER::run_hook(
$hook
,
@params
);
}
}
sub
_add_build_flags {
my
(
$self
,
$flags
) =
@_
;
my
%use_feature
= (
future
=> {
lfs
=> 0,
},
qa
=> {
bug
=> 0,
canary
=> 0,
},
reproducible
=> {
timeless
=> 1,
fixfilepath
=> 1,
fixdebugpath
=> 1,
},
sanitize
=> {
address
=> 0,
thread
=> 0,
leak
=> 0,
undefined
=> 0,
},
hardening
=> {
pie
=>
undef
,
stackprotector
=> 1,
stackprotectorstrong
=> 1,
fortify
=> 1,
format
=> 1,
relro
=> 1,
bindnow
=> 0,
},
);
my
%builtin_feature
= (
hardening
=> {
pie
=> 1,
},
);
my
$opts_build
= Dpkg::BuildOptions->new(
envvar
=>
'DEB_BUILD_OPTIONS'
);
my
$opts_maint
= Dpkg::BuildOptions->new(
envvar
=>
'DEB_BUILD_MAINT_OPTIONS'
);
foreach
my
$area
(
sort
keys
%use_feature
) {
$opts_build
->parse_features(
$area
,
$use_feature
{
$area
});
$opts_maint
->parse_features(
$area
,
$use_feature
{
$area
});
}
my
$arch
= Dpkg::Arch::get_host_arch();
my
(
$abi
,
$libc
,
$os
,
$cpu
) = Dpkg::Arch::debarch_to_debtuple(
$arch
);
unless
(
defined
$abi
and
defined
$libc
and
defined
$os
and
defined
$cpu
) {
warning(g_(
"unknown host architecture '%s'"
),
$arch
);
(
$abi
,
$os
,
$cpu
) = (
''
,
''
,
''
);
}
my
$default_flags
;
my
$default_d_flags
;
if
(
$opts_build
->
has
(
'noopt'
)) {
$default_flags
=
'-g -O0'
;
$default_d_flags
=
'-fdebug'
;
}
else
{
$default_flags
=
'-g -O2'
;
$default_d_flags
=
'-frelease'
;
}
$flags
->append(
'CFLAGS'
,
$default_flags
);
$flags
->append(
'CXXFLAGS'
,
$default_flags
);
$flags
->append(
'OBJCFLAGS'
,
$default_flags
);
$flags
->append(
'OBJCXXFLAGS'
,
$default_flags
);
$flags
->append(
'FFLAGS'
,
$default_flags
);
$flags
->append(
'FCFLAGS'
,
$default_flags
);
$flags
->append(
'GCJFLAGS'
,
$default_flags
);
$flags
->append(
'DFLAGS'
,
$default_d_flags
);
if
(
$use_feature
{future}{lfs}) {
my
(
$abi_bits
,
$abi_endian
) = Dpkg::Arch::debarch_to_abiattrs(
$arch
);
my
$cpu_bits
= Dpkg::Arch::debarch_to_cpubits(
$arch
);
if
(
$abi_bits
== 32 and
$cpu_bits
== 32) {
$flags
->append(
'CPPFLAGS'
,
'-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
);
}
}
if
(
$use_feature
{qa}{bug}) {
my
@cflags
=
qw(
implicit-function-declaration
)
;
foreach
my
$warnflag
(
@cflags
) {
$flags
->append(
'CFLAGS'
,
"-Werror=$warnflag"
);
}
my
@cfamilyflags
=
qw(
array-bounds
clobbered
volatile-register-var
)
;
foreach
my
$warnflag
(
@cfamilyflags
) {
$flags
->append(
'CFLAGS'
,
"-Werror=$warnflag"
);
$flags
->append(
'CXXFLAGS'
,
"-Werror=$warnflag"
);
}
}
if
(
$use_feature
{qa}{canary}) {
my
$id
= Digest::MD5::md5_hex(
int
rand
4096);
foreach
my
$flag
(
qw(CPPFLAGS CFLAGS OBJCFLAGS CXXFLAGS OBJCXXFLAGS)
) {
$flags
->append(
$flag
,
"-D__DEB_CANARY_${flag}_${id}__"
);
}
$flags
->append(
'LDFLAGS'
,
"-Wl,-z,deb-canary-${id}"
);
}
my
$build_path
;
if
(
$use_feature
{reproducible}{fixfilepath} or
$use_feature
{reproducible}{fixdebugpath}) {
$build_path
=
$ENV
{DEB_BUILD_PATH} || Cwd::getcwd();
if
(
$build_path
=~ m/[^-+:.0-9a-zA-Z~\/_]/) {
$use_feature
{reproducible}{fixfilepath} = 0;
$use_feature
{reproducible}{fixdebugpath} = 0;
}
}
if
(
$use_feature
{reproducible}{timeless}) {
$flags
->append(
'CPPFLAGS'
,
'-Wdate-time'
);
}
if
(
$use_feature
{reproducible}{fixfilepath} or
$use_feature
{reproducible}{fixdebugpath}) {
my
$map
;
if
(
$use_feature
{reproducible}{fixfilepath}) {
$map
=
'-ffile-prefix-map='
.
$build_path
.
'=.'
;
}
else
{
$map
=
'-fdebug-prefix-map='
.
$build_path
.
'=.'
;
}
$flags
->append(
'CFLAGS'
,
$map
);
$flags
->append(
'CXXFLAGS'
,
$map
);
$flags
->append(
'OBJCFLAGS'
,
$map
);
$flags
->append(
'OBJCXXFLAGS'
,
$map
);
$flags
->append(
'FFLAGS'
,
$map
);
$flags
->append(
'FCFLAGS'
,
$map
);
$flags
->append(
'GCJFLAGS'
,
$map
);
}
if
(
$use_feature
{sanitize}{address} and
$use_feature
{sanitize}{thread}) {
$use_feature
{sanitize}{thread} = 0;
}
if
(
$use_feature
{sanitize}{address} or
$use_feature
{sanitize}{thread}) {
$use_feature
{sanitize}{leak} = 0;
}
if
(
$use_feature
{sanitize}{address}) {
my
$flag
=
'-fsanitize=address -fno-omit-frame-pointer'
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'LDFLAGS'
,
'-fsanitize=address'
);
}
if
(
$use_feature
{sanitize}{thread}) {
my
$flag
=
'-fsanitize=thread'
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'LDFLAGS'
,
$flag
);
}
if
(
$use_feature
{sanitize}{leak}) {
$flags
->append(
'LDFLAGS'
,
'-fsanitize=leak'
);
}
if
(
$use_feature
{sanitize}{undefined}) {
my
$flag
=
'-fsanitize=undefined'
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'LDFLAGS'
,
$flag
);
}
my
%builtin_pie_arch
=
map
{
$_
=> 1 }
qw(
amd64
arm64
armel
armhf
hurd-i386
i386
kfreebsd-amd64
kfreebsd-i386
mips
mipsel
mips64el
powerpc
ppc64
ppc64el
riscv64
s390x
sparc
sparc64
)
;
if
(not
exists
$builtin_pie_arch
{
$arch
}) {
$builtin_feature
{hardening}{pie} = 0;
}
if
(
$os
!~ /^(?:linux|kfreebsd|knetbsd|hurd)$/ or
$cpu
=~ /^(?:hppa|avr32)$/) {
$use_feature
{hardening}{pie} = 0;
}
if
(
$cpu
=~ /^(?:ia64|alpha|hppa|nios2)$/ or
$arch
eq
'arm'
) {
$use_feature
{hardening}{stackprotector} = 0;
}
if
(
$cpu
=~ /^(?:ia64|hppa|avr32)$/) {
$use_feature
{hardening}{relro} = 0;
}
if
(
$opts_build
->
has
(
'noopt'
)) {
$use_feature
{hardening}{fortify} = 0;
}
if
(
$use_feature
{hardening}{relro} == 0) {
$use_feature
{hardening}{bindnow} = 0;
}
if
(
$use_feature
{hardening}{stackprotector} == 0) {
$use_feature
{hardening}{stackprotectorstrong} = 0;
}
if
(
defined
$use_feature
{hardening}{pie} and
$use_feature
{hardening}{pie} and
not
$builtin_feature
{hardening}{pie}) {
my
$flag
=
"-specs=$Dpkg::DATADIR/pie-compile.specs"
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'OBJCFLAGS'
,
$flag
);
$flags
->append(
'OBJCXXFLAGS'
,
$flag
);
$flags
->append(
'FFLAGS'
,
$flag
);
$flags
->append(
'FCFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'GCJFLAGS'
,
$flag
);
$flags
->append(
'LDFLAGS'
,
"-specs=$Dpkg::DATADIR/pie-link.specs"
);
}
elsif
(
defined
$use_feature
{hardening}{pie} and
not
$use_feature
{hardening}{pie} and
$builtin_feature
{hardening}{pie}) {
my
$flag
=
"-specs=$Dpkg::DATADIR/no-pie-compile.specs"
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'OBJCFLAGS'
,
$flag
);
$flags
->append(
'OBJCXXFLAGS'
,
$flag
);
$flags
->append(
'FFLAGS'
,
$flag
);
$flags
->append(
'FCFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'GCJFLAGS'
,
$flag
);
$flags
->append(
'LDFLAGS'
,
"-specs=$Dpkg::DATADIR/no-pie-link.specs"
);
}
if
(
$use_feature
{hardening}{stackprotectorstrong}) {
my
$flag
=
'-fstack-protector-strong'
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'OBJCFLAGS'
,
$flag
);
$flags
->append(
'OBJCXXFLAGS'
,
$flag
);
$flags
->append(
'FFLAGS'
,
$flag
);
$flags
->append(
'FCFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'GCJFLAGS'
,
$flag
);
}
elsif
(
$use_feature
{hardening}{stackprotector}) {
my
$flag
=
'-fstack-protector --param=ssp-buffer-size=4'
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'OBJCFLAGS'
,
$flag
);
$flags
->append(
'OBJCXXFLAGS'
,
$flag
);
$flags
->append(
'FFLAGS'
,
$flag
);
$flags
->append(
'FCFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'GCJFLAGS'
,
$flag
);
}
if
(
$use_feature
{hardening}{fortify}) {
$flags
->append(
'CPPFLAGS'
,
'-D_FORTIFY_SOURCE=2'
);
}
if
(
$use_feature
{hardening}{
format
}) {
my
$flag
=
'-Wformat -Werror=format-security'
;
$flags
->append(
'CFLAGS'
,
$flag
);
$flags
->append(
'CXXFLAGS'
,
$flag
);
$flags
->append(
'OBJCFLAGS'
,
$flag
);
$flags
->append(
'OBJCXXFLAGS'
,
$flag
);
}
if
(
$use_feature
{hardening}{relro}) {
$flags
->append(
'LDFLAGS'
,
'-Wl,-z,relro'
);
}
if
(
$use_feature
{hardening}{bindnow}) {
$flags
->append(
'LDFLAGS'
,
'-Wl,-z,now'
);
}
foreach
my
$area
(
sort
keys
%builtin_feature
) {
foreach
my
$feature
(
keys
%{
$builtin_feature
{
$area
}}) {
$use_feature
{
$area
}{
$feature
} //=
$builtin_feature
{
$area
}{
$feature
};
}
}
foreach
my
$area
(
sort
keys
%use_feature
) {
while
(
my
(
$feature
,
$enabled
) =
each
%{
$use_feature
{
$area
}}) {
$flags
->set_feature(
$area
,
$feature
,
$enabled
);
}
}
}
sub
_build_tainted_by {
my
$self
=
shift
;
my
%tainted
;
foreach
my
$pathname
(
qw(/bin /sbin /lib /lib32 /libo32 /libx32 /lib64)
) {
next
unless
-l
$pathname
;
my
$linkname
=
readlink
$pathname
;
if
(
$linkname
eq
"usr$pathname"
or
$linkname
eq
"/usr$pathname"
) {
$tainted
{
'merged-usr-via-aliased-dirs'
} = 1;
last
;
}
}
my
%usr_local_types
= (
configs
=> [
qw(etc)
],
includes
=> [
qw(include)
],
programs
=> [
qw(bin sbin)
],
libraries
=> [
qw(lib)
],
);
foreach
my
$type
(
keys
%usr_local_types
) {
File::Find::find({
wanted
=>
sub
{
$tainted
{
"usr-local-has-$type"
} = 1
if
-f },
no_chdir
=> 1,
},
grep
{ -d }
map
{
"/usr/local/$_"
} @{
$usr_local_types
{
$type
}});
}
my
@tainted
=
sort
keys
%tainted
;
return
@tainted
;
}
1;