Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 fixes from Ingo Molnar:
"This is unusually large, partly due to the EFI fixes that prevent
accidental deletion of EFI variables through efivarfs that may brick
machines. These fixes are somewhat involved to maintain compatibility
with existing install methods and other usage modes, while trying to
turn off the 'rm -rf' bricking vector.

Other fixes are for large page ioremap()s and for non-temporal
user-memcpy()s"

* 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/mm: Fix vmalloc_fault() to handle large pages properly
hpet: Drop stale URLs
x86/uaccess/64: Handle the caching of 4-byte nocache copies properly in __copy_user_nocache()
x86/uaccess/64: Make the __copy_user_nocache() assembly code more readable
lib/ucs2_string: Correct ucs2 -> utf8 conversion
efi: Add pstore variables to the deletion whitelist
efi: Make efivarfs entries immutable by default
efi: Make our variable validation list include the guid
efi: Do variable name validation tests in utf8
efi: Use ucs2_as_utf8 in efivarfs instead of open coding a bad version
lib/ucs2_string: Add ucs2 -> utf8 helper functions

+501 -135
+7
Documentation/filesystems/efivarfs.txt
··· 14 14 efivarfs is typically mounted like this, 15 15 16 16 mount -t efivarfs none /sys/firmware/efi/efivars 17 + 18 + Due to the presence of numerous firmware bugs where removing non-standard 19 + UEFI variables causes the system firmware to fail to POST, efivarfs 20 + files that are not well-known standardized variables are created 21 + as immutable files. This doesn't prevent removal - "chattr -i" will work - 22 + but it does prevent this kind of failure from being accomplished 23 + accidentally.
+1 -3
Documentation/timers/hpet.txt
··· 1 1 High Precision Event Timer Driver for Linux 2 2 3 3 The High Precision Event Timer (HPET) hardware follows a specification 4 - by Intel and Microsoft which can be found at 5 - 6 - http://www.intel.com/hardwaredesign/hpetspec_1.pdf 4 + by Intel and Microsoft, revision 1. 7 5 8 6 Each HPET has one fixed-rate counter (at 10+ MHz, hence "High Precision") 9 7 and up to 32 comparators. Normally three or more comparators are provided,
+2 -2
arch/x86/Kconfig
··· 778 778 HPET is the next generation timer replacing legacy 8254s. 779 779 The HPET provides a stable time base on SMP 780 780 systems, unlike the TSC, but it is more expensive to access, 781 - as it is off-chip. You can find the HPET spec at 782 - <http://www.intel.com/hardwaredesign/hpetspec_1.pdf>. 781 + as it is off-chip. The interface used is documented 782 + in the HPET spec, revision 1. 783 783 784 784 You can safely choose Y here. However, HPET will only be 785 785 activated if the platform and the BIOS support this feature.
+101 -41
arch/x86/lib/copy_user_64.S
··· 232 232 233 233 /* 234 234 * copy_user_nocache - Uncached memory copy with exception handling 235 - * This will force destination/source out of cache for more performance. 235 + * This will force destination out of cache for more performance. 236 + * 237 + * Note: Cached memory copy is used when destination or size is not 238 + * naturally aligned. That is: 239 + * - Require 8-byte alignment when size is 8 bytes or larger. 240 + * - Require 4-byte alignment when size is 4 bytes. 236 241 */ 237 242 ENTRY(__copy_user_nocache) 238 243 ASM_STAC 244 + 245 + /* If size is less than 8 bytes, go to 4-byte copy */ 239 246 cmpl $8,%edx 240 - jb 20f /* less then 8 bytes, go to byte copy loop */ 247 + jb .L_4b_nocache_copy_entry 248 + 249 + /* If destination is not 8-byte aligned, "cache" copy to align it */ 241 250 ALIGN_DESTINATION 251 + 252 + /* Set 4x8-byte copy count and remainder */ 242 253 movl %edx,%ecx 243 254 andl $63,%edx 244 255 shrl $6,%ecx 245 - jz 17f 256 + jz .L_8b_nocache_copy_entry /* jump if count is 0 */ 257 + 258 + /* Perform 4x8-byte nocache loop-copy */ 259 + .L_4x8b_nocache_copy_loop: 246 260 1: movq (%rsi),%r8 247 261 2: movq 1*8(%rsi),%r9 248 262 3: movq 2*8(%rsi),%r10 ··· 276 262 leaq 64(%rsi),%rsi 277 263 leaq 64(%rdi),%rdi 278 264 decl %ecx 279 - jnz 1b 280 - 17: movl %edx,%ecx 265 + jnz .L_4x8b_nocache_copy_loop 266 + 267 + /* Set 8-byte copy count and remainder */ 268 + .L_8b_nocache_copy_entry: 269 + movl %edx,%ecx 281 270 andl $7,%edx 282 271 shrl $3,%ecx 283 - jz 20f 284 - 18: movq (%rsi),%r8 285 - 19: movnti %r8,(%rdi) 272 + jz .L_4b_nocache_copy_entry /* jump if count is 0 */ 273 + 274 + /* Perform 8-byte nocache loop-copy */ 275 + .L_8b_nocache_copy_loop: 276 + 20: movq (%rsi),%r8 277 + 21: movnti %r8,(%rdi) 286 278 leaq 8(%rsi),%rsi 287 279 leaq 8(%rdi),%rdi 288 280 decl %ecx 289 - jnz 18b 290 - 20: andl %edx,%edx 291 - jz 23f 281 + jnz .L_8b_nocache_copy_loop 282 + 283 + /* If no byte left, we're done */ 284 + .L_4b_nocache_copy_entry: 285 + andl %edx,%edx 286 + jz .L_finish_copy 287 + 288 + /* If destination is not 4-byte aligned, go to byte copy: */ 289 + movl %edi,%ecx 290 + andl $3,%ecx 291 + jnz .L_1b_cache_copy_entry 292 + 293 + /* Set 4-byte copy count (1 or 0) and remainder */ 292 294 movl %edx,%ecx 293 - 21: movb (%rsi),%al 294 - 22: movb %al,(%rdi) 295 + andl $3,%edx 296 + shrl $2,%ecx 297 + jz .L_1b_cache_copy_entry /* jump if count is 0 */ 298 + 299 + /* Perform 4-byte nocache copy: */ 300 + 30: movl (%rsi),%r8d 301 + 31: movnti %r8d,(%rdi) 302 + leaq 4(%rsi),%rsi 303 + leaq 4(%rdi),%rdi 304 + 305 + /* If no bytes left, we're done: */ 306 + andl %edx,%edx 307 + jz .L_finish_copy 308 + 309 + /* Perform byte "cache" loop-copy for the remainder */ 310 + .L_1b_cache_copy_entry: 311 + movl %edx,%ecx 312 + .L_1b_cache_copy_loop: 313 + 40: movb (%rsi),%al 314 + 41: movb %al,(%rdi) 295 315 incq %rsi 296 316 incq %rdi 297 317 decl %ecx 298 - jnz 21b 299 - 23: xorl %eax,%eax 318 + jnz .L_1b_cache_copy_loop 319 + 320 + /* Finished copying; fence the prior stores */ 321 + .L_finish_copy: 322 + xorl %eax,%eax 300 323 ASM_CLAC 301 324 sfence 302 325 ret 303 326 304 327 .section .fixup,"ax" 305 - 30: shll $6,%ecx 328 + .L_fixup_4x8b_copy: 329 + shll $6,%ecx 306 330 addl %ecx,%edx 307 - jmp 60f 308 - 40: lea (%rdx,%rcx,8),%rdx 309 - jmp 60f 310 - 50: movl %ecx,%edx 311 - 60: sfence 331 + jmp .L_fixup_handle_tail 332 + .L_fixup_8b_copy: 333 + lea (%rdx,%rcx,8),%rdx 334 + jmp .L_fixup_handle_tail 335 + .L_fixup_4b_copy: 336 + lea (%rdx,%rcx,4),%rdx 337 + jmp .L_fixup_handle_tail 338 + .L_fixup_1b_copy: 339 + movl %ecx,%edx 340 + .L_fixup_handle_tail: 341 + sfence 312 342 jmp copy_user_handle_tail 313 343 .previous 314 344 315 - _ASM_EXTABLE(1b,30b) 316 - _ASM_EXTABLE(2b,30b) 317 - _ASM_EXTABLE(3b,30b) 318 - _ASM_EXTABLE(4b,30b) 319 - _ASM_EXTABLE(5b,30b) 320 - _ASM_EXTABLE(6b,30b) 321 - _ASM_EXTABLE(7b,30b) 322 - _ASM_EXTABLE(8b,30b) 323 - _ASM_EXTABLE(9b,30b) 324 - _ASM_EXTABLE(10b,30b) 325 - _ASM_EXTABLE(11b,30b) 326 - _ASM_EXTABLE(12b,30b) 327 - _ASM_EXTABLE(13b,30b) 328 - _ASM_EXTABLE(14b,30b) 329 - _ASM_EXTABLE(15b,30b) 330 - _ASM_EXTABLE(16b,30b) 331 - _ASM_EXTABLE(18b,40b) 332 - _ASM_EXTABLE(19b,40b) 333 - _ASM_EXTABLE(21b,50b) 334 - _ASM_EXTABLE(22b,50b) 345 + _ASM_EXTABLE(1b,.L_fixup_4x8b_copy) 346 + _ASM_EXTABLE(2b,.L_fixup_4x8b_copy) 347 + _ASM_EXTABLE(3b,.L_fixup_4x8b_copy) 348 + _ASM_EXTABLE(4b,.L_fixup_4x8b_copy) 349 + _ASM_EXTABLE(5b,.L_fixup_4x8b_copy) 350 + _ASM_EXTABLE(6b,.L_fixup_4x8b_copy) 351 + _ASM_EXTABLE(7b,.L_fixup_4x8b_copy) 352 + _ASM_EXTABLE(8b,.L_fixup_4x8b_copy) 353 + _ASM_EXTABLE(9b,.L_fixup_4x8b_copy) 354 + _ASM_EXTABLE(10b,.L_fixup_4x8b_copy) 355 + _ASM_EXTABLE(11b,.L_fixup_4x8b_copy) 356 + _ASM_EXTABLE(12b,.L_fixup_4x8b_copy) 357 + _ASM_EXTABLE(13b,.L_fixup_4x8b_copy) 358 + _ASM_EXTABLE(14b,.L_fixup_4x8b_copy) 359 + _ASM_EXTABLE(15b,.L_fixup_4x8b_copy) 360 + _ASM_EXTABLE(16b,.L_fixup_4x8b_copy) 361 + _ASM_EXTABLE(20b,.L_fixup_8b_copy) 362 + _ASM_EXTABLE(21b,.L_fixup_8b_copy) 363 + _ASM_EXTABLE(30b,.L_fixup_4b_copy) 364 + _ASM_EXTABLE(31b,.L_fixup_4b_copy) 365 + _ASM_EXTABLE(40b,.L_fixup_1b_copy) 366 + _ASM_EXTABLE(41b,.L_fixup_1b_copy) 335 367 ENDPROC(__copy_user_nocache)
+11 -4
arch/x86/mm/fault.c
··· 287 287 if (!pmd_k) 288 288 return -1; 289 289 290 + if (pmd_huge(*pmd_k)) 291 + return 0; 292 + 290 293 pte_k = pte_offset_kernel(pmd_k, address); 291 294 if (!pte_present(*pte_k)) 292 295 return -1; ··· 363 360 * 64-bit: 364 361 * 365 362 * Handle a fault on the vmalloc area 366 - * 367 - * This assumes no large pages in there. 368 363 */ 369 364 static noinline int vmalloc_fault(unsigned long address) 370 365 { ··· 404 403 if (pud_none(*pud_ref)) 405 404 return -1; 406 405 407 - if (pud_none(*pud) || pud_page_vaddr(*pud) != pud_page_vaddr(*pud_ref)) 406 + if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref)) 408 407 BUG(); 408 + 409 + if (pud_huge(*pud)) 410 + return 0; 409 411 410 412 pmd = pmd_offset(pud, address); 411 413 pmd_ref = pmd_offset(pud_ref, address); 412 414 if (pmd_none(*pmd_ref)) 413 415 return -1; 414 416 415 - if (pmd_none(*pmd) || pmd_page(*pmd) != pmd_page(*pmd_ref)) 417 + if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref)) 416 418 BUG(); 419 + 420 + if (pmd_huge(*pmd)) 421 + return 0; 417 422 418 423 pte_ref = pte_offset_kernel(pmd_ref, address); 419 424 if (!pte_present(*pte_ref))
+1 -1
drivers/char/hpet.c
··· 42 42 /* 43 43 * The High Precision Event Timer driver. 44 44 * This driver is closely modelled after the rtc.c driver. 45 - * http://www.intel.com/hardwaredesign/hpetspec_1.pdf 45 + * See HPET spec revision 1. 46 46 */ 47 47 #define HPET_USER_FREQ (64) 48 48 #define HPET_DRIFT (500)
+14 -21
drivers/firmware/efi/efivars.c
··· 221 221 } 222 222 223 223 if ((attributes & ~EFI_VARIABLE_MASK) != 0 || 224 - efivar_validate(name, data, size) == false) { 224 + efivar_validate(vendor, name, data, size) == false) { 225 225 printk(KERN_ERR "efivars: Malformed variable content\n"); 226 226 return -EINVAL; 227 227 } ··· 447 447 } 448 448 449 449 if ((attributes & ~EFI_VARIABLE_MASK) != 0 || 450 - efivar_validate(name, data, size) == false) { 450 + efivar_validate(new_var->VendorGuid, name, data, 451 + size) == false) { 451 452 printk(KERN_ERR "efivars: Malformed variable content\n"); 452 453 return -EINVAL; 453 454 } ··· 541 540 static int 542 541 efivar_create_sysfs_entry(struct efivar_entry *new_var) 543 542 { 544 - int i, short_name_size; 543 + int short_name_size; 545 544 char *short_name; 546 - unsigned long variable_name_size; 547 - efi_char16_t *variable_name; 545 + unsigned long utf8_name_size; 546 + efi_char16_t *variable_name = new_var->var.VariableName; 548 547 int ret; 549 548 550 - variable_name = new_var->var.VariableName; 551 - variable_name_size = ucs2_strlen(variable_name) * sizeof(efi_char16_t); 552 - 553 549 /* 554 - * Length of the variable bytes in ASCII, plus the '-' separator, 550 + * Length of the variable bytes in UTF8, plus the '-' separator, 555 551 * plus the GUID, plus trailing NUL 556 552 */ 557 - short_name_size = variable_name_size / sizeof(efi_char16_t) 558 - + 1 + EFI_VARIABLE_GUID_LEN + 1; 553 + utf8_name_size = ucs2_utf8size(variable_name); 554 + short_name_size = utf8_name_size + 1 + EFI_VARIABLE_GUID_LEN + 1; 559 555 560 - short_name = kzalloc(short_name_size, GFP_KERNEL); 561 - 556 + short_name = kmalloc(short_name_size, GFP_KERNEL); 562 557 if (!short_name) 563 558 return -ENOMEM; 564 559 565 - /* Convert Unicode to normal chars (assume top bits are 0), 566 - ala UTF-8 */ 567 - for (i=0; i < (int)(variable_name_size / sizeof(efi_char16_t)); i++) { 568 - short_name[i] = variable_name[i] & 0xFF; 569 - } 560 + ucs2_as_utf8(short_name, variable_name, short_name_size); 561 + 570 562 /* This is ugly, but necessary to separate one vendor's 571 563 private variables from another's. */ 572 - 573 - *(short_name + strlen(short_name)) = '-'; 564 + short_name[utf8_name_size] = '-'; 574 565 efi_guid_to_str(&new_var->var.VendorGuid, 575 - short_name + strlen(short_name)); 566 + short_name + utf8_name_size + 1); 576 567 577 568 new_var->kobj.kset = efivars_kset; 578 569
+106 -40
drivers/firmware/efi/vars.c
··· 165 165 } 166 166 167 167 struct variable_validate { 168 + efi_guid_t vendor; 168 169 char *name; 169 170 bool (*validate)(efi_char16_t *var_name, int match, u8 *data, 170 171 unsigned long len); 171 172 }; 172 173 174 + /* 175 + * This is the list of variables we need to validate, as well as the 176 + * whitelist for what we think is safe not to default to immutable. 177 + * 178 + * If it has a validate() method that's not NULL, it'll go into the 179 + * validation routine. If not, it is assumed valid, but still used for 180 + * whitelisting. 181 + * 182 + * Note that it's sorted by {vendor,name}, but globbed names must come after 183 + * any other name with the same prefix. 184 + */ 173 185 static const struct variable_validate variable_validate[] = { 174 - { "BootNext", validate_uint16 }, 175 - { "BootOrder", validate_boot_order }, 176 - { "DriverOrder", validate_boot_order }, 177 - { "Boot*", validate_load_option }, 178 - { "Driver*", validate_load_option }, 179 - { "ConIn", validate_device_path }, 180 - { "ConInDev", validate_device_path }, 181 - { "ConOut", validate_device_path }, 182 - { "ConOutDev", validate_device_path }, 183 - { "ErrOut", validate_device_path }, 184 - { "ErrOutDev", validate_device_path }, 185 - { "Timeout", validate_uint16 }, 186 - { "Lang", validate_ascii_string }, 187 - { "PlatformLang", validate_ascii_string }, 188 - { "", NULL }, 186 + { EFI_GLOBAL_VARIABLE_GUID, "BootNext", validate_uint16 }, 187 + { EFI_GLOBAL_VARIABLE_GUID, "BootOrder", validate_boot_order }, 188 + { EFI_GLOBAL_VARIABLE_GUID, "Boot*", validate_load_option }, 189 + { EFI_GLOBAL_VARIABLE_GUID, "DriverOrder", validate_boot_order }, 190 + { EFI_GLOBAL_VARIABLE_GUID, "Driver*", validate_load_option }, 191 + { EFI_GLOBAL_VARIABLE_GUID, "ConIn", validate_device_path }, 192 + { EFI_GLOBAL_VARIABLE_GUID, "ConInDev", validate_device_path }, 193 + { EFI_GLOBAL_VARIABLE_GUID, "ConOut", validate_device_path }, 194 + { EFI_GLOBAL_VARIABLE_GUID, "ConOutDev", validate_device_path }, 195 + { EFI_GLOBAL_VARIABLE_GUID, "ErrOut", validate_device_path }, 196 + { EFI_GLOBAL_VARIABLE_GUID, "ErrOutDev", validate_device_path }, 197 + { EFI_GLOBAL_VARIABLE_GUID, "Lang", validate_ascii_string }, 198 + { EFI_GLOBAL_VARIABLE_GUID, "OsIndications", NULL }, 199 + { EFI_GLOBAL_VARIABLE_GUID, "PlatformLang", validate_ascii_string }, 200 + { EFI_GLOBAL_VARIABLE_GUID, "Timeout", validate_uint16 }, 201 + { LINUX_EFI_CRASH_GUID, "*", NULL }, 202 + { NULL_GUID, "", NULL }, 189 203 }; 190 204 205 + static bool 206 + variable_matches(const char *var_name, size_t len, const char *match_name, 207 + int *match) 208 + { 209 + for (*match = 0; ; (*match)++) { 210 + char c = match_name[*match]; 211 + char u = var_name[*match]; 212 + 213 + /* Wildcard in the matching name means we've matched */ 214 + if (c == '*') 215 + return true; 216 + 217 + /* Case sensitive match */ 218 + if (!c && *match == len) 219 + return true; 220 + 221 + if (c != u) 222 + return false; 223 + 224 + if (!c) 225 + return true; 226 + } 227 + return true; 228 + } 229 + 191 230 bool 192 - efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len) 231 + efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, 232 + unsigned long data_size) 193 233 { 194 234 int i; 195 - u16 *unicode_name = var_name; 235 + unsigned long utf8_size; 236 + u8 *utf8_name; 196 237 197 - for (i = 0; variable_validate[i].validate != NULL; i++) { 238 + utf8_size = ucs2_utf8size(var_name); 239 + utf8_name = kmalloc(utf8_size + 1, GFP_KERNEL); 240 + if (!utf8_name) 241 + return false; 242 + 243 + ucs2_as_utf8(utf8_name, var_name, utf8_size); 244 + utf8_name[utf8_size] = '\0'; 245 + 246 + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { 198 247 const char *name = variable_validate[i].name; 199 - int match; 248 + int match = 0; 200 249 201 - for (match = 0; ; match++) { 202 - char c = name[match]; 203 - u16 u = unicode_name[match]; 250 + if (efi_guidcmp(vendor, variable_validate[i].vendor)) 251 + continue; 204 252 205 - /* All special variables are plain ascii */ 206 - if (u > 127) 207 - return true; 208 - 209 - /* Wildcard in the matching name means we've matched */ 210 - if (c == '*') 211 - return variable_validate[i].validate(var_name, 212 - match, data, len); 213 - 214 - /* Case sensitive match */ 215 - if (c != u) 253 + if (variable_matches(utf8_name, utf8_size+1, name, &match)) { 254 + if (variable_validate[i].validate == NULL) 216 255 break; 217 - 218 - /* Reached the end of the string while matching */ 219 - if (!c) 220 - return variable_validate[i].validate(var_name, 221 - match, data, len); 256 + kfree(utf8_name); 257 + return variable_validate[i].validate(var_name, match, 258 + data, data_size); 222 259 } 223 260 } 224 - 261 + kfree(utf8_name); 225 262 return true; 226 263 } 227 264 EXPORT_SYMBOL_GPL(efivar_validate); 265 + 266 + bool 267 + efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, 268 + size_t len) 269 + { 270 + int i; 271 + bool found = false; 272 + int match = 0; 273 + 274 + /* 275 + * Check if our variable is in the validated variables list 276 + */ 277 + for (i = 0; variable_validate[i].name[0] != '\0'; i++) { 278 + if (efi_guidcmp(variable_validate[i].vendor, vendor)) 279 + continue; 280 + 281 + if (variable_matches(var_name, len, 282 + variable_validate[i].name, &match)) { 283 + found = true; 284 + break; 285 + } 286 + } 287 + 288 + /* 289 + * If it's in our list, it is removable. 290 + */ 291 + return found; 292 + } 293 + EXPORT_SYMBOL_GPL(efivar_variable_is_removable); 228 294 229 295 static efi_status_t 230 296 check_var_size(u32 attributes, unsigned long size) ··· 918 852 919 853 *set = false; 920 854 921 - if (efivar_validate(name, data, *size) == false) 855 + if (efivar_validate(*vendor, name, data, *size) == false) 922 856 return -EINVAL; 923 857 924 858 /*
+70
fs/efivarfs/file.c
··· 10 10 #include <linux/efi.h> 11 11 #include <linux/fs.h> 12 12 #include <linux/slab.h> 13 + #include <linux/mount.h> 13 14 14 15 #include "internal.h" 15 16 ··· 104 103 return size; 105 104 } 106 105 106 + static int 107 + efivarfs_ioc_getxflags(struct file *file, void __user *arg) 108 + { 109 + struct inode *inode = file->f_mapping->host; 110 + unsigned int i_flags; 111 + unsigned int flags = 0; 112 + 113 + i_flags = inode->i_flags; 114 + if (i_flags & S_IMMUTABLE) 115 + flags |= FS_IMMUTABLE_FL; 116 + 117 + if (copy_to_user(arg, &flags, sizeof(flags))) 118 + return -EFAULT; 119 + return 0; 120 + } 121 + 122 + static int 123 + efivarfs_ioc_setxflags(struct file *file, void __user *arg) 124 + { 125 + struct inode *inode = file->f_mapping->host; 126 + unsigned int flags; 127 + unsigned int i_flags = 0; 128 + int error; 129 + 130 + if (!inode_owner_or_capable(inode)) 131 + return -EACCES; 132 + 133 + if (copy_from_user(&flags, arg, sizeof(flags))) 134 + return -EFAULT; 135 + 136 + if (flags & ~FS_IMMUTABLE_FL) 137 + return -EOPNOTSUPP; 138 + 139 + if (!capable(CAP_LINUX_IMMUTABLE)) 140 + return -EPERM; 141 + 142 + if (flags & FS_IMMUTABLE_FL) 143 + i_flags |= S_IMMUTABLE; 144 + 145 + 146 + error = mnt_want_write_file(file); 147 + if (error) 148 + return error; 149 + 150 + inode_lock(inode); 151 + inode_set_flags(inode, i_flags, S_IMMUTABLE); 152 + inode_unlock(inode); 153 + 154 + mnt_drop_write_file(file); 155 + 156 + return 0; 157 + } 158 + 159 + long 160 + efivarfs_file_ioctl(struct file *file, unsigned int cmd, unsigned long p) 161 + { 162 + void __user *arg = (void __user *)p; 163 + 164 + switch (cmd) { 165 + case FS_IOC_GETFLAGS: 166 + return efivarfs_ioc_getxflags(file, arg); 167 + case FS_IOC_SETFLAGS: 168 + return efivarfs_ioc_setxflags(file, arg); 169 + } 170 + 171 + return -ENOTTY; 172 + } 173 + 107 174 const struct file_operations efivarfs_file_operations = { 108 175 .open = simple_open, 109 176 .read = efivarfs_file_read, 110 177 .write = efivarfs_file_write, 111 178 .llseek = no_llseek, 179 + .unlocked_ioctl = efivarfs_file_ioctl, 112 180 };
+19 -11
fs/efivarfs/inode.c
··· 15 15 #include "internal.h" 16 16 17 17 struct inode *efivarfs_get_inode(struct super_block *sb, 18 - const struct inode *dir, int mode, dev_t dev) 18 + const struct inode *dir, int mode, 19 + dev_t dev, bool is_removable) 19 20 { 20 21 struct inode *inode = new_inode(sb); 21 22 ··· 24 23 inode->i_ino = get_next_ino(); 25 24 inode->i_mode = mode; 26 25 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 26 + inode->i_flags = is_removable ? 0 : S_IMMUTABLE; 27 27 switch (mode & S_IFMT) { 28 28 case S_IFREG: 29 29 inode->i_fop = &efivarfs_file_operations; ··· 104 102 static int efivarfs_create(struct inode *dir, struct dentry *dentry, 105 103 umode_t mode, bool excl) 106 104 { 107 - struct inode *inode; 105 + struct inode *inode = NULL; 108 106 struct efivar_entry *var; 109 107 int namelen, i = 0, err = 0; 108 + bool is_removable = false; 110 109 111 110 if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) 112 111 return -EINVAL; 113 112 114 - inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); 115 - if (!inode) 116 - return -ENOMEM; 117 - 118 113 var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); 119 - if (!var) { 120 - err = -ENOMEM; 121 - goto out; 122 - } 114 + if (!var) 115 + return -ENOMEM; 123 116 124 117 /* length of the variable name itself: remove GUID and separator */ 125 118 namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; 126 119 127 120 efivarfs_hex_to_guid(dentry->d_name.name + namelen + 1, 128 121 &var->var.VendorGuid); 122 + 123 + if (efivar_variable_is_removable(var->var.VendorGuid, 124 + dentry->d_name.name, namelen)) 125 + is_removable = true; 126 + 127 + inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); 128 + if (!inode) { 129 + err = -ENOMEM; 130 + goto out; 131 + } 129 132 130 133 for (i = 0; i < namelen; i++) 131 134 var->var.VariableName[i] = dentry->d_name.name[i]; ··· 145 138 out: 146 139 if (err) { 147 140 kfree(var); 148 - iput(inode); 141 + if (inode) 142 + iput(inode); 149 143 } 150 144 return err; 151 145 }
+2 -1
fs/efivarfs/internal.h
··· 15 15 extern const struct inode_operations efivarfs_dir_inode_operations; 16 16 extern bool efivarfs_valid_name(const char *str, int len); 17 17 extern struct inode *efivarfs_get_inode(struct super_block *sb, 18 - const struct inode *dir, int mode, dev_t dev); 18 + const struct inode *dir, int mode, dev_t dev, 19 + bool is_removable); 19 20 20 21 extern struct list_head efivarfs_list; 21 22
+10 -6
fs/efivarfs/super.c
··· 118 118 struct dentry *dentry, *root = sb->s_root; 119 119 unsigned long size = 0; 120 120 char *name; 121 - int len, i; 121 + int len; 122 122 int err = -ENOMEM; 123 + bool is_removable = false; 123 124 124 125 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 125 126 if (!entry) ··· 129 128 memcpy(entry->var.VariableName, name16, name_size); 130 129 memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); 131 130 132 - len = ucs2_strlen(entry->var.VariableName); 131 + len = ucs2_utf8size(entry->var.VariableName); 133 132 134 133 /* name, plus '-', plus GUID, plus NUL*/ 135 134 name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); 136 135 if (!name) 137 136 goto fail; 138 137 139 - for (i = 0; i < len; i++) 140 - name[i] = entry->var.VariableName[i] & 0xFF; 138 + ucs2_as_utf8(name, entry->var.VariableName, len); 139 + 140 + if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) 141 + is_removable = true; 141 142 142 143 name[len] = '-'; 143 144 ··· 147 144 148 145 name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; 149 146 150 - inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0); 147 + inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0, 148 + is_removable); 151 149 if (!inode) 152 150 goto fail_name; 153 151 ··· 204 200 sb->s_d_op = &efivarfs_d_ops; 205 201 sb->s_time_gran = 1; 206 202 207 - inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); 203 + inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0, true); 208 204 if (!inode) 209 205 return -ENOMEM; 210 206 inode->i_op = &efivarfs_dir_inode_operations;
+4 -1
include/linux/efi.h
··· 1199 1199 struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, 1200 1200 struct list_head *head, bool remove); 1201 1201 1202 - bool efivar_validate(efi_char16_t *var_name, u8 *data, unsigned long len); 1202 + bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, 1203 + unsigned long data_size); 1204 + bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, 1205 + size_t len); 1203 1206 1204 1207 extern struct work_struct efivar_work; 1205 1208 void efivar_run_worker(void);
+4
include/linux/ucs2_string.h
··· 11 11 unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength); 12 12 int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); 13 13 14 + unsigned long ucs2_utf8size(const ucs2_char_t *src); 15 + unsigned long ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, 16 + unsigned long maxlength); 17 + 14 18 #endif /* _LINUX_UCS2_STRING_H_ */
+62
lib/ucs2_string.c
··· 49 49 } 50 50 } 51 51 EXPORT_SYMBOL(ucs2_strncmp); 52 + 53 + unsigned long 54 + ucs2_utf8size(const ucs2_char_t *src) 55 + { 56 + unsigned long i; 57 + unsigned long j = 0; 58 + 59 + for (i = 0; i < ucs2_strlen(src); i++) { 60 + u16 c = src[i]; 61 + 62 + if (c >= 0x800) 63 + j += 3; 64 + else if (c >= 0x80) 65 + j += 2; 66 + else 67 + j += 1; 68 + } 69 + 70 + return j; 71 + } 72 + EXPORT_SYMBOL(ucs2_utf8size); 73 + 74 + /* 75 + * copy at most maxlength bytes of whole utf8 characters to dest from the 76 + * ucs2 string src. 77 + * 78 + * The return value is the number of characters copied, not including the 79 + * final NUL character. 80 + */ 81 + unsigned long 82 + ucs2_as_utf8(u8 *dest, const ucs2_char_t *src, unsigned long maxlength) 83 + { 84 + unsigned int i; 85 + unsigned long j = 0; 86 + unsigned long limit = ucs2_strnlen(src, maxlength); 87 + 88 + for (i = 0; maxlength && i < limit; i++) { 89 + u16 c = src[i]; 90 + 91 + if (c >= 0x800) { 92 + if (maxlength < 3) 93 + break; 94 + maxlength -= 3; 95 + dest[j++] = 0xe0 | (c & 0xf000) >> 12; 96 + dest[j++] = 0x80 | (c & 0x0fc0) >> 6; 97 + dest[j++] = 0x80 | (c & 0x003f); 98 + } else if (c >= 0x80) { 99 + if (maxlength < 2) 100 + break; 101 + maxlength -= 2; 102 + dest[j++] = 0xc0 | (c & 0x7c0) >> 6; 103 + dest[j++] = 0x80 | (c & 0x03f); 104 + } else { 105 + maxlength -= 1; 106 + dest[j++] = c & 0x7f; 107 + } 108 + } 109 + if (maxlength) 110 + dest[j] = '\0'; 111 + return j; 112 + } 113 + EXPORT_SYMBOL(ucs2_as_utf8);
+16 -3
tools/testing/selftests/efivarfs/efivarfs.sh
··· 88 88 exit 1 89 89 fi 90 90 91 - rm $file 91 + rm $file 2>/dev/null 92 + if [ $? -ne 0 ]; then 93 + chattr -i $file 94 + rm $file 95 + fi 92 96 93 97 if [ -e $file ]; then 94 98 echo "$file couldn't be deleted" >&2 ··· 115 111 exit 1 116 112 fi 117 113 114 + chattr -i $file 118 115 printf "$attrs" > $file 119 116 120 117 if [ -e $file ]; then ··· 146 141 echo "$file could not be created" >&2 147 142 ret=1 148 143 else 149 - rm $file 144 + rm $file 2>/dev/null 145 + if [ $? -ne 0 ]; then 146 + chattr -i $file 147 + rm $file 148 + fi 150 149 fi 151 150 done 152 151 ··· 183 174 184 175 if [ -e $file ]; then 185 176 echo "Creating $file should have failed" >&2 186 - rm $file 177 + rm $file 2>/dev/null 178 + if [ $? -ne 0 ]; then 179 + chattr -i $file 180 + rm $file 181 + fi 187 182 ret=1 188 183 fi 189 184 done
+71 -1
tools/testing/selftests/efivarfs/open-unlink.c
··· 1 + #include <errno.h> 1 2 #include <stdio.h> 2 3 #include <stdint.h> 3 4 #include <stdlib.h> 4 5 #include <unistd.h> 6 + #include <sys/ioctl.h> 5 7 #include <sys/types.h> 6 8 #include <sys/stat.h> 7 9 #include <fcntl.h> 10 + #include <linux/fs.h> 11 + 12 + static int set_immutable(const char *path, int immutable) 13 + { 14 + unsigned int flags; 15 + int fd; 16 + int rc; 17 + int error; 18 + 19 + fd = open(path, O_RDONLY); 20 + if (fd < 0) 21 + return fd; 22 + 23 + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); 24 + if (rc < 0) { 25 + error = errno; 26 + close(fd); 27 + errno = error; 28 + return rc; 29 + } 30 + 31 + if (immutable) 32 + flags |= FS_IMMUTABLE_FL; 33 + else 34 + flags &= ~FS_IMMUTABLE_FL; 35 + 36 + rc = ioctl(fd, FS_IOC_SETFLAGS, &flags); 37 + error = errno; 38 + close(fd); 39 + errno = error; 40 + return rc; 41 + } 42 + 43 + static int get_immutable(const char *path) 44 + { 45 + unsigned int flags; 46 + int fd; 47 + int rc; 48 + int error; 49 + 50 + fd = open(path, O_RDONLY); 51 + if (fd < 0) 52 + return fd; 53 + 54 + rc = ioctl(fd, FS_IOC_GETFLAGS, &flags); 55 + if (rc < 0) { 56 + error = errno; 57 + close(fd); 58 + errno = error; 59 + return rc; 60 + } 61 + close(fd); 62 + if (flags & FS_IMMUTABLE_FL) 63 + return 1; 64 + return 0; 65 + } 8 66 9 67 int main(int argc, char **argv) 10 68 { ··· 85 27 buf[4] = 0; 86 28 87 29 /* create a test variable */ 88 - fd = open(path, O_WRONLY | O_CREAT); 30 + fd = open(path, O_WRONLY | O_CREAT, 0600); 89 31 if (fd < 0) { 90 32 perror("open(O_WRONLY)"); 91 33 return EXIT_FAILURE; ··· 98 40 } 99 41 100 42 close(fd); 43 + 44 + rc = get_immutable(path); 45 + if (rc < 0) { 46 + perror("ioctl(FS_IOC_GETFLAGS)"); 47 + return EXIT_FAILURE; 48 + } else if (rc) { 49 + rc = set_immutable(path, 0); 50 + if (rc < 0) { 51 + perror("ioctl(FS_IOC_SETFLAGS)"); 52 + return EXIT_FAILURE; 53 + } 54 + } 101 55 102 56 fd = open(path, O_RDONLY); 103 57 if (fd < 0) {