Example #1
0
func process_package(packages []string, filename string) {
	// RPM transcation stuff
	ts := C.rpmtsCreate()
	defer C.rpmtsFree(ts)
	C.rpmtsSetRootDir(ts, nil)
	C.rpmtsSetVSFlags(ts, C._RPMVSF_NOSIGNATURES)

	// create a lookup table for the files in debuginfo RPM
	// libarchive is too slow for doing this due to lzma decoding!
	cmode := C.CString("r")
	defer C.free(unsafe.Pointer(cmode))
	debug_package := filename
	cfilename := C.CString(debug_package)
	defer C.free(unsafe.Pointer(cfilename))
	/* debug_files := make(map[string]bool)
	dfd := C.Fopen(cfilename, cmode)
	defer C.Fclose(dfd)
	var dhdr C.Header
	drc := C.rpmReadPackageFile(ts, dfd, cfilename, &dhdr)
	if drc != C.RPMRC_OK {
		log.Println("[-] %s, broken RPM?", filename)
		return
	}
	defer C.headerFree(dhdr)
	fi := C.rpmfiNew(ts, dhdr, C.RPMTAG_BASENAMES, C.RPMFI_FLAGS_QUERY)
	defer C.rpmfiFree(fi)
	fi = C.rpmfiInit(fi, 0)
	for C.rpmfiNext(fi) >= 0 {
		fn := C.rpmfiFN(fi)
		// defer C.free(unsafe.Pointer(fn))
		gfn := C.GoString(fn)
		if strings.HasSuffix(gfn, ".debug") {
			debug_files[gfn] = true
		}
	} */

	// get the "dwz" content for this debug_package
	a := C.archive_read_new()
	defer C.archive_read_free(a)
	C.archive_read_support_filter_all(a)
	C.archive_read_support_format_all(a)
	r := C.archive_read_open_filename(a, cfilename, 30240)
	if r != C.ARCHIVE_OK {
		log.Println("[-] %s, broken archive?", debug_package)
	}
	pentry := C.archive_entry_new()
	var dwzfile *elf.File
	var err error
	for C.archive_read_next_header(a, &pentry) == C.ARCHIVE_OK {
		f := C.archive_entry_pathname(pentry)
		entryname := C.GoString(f)
		size := C.archive_entry_size(pentry)

		// skip folders
		mode := C.archive_entry_mode(pentry)
		gmode := int(mode)
		if gmode&0040000 != 0 {
			continue
		}

		// get the "dwz" content for this debug_package
		if strings.Contains(entryname, "lib/debug/.dwz/") {
			dwzbuf := unsafe.Pointer((*C.char)(C.malloc((C.size_t)(size))))
			defer C.free(unsafe.Pointer(dwzbuf))
			read_length := C.archive_read_data(a, dwzbuf, C.size_t(size))

			log.Println("[DWZ] read", read_length, "bytes from", entryname)

			// C array to Go array without explicit copying
			// https://code.google.com/p/go-wiki/wiki/cgo
			// dwzdata := (*[1<<31 - 1]byte)(unsafe.Pointer(dwzbuf))[:size]
			// https://code.google.com/p/go-wiki/wiki/cgo#Turning_C_arrays_into_Go_slices
			length := int(size)
			hdr := reflect.SliceHeader{
				Data: uintptr(unsafe.Pointer(dwzbuf)),
				Len:  length,
				Cap:  length,
			}
			dwzdata := *(*[]byte)(unsafe.Pointer(&hdr))

			if len(dwzdata) > 0 {
				dwzfile, err = elf.NewFile(bytes.NewReader(dwzdata))
				if err != nil {
					log.Println(err)
				}
			}
			break
		}
	}

	// process ".debug" file(s) in debug_package
	m := make(map[string][]string)
	var debugfile *elf.File
	var e error
	b := C.archive_read_new()
	defer C.archive_read_free(b)
	C.archive_read_support_filter_all(b)
	C.archive_read_support_format_all(b)
	pentry = C.archive_entry_new()
	C.archive_read_open_filename(b, cfilename, 30240)
	for C.archive_read_next_header(b, &pentry) == C.ARCHIVE_OK {
		f := C.archive_entry_pathname(pentry)
		entryname := C.GoString(f)
		size := C.archive_entry_size(pentry)

		// skip folders and symlinks
		mode := C.archive_entry_mode(pentry)
		gmode := int(mode)
		// S_IFLNK    0120000   symbolic link
		// S_IFMT     0170000   bit mask for the file type bit fields
		// S_IFDIR    0040000   directory
		if gmode&0040000 != 0 || gmode&0170000 == 0120000 {
			continue
		}

		// skip zero sized entries
		if size == 0 {
			continue
		}
		// skip non-debug files
		if !strings.HasSuffix(entryname, ".debug") || strings.Contains(entryname, "debug/.build-id/") {
			continue
		}

		// log.Println("<+> loading", entryname)

		// allocate buffer for reading data
		cbuf := unsafe.Pointer((*C.char)(C.malloc((C.size_t)(size))))
		read_length := C.archive_read_data(b, cbuf, C.size_t(size))
		log.Println("[DEBUG] read", read_length, "bytes from", entryname)

		// data := (*[1<<31 - 1]byte)(unsafe.Pointer(cbuf))[:size]  // will break at 2.14 GB!
		// https://code.google.com/p/go-wiki/wiki/cgo#Turning_C_arrays_into_Go_slices
		length := int(size)
		hdr := reflect.SliceHeader{
			Data: uintptr(unsafe.Pointer(cbuf)),
			Len:  length,
			Cap:  length,
		}
		data := *(*[]byte)(unsafe.Pointer(&hdr))

		if len(data) > 0 {
			debugfile, e = elf.NewFile(bytes.NewReader(data))
			if e != nil {
				log.Println(e, entryname, len(data))
				continue
			}
		} else {
			log.Println(len(data), entryname, debug_package)
		}

		// log.Println("<+> loaded", entryname)
		// time.Sleep(1 * time.Millisecond)

		// real action time ;(
		output := producer(debugfile, dwzfile, entryname, filename)
		m[entryname] = output
		C.free(unsafe.Pointer(cbuf))
	}
	stuff, bad := json.Marshal(m)
	if bad != nil {
		log.Panic(bad)
	}
	fmt.Println(string(stuff))
}
Example #2
0
func process_packages(packages []string, debug_packages []string) {
	m := make(map[string][]string)

	ts := C.rpmtsCreate()
	defer C.rpmtsFree(ts)
	C.rpmtsSetRootDir(ts, nil)
	C.rpmtsSetVSFlags(ts, C._RPMVSF_NOSIGNATURES)

	for _, filename := range packages {
		cfilename := C.CString(filename)
		defer C.free(unsafe.Pointer(cfilename))
		cmode := C.CString("r")
		defer C.free(unsafe.Pointer(cmode))

		// extract metadata (RPM headers) from filename
		fd := C.Fopen(cfilename, cmode)
		if fd == nil {
			log.Println("fd == NULL while processing", filename)
			time.Sleep(100000 * time.Millisecond)
			panic("^^^")
		}
		var hdr C.Header
		rc := C.rpmReadPackageFile(ts, fd, cfilename, &hdr)

		// read header stuff
		if rc != C.RPMRC_OK {
			log.Println("[-] broken RPM?", filename)
			continue
		}

		// extract various "tags" from the RPM file
		csrpm := C.headerGetAsString(hdr, C.RPMTAG_SOURCERPM)
		defer C.free((unsafe.Pointer)(csrpm))
		srpm := C.GoString(csrpm)
		C.headerFree(hdr)
		/* cnvr := C.headerGetAsString(hdr, C.RPMTAG_NVRA)
		defer C.free((unsafe.Pointer)(cnvr))
		nvr := C.GoString(cnvr)
		log.Println(nvr) */

		// determine the name of debuginfo package from srpm name
		re := regexp.MustCompile("(?P<name>.*)-.*-.*")
		res := re.FindAllStringSubmatch(srpm, -1)[0]
		if len(res) == 0 {
			log.Println("[-] SRPM name missing for", filename)
		}
		names := re.SubexpNames()
		md := map[string]string{}
		for i, n := range res {
			md[names[i]] = n
		}
		target_debug_package := md["name"] + "-debuginfo-"

		// do we have this "target_debug_package" in "debug_packages"?
		debug_package := ""
		re = regexp.MustCompile(regexp.QuoteMeta(target_debug_package))
		for _, name := range debug_packages {
			if re.MatchString(path.Base(name)+"\\d") == true {
				debug_package = name
			}
		}
		if debug_package == "" {
			log.Println("[-] debuginfo missing (during preliminary scan) for", filename)
		}
		m[debug_package] = append(m[debug_package], filename)
		C.Fclose(fd) // critical step!
	}
	b, err := json.Marshal(m)
	if err != nil {
		log.Panic("JSON encoding problem ;(")
	}

	fmt.Println(string(b)) // output
}