From patchwork Tue Oct 9 11:26:58 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andy Whitcroft X-Patchwork-Id: 190280 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from chlorine.canonical.com (chlorine.canonical.com [91.189.94.204]) by ozlabs.org (Postfix) with ESMTP id B29262C00DA for ; Tue, 9 Oct 2012 22:27:19 +1100 (EST) Received: from localhost ([127.0.0.1] helo=chlorine.canonical.com) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1TLXxs-0003mX-Ra; Tue, 09 Oct 2012 11:27:08 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by chlorine.canonical.com with esmtp (Exim 4.71) (envelope-from ) id 1TLXxo-0003iV-DT for kernel-team@lists.ubuntu.com; Tue, 09 Oct 2012 11:27:04 +0000 Received: from 79-78-210-136.dynamic.dsl.as9105.com ([79.78.210.136] helo=localhost) by youngberry.canonical.com with esmtpsa (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1TLXxo-0002y7-0c; Tue, 09 Oct 2012 11:27:04 +0000 From: Andy Whitcroft To: kernel-team@lists.ubuntu.com Subject: [PATCH 2/4] efi: Handle deletions and size changes in efivarfs_write_file Date: Tue, 9 Oct 2012 12:26:58 +0100 Message-Id: <1349782020-18070-3-git-send-email-apw@canonical.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1349782020-18070-1-git-send-email-apw@canonical.com> References: <1349782020-18070-1-git-send-email-apw@canonical.com> Cc: Andy Whitcroft X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.13 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: kernel-team-bounces@lists.ubuntu.com Errors-To: kernel-team-bounces@lists.ubuntu.com From: Jeremy Kerr A write to an efivarfs file will not always result in a variable of 'count' size after the EFI SetVariable() call. We may have appended to the existing data (ie, with the EFI_VARIABLE_APPEND_WRITE attribute), or even have deleted the variable (with an authenticated variable update, with a zero datasize). This change re-reads the updated variable from firmware, to check for size changes and deletions. In the latter case, we need to drop the dentry. Signed-off-by: Jeremy Kerr Signed-off-by: Matt Fleming (cherry-picked from commit bd5967e2702f3e918c23b3fb1590312699645608 efi.git) BugLink: http://bugs.launchpad.net/bugs/1063061 Signed-off-by: Andy Whitcroft --- drivers/firmware/efivars.c | 49 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index a1d6940..6d43bbd 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -658,6 +658,7 @@ static ssize_t efivarfs_file_write(struct file *file, u32 attributes; struct inode *inode = file->f_mapping->host; int datasize = count - sizeof(attributes); + unsigned long newdatasize; if (count < sizeof(attributes)) return -EINVAL; @@ -696,32 +697,60 @@ static ssize_t efivarfs_file_write(struct file *file, switch (status) { case EFI_SUCCESS: - mutex_lock(&inode->i_mutex); - i_size_write(inode, count); - mutex_unlock(&inode->i_mutex); break; case EFI_INVALID_PARAMETER: count = -EINVAL; - break; + goto out; case EFI_OUT_OF_RESOURCES: count = -ENOSPC; - break; + goto out; case EFI_DEVICE_ERROR: count = -EIO; - break; + goto out; case EFI_WRITE_PROTECTED: count = -EROFS; - break; + goto out; case EFI_SECURITY_VIOLATION: count = -EACCES; - break; + goto out; case EFI_NOT_FOUND: count = -ENOENT; - break; + goto out; default: count = -EINVAL; - break; + goto out; } + + /* + * Writing to the variable may have caused a change in size (which + * could either be an append or an overwrite), or the variable to be + * deleted. Perform a GetVariable() so we can tell what actually + * happened. + */ + newdatasize = 0; + status = efivars->ops->get_variable(var->var.VariableName, + &var->var.VendorGuid, + NULL, &newdatasize, + NULL); + + if (status == EFI_BUFFER_TOO_SMALL) { + mutex_lock(&inode->i_mutex); + i_size_write(inode, newdatasize + sizeof(attributes)); + mutex_unlock(&inode->i_mutex); + + } else if (status == EFI_NOT_FOUND) { + spin_lock(&efivars->lock); + list_del(&var->list); + spin_unlock(&efivars->lock); + efivar_unregister(var); + drop_nlink(inode); + dput(file->f_dentry); + + } else { + pr_warn("efivarfs: inconsistent EFI variable implementation? " + "status = %lx\n", status); + } + out: kfree(data);