blob: 62ab1bc863f84457c22d146da0d8e64262776e51 [file] [log] [blame]
/* Copyright 2020 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/* For strdup */
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "2api.h"
#include "2return_codes.h"
#include "host_misc.h"
#include "flashrom.h"
#include "subprocess.h"
#define FLASHROM_EXEC_NAME "flashrom"
/**
* Helper to create a temporary file, and optionally write some data
* into it.
*
* @param data If data needs to be written to the file, a
* pointer to the buffer. Pass NULL to just
* create an empty temporary file.
* @param data_size The size of the buffer to write, if applicable.
* @param path_out An output pointer for the filename. Caller
* should free.
*
* @return VB2_SUCCESS on success, or a relevant error.
*/
static vb2_error_t write_temp_file(const uint8_t *data, uint32_t data_size,
char **path_out)
{
int fd;
ssize_t write_rv;
vb2_error_t rv;
char *path;
mode_t umask_save;
#if defined(__FreeBSD__)
#define P_tmpdir "/tmp"
#endif
*path_out = NULL;
path = strdup(P_tmpdir "/vb2_flashrom.XXXXXX");
/* Set the umask before mkstemp for security considerations. */
umask_save = umask(077);
fd = mkstemp(path);
umask(umask_save);
if (fd < 0) {
rv = VB2_ERROR_WRITE_FILE_OPEN;
goto fail;
}
while (data && data_size > 0) {
write_rv = write(fd, data, data_size);
if (write_rv < 0) {
close(fd);
unlink(path);
rv = VB2_ERROR_WRITE_FILE_DATA;
goto fail;
}
data_size -= write_rv;
data += write_rv;
}
close(fd);
*path_out = path;
return VB2_SUCCESS;
fail:
free(path);
return rv;
}
static vb2_error_t run_flashrom(const char *const argv[])
{
int status = subprocess_run(argv, &subprocess_null, &subprocess_null,
&subprocess_null);
if (status) {
fprintf(stderr, "Flashrom invocation failed (exit status %d):",
status);
for (const char *const *argp = argv; *argp; argp++)
fprintf(stderr, " %s", *argp);
fprintf(stderr, "\n");
return VB2_ERROR_FLASHROM;
}
return VB2_SUCCESS;
}
vb2_error_t flashrom_read(const char *programmer, const char *region,
uint8_t **data_out, uint32_t *size_out)
{
char *tmpfile;
char region_param[PATH_MAX];
vb2_error_t rv;
*data_out = NULL;
*size_out = 0;
VB2_TRY(write_temp_file(NULL, 0, &tmpfile));
if (region)
snprintf(region_param, sizeof(region_param), "%s:%s", region,
tmpfile);
const char *const argv[] = {
FLASHROM_EXEC_NAME,
"-p",
programmer,
"-r",
region ? "-i" : tmpfile,
region ? region_param : NULL,
NULL,
};
rv = run_flashrom(argv);
if (rv == VB2_SUCCESS)
rv = vb2_read_file(tmpfile, data_out, size_out);
unlink(tmpfile);
free(tmpfile);
return rv;
}
vb2_error_t flashrom_write(const char *programmer, const char *region,
uint8_t *data, uint32_t size)
{
char *tmpfile;
char region_param[PATH_MAX];
vb2_error_t rv;
VB2_TRY(write_temp_file(data, size, &tmpfile));
if (region)
snprintf(region_param, sizeof(region_param), "%s:%s", region,
tmpfile);
const char *const argv[] = {
FLASHROM_EXEC_NAME,
"-p",
programmer,
"--fast-verify",
"-w",
region ? "-i" : tmpfile,
region ? region_param : NULL,
NULL,
};
rv = run_flashrom(argv);
unlink(tmpfile);
free(tmpfile);
return rv;
}