Skip to content

Commit

Permalink
[paver] support writing authorized_keys
Browse files Browse the repository at this point in the history
Test: fx pave --authorized_keys ~/.ssh/authorized_keys && fx shell cat /data/ssh/authorized_keys
Bug: US-548 #comment paver can write authorized_keys
Change-Id: I1c049f19556adaaf6bdcd1a9576d25bf5bfed0f5
  • Loading branch information
James Tucker authored and CQ bot account: [email protected] committed Nov 5, 2018
1 parent a66dd15 commit 691abf7
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 13 deletions.
7 changes: 6 additions & 1 deletion system/core/netsvc/tftp.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ static int paver_copy_buffer(void* arg) {

static tftp_status paver_open_write(const char* filename, size_t size, file_info_t* file_info) {
// paving an image to disk
const char* argv[] = {"/boot/bin/install-disk-image", NULL, NULL};
const char* argv[] = {"/boot/bin/install-disk-image", NULL, NULL, NULL, NULL};

if (!strcmp(filename + NB_IMAGE_PREFIX_LEN, NB_FVM_HOST_FILENAME)) {
printf("netsvc: Running FVM Paver\n");
Expand All @@ -230,6 +230,11 @@ static tftp_status paver_open_write(const char* filename, size_t size, file_info
} else if (!strcmp(filename + NB_IMAGE_PREFIX_LEN, NB_ZIRCONR_HOST_FILENAME)) {
printf("netsvc: Running ZIRCON-R Paver\n");
argv[1] = "install-zirconr";
} else if (!strcmp(filename + NB_IMAGE_PREFIX_LEN, NB_SSHAUTH_HOST_FILENAME)) {
printf("netsvc: Installing SSH authorized_keys\n");
argv[1] = "install-data-file";
argv[2] = "--path";
argv[3] = "ssh/authorized_keys";
} else {
fprintf(stderr, "netsvc: Unknown Paver\n");
return TFTP_ERR_IO;
Expand Down
28 changes: 21 additions & 7 deletions system/host/bootserver/bootserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,14 @@ void usage(void) {
" (ignored with --tftp)\n"
" -n only boot device with this nodename\n"
" -w <sz> tftp window size (default=%d, ignored with --netboot)\n"
" --fvm <file> use the supplied file as a sparse FVM image (up to 4 times)\n"
" --bootloader <file> use the supplied file as a BOOTLOADER image\n"
" --efi <file> use the supplied file as an EFI image\n"
" --kernc <file> use the supplied file as a KERN-C CrOS image\n"
" --zircona <file> use the supplied file as a ZIRCON-A ZBI\n"
" --zirconb <file> use the supplied file as a ZIRCON-B ZBI\n"
" --zirconr <file> use the supplied file as a ZIRCON-R ZBI\n"
" --fvm <file> use the supplied file as a sparse FVM image (up to 4 times)\n"
" --bootloader <file> use the supplied file as a BOOTLOADER image\n"
" --efi <file> use the supplied file as an EFI image\n"
" --kernc <file> use the supplied file as a KERN-C CrOS image\n"
" --zircona <file> use the supplied file as a ZIRCON-A ZBI\n"
" --zirconb <file> use the supplied file as a ZIRCON-B ZBI\n"
" --zirconr <file> use the supplied file as a ZIRCON-R ZBI\n"
" --authorized_keys <file> use the supplied file as an authorized_keys file\n"
" --netboot use the netboot protocol\n"
" --tftp use the tftp protocol (default)\n"
" --nocolor disable ANSI color (false)\n",
Expand Down Expand Up @@ -293,6 +294,7 @@ int main(int argc, char** argv) {
const char* zircona_image = NULL;
const char* zirconb_image = NULL;
const char* zirconr_image = NULL;
const char* authorized_keys = NULL;
const char* fvm_images[MAX_FVM_IMAGES] = {NULL, NULL, NULL, NULL};
const char* kernel_fn = NULL;
const char* ramdisk_fn = NULL;
Expand Down Expand Up @@ -376,6 +378,15 @@ int main(int argc, char** argv) {
return -1;
}
zirconr_image = argv[1];
} else if (!strcmp(argv[1], "--authorized_keys")) {
argc--;
argv++;
if (argc <= 1) {
fprintf(stderr,
"'--authorized_keys' option requires an argument (authorized_keys)\n");
return -1;
}
authorized_keys = argv[1];
} else if (!strcmp(argv[1], "-1")) {
once = 1;
} else if (!strcmp(argv[1], "-b")) {
Expand Down Expand Up @@ -608,6 +619,9 @@ int main(int argc, char** argv) {
if (status == 0 && zirconr_image) {
status = xfer(&ra, zirconr_image, NB_ZIRCONR_FILENAME);
}
if (status == 0 && authorized_keys) {
status = xfer(&ra, authorized_keys, NB_SSHAUTH_FILENAME);
}
if (status == 0 && kernel_fn) {
status = xfer(&ra, kernel_fn, NB_KERNEL_FILENAME);
}
Expand Down
2 changes: 2 additions & 0 deletions system/public/zircon/boot/netboot.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
#define NB_ZIRCONB_FILENAME NB_IMAGE_PREFIX NB_ZIRCONB_HOST_FILENAME
#define NB_ZIRCONR_HOST_FILENAME "zirconr.img"
#define NB_ZIRCONR_FILENAME NB_IMAGE_PREFIX NB_ZIRCONR_HOST_FILENAME
#define NB_SSHAUTH_HOST_FILENAME "authorized_keys"
#define NB_SSHAUTH_FILENAME NB_IMAGE_PREFIX NB_SSHAUTH_HOST_FILENAME

typedef struct nbmsg_t {
uint32_t magic;
Expand Down
19 changes: 18 additions & 1 deletion system/uapp/disk-pave/disk-pave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
#include <string.h>
#include <unistd.h>

#include "pave-logging.h"
#include "pave-lib.h"
#include "pave-logging.h"

namespace {

Expand All @@ -29,10 +29,12 @@ void PrintUsage() {
ERROR(" install-zirconb : Install a ZIRCON-B partition to the device\n");
ERROR(" install-zirconr : Install a ZIRCON-R partition to the device\n");
ERROR(" install-fvm : Install a sparse FVM to the device\n");
ERROR(" install-data-file : Install a file to DATA (--path required)\n");
ERROR(" wipe : Clean up the install disk\n");
ERROR("Options:\n");
ERROR(" --file <file>: Read from FILE instead of stdin\n");
ERROR(" --force: Install partition even if inappropriate for the device\n");
ERROR(" --path <path>: Install DATA file to path\n");
}

bool ParseFlags(int argc, char** argv, Flags* flags) {
Expand Down Expand Up @@ -61,6 +63,8 @@ bool ParseFlags(int argc, char** argv, Flags* flags) {
flags->cmd = Command::kInstallZirconB;
} else if (!strcmp(argv[0], "install-zirconr")) {
flags->cmd = Command::kInstallZirconR;
} else if (!strcmp(argv[0], "install-data-file")) {
flags->cmd = Command::kInstallDataFile;
} else if (!strcmp(argv[0], "install-fvm")) {
flags->cmd = Command::kInstallFvm;
} else if (!strcmp(argv[0], "wipe")) {
Expand Down Expand Up @@ -91,13 +95,26 @@ bool ParseFlags(int argc, char** argv, Flags* flags) {
ERROR("Couldn't open supplied file\n");
return false;
}
} else if (!strcmp(argv[0], "--path")) {
SHIFT_ARGS;
if (argc < 1) {
ERROR("'--path' argument requires a path\n");
return false;
}
flags->path = argv[0];
} else if (!strcmp(argv[0], "--force")) {
flags->force = true;
} else {
return false;
}
SHIFT_ARGS;
}

if (flags->cmd == Command::kInstallDataFile && flags->path == nullptr) {
ERROR("install-data-file requires --path\n");
return false;
}

return true;
#undef SHIFT_ARGS
}
Expand Down
119 changes: 115 additions & 4 deletions system/uapp/disk-pave/pave-lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <dirent.h>
#include <fcntl.h>
#include <libgen.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
Expand Down Expand Up @@ -40,11 +41,13 @@
#include "pave-logging.h"
#include "pave-utils.h"

#define ZXCRYPT_DRIVER_LIB "/boot/driver/zxcrypt.so"

namespace paver {
namespace {

static Partition PartitionType(const Command command) {
switch(command) {
switch (command) {
case Command::kInstallBootloader:
return Partition::kBootloader;
case Command::kInstallEfi:
Expand Down Expand Up @@ -88,7 +91,8 @@ zx_status_t FvmIsVirtualPartition(const fbl::unique_fd& fd, bool* out) {
// Describes the state of a partition actively being written
// out to disk.
struct PartitionInfo {
PartitionInfo() : pd(nullptr) {}
PartitionInfo()
: pd(nullptr) {}

fvm::partition_descriptor_t* pd;
fbl::unique_fd new_part;
Expand Down Expand Up @@ -619,7 +623,6 @@ zx_status_t ValidatePartitions(const fbl::unique_fd& fvm_fd,

*out_requested_slices = requested_slices;
return ZX_OK;

}

// Allocates the space requested by the partitions by creating new
Expand Down Expand Up @@ -977,12 +980,120 @@ zx_status_t RealMain(Flags flags) {
return ZX_OK;
}
break;
case Command::kInstallDataFile:
return DataFilePave(fbl::move(device_partitioner), fbl::move(flags.payload_fd), flags.path);

default:
ERROR("Unsupported command.");
return ZX_ERR_NOT_SUPPORTED;
}
return PartitionPave(fbl::move(device_partitioner), fbl::move(flags.payload_fd),
PartitionType(flags.cmd), flags.arch);
PartitionType(flags.cmd), flags.arch);
}

zx_status_t DataFilePave(fbl::unique_ptr<DevicePartitioner> partitioner,
fbl::unique_fd payload_fd, char* data_path) {

const char* mount_path = "/volume/data";
const uint8_t data_guid[] = GUID_DATA_VALUE;
char minfs_path[PATH_MAX] = {0};
char path[PATH_MAX] = {0};
zx_status_t status = ZX_OK;

fbl::unique_fd part_fd(open_partition(nullptr, data_guid, ZX_SEC(1), path));
if (!part_fd) {
ERROR("DATA partition not found in FVM\n");
Drain(fbl::move(payload_fd));
return ZX_ERR_NOT_FOUND;
}

switch (detect_disk_format(part_fd.get())) {
case DISK_FORMAT_MINFS:
// If the disk we found is actually minfs, we can just use the block
// device path we were given by open_partition.
strncpy(minfs_path, path, PATH_MAX);
break;

case DISK_FORMAT_ZXCRYPT:
// Compute the topological path of the FVM block driver, and then tack
// the zxcrypt-device string onto the end. This should be improved.
ioctl_device_get_topo_path(part_fd.get(), path, sizeof(path));
snprintf(minfs_path, sizeof(minfs_path), "%s/zxcrypt/block", path);

// TODO(security): ZX-1130. We need to bind with channel in order to
// pass a key here. Where does the key come from? We need to determine
// if this is unattended.
ioctl_device_bind(part_fd.get(), ZXCRYPT_DRIVER_LIB, strlen(ZXCRYPT_DRIVER_LIB));

if ((status = wait_for_device(minfs_path, ZX_SEC(5))) != ZX_OK) {
ERROR("zxcrypt bind error: %s\n", zx_status_get_string(status));
return status;
}

break;

default:
ERROR("unsupported disk format at %s\n", path);
return ZX_ERR_NOT_SUPPORTED;
}

mount_options_t opts(default_mount_options);
opts.create_mountpoint = true;
if ((status = mount(open(minfs_path, O_RDWR), mount_path, DISK_FORMAT_MINFS,
&opts, launch_logs_async)) != ZX_OK) {
ERROR("mount error: %s\n", zx_status_get_string(status));
Drain(fbl::move(payload_fd));
return status;
}

// mkdir any intermediate directories between mount_path and basename(data_path)
snprintf(path, sizeof(path), "%s/%s", mount_path, data_path);
size_t cur = strlen(mount_path);
size_t max = strlen(path) - strlen(basename(path));
// note: the call to basename above modifies path, so it needs reconstruction.
snprintf(path, sizeof(path), "%s/%s", mount_path, data_path);
while (cur < max) {
++cur;
if (path[cur] == '/') {
path[cur] = 0;
// errors ignored, let the open() handle that later.
mkdir(path, 0700);
path[cur] = '/';
}
}

// We append here, because the primary use case here is to send SSH keys
// which can be appended, but we may want to revisit this choice for other
// files in the future.
{
char buf[8192];
ssize_t n;
fbl::unique_fd kfd(open(path, O_CREAT | O_WRONLY | O_APPEND, 0600));
if (!kfd) {
umount(mount_path);
ERROR("open %s error: %s\n", data_path, strerror(errno));
Drain(fbl::move(payload_fd));
return ZX_ERR_IO;
}
while ((n = read(payload_fd.get(), &buf, sizeof(buf))) > 0) {
if (write(kfd.get(), &buf, n) != n) {
umount(mount_path);
ERROR("write %s error: %s\n", data_path, strerror(errno));
Drain(fbl::move(payload_fd));
return ZX_ERR_IO;
}
}
fsync(kfd.get());
}

if ((status = umount(mount_path)) != ZX_OK) {
ERROR("unmount %s failed: %s\n", mount_path,
zx_status_get_string(status));
return status;
}

LOG("Wrote %s\n", data_path);
return ZX_OK;
}

} // namespace paver
6 changes: 6 additions & 0 deletions system/uapp/disk-pave/pave-lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum class Command {
kInstallZirconA,
kInstallZirconB,
kInstallZirconR,
kInstallDataFile,
kInstallFvm,
kWipe,
};
Expand All @@ -36,12 +37,17 @@ struct Flags {
Arch arch = Arch::X64;
bool force = false;
fbl::unique_fd payload_fd;
char* path = nullptr;
};

// Paves an image onto the disk.
extern zx_status_t PartitionPave(fbl::unique_ptr<DevicePartitioner> partitioner,
fbl::unique_fd payload_fd, Partition partition_type, Arch arch);

// Paves |fd| to a target |data_path| within the /data partition.
zx_status_t DataFilePave(fbl::unique_ptr<DevicePartitioner> partitioner,
fbl::unique_fd payload_fd, char* data_path);

// Reads the entire file from supplied file descriptor. This is necessary due to
// implementation of streaming protocol which forces entire file to be
// transferred.
Expand Down

0 comments on commit 691abf7

Please sign in to comment.