Go to main content

man pages section 3: Extended Library Functions, Volume 1

Exit Print View

Updated: Wednesday, July 27, 2022
 
 

elf32_sign_range(3ELF)

Name

elf32_sign_range, elf64_sign_range, elf32_checksum, elf64_checksum - return a signature range, or checksum of an elf image

Synopsis

cc [ flag ... ] file ... –lelf [ library ... ]
#include <libelf.h>

int elf32_sign_range(Elf *elf, elf_sign_range_cb_func cb,
    Elf_Signrange type, void *udata);
int elf64_sign_range(Elf *elf, elf_sign_range_cb_func cb,
    Elf_Signrange type, void *udata);
typedef void (* elf_sign_range_cb_func)(size_t offset, size_t size,
    void *udata);
long elf32_checksum(Elf *elf);
long elf64_checksum(Elf *elf);

Description

The elf32_sign_range() and elf64_sign_range() functions provide data ranges of the image identified by elf that should be processed to produce a hash of the image contents.

A hash can be used to generate a signature or checksum of the file. A signature or checksum can be used to compare different versions of a given file. A signature or checksum can also be written back to the file in a manner that does not alter the hashed value, thus facilitating easy comparisons between files.

In each case, the data range used to generate a hash can be targeted toward the type of ELF file. When writing a signature or checksum to a file, the data included in the hash must accommodate the file being updated after the hash has been created. In addition, dynamic objects may also undergo post-processing, where non-allocatable sections are removed, added, or changed. Hence, certain items of ELF data must be omitted from the hash calculation so that the hash value remains valid should these post-processing operations occur.

elf32_sign_range() and elf64_sign_range() are designed for ELF files created using libelf(3LIB). See NOTES.

elf32_sign_range() and elf64_sign_range() provide one or more data ranges that are appropriate to the ELF file, and separate any ELF data that must be omitted from the hash calculation. These data ranges are conveyed to the caller through the elf_sign_range_cb_func call back function. See EXAMPLES.

The data range desired is defined by the type.

ELF_SR_INTERPRET

The type of the elf file is used to determine the appropriate data ranges.

For dynamic executables and shared objects, the data range is derived from the file program header information. Effectively, the data ranges define the data associated with the memory image of the file that is created when the file is used to create an executing process.

For relocatable objects, the data range is derived from the files section header information, rather than the program header information.

Any existing SHT_SUNW_SIGNATURE section is omitted from the supplied data ranges. For dynamic executables and shared objects, this section is omitted as it typically is not associated with the memory image. For relocatable objects, this section is explicitly ignored.

ELF_SR_INTERPRET is appropriate for hashing the data of a file that is significant to the files eventual use. This hash value is suitable for generating a SHT_SUNW_SIGNATURE section that can added to the file. A subsequent ELF_SR_INTERPRET request of the file produces the same hash value, thus providing the foundation for cryptographic signature verification.

When processing a relocatable object, ELF_SR_INTERPRET is equivalent to using ELF_SR_RELOBJ.

ELF_SR_SIGNED_INTERPRET

The data range is the same as ELF_SR_INTERPRET, with the addition of any SHT_SUNW_SIGNATURE section data.

ELF_SR_SIGNED_INTERPRET is appropriate for hashing the data of a file that is significant to the files eventual use, including the signature, and using the generated signature or checksum for future release management.

ELF_SR_RELOBJ

The data range is derived as if the object was interpreted as a relocatable object. The data range is derived from the files section header information, rather than the program header information. Any SHT_SUNW_SIGNATURE section is explicitly omitted.

ELF_SR_RELOBJ is appropriate for hashing all the data of a file. This hash value is suitable for generating a SHT_SUNW_SIGNATURE section that can be added to the file. A subsequent ELF_SR_RELOBJ request of the file produces the same hash value.

ELF_SR_FILE

The data range encompasses the data in the whole file without regard to any ELF structures that may be present.

For all interpretation types besides ELF_SR_FILE, data ranges are established from the ELF data of the file. As ELF_SR_FILE captures the whole file, any data that might exist outside the ELF file image is captured in the data range. For example, ELF_SR_FILE captures any data that might be concatenated to the end of an ELF file image.

ELF_SR_CHECKSUM

The data range is similar to ELF_SR_RELOBJ, however certain dynamic information is skipped, such as the SHT_DYNAMIC and SHT_SUNW_ancillary sections.

ELF_SR_CHECKSUM is used by ld(1), to update the associated dynamic information with a simple checksum when creating an ELF file.

Data ranges are provided to the elf_sign_range_cb_func call back function. These ranges are identified as an offset from the start of the file, and the size of the number of bytes that comprise the range.

The udata supplied to elf32_sign_range() and elf64_sign_range() is provided to the call back. This udata points to a data item that coordinates the collection of a checksum or signature, and should contain a pointer to the raw file image. This exclusive image is recommended, rather than using any underlying image that might be created from elf_begin(3ELF). This latter image can be transformed as a result of inspecting data though libelf(3LIB) routines, which can compromise the checksum computation.

