File: //usr/share/perl5/File/StripNondeterminism/handlers/uimage.pm
#
# Copyright 2016 Evgueni Souleimanov
#
# This file is part of strip-nondeterminism.
#
# strip-nondeterminism is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# strip-nondeterminism is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with strip-nondeterminism. If not, see <http://www.gnu.org/licenses/>.
#
package File::StripNondeterminism::handlers::uimage;
use strict;
use warnings;
use Archive::Zip ();
use File::StripNondeterminism;
use Fcntl q/SEEK_SET/;
=head1 DEPRECATION PLAN
As of 2020-04-30 there are zero .uimage files being shipped in Debian packages
so this handler is a good candidate to commence deprecation via first making it
optional, etc., perhaps surveying whether any embedded distributions could be
relying on this.
Also see the uimage handler.
=cut
# /*
# * Legacy format image header,
# * all data in network byte order (aka natural aka bigendian).
# */
# typedef struct image_header {
# uint32_t ih_magic; /* Image Header Magic Number */
# uint32_t ih_hcrc; /* Image Header CRC Checksum */
# uint32_t ih_time; /* Image Creation Timestamp */
# uint32_t ih_size; /* Image Data Size */
# uint32_t ih_load; /* Data Load Address */
# uint32_t ih_ep; /* Entry Point Address */
# uint32_t ih_dcrc; /* Image Data CRC Checksum */
# uint8_t ih_os; /* Operating System */
# uint8_t ih_arch; /* CPU architecture */
# uint8_t ih_type; /* Image Type */
# uint8_t ih_comp; /* Compression Type */
# uint8_t ih_name[IH_NMLEN]; /* Image Name */
#} image_header_t;
use constant IH_MAGIC => 0x27051956;
use constant IH_NMLEN => 32;
use constant IH_HEADERLEN => 64; # 7 * 4 + 4 + 32
sub crc {
my ($data) = @_;
return Archive::Zip::computeCRC32($data);
}
sub is_uimage_fh {
my ($fh) = @_;
my $hdr;
my $bytes_read = sysread($fh, $hdr, IH_HEADERLEN);
return 0 unless $bytes_read == IH_HEADERLEN;
my ($ih_magic, $ih_hcrc) = unpack('NN', $hdr);
# If this is a uImage file, first 64 bytes will contain the signature
return 0 unless $ih_magic == IH_MAGIC;
return 1;
}
sub is_uimage_file {
my ($filename) = @_;
my $fh;
return open($fh, '<', $filename) && is_uimage_fh($fh);
}
sub normalize {
my ($filename) = @_;
my $hdr;
open(my $fh, '+<', $filename)
or die("failed to open $filename for read+write: $!");
binmode($fh);
my $bytes_read = sysread($fh, $hdr, IH_HEADERLEN);
return 0 unless $bytes_read == IH_HEADERLEN;
my ($ih_magic, $ih_hcrc, $ih_time, $ih_size,
$ih_load, $ih_ep, $ih_dcrc, $ih_os_arch_type_comp,
$ih_name_0, $ih_name_1, $ih_name_2, $ih_name_3,
$ih_name_4, $ih_name_5, $ih_name_6, $ih_name_7) =
unpack('NNNNNNNNNNNNNNNN', $hdr);
return 0 unless $ih_magic == IH_MAGIC;
## Generate header with ih_hcrc == 0 for checksum verification
my $hdr_comp = pack('NNNNNNNNNNNNNNNN',
$ih_magic, 0, $ih_time, $ih_size,
$ih_load, $ih_ep, $ih_dcrc, $ih_os_arch_type_comp,
$ih_name_0, $ih_name_1, $ih_name_2, $ih_name_3,
$ih_name_4, $ih_name_5, $ih_name_6, $ih_name_7);
my $crc_comp = crc($hdr_comp);
return 0 unless $crc_comp == $ih_hcrc;
my $ih_time_orig = $ih_time;
unless ($ih_time == 0) { # Don't set a deterministic timestamp if there wasn't already a timestamp
if (defined $File::StripNondeterminism::canonical_time) {
if (!$File::StripNondeterminism::clamp_time || $ih_time > $File::StripNondeterminism::canonical_time) {
$ih_time = $File::StripNondeterminism::canonical_time;
}
} else {
$ih_time = 0; # 0 is "no timestamp"
}
}
return 0 if $ih_time == $ih_time_orig;
## Generate header with ih_hcrc == 0 for checksum computation
my $hdr_new = pack('NNNNNNNNNNNNNNNN',
$ih_magic, 0, $ih_time, $ih_size,
$ih_load, $ih_ep, $ih_dcrc, $ih_os_arch_type_comp,
$ih_name_0, $ih_name_1, $ih_name_2, $ih_name_3,
$ih_name_4, $ih_name_5, $ih_name_6, $ih_name_7);
my $crc_new = crc($hdr_new);
## Generate header with ih_hcrc == $crc_new
$hdr_new = pack('NNNNNNNNNNNNNNNN',
$ih_magic, $crc_new, $ih_time, $ih_size,
$ih_load, $ih_ep, $ih_dcrc, $ih_os_arch_type_comp,
$ih_name_0, $ih_name_1, $ih_name_2, $ih_name_3,
$ih_name_4, $ih_name_5, $ih_name_6, $ih_name_7);
seek $fh, 0, SEEK_SET;
syswrite ($fh, $hdr_new, IH_HEADERLEN);
return 1;
}
1;