Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  macos.rs   Sprache: unbekannt

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use nserror::{
    nsresult, NS_ERROR_FILE_COPY_OR_MOVE_FAILED, NS_ERROR_ILLEGAL_VALUE, NS_ERROR_INVALID_ARG,
    NS_ERROR_INVALID_POINTER, NS_ERROR_INVALID_SIGNATURE, NS_ERROR_NOT_AVAILABLE,
    NS_ERROR_NOT_INITIALIZED,
};

use goblin::mach;

use super::BuildIdReader;

use log::{error, trace};

const HEADER_SIZE: usize = std::mem::size_of::<goblin::mach::header::Header64>();

impl BuildIdReader {
    pub fn get_build_id_bytes(
        &mut self,
        buffer: &[u8],
        note_name: &str,
    ) -> Result<Vec<u8>, nsresult> {
        trace!("get_build_id_bytes: {}", note_name);
        let (section, note) = note_name
            .split_once(",")
            .ok_or(NS_ERROR_INVALID_SIGNATURE)?;
        trace!("get_build_id_bytes: {} {}", section, note);

        let fat_header = mach::fat::FatHeader::parse(buffer).map_err(|e| {
            error!("Failed FatHeader::parse(): {}", e);
            NS_ERROR_NOT_INITIALIZED
        })?;
        trace!("get_build_id_bytes: fat header: {:?}", fat_header);

        /* First we attempt to parse if there's a Fat header there
         *
         * If we have one, then we have a universal binary so we are going to
         * search the architectures to find the one we want, extract the correct
         * MachO buffer as well as the offset at which the MachO binary is.
         * Testing Universal binaries will require running gtest against a
         * Shippable build.
         *
         * If not we have a normal MachO and we directly parse the buffer we
         * have read earlier, and use a 0 offset.
         */
        let (buf /*: [u8; HEADER_SIZE] */, main_offset /*: usize */) = if fat_header.magic
            == mach::fat::FAT_CIGAM
            || fat_header.magic == mach::fat::FAT_MAGIC
        {
            let total = std::mem::size_of::<mach::fat::FatHeader>() as usize
                + (std::mem::size_of::<mach::fat::FatArch>() * fat_header.nfat_arch as usize);

            let mach_buffer = self.copy_bytes(0, total).map_err(|e| {
                error!(
                    "get_build_id_bytes: failed to copy Mach ({}) bytes with error {}",
                    total, e
                );
                NS_ERROR_FILE_COPY_OR_MOVE_FAILED
            })?;

            if let mach::Mach::Fat(multi_arch) =
                mach::Mach::parse_lossy(&mach_buffer).map_err(|e| {
                    error!("Failed Mach::parse_lossy(): {}", e);
                    NS_ERROR_NOT_INITIALIZED
                })?
            {
                let arches = multi_arch.arches().map_err(|e| {
                    error!("Error getting arches(): {}", e);
                    NS_ERROR_FILE_COPY_OR_MOVE_FAILED
                })?;

                #[cfg(target_arch = "x86_64")]
                let that_arch = mach::constants::cputype::CPU_TYPE_X86_64;
                #[cfg(target_arch = "aarch64")]
                let that_arch = mach::constants::cputype::CPU_TYPE_ARM64;

                let arch_index = arches
                    .iter()
                    .position(|&x| x.cputype == that_arch)
                    .ok_or(NS_ERROR_FILE_COPY_OR_MOVE_FAILED)?;
                trace!("get_build_id_bytes: arches[]: {:?}", arches[arch_index]);

                let offset = arches[arch_index].offset as usize;

                if let Ok(b) = self
                    .copy_bytes(offset, HEADER_SIZE)
                    .map_err(|e| {
                        error!("get_build_id_bytes: failed to copy Mach-O header bytes at {} ({} bytes) with error {}", offset, HEADER_SIZE, e);
                        NS_ERROR_FILE_COPY_OR_MOVE_FAILED
                    })?.try_into() {
                    (b, offset)
                } else {
                    return Err(NS_ERROR_FILE_COPY_OR_MOVE_FAILED);
                }
            } else {
                return Err(NS_ERROR_INVALID_ARG);
            }
        } else {
            (
                buffer.try_into().map_err(|e| {
                    error!(
                        "get_build_id_bytes: failed to get buffer of {} bytes with error {}",
                        HEADER_SIZE, e
                    );
                    NS_ERROR_NOT_INITIALIZED
                })?,
                0,
            )
        };
        trace!("get_build_id_bytes: {} {}", section, note);

        let macho_head = mach::header::Header64::from_bytes(&buf);
        let mut address = main_offset + HEADER_SIZE;
        let end_of_commands = address + (macho_head.sizeofcmds as usize);

        while address < end_of_commands {
            let command = unsafe {
                self.copy::<mach::load_command::LoadCommandHeader>(address as usize)
                    .map_err(|e| {
                        error!(
                            "get_build_id_bytes: failed to load MachO command at {} with error {}",
                            address, e
                        );
                        NS_ERROR_INVALID_ARG
                    })?
            };
            trace!("get_build_id_bytes: command {:?}", command);

            if command.cmd == mach::load_command::LC_SEGMENT_64 {
                let segment = unsafe {
                    self.copy::<mach::load_command::SegmentCommand64>(address as usize)
                        .map_err(|e| {
                            error!("get_build_id_bytes: failed to load MachO segment at {} with error {}", address, e);
                            NS_ERROR_INVALID_POINTER
                        })?
                };
                trace!("get_build_id_bytes: segment {:?}", segment);

                let name = segment.name().map_err(|e| {
                    error!(
                        "get_build_id_bytes: failed to get segment name with error {}",
                        e
                    );
                    NS_ERROR_ILLEGAL_VALUE
                })?;
                if name == section {
                    let sections_addr =
                        address + std::mem::size_of::<mach::load_command::SegmentCommand64>();
                    let sections = unsafe {
                        self.copy_array::<mach::load_command::Section64>(
                            sections_addr as usize,
                            segment.nsects as usize,
                        )
                        .map_err(|e| {
                            error!("get_build_id_bytes: failed to get MachO sections at {} with error {}", sections_addr, e);
                            NS_ERROR_FILE_COPY_OR_MOVE_FAILED
                        })?
                    };
                    trace!("get_build_id_bytes: sections {:?}", sections);

                    for section in §ions {
                        trace!("get_build_id_bytes: section {:?}", section);
                        if let Some(sname) = Self::string_from_bytes(§ion.sectname) {
                            trace!("get_build_id_bytes: sname {:?}", sname);
                            if (sname.len() == 0) || (sname != note) {
                                continue;
                            }

                            return self
                                .copy_bytes(main_offset + section.addr as usize, section.size as usize)
                                .map_err(|e| {
                                    error!("get_build_id_bytes: failed to copy section bytes at {} ({} bytes) with error {}", section.addr, section.size, e);
                                    NS_ERROR_FILE_COPY_OR_MOVE_FAILED
                                });
                        }
                    }
                }
            }
            address += command.cmdsize as usize;
        }

        Err(NS_ERROR_NOT_AVAILABLE)
    }
}

[ Dauer der Verarbeitung: 0.25 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge