// SPDX-License-Identifier: GPL-2.0+ /* * EFI Test Driver for Runtime Services * * Copyright(C) 2012-2016 Canonical Ltd. * * This driver exports EFI runtime services interfaces into userspace, which * allow to use and test UEFI runtime services provided by firmware. *
*/
MODULE_AUTHOR("Ivan Hu ");
MODULE_DESCRIPTION("EFI Test Driver");
MODULE_LICENSE("GPL");
/* * Count the bytes in 'str', including the terminating NULL. * * Note this function returns the number of *bytes*, not the number of * ucs2 characters.
*/ staticinline size_t user_ucs2_strsize(efi_char16_t __user *str)
{
efi_char16_t *s = str, c;
size_t len;
if (!str) return 0;
/* Include terminating NULL */
len = sizeof(efi_char16_t);
if (get_user(c, s++)) { /* Can't read userspace memory for size */ return 0;
}
while (c != 0) { if (get_user(c, s++)) { /* Can't read userspace memory for size */ return 0;
}
len += sizeof(efi_char16_t);
} return len;
}
/* * Allocate a buffer and copy a ucs2 string from user space into it.
*/ staticinlineint
copy_ucs2_from_user_len(efi_char16_t **dst, efi_char16_t __user *src,
size_t len)
{
efi_char16_t *buf;
/* * Count the bytes in 'str', including the terminating NULL. * * Just a wrap for user_ucs2_strsize
*/ staticinlineint
get_ucs2_strsize_from_user(efi_char16_t __user *src, size_t *len)
{
*len = user_ucs2_strsize(src); if (*len == 0) return -EFAULT;
return 0;
}
/* * Calculate the required buffer allocation size and copy a ucs2 string * from user space into it. * * This function differs from copy_ucs2_from_user_len() because it * calculates the size of the buffer to allocate by taking the length of * the string 'src'. * * If a non-zero value is returned, the caller MUST NOT access 'dst'. * * It is the caller's responsibility to free 'dst'.
*/ staticinlineint
copy_ucs2_from_user(efi_char16_t **dst, efi_char16_t __user *src)
{
size_t len;
len = user_ucs2_strsize(src); if (len == 0) return -EFAULT; return copy_ucs2_from_user_len(dst, src, len);
}
/* * Copy a ucs2 string to a user buffer. * * This function is a simple wrapper around copy_to_user() that does * nothing if 'src' is NULL, which is useful for reducing the amount of * NULL checking the caller has to do. * * 'len' specifies the number of bytes to copy.
*/ staticinlineint
copy_ucs2_to_user_len(efi_char16_t __user *dst, efi_char16_t *src, size_t len)
{ if (!src) return 0;
if (copy_from_user(&getnextvariablename, getnextvariablename_user, sizeof(getnextvariablename))) return -EFAULT;
if (getnextvariablename.variable_name_size) { if (get_user(name_size, getnextvariablename.variable_name_size)) return -EFAULT;
ns = &name_size;
prev_name_size = name_size;
}
if (getnextvariablename.vendor_guid) { if (copy_from_user(&vendor_guid,
getnextvariablename.vendor_guid, sizeof(vendor_guid))) return -EFAULT;
vd = &vendor_guid;
}
if (getnextvariablename.variable_name) {
size_t name_string_size = 0;
rv = get_ucs2_strsize_from_user(
getnextvariablename.variable_name,
&name_string_size); if (rv) return rv; /* * The name_size may be smaller than the real buffer size where * variable name located in some use cases. The most typical * case is passing a 0 to get the required buffer size for the * 1st time call. So we need to copy the content from user * space for at least the string size of variable name, or else * the name passed to UEFI may not be terminated as we expected.
*/
rv = copy_ucs2_from_user_len(&name,
getnextvariablename.variable_name,
prev_name_size > name_string_size ?
prev_name_size : name_string_size); if (rv) return rv;
}
status = efi.get_next_variable(ns, name, vd);
if (put_user(status, getnextvariablename.status)) {
rv = -EFAULT; goto out;
}
if (status != EFI_SUCCESS) { if (status == EFI_BUFFER_TOO_SMALL) { if (ns && put_user(*ns,
getnextvariablename.variable_name_size)) {
rv = -EFAULT; goto out;
}
}
rv = -EINVAL; goto out;
}
if (name) { if (copy_ucs2_to_user_len(getnextvariablename.variable_name,
name, prev_name_size)) {
rv = -EFAULT; goto out;
}
}
if (ns) { if (put_user(*ns, getnextvariablename.variable_name_size)) {
rv = -EFAULT; goto out;
}
}
if (vd) { if (copy_to_user(getnextvariablename.vendor_guid, vd, sizeof(efi_guid_t)))
rv = -EFAULT;
}
for (i = 0; i < qcaps.capsule_count; i++) {
efi_capsule_header_t *c; /* * We cannot dereference qcaps.capsule_header_array directly to * obtain the address of the capsule as it resides in the * user space
*/ if (get_user(c, qcaps.capsule_header_array + i)) {
rv = -EFAULT; goto out;
} if (copy_from_user(&capsules[i], c, sizeof(efi_capsule_header_t))) {
rv = -EFAULT; goto out;
}
}
qcaps.capsule_header_array = &capsules;
status = efi.query_capsule_caps((efi_capsule_header_t **)
qcaps.capsule_header_array,
qcaps.capsule_count,
&max_size, &reset_type);
if (put_user(status, qcaps.status)) {
rv = -EFAULT; goto out;
}
case EFI_RUNTIME_SET_VARIABLE: return efi_runtime_set_variable(arg);
case EFI_RUNTIME_GET_TIME: return efi_runtime_get_time(arg);
case EFI_RUNTIME_SET_TIME: return efi_runtime_set_time(arg);
case EFI_RUNTIME_GET_WAKETIME: return efi_runtime_get_waketime(arg);
case EFI_RUNTIME_SET_WAKETIME: return efi_runtime_set_waketime(arg);
case EFI_RUNTIME_GET_NEXTVARIABLENAME: return efi_runtime_get_nextvariablename(arg);
case EFI_RUNTIME_GET_NEXTHIGHMONOTONICCOUNT: return efi_runtime_get_nexthighmonocount(arg);
case EFI_RUNTIME_QUERY_VARIABLEINFO: return efi_runtime_query_variableinfo(arg);
case EFI_RUNTIME_QUERY_CAPSULECAPABILITIES: return efi_runtime_query_capsulecaps(arg);
case EFI_RUNTIME_RESET_SYSTEM: return efi_runtime_reset_system(arg);
case EFI_RUNTIME_GET_SUPPORTED_MASK: return efi_runtime_get_supported_mask(arg);
}
return -ENOTTY;
}
staticint efi_test_open(struct inode *inode, struct file *file)
{ int ret = security_locked_down(LOCKDOWN_EFI_TEST);
if (ret) return ret;
if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* * nothing special to do here * We do accept multiple open files at the same time as we * synchronize on the per call operation.
*/ return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.