307 lines
7.1 KiB
C
307 lines
7.1 KiB
C
#include <VasEBoot/types.h>
|
|
#include <VasEBoot/err.h>
|
|
#include <VasEBoot/linux.h>
|
|
#include <VasEBoot/misc.h>
|
|
#include <VasEBoot/file.h>
|
|
#include <VasEBoot/mm.h>
|
|
#include <VasEBoot/tpm.h>
|
|
|
|
struct newc_head
|
|
{
|
|
char magic[6];
|
|
char ino[8];
|
|
char mode[8];
|
|
char uid[8];
|
|
char gid[8];
|
|
char nlink[8];
|
|
char mtime[8];
|
|
char filesize[8];
|
|
char devmajor[8];
|
|
char devminor[8];
|
|
char rdevmajor[8];
|
|
char rdevminor[8];
|
|
char namesize[8];
|
|
char check[8];
|
|
} VasEBoot_PACKED;
|
|
|
|
struct VasEBoot_linux_initrd_component
|
|
{
|
|
VasEBoot_file_t file;
|
|
char *newc_name;
|
|
VasEBoot_off_t size;
|
|
};
|
|
|
|
struct dir
|
|
{
|
|
char *name;
|
|
struct dir *next;
|
|
struct dir *child;
|
|
};
|
|
|
|
static char
|
|
hex (VasEBoot_uint8_t val)
|
|
{
|
|
if (val < 10)
|
|
return '0' + val;
|
|
return 'a' + val - 10;
|
|
}
|
|
|
|
static void
|
|
set_field (char *var, VasEBoot_uint32_t val)
|
|
{
|
|
int i;
|
|
char *ptr = var;
|
|
for (i = 28; i >= 0; i -= 4)
|
|
*ptr++ = hex((val >> i) & 0xf);
|
|
}
|
|
|
|
static VasEBoot_uint8_t *
|
|
make_header (VasEBoot_uint8_t *ptr,
|
|
const char *name, VasEBoot_size_t len,
|
|
VasEBoot_uint32_t mode,
|
|
VasEBoot_off_t fsize)
|
|
{
|
|
struct newc_head *head = (struct newc_head *) ptr;
|
|
VasEBoot_uint8_t *optr;
|
|
VasEBoot_size_t oh = 0;
|
|
VasEBoot_memcpy (head->magic, "070701", 6);
|
|
set_field (head->ino, 0);
|
|
set_field (head->mode, mode);
|
|
set_field (head->uid, 0);
|
|
set_field (head->gid, 0);
|
|
set_field (head->nlink, 1);
|
|
set_field (head->mtime, 0);
|
|
set_field (head->filesize, fsize);
|
|
set_field (head->devmajor, 0);
|
|
set_field (head->devminor, 0);
|
|
set_field (head->rdevmajor, 0);
|
|
set_field (head->rdevminor, 0);
|
|
set_field (head->namesize, len);
|
|
set_field (head->check, 0);
|
|
optr = ptr;
|
|
ptr += sizeof (struct newc_head);
|
|
VasEBoot_memcpy (ptr, name, len);
|
|
ptr += len;
|
|
oh = ALIGN_UP_OVERHEAD (ptr - optr, 4);
|
|
VasEBoot_memset (ptr, 0, oh);
|
|
ptr += oh;
|
|
return ptr;
|
|
}
|
|
|
|
static void
|
|
free_dir (struct dir *root)
|
|
{
|
|
if (!root)
|
|
return;
|
|
free_dir (root->next);
|
|
free_dir (root->child);
|
|
VasEBoot_free (root->name);
|
|
VasEBoot_free (root);
|
|
}
|
|
|
|
static VasEBoot_size_t
|
|
insert_dir (const char *name, struct dir **root,
|
|
VasEBoot_uint8_t *ptr)
|
|
{
|
|
struct dir *cur, **head = root;
|
|
const char *cb, *ce = name;
|
|
VasEBoot_size_t size = 0;
|
|
while (1)
|
|
{
|
|
for (cb = ce; *cb == '/'; cb++);
|
|
for (ce = cb; *ce && *ce != '/'; ce++);
|
|
if (!*ce)
|
|
break;
|
|
|
|
for (cur = *root; cur; cur = cur->next)
|
|
if (VasEBoot_memcmp (cur->name, cb, ce - cb)
|
|
&& cur->name[ce - cb] == 0)
|
|
break;
|
|
if (!cur)
|
|
{
|
|
struct dir *n;
|
|
n = VasEBoot_zalloc (sizeof (*n));
|
|
if (!n)
|
|
return 0;
|
|
n->next = *head;
|
|
n->name = VasEBoot_strndup (cb, ce - cb);
|
|
if (ptr)
|
|
{
|
|
VasEBoot_dprintf ("linux", "Creating directory %s, %s\n", name, ce);
|
|
ptr = make_header (ptr, name, ce - name,
|
|
040777, 0);
|
|
}
|
|
size += ALIGN_UP ((ce - (char *) name)
|
|
+ sizeof (struct newc_head), 4);
|
|
*head = n;
|
|
cur = n;
|
|
}
|
|
root = &cur->next;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
VasEBoot_err_t
|
|
VasEBoot_initrd_init (int argc, char *argv[],
|
|
struct VasEBoot_linux_initrd_context *initrd_ctx)
|
|
{
|
|
int i;
|
|
int newc = 0;
|
|
struct dir *root = 0;
|
|
|
|
initrd_ctx->nfiles = 0;
|
|
initrd_ctx->components = 0;
|
|
|
|
initrd_ctx->components = VasEBoot_zalloc (argc
|
|
* sizeof (initrd_ctx->components[0]));
|
|
if (!initrd_ctx->components)
|
|
return VasEBoot_errno;
|
|
|
|
initrd_ctx->size = 0;
|
|
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
const char *fname = argv[i];
|
|
|
|
initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
|
|
|
|
if (VasEBoot_memcmp (argv[i], "newc:", 5) == 0)
|
|
{
|
|
const char *ptr, *eptr;
|
|
ptr = argv[i] + 5;
|
|
while (*ptr == '/')
|
|
ptr++;
|
|
eptr = VasEBoot_strchr (ptr, ':');
|
|
if (eptr)
|
|
{
|
|
VasEBoot_file_filter_disable_compression ();
|
|
initrd_ctx->components[i].newc_name = VasEBoot_strndup (ptr, eptr - ptr);
|
|
if (!initrd_ctx->components[i].newc_name)
|
|
{
|
|
VasEBoot_initrd_close (initrd_ctx);
|
|
return VasEBoot_errno;
|
|
}
|
|
initrd_ctx->size
|
|
+= ALIGN_UP (sizeof (struct newc_head)
|
|
+ VasEBoot_strlen (initrd_ctx->components[i].newc_name),
|
|
4);
|
|
initrd_ctx->size += insert_dir (initrd_ctx->components[i].newc_name,
|
|
&root, 0);
|
|
newc = 1;
|
|
fname = eptr + 1;
|
|
}
|
|
}
|
|
else if (newc)
|
|
{
|
|
initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
|
|
+ sizeof ("TRAILER!!!") - 1, 4);
|
|
free_dir (root);
|
|
root = 0;
|
|
newc = 0;
|
|
}
|
|
VasEBoot_file_filter_disable_compression ();
|
|
initrd_ctx->components[i].file = VasEBoot_file_open (fname);
|
|
if (!initrd_ctx->components[i].file)
|
|
{
|
|
VasEBoot_initrd_close (initrd_ctx);
|
|
return VasEBoot_errno;
|
|
}
|
|
initrd_ctx->nfiles++;
|
|
initrd_ctx->components[i].size
|
|
= VasEBoot_file_size (initrd_ctx->components[i].file);
|
|
initrd_ctx->size += initrd_ctx->components[i].size;
|
|
}
|
|
|
|
if (newc)
|
|
{
|
|
initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
|
|
initrd_ctx->size += ALIGN_UP (sizeof (struct newc_head)
|
|
+ sizeof ("TRAILER!!!") - 1, 4);
|
|
free_dir (root);
|
|
root = 0;
|
|
}
|
|
|
|
return VasEBoot_ERR_NONE;
|
|
}
|
|
|
|
VasEBoot_size_t
|
|
VasEBoot_get_initrd_size (struct VasEBoot_linux_initrd_context *initrd_ctx)
|
|
{
|
|
return initrd_ctx->size;
|
|
}
|
|
|
|
void
|
|
VasEBoot_initrd_close (struct VasEBoot_linux_initrd_context *initrd_ctx)
|
|
{
|
|
int i;
|
|
if (!initrd_ctx->components)
|
|
return;
|
|
for (i = 0; i < initrd_ctx->nfiles; i++)
|
|
{
|
|
VasEBoot_free (initrd_ctx->components[i].newc_name);
|
|
VasEBoot_file_close (initrd_ctx->components[i].file);
|
|
}
|
|
VasEBoot_free (initrd_ctx->components);
|
|
initrd_ctx->components = 0;
|
|
}
|
|
|
|
VasEBoot_err_t
|
|
VasEBoot_initrd_load (struct VasEBoot_linux_initrd_context *initrd_ctx,
|
|
char *argv[], void *target)
|
|
{
|
|
VasEBoot_uint8_t *ptr = target;
|
|
int i;
|
|
int newc = 0;
|
|
struct dir *root = 0;
|
|
VasEBoot_ssize_t cursize = 0;
|
|
|
|
for (i = 0; i < initrd_ctx->nfiles; i++)
|
|
{
|
|
VasEBoot_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
|
|
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
|
|
|
|
if (initrd_ctx->components[i].newc_name)
|
|
{
|
|
ptr += insert_dir (initrd_ctx->components[i].newc_name,
|
|
&root, ptr);
|
|
ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
|
|
VasEBoot_strlen (initrd_ctx->components[i].newc_name),
|
|
0100777,
|
|
initrd_ctx->components[i].size);
|
|
newc = 1;
|
|
}
|
|
else if (newc)
|
|
{
|
|
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1,
|
|
0, 0);
|
|
free_dir (root);
|
|
root = 0;
|
|
newc = 0;
|
|
}
|
|
|
|
cursize = initrd_ctx->components[i].size;
|
|
if (VasEBoot_file_read (initrd_ctx->components[i].file, ptr, cursize)
|
|
!= cursize)
|
|
{
|
|
if (!VasEBoot_errno)
|
|
VasEBoot_error (VasEBoot_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
|
|
argv[i]);
|
|
VasEBoot_initrd_close (initrd_ctx);
|
|
return VasEBoot_errno;
|
|
}
|
|
VasEBoot_tpm_measure (ptr, cursize, VasEBoot_BINARY_PCR, "VasEBoot_initrd", "Initrd");
|
|
VasEBoot_print_error();
|
|
|
|
ptr += cursize;
|
|
}
|
|
if (newc)
|
|
{
|
|
VasEBoot_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
|
|
ptr += ALIGN_UP_OVERHEAD (cursize, 4);
|
|
ptr = make_header (ptr, "TRAILER!!!", sizeof ("TRAILER!!!") - 1, 0, 0);
|
|
}
|
|
free_dir (root);
|
|
root = 0;
|
|
return VasEBoot_ERR_NONE;
|
|
}
|