Edit

IABSD.fr/src/usr.sbin/mkuboot/mkuboot.c

Branch :

  • Show log

    Commit

  • Author : deraadt
    Date : 2019-06-28 13:32:41
    Hash : df69c215
    Message : When system calls indicate an error they return -1, not some arbitrary value < 0. errno is only updated in this case. Change all (most?) callers of syscalls to follow this better, and let's see if this strictness helps us in the future.

  • usr.sbin/mkuboot/mkuboot.c
  • /*	$OpenBSD: mkuboot.c,v 1.9 2019/06/28 13:32:48 deraadt Exp $	*/
    
    /*
     * Copyright (c) 2008 Mark Kettenis
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    #include <sys/types.h>
    #include <sys/stat.h>
    
    #include <elf.h>
    #include <err.h>
    #include <fcntl.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <unistd.h>
    #include <zlib.h>
    
    #define IH_OS_OPENBSD		1 /* OpenBSD */
    #define IH_OS_LINUX		5 /* Linux */
    
    #define IH_ARCH_ALPHA           1       /* Alpha        */
    #define IH_ARCH_ARM             2       /* ARM          */
    #define IH_ARCH_I386            3       /* Intel x86    */
    #define IH_ARCH_IA64            4       /* IA64         */
    #define IH_ARCH_MIPS            5       /* MIPS         */
    #define IH_ARCH_MIPS64          6       /* MIPS  64 Bit */
    #define IH_ARCH_PPC             7       /* PowerPC      */
    #define IH_ARCH_SH              9       /* SuperH       */
    #define IH_ARCH_SPARC           10      /* Sparc        */
    #define IH_ARCH_SPARC64         11      /* Sparc 64 Bit */
    #define IH_ARCH_M68K            12      /* M68K         */
    #define IH_ARCH_ARM64           22      /* AARCH64      */
    
    #define IH_TYPE_STANDALONE	1 /* Standalone */
    #define IH_TYPE_KERNEL		2 /* OS Kernel Image */
    #define IH_TYPE_SCRIPT		6 /* Script file */
    
    #define IH_COMP_NONE		0 /* No compression */
    
    #define IH_MAGIC		0x27051956	/* Image Magic Number */
    #define IH_NMLEN		32 		/* Image Name Length */
    
    struct image_header {
    	uint32_t	ih_magic;
    	uint32_t	ih_hcrc;
    	uint32_t	ih_time;
    	uint32_t	ih_size;
    	uint32_t	ih_load;
    	uint32_t	ih_ep;
    	uint32_t	ih_dcrc;
    	uint8_t		ih_os;
    	uint8_t		ih_arch;
    	uint8_t		ih_type;
    	uint8_t		ih_comp;
    	uint8_t		ih_name[IH_NMLEN];
    };
    
    extern char *__progname;
    
    extern u_long	elf32_copy_elf(int, const char *, int, const char *, u_long,
    	    struct image_header *);
    extern u_long	elf64_copy_elf(int, const char *, int, const char *, u_long,
    	    struct image_header *);
    
    u_long	copy_data(int, const char *, int, const char *, u_long,
    	    struct image_header *, Elf_Word);
    u_long	(*copy_elf)(int, const char *, int, const char *, u_long,
    	    struct image_header *);
    
    u_long	copy_mem(void *, int, const char *, u_long, struct image_header *,
    	    Elf_Word);
    u_long	copy_raw(int, const char *, int, const char *, u_long,
    	    struct image_header *);
    u_long	fill_zeroes(int, const char *, u_long, struct image_header *, Elf_Word);
    int	is_elf(int, const char *);
    void	usage(void);
    
    struct arch_map {
    	int id;
    	const char *arch;
    };
    
    static const struct arch_map archmap[] = {
        { IH_ARCH_ARM64,	"aarch64" },
        { IH_ARCH_ALPHA,	"alpha" },
        { IH_ARCH_IA64,	"amd64" },
        { IH_ARCH_ARM,	"arm" },
        { IH_ARCH_I386,	"i386" },
        { IH_ARCH_M68K,	"m68k" },
        { IH_ARCH_MIPS,	"mips" },
        { IH_ARCH_MIPS64,	"mips64" },
        { IH_ARCH_PPC,	"powerpc" },
        { IH_ARCH_SPARC,	"sparc" },
        { IH_ARCH_SPARC64,	"sparc64" },
        { IH_ARCH_SH,	"superh" },
        { 0, NULL }
    };
    
    struct type_map {
    	int id;
    	const char *type;
    };
    static const struct type_map typemap[] = {
        { IH_TYPE_STANDALONE,	"standalone" },
        { IH_TYPE_KERNEL,		"kernel" },
        { IH_TYPE_SCRIPT,		"script" },
        { 0, NULL }
    };
    
    struct os_map {
    	int id;
    	const char *arch;
    };
    
    static const struct os_map osmap[] = {
        { IH_OS_OPENBSD,	"OpenBSD" },
        { IH_OS_LINUX,	"Linux" },
        { 0, NULL }
    };
    
    
    int
    main(int argc, char *argv[])
    {
    	struct image_header ih;
    	struct stat sb;
    	const struct arch_map *mapptr;
    	const struct os_map *osmapptr;
    	const struct type_map *typemapptr;
    	const char *iname, *oname;
    	const char *arch = MACHINE_ARCH;
    	const char *os = "OpenBSD";
    	const char *type = "kernel";
    	const char *imgname = "boot";
    	int ifd, ofd;
    	uint32_t fsize;
    	u_long crc;
    	int c, ep, load;
    
    	ep = load = 0;
    	while ((c = getopt(argc, argv, "a:e:l:n:o:t:")) != -1) {
    		switch (c) {
    		case 'a':
    			arch = optarg;
    			break;
    		case 'e':
    			sscanf(optarg, "0x%x", &ep);
    			break;
    		case 'l':
    			sscanf(optarg, "0x%x", &load);
    			break;
    		case 'n':
    			imgname = optarg;
    			break;
    		case 'o':
    			os = optarg;
    			break;
    		case 't':
    			type = optarg;
    			break;
    		default:
    			usage();
    		}
    	}
    
    	for (mapptr = archmap; mapptr->arch; mapptr++)
    		if (strcasecmp(arch, mapptr->arch) == 0)
    			break;
    
    	if (mapptr->arch == NULL) {
    		printf("unknown arch '%s'\n", arch);
    		usage();
    	}
    
    	for (osmapptr = osmap; osmapptr->arch; osmapptr++)
    		if (strcasecmp(os, osmapptr->arch) == 0)
    			break;
    
    	if (osmapptr->arch == NULL) {
    		printf("unknown OS '%s'\n", os);
    		usage();
    	}
    
    	for (typemapptr = typemap; typemapptr->type; typemapptr++)
    		if (strcasecmp(type, typemapptr->type) == 0)
    			break;
    
    	if (typemapptr->type == NULL) {
    		printf("unknown type '%s'\n", os);
    		usage();
    	}
    
    	if (argc - optind != 2)
    		usage();
    
    	iname = argv[optind++];
    	oname = argv[optind++];
    
    	/* Initialize U-Boot header. */
    	bzero(&ih, sizeof ih);
    	ih.ih_magic = htobe32(IH_MAGIC);
    	ih.ih_time = htobe32(time(NULL));
    	ih.ih_load = htobe32(load);
    	ih.ih_ep = htobe32(ep);
    	ih.ih_os = osmapptr->id;
    	ih.ih_arch = mapptr->id;
    	ih.ih_type = typemapptr->id;
    	ih.ih_comp = IH_COMP_NONE;
    	strlcpy((char *)ih.ih_name, imgname, sizeof ih.ih_name);
    
    	ifd = open(iname, O_RDONLY);
    	if (ifd == -1)
    		err(1, "%s", iname);
    	if (fstat(ifd, &sb) == -1)
    		err(1, "%s", iname);
    
    	ofd = open(oname, O_RDWR | O_TRUNC | O_CREAT, 0644);
    	if (ofd == -1)
    		err(1, "%s", oname);
    
    	if (pledge("stdio", NULL) == -1)
    		err(1, "pledge");
    
    	/* Write initial header. */
    	if (write(ofd, &ih, sizeof ih) != sizeof ih)
    		err(1, "%s", oname);
    
    	/* Write data, calculating the data CRC as we go. */
    	crc = crc32(0L, Z_NULL, 0);
    
    	if (ih.ih_type == IH_TYPE_SCRIPT) {
    		/* scripts have two extra words of size/pad */
    		fsize = htobe32(sb.st_size);
    		crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
    		if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
    			err(1, "%s", oname);
    		fsize = 0;
    		crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
    		if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
    			err(1, "%s", oname);
    	}
    
    	if (is_elf(ifd, iname))
    		crc = copy_elf(ifd, iname, ofd, oname, crc, &ih);
    	else
    		crc = copy_raw(ifd, iname, ofd, oname, crc, &ih);
    	ih.ih_dcrc = htobe32(crc);
    
    	if (ih.ih_type == IH_TYPE_SCRIPT) {
    		ih.ih_size += 8; /* two extra pad words */
    	}
    
    	ih.ih_size = htobe32(ih.ih_size);
    
    	/* Calculate header CRC. */
    	crc = crc32(0, (Bytef *)&ih, sizeof ih);
    	ih.ih_hcrc = htobe32(crc);
    
    	/* Write finalized header. */
    	if (lseek(ofd, 0, SEEK_SET) != 0)
    		err(1, "%s", oname);
    	if (write(ofd, &ih, sizeof ih) != sizeof ih)
    		err(1, "%s", oname);
    
    	return(0);
    }
    
    int
    is_elf(int ifd, const char *iname)
    {
    	ssize_t nbytes;
    	Elf_Ehdr ehdr;
    
    	nbytes = read(ifd, &ehdr, sizeof ehdr);
    	if (nbytes == -1)
    		err(1, "%s", iname);
    	if (lseek(ifd, 0, SEEK_SET) != 0)
    		err(1, "%s", iname);
    
    	if (nbytes != sizeof ehdr || !IS_ELF(ehdr))
    		return 0;
    
    	if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
    		copy_elf = elf32_copy_elf;
    	else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
    		copy_elf = elf64_copy_elf;
    	else
    		err(1, "%s: invalid elf, not 32 or 64 bit", iname);
    	return 1;
    }
    
    u_long
    copy_data(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
        struct image_header *ih, Elf_Word size)
    {
    	ssize_t nbytes, chunk;
    	char buf[BUFSIZ];
    
    	while (size != 0) {
    		chunk = size > BUFSIZ ? BUFSIZ : size;
    		nbytes = read(ifd, buf, chunk);
    		if (nbytes != chunk)
    			err(1, "%s", iname);
    		if (write(ofd, buf, nbytes) != nbytes)
    			err(1, "%s", oname);
    		crc = crc32(crc, (Bytef *)buf, nbytes);
    		ih->ih_size += nbytes;
    		size -= nbytes;
    	}
    
    	return crc;
    }
    
    u_long
    copy_mem(void *mem, int ofd, const char *oname, u_long crc,
        struct image_header *ih, Elf_Word size)
    {
    	ssize_t nbytes;
    	char *memp = (char *)mem;
    
    	while (size != 0) {
    		nbytes = size > BUFSIZ ? BUFSIZ : size;
    		if (write(ofd, memp, nbytes) != nbytes)
    			err(1, "%s", oname);
    		crc = crc32(crc, (Bytef *)memp, nbytes);
    		memp += nbytes;
    		ih->ih_size += nbytes;
    		size -= nbytes;
    	}
    
    	return crc;
    }
    
    u_long
    fill_zeroes(int ofd, const char *oname, u_long crc, struct image_header *ih,
        Elf_Word size)
    {
    	ssize_t nbytes, chunk;
    	char buf[BUFSIZ];
    
    	memset(buf, 0, BUFSIZ);
    	while (size != 0) {
    		chunk = size > BUFSIZ ? BUFSIZ : size;
    		nbytes = write(ofd, buf, chunk);
    		if (nbytes != chunk)
    			err(1, "%s", oname);
    		crc = crc32(crc, (Bytef *)buf, nbytes);
    		ih->ih_size += nbytes;
    		size -= nbytes;
    	}
    
    	return crc;
    }
    
    u_long
    copy_raw(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
        struct image_header *ih)
    {
    	ssize_t nbytes;
    	char buf[BUFSIZ];
    
    	while ((nbytes = read(ifd, buf, sizeof buf)) != 0) {
    		if (nbytes == -1)
    			err(1, "%s", iname);
    		if (write(ofd, buf, nbytes) != nbytes)
    			err(1, "%s", oname);
    		crc = crc32(crc, (Bytef *)buf, nbytes);
    		ih->ih_size += nbytes;
    	}
    
    	return crc;
    }
    
    void
    usage(void)
    {
    	const struct arch_map *mapptr;
    	const struct os_map *osmapptr;
    
    	(void)fprintf(stderr,
    	    "usage: %s [-a arch] [-e entry] [-l loadaddr] [-n name] [-o os] "
    	    "[-t type] infile outfile\n", __progname);
    	(void)fprintf(stderr,
    	    "arch is one of:");
    	for (mapptr = archmap; mapptr->arch; mapptr++)
    		(void)fprintf(stderr, " %s", mapptr->arch);
    	(void)fprintf(stderr, "\n");
    	(void)fprintf(stderr,
    	    "os is one of:");
    	for (osmapptr = osmap; osmapptr->arch; osmapptr++)
    		(void)fprintf(stderr, " %s", osmapptr->arch);
    	(void)fprintf(stderr, "\n");
    	
    	exit(1);
    }