From patchwork Mon Apr 9 02:22:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ge Song X-Patchwork-Id: 896084 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40KDdm156kz9rvt for ; Mon, 9 Apr 2018 12:24:28 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ow3MZO3R"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 40KDdl6G7mzF29l for ; Mon, 9 Apr 2018 12:24:27 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ow3MZO3R"; dkim-atps=neutral X-Original-To: petitboot@lists.ozlabs.org Delivered-To: petitboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:400e:c00::244; helo=mail-pf0-x244.google.com; envelope-from=songgebird@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ow3MZO3R"; dkim-atps=neutral Received: from mail-pf0-x244.google.com (mail-pf0-x244.google.com [IPv6:2607:f8b0:400e:c00::244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 40KDdS6lmjzDrpW for ; Mon, 9 Apr 2018 12:24:12 +1000 (AEST) Received: by mail-pf0-x244.google.com with SMTP id q9so4931245pff.1 for ; Sun, 08 Apr 2018 19:24:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=rH5Rk4OAfIS76Z4vylYcqYRCaA/Ah+FMvrM5IIOKZZk=; b=Ow3MZO3RwlCAq07ByQ6fs4Rfxu7oQ6w45ba+kiMoEkLVarmJviWEuQh0TRUCS4jlzQ 6ZlzXan0a0MSqo2yJYv7+g0XcekCGMbILCPG/D/UePzXokFayxpbBrA3UuPi9cYLBCps vn5KPzBOLgUdlnYN5xc6zEDF2G1JtpTUvYSn5bRHpXBUB+O7FdFlI3ljfe6pLOGrhJct +9IjWx3ek5ifo2+MzH3MdsTeiOUZo/UVUL5mX6yvE4vnrOoFXV5XnXp2iL162JODwxLc UrFLvWuKTxxJyHRlHm24js70gh0F/3F8lzWVxiqoTtZiDSGqLm/ehqT2yK4WPmUYn7g6 7NEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=rH5Rk4OAfIS76Z4vylYcqYRCaA/Ah+FMvrM5IIOKZZk=; b=RhyESk/HwOssOpq/OY6A7vdgUGBa3V02KbMbmIElMymmsoak3ls+GaanKPmkVn4g8Z yNwiea9frOEtVFkEWLzHvOf7LmbFwQ5PkyZb4dt9ivjE11l+Pp9DDPeYyt+88Kr/z12z +asZUpy6KrHHVoiD39EV9OAaTHFWeG7HYO7MUsmMSGvA/bdkJCNSHvczN79VbK6xNsvr RlnRqEWYkIvKnUFkX2tUy2ccUyljLRQSFYazjKdtFiROQno4xRTG50hFZrtHaRO5mq8W N3jNE5/cea1t+pb9MJZ7tqEecQR4iC6L8TIehXuaDlq2mYW56sSqSffZQfVIhMr5Ih1n YBZw== X-Gm-Message-State: AElRT7FYeiHVOqiFSAHWuE4R3lutQawBWdFVlndfCxnd6sos1sKhWz9R 2NNBji5Dl+vAF8S+JoU/YBZsqA== X-Google-Smtp-Source: AIpwx49H7uCQC/NZJ5CxR9/luvsu3+KZMMzQQa+N8HEjgtfHOR1qEwrBRKbwSxXiy5THs2W2gKy1iQ== X-Received: by 10.98.153.204 with SMTP id t73mr27718750pfk.121.1523240650775; Sun, 08 Apr 2018 19:24:10 -0700 (PDT) Received: from vbox.hxtcorp.net ([101.81.130.12]) by smtp.gmail.com with ESMTPSA id i127sm24587548pgc.12.2018.04.08.19.24.09 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 08 Apr 2018 19:24:10 -0700 (PDT) From: Ge Song X-Google-Original-From: Ge Song To: petitboot@lists.ozlabs.org Subject: [PATCH v2 1/2] lib: Support to deal with petitboot's configuration on efi-based platforms Date: Mon, 9 Apr 2018 10:22:01 +0800 Message-Id: <20180409022202.16476-2-ge.song@hxt-semitech.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180409022202.16476-1-ge.song@hxt-semitech.com> References: <20180409022202.16476-1-ge.song@hxt-semitech.com> X-BeenThere: petitboot@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Petitboot bootloader development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: petitboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Petitboot" Provide methods to load/store petitboot's configuration on efi-based platforms. A test case is also provided. Signed-off-by: Ge Song Signed-off-by: Ge Song <ge.song@hxt-semitech.com> --- lib/Makefile.am | 2 + test/lib/Makefile.am | 3 +- lib/efi/efivar.h | 43 +++++ lib/efi/efivar.c | 179 ++++++++++++++++++++ test/lib/test-efivar.c | 68 ++++++++ 5 files changed, 294 insertions(+), 1 deletion(-) diff --git a/lib/Makefile.am b/lib/Makefile.am index bb7dfe489132..50fb9d14df49 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -58,6 +58,8 @@ lib_libpbcore_la_SOURCES = \ lib/util/util.h \ lib/flash/config.h \ lib/flash/flash.h \ + lib/efi/efivar.h \ + lib/efi/efivar.c \ $(gpg_int_SOURCES) if ENABLE_MTD diff --git a/test/lib/Makefile.am b/test/lib/Makefile.am index 9636b08d6a6b..22e3ac91499d 100644 --- a/test/lib/Makefile.am +++ b/test/lib/Makefile.am @@ -23,7 +23,8 @@ lib_TESTS = \ test/lib/test-process-parent-stdout \ test/lib/test-process-both \ test/lib/test-process-stdout-eintr \ - test/lib/test-fold + test/lib/test-fold \ + test/lib/test-efivar $(lib_TESTS): LIBS += $(core_lib) diff --git a/lib/efi/efivar.h b/lib/efi/efivar.h new file mode 100644 index 000000000000..da0e0d68b6c8 --- /dev/null +++ b/lib/efi/efivar.h @@ -0,0 +1,43 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights + * reserved. + * Author: Ge Song + */ +#ifndef EFIVAR_H +#define EFIVAR_H + +#include + +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 + +#define EFIVARFS_MAGIC 0xde5e81e4 + +static inline const char* get_efivarfs_path(void) +{ + return "/sys/firmware/efi/efivars/"; +} +int efi_get_variable(void *ctx, const char *guidstr, const char *name, + uint8_t **data, size_t *data_size, uint32_t *attributes); +int efi_set_variable(void *ctx, const char *guidstr, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes); +int efi_del_variable(void *ctx, const char *guidstr, const char *name); +#endif /* EFIVAR_H */ diff --git a/lib/efi/efivar.c b/lib/efi/efivar.c new file mode 100644 index 000000000000..5ce3464b9e77 --- /dev/null +++ b/lib/efi/efivar.c @@ -0,0 +1,179 @@ +/* + * Methods to manipulation of EFI variables on UEFI-based platforms + * + * The library relies on pesudo file system named "efivarfs". This is the + * new interface to manipulate EFI varibles and was part of the linux + * kernel v3.10 release. + * + * There is also a legacy efivars interface exported via the path + * "firmware/efi/vars/" relative to the mount point of sysfs. Since it has + * some drawbacks and is deprecated, we don't support this interface. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights + * reserved. + * Author: Ge Song + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "efivar.h" +#include "talloc/talloc.h" + +int efi_del_variable(void *ctx, const char *guidstr, + const char *name) +{ + int fd, flag, errno_value; + int rc = -1; + char *path; + + path = talloc_asprintf(ctx, "%s%s-%s", + get_efivarfs_path(), name, guidstr); + if (!path) + return ENOMEM; + + fd = open(path, O_RDONLY|O_NONBLOCK); + if (fd == -1) + goto err; + + rc = ioctl(fd, FS_IOC_GETFLAGS, &flag); + if (rc == -1) + goto err; + + flag &= ~FS_IMMUTABLE_FL; + rc = ioctl(fd, FS_IOC_SETFLAGS, &flag); + if (rc == -1) + goto err; + + close(fd); + rc = unlink(path); + +err: + errno_value = errno; + if (fd > 0) + close(fd); + + errno = errno_value; + return rc; +} + +int efi_get_variable(void *ctx, const char *guidstr, const char *name, + uint8_t **data, size_t *data_size, uint32_t *attributes) +{ + int fd, errno_value; + int rc = -1; + void *p, *buf; + size_t bufsize = 4096; + size_t filesize = 0; + ssize_t sz; + char *path; + + path = talloc_asprintf(ctx, "%s%s-%s", + get_efivarfs_path(), name, guidstr); + if (!path) + return ENOMEM; + + fd = open(path, O_RDONLY); + if (fd < 0) + goto err; + + buf = talloc_size(ctx, bufsize); + if (!buf) + goto err; + + do { + p = buf + filesize; + sz = read(fd, p, bufsize); + if (sz < 0 && errno == EAGAIN) { + continue; + } else if (sz == 0) { + break; + } + filesize += sz; + } while (1); + + *attributes = *(uint32_t *)buf; + *data = (uint8_t *)(buf + sizeof(uint32_t)); + *data_size = strlen(buf + sizeof(uint32_t)); + rc = 0; + +err: + errno_value = errno; + if (fd > 0) + close(fd); + + errno = errno_value; + return rc; +} + +int efi_set_variable(void *ctx, const char *guidstr, const char *name, + uint8_t *data, size_t data_size, uint32_t attributes) +{ + int rc = -1, errno_value; + int fd = -1; + ssize_t len; + char *path; + void *buf; + size_t bufsize; + mode_t mask = umask(umask(0)); + + path = talloc_asprintf(ctx, "%s%s-%s", + get_efivarfs_path(), name, guidstr); + if (!path) + return ENOMEM; + + if (!access(path, F_OK)) { + rc = efi_del_variable(ctx, guidstr, name); + if (rc < 0) { + goto err; + } + } + + fd = open(path, O_CREAT|O_WRONLY, mask); + if (fd < 0) + goto err; + + bufsize = sizeof(uint32_t) + data_size; + buf = talloc_size(ctx, bufsize); + if (!buf) + goto err; + + *(uint32_t *)buf = attributes; + memcpy(buf + sizeof(uint32_t), data, data_size); + + len = write(fd, buf, bufsize); + if ((size_t)len != bufsize) + goto err; + else + rc = 0; + +err: + errno_value = errno; + if (fd > 0) + close(fd); + + errno = errno_value; + return rc; +} diff --git a/test/lib/test-efivar.c b/test/lib/test-efivar.c new file mode 100644 index 000000000000..aec2549c4993 --- /dev/null +++ b/test/lib/test-efivar.c @@ -0,0 +1,68 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights + * reserved. + * Author: Ge Song + */ +#include +#include +#include +#include +#include + +#include "efi/efivar.h" +#include "talloc/talloc.h" + +#define DEF_ATTR (EFI_VARIABLE_NON_VOLATILE | \ + EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS) + +static const char *test_efivar_guid = "c9c07add-256e-4452-b911-f8d0d35a1ac7"; +static const char *test_varname = "efivartest"; +static const char *test_data = "petitboot"; + +int main(int argc, char *argv[]) +{ + void *ctx = NULL; + int rc, errno_value; + size_t size; + uint8_t *data = NULL; + uint32_t attr = DEF_ATTR; + + talloc_new(ctx); + + size = strlen(test_data) + 1; + rc = efi_set_variable(ctx, test_efivar_guid, test_varname, + (uint8_t *)test_data, size, attr); + + rc = efi_get_variable(ctx, test_efivar_guid, test_varname, + &data, &size, &attr); + + rc = strcmp((char *)data, test_data); + if (rc) { + talloc_free(ctx); + assert(0); + } + + rc = efi_del_variable(ctx, test_efivar_guid, test_varname); + + rc = efi_get_variable(ctx, test_efivar_guid, test_varname, + &data, &size, &attr); + + errno_value = errno; + talloc_free(ctx); + assert(errno_value == ENOENT); + + return EXIT_SUCCESS; +}