The udata can then be used to accumulate a checksum or signature from the various data ranges. See EXAMPLES.

The elf32_checksum() and elf64_checksum() functions return a simple checksum of the image identified by elf. These functions use elf32_sign_range() and elf64_sign_range() respectively, with the ELF_SR_CHECKSUM type. The checksum is typically used as the SHT_DYNAMIC section tag DT_CHECKSUM, and SHT_SUNW_ancillary section elements, that can be recorded in dynamic objects.

Return Values

elf32_sign_range() and elf64_sign_range() return 1 on success, or 0 if the ELF image is determined to be invalid. elf32_checksum() and elf64_checksum() return a checksum on success, or 0 if the ELF image is determined to be invalid.

Examples

Example 1 Calculate a Simple Checksum of an ELF File

This program demonstrates the use of the sign-range routines to obtain a simple checksum. Effectively, this program mimics the checksum functions that are implemented internally using this approach.

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <libelf.h>
#include <gelf.h>

typedef struct {
        char    *s_addr;
        ulong_t s_sum;
} Sum;

static void
callback(size_t offset, size_t size, void *udata)
{
        Sum     *sum = (Sum *)udata;
        char    *addr = sum->s_addr + offset;

        while (size--)
                sum->s_sum += *addr++ & 0xff;
}

#define MSW(l)  (((l) >> 16) & 0x0000ffffL)
#define LSW(l)  ((l) & 0x0000ffffL)

int
main(int argc, char *argv[])
{
        char            *addr;
        int             fd;
        Elf             *elf;
        Sum             sum;
        struct stat     status;

        if ((fd = open(argv[1], O_RDONLY, 0)) == −1)
                return (1);

        (void) elf_version(EV_CURRENT);

        /* Assign an ELF descriptor to the file */
        if (((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) ||
            (elf_kind(elf) != ELF_K_ELF))
                return (1);

        /* Establish a mapping for obtaining the checksum */
        if ((fstat(fd, &status) == -1) ||
            ((addr = mmap(NULL, status.st_size, PROT_READ,
            MAP_PRIVATE, fd, 0)) == MAP_FAILED))
                return (1);

        /* Initialize checksum data */
        sum.s_addr = addr;
        sum.s_sum = 0;

        /* Accumulate checksum from data ranges via callback() */
        if (gelf_getclass(elf) == ELFCLASS32) {
                if (elf32_sign_range(elf, callback, ELF_SR_CHECKSUM,
                   &sum) == 0)
                        return (1);
        } else {
                if (elf64_sign_range(elf, callback, ELF_SR_CHECKSUM,
                   &sum) == 0)
                        return (1);
        }

        /* Finalize checksum */
        sum.s_sum = LSW(sum.s_sum) + MSW(sum.s_sum);
        sum.s_sum = ((ushort_t)(LSW(sum.s_sum) + MSW(sum.s_sum)));

        (void) printf("%s: checksum=0x%x\n", argv[1], sum.s_sum);
        return (0);
}
% cc -m64 -o main main.c -lelf
% main foo.so
foo.so: checksum=0x784
% elfdump -k foo.so
elf checksum: 0x784

Attributes

See attributes(7) for descriptions of the following attributes:

ATTRIBUTE TYPE
ATTRIBUTE VALUE
Interface Stability
Committed
MT-Level
MT-Safe

See Also

ld(1), mmap(2), open(2), stat(2), elf(3ELF), elf_begin(3ELF), elf_kind(3ELF), elf_update(3ELF), elf_version(3ELF), gelf(3ELF), libelf(3LIB), attributes(7)

Notes

A primary goal of elf32_sign_range() and elf64_sign_range() is to sign and verify an ELF file. This model requires computing the hash of the original ELF file using the signing functions, and updating the file to contain this hash information. The expectation is that a recomputed hash value of the new file, will match the hash value that is stored in the file.

However, ELF provides significant flexibility in regards the layout of a file. Anticipating how the file layout might change from computing the hash to updating the file with the hash, without omitting significant amounts of ELF metadata to compute the hash, can be hard to achieve.

To provide a signing model, and to minimize the amount of ELF metadata that must be omitted from the hash computation, the original ELF file should follow a libelf(3LIB) format. This format is created by using libelf interfaces that finalize the file layout with elf_update(3ELF). Attempts to sign an ELF file that does not follow a libelf format can result in computing a hash value that does not match the hash value recorded in the file. To ensure a signing model can be achieved, the following steps are recommended for a signing utility.

  • Create an intermediate ELF file from the original ELF file. This intermediate file should contain an empty signature section as the last section of the ELF file, and conform to a libelf(3LIB) format.

  • Compute the hash of this intermediate file using the desired Elf_Signrange type.

  • Update the signature section of the intermediate file with the hash value and the Elf_Signrange type, and finalize the file with elf_update(3ELF).

  • Replace the original ELF file with the intermediate ELF file.

  • The hash of the new ELF file, created using the recorded Elf_Signrange type, should match the hash value recorded in the file.