Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ostree=aboot for signed Android Boot Images #2844

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 171 additions & 4 deletions src/switchroot/ostree-mount-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,20 @@
#ifndef __OSTREE_MOUNT_UTIL_H_
#define __OSTREE_MOUNT_UTIL_H_

#include <dirent.h>
#include <err.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/statvfs.h>
#include <stdio.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdbool.h>

#define INITRAMFS_MOUNT_VAR "/run/ostree/initramfs-mount-var"
#define _OSTREE_SYSROOT_READONLY_STAMP "/run/ostree-sysroot-ro.stamp"
#define ABOOT_KARG "aboot"

static inline int
path_is_on_readonly_fs (const char *path)
Expand Down Expand Up @@ -72,6 +75,26 @@ read_proc_cmdline (void)
return cmdline;
}

static inline void
free_char (char **to_free)
{
free (*to_free);
}

static inline void
close_dir (DIR **dir)
{
if (*dir)
closedir (*dir);
}

static inline void
close_file (FILE **f)
{
if (*f)
fclose (*f);
}

static inline char *
read_proc_cmdline_ostree (void)
{
Expand Down Expand Up @@ -106,6 +129,150 @@ read_proc_cmdline_ostree (void)
return ret;
}

static inline void
cpy_and_null (char **dest, char **src)
{
*dest = *src;
*src = NULL;
}

/* If the key matches the start of the line, copy line to out
*/
static inline bool
cpy_if_key_match (char **line, const char *key, char **out)
{
/* There should only be one of each key per BLS file, so check for NULL, we
* should only parse the first occurance of a key, if there's two, it's a
* malformed BLS file
*/
if (!*out && strstr (*line, key) == *line)
{
cpy_and_null (out, line);
return true;
}

return false;
}

static inline bool
has_suffix (const char *str, const char *suffix)
{
if (!str || !suffix)
return false;

const size_t str_len = strlen (str);
const size_t suffix_len = strlen (suffix);
if (str_len < suffix_len)
return false;

return !strcmp (str + str_len - suffix_len, suffix);
}

/* On completion version and options will be set to new values if the version
* is more recent. Will loop line through line on the passed in open FILE.
*/
static inline void
copy_if_higher_version (FILE *f, char **version, char **options)
{
char __attribute__ ((cleanup (free_char))) *line = NULL;
char __attribute__ ((cleanup (free_char))) *version_local = NULL;
char __attribute__ ((cleanup (free_char))) *options_local = NULL;
char __attribute__ ((cleanup (free_char))) *linux_local = NULL;
/* Note getline() will reuse the previous buffer when not zero */
for (size_t len = 0; getline (&line, &len, f) != -1;)
{
/* This is an awful hack to avoid depending on GLib in the
* initramfs right now.
*/
if (cpy_if_key_match (&line, "version ", &version_local))
continue;

if (cpy_if_key_match (&line, "options ", &options_local))
continue;

if (cpy_if_key_match (&line, "linux ", &linux_local))
continue;
}

/* The case where we have no version set yet */
if (!*version
|| strverscmp (version_local + sizeof ("version"), (*version) + sizeof ("version")) > 0)
{
struct utsname buf;
uname (&buf);
strtok (linux_local + sizeof ("linux"), " \t\r\n");
if (!has_suffix (linux_local, buf.release))
return;

cpy_and_null (version, &version_local);
cpy_and_null (options, &options_local);
}

return;
}

static inline char *
parse_ostree_from_options (const char *options)
{
if (options)
{
options += sizeof ("options");
char *start_of_ostree = strstr (options, "ostree=");
if (start_of_ostree > options)
{
start_of_ostree += sizeof ("ostree");
/* trim everything to the right */
strtok (start_of_ostree, " \t\r\n");
return strdup (start_of_ostree);
}
}

return NULL;
}

/* This function is for boot arrangements where it is not possible to use a
* karg/cmdline, this is the case when the cmdline is part of the signed
* boot image, alternatively this function takes the karg from the bls entry
* which will have the correct ostree= karg set. This bls entry is not parsed
* from the bootloader but from the initramfs instead.
*/
static inline char *
bls_parser_get_ostree_option (const char *sysroot)
{
char out[PATH_MAX] = "";
int written = snprintf (out, PATH_MAX, "%s/boot/loader/entries", sysroot);
DIR __attribute__ ((cleanup (close_dir))) *dir = opendir (out);
if (!dir)
{
fprintf (stderr, "opendir(\"%s\") failed with %d\n", out, errno);
return NULL;
}

char __attribute__ ((cleanup (free_char))) *version = NULL;
char __attribute__ ((cleanup (free_char))) *options = NULL;
for (struct dirent *ent = 0; (ent = readdir (dir));)
{
if (ent->d_name[0] == '.')
ericcurtin marked this conversation as resolved.
Show resolved Hide resolved
continue;

if (!has_suffix (ent->d_name, ".conf"))
continue;

snprintf (out + written, PATH_MAX - written, "/%s", ent->d_name);

FILE __attribute__ ((cleanup (close_file))) *f = fopen (out, "r");
if (!f)
{
fprintf (stderr, "fopen(\"%s\", \"r\") failed with %d\n", out, errno);
continue;
}

copy_if_higher_version (f, &version, &options);
}

return parse_ostree_from_options (options);
}

/* This is an API for other projects to determine whether or not the
* currently running system is ostree-controlled.
*/
Expand Down
6 changes: 5 additions & 1 deletion src/switchroot/ostree-prepare-root.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,13 @@ resolve_deploy_path (const char * root_mountpoint)
{
char destpath[PATH_MAX];
struct stat stbuf;
char *ostree_target, *deploy_path;
char __attribute__ ((cleanup (free_char))) *ostree_target;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure this was leaking here and in src/switchroot/ostree-system-generator.c all along, but both are short lived processes so you wouldn't really notice.

char *deploy_path;

ostree_target = read_proc_cmdline_ostree ();
if (!strcmp (ostree_target, ABOOT_KARG))
ostree_target = bls_parser_get_ostree_option (root_mountpoint);

if (!ostree_target)
errx (EXIT_FAILURE, "No OSTree target; expected ostree=/ostree/boot.N/...");

Expand Down
5 changes: 4 additions & 1 deletion src/switchroot/ostree-system-generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ main(int argc, char *argv[])
* exit so that we don't error, but at the same time work where switchroot
* is PID 1 (and so hasn't created /run/ostree-booted).
*/
char *ostree_cmdline = read_proc_cmdline_ostree ();
char __attribute__ ((cleanup (free_char))) *ostree_cmdline = read_proc_cmdline_ostree ();
if (!strcmp (ostree_cmdline, ABOOT_KARG))
ostree_cmdline = bls_parser_get_ostree_option ("/sysroot");

if (!ostree_cmdline)
exit (EXIT_SUCCESS);

Expand Down