If the caller, in this case efivarfs_callback(), only provides sufficent room for the expanded utf8 and not enough to include the terminating NUL byte, that NUL byte is skipped. When the caller then interprets it as a string, it may then read from past its allocated memory: [ 170.605647] WARNING: kmemcheck: Caught 8-bit read from uninitialized memory (ffff8804079ae786) [ 170.605677] 436f6e4f757400004c44322d35363062663538612d316530642d346437652d39 [ 170.606037] i i i i i i u u u u u u u u u u u u u u u u u u u u u u u u u u [ 170.606236] ^ [ 170.606243] RIP: 0010:[<ffffffff813a251f>] [<ffffffff813a251f>] efivar_variable_is_removable+0xaf/0xf0 [ 170.606346] RSP: 0018:ffff880408e73c20 EFLAGS: 00010206 [ 170.606352] RAX: 0000000000000000 RBX: 0000000000000006 RCX: 0000000000000006 [ 170.606359] RDX: 0000000000000000 RSI: 0000000000000074 RDI: ffff880408e73c30 [ 170.606365] RBP: ffff880408e73c80 R08: 0000000000000006 R09: 000000000000008c [ 170.606371] R10: 0000000000000006 R11: 0000000000000000 R12: ffffffff8166ed20 [ 170.606378] R13: 11d293ca8be4df61 R14: ffffffff81773834 R15: ffff8804079ae780 [ 170.606385] FS: 0000000000000000(0000) GS:ffff88041ca00000(0000) knlGS:0000000000000000 [ 170.606392] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 170.606399] CR2: ffff880409cbe4c0 CR3: 00000004085fd000 CR4: 00000000001406f0 [ 170.606405] [<ffffffff811eb938>] efivarfs_callback+0xf8/0x275 [ 170.606418] [<ffffffff813a3368>] efivar_init+0x248/0x2e0 [ 170.606440] [<ffffffff811eb6b4>] efivarfs_fill_super+0xb4/0xf0 [ 170.606452] [<ffffffff811333e7>] mount_single+0x87/0xb0 [ 170.606463] [<ffffffff811eb5f3>] efivarfs_mount+0x13/0x20 [ 170.606475] [<ffffffff81133480>] mount_fs+0x10/0x90 [ 170.606497] [<ffffffff8114c732>] vfs_kern_mount+0x62/0x100 [ 170.606508] [<ffffffff8114ecb0>] do_mount+0x1e0/0xcd0 [ 170.606519] [<ffffffff8114fa9f>] SyS_mount+0x8f/0xd0 [ 170.606530] [<ffffffff81451d1f>] entry_SYSCALL_64_fastpath+0x17/0x93 [ 170.606542] [<ffffffffffffffff>] 0xffffffffffffffff Cc: Matt Fleming <matt@xxxxxxxxxxxxxxxxxxx> Cc: Jason Andryuk <jandryuk@xxxxxxxxx> Cc: Matthew Garrett <mjg59@xxxxxxxxxx> Cc: Laszlo Ersek <lersek@xxxxxxxxxx> Cc: Peter Jones <pjones@xxxxxxxxxx> Cc: linux-efi@xxxxxxxxxxxxxxx Cc: linux-kernel@xxxxxxxxxxxxxxx --- drivers/firmware/efi/vars.c | 2 +- lib/ucs2_string.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/efi/vars.c b/drivers/firmware/efi/vars.c index 0ac594c0a234..8dd503bac35d 100644 --- a/drivers/firmware/efi/vars.c +++ b/drivers/firmware/efi/vars.c @@ -166,7 +166,7 @@ validate_ascii_string(efi_char16_t *var_name, int match, u8 *buffer, struct variable_validate { efi_guid_t vendor; - char *name; + const char *name; bool (*validate)(efi_char16_t *var_name, int match, u8 *data, unsigned long len); }; diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c index f0b323abb4c6..fb8d03966656 100644 --- a/lib/ucs2_string.c +++ b/lib/ucs2_string.c @@ -85,29 +85,34 @@ ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) unsigned long j = 0; unsigned long limit = ucs2_strnlen(src, maxlength); - for (i = 0; maxlength && i < limit; i++) { + if (maxlength == 0) + return 0; + + for (i = 0; i < limit; i++) { u16 c = src[i]; if (c >= 0x800) { - if (maxlength < 3) + if (maxlength <= 3) break; maxlength -= 3; dest[j++] = 0xe0 | (c & 0xf000) >> 12; dest[j++] = 0x80 | (c & 0x0fc0) >> 6; dest[j++] = 0x80 | (c & 0x003f); } else if (c >= 0x80) { - if (maxlength < 2) + if (maxlength <= 2) break; maxlength -= 2; dest[j++] = 0xc0 | (c & 0x7c0) >> 6; dest[j++] = 0x80 | (c & 0x03f); } else { + if (maxlength <= 1) + break; maxlength -= 1; dest[j++] = c & 0x7f; } } - if (maxlength) - dest[j] = '\0'; + dest[j] = '\0'; + return j; } EXPORT_SYMBOL(ucs2_as_utf8); -- 2.8.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html