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

Merge tag 'vfs-6.13.exec.deny_write_access.revert' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs

Pull deny_write_access revert from Christian Brauner:
"It turns out that the mold linker relies on the deny_write_access()
mechanism for executables.

The mold linker tries to open a file for writing and if ETXTBSY is
returned mold falls back to creating a new file"

* tag 'vfs-6.13.exec.deny_write_access.revert' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
Revert "fs: don't block i_writecount during exec"

+49 -14
+2
fs/binfmt_elf.c
··· 1257 1257 } 1258 1258 reloc_func_desc = interp_load_addr; 1259 1259 1260 + allow_write_access(interpreter); 1260 1261 fput(interpreter); 1261 1262 1262 1263 kfree(interp_elf_ex); ··· 1354 1353 kfree(interp_elf_ex); 1355 1354 kfree(interp_elf_phdata); 1356 1355 out_free_file: 1356 + allow_write_access(interpreter); 1357 1357 if (interpreter) 1358 1358 fput(interpreter); 1359 1359 out_free_ph:
+4 -1
fs/binfmt_elf_fdpic.c
··· 394 394 goto error; 395 395 } 396 396 397 + allow_write_access(interpreter); 397 398 fput(interpreter); 398 399 interpreter = NULL; 399 400 } ··· 466 465 retval = 0; 467 466 468 467 error: 469 - if (interpreter) 468 + if (interpreter) { 469 + allow_write_access(interpreter); 470 470 fput(interpreter); 471 + } 471 472 kfree(interpreter_name); 472 473 kfree(exec_params.phdrs); 473 474 kfree(exec_params.loadmap);
+5 -2
fs/binfmt_misc.c
··· 247 247 if (retval < 0) 248 248 goto ret; 249 249 250 - if (fmt->flags & MISC_FMT_OPEN_FILE) 250 + if (fmt->flags & MISC_FMT_OPEN_FILE) { 251 251 interp_file = file_clone_open(fmt->interp_file); 252 - else 252 + if (!IS_ERR(interp_file)) 253 + deny_write_access(interp_file); 254 + } else { 253 255 interp_file = open_exec(fmt->interpreter); 256 + } 254 257 retval = PTR_ERR(interp_file); 255 258 if (IS_ERR(interp_file)) 256 259 goto ret;
+15 -8
fs/exec.c
··· 883 883 */ 884 884 static struct file *do_open_execat(int fd, struct filename *name, int flags) 885 885 { 886 - struct file *file; 886 + int err; 887 + struct file *file __free(fput) = NULL; 887 888 struct open_flags open_exec_flags = { 888 889 .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 889 890 .acc_mode = MAY_EXEC, ··· 909 908 * an invariant that all non-regular files error out before we get here. 910 909 */ 911 910 if (WARN_ON_ONCE(!S_ISREG(file_inode(file)->i_mode)) || 912 - path_noexec(&file->f_path)) { 913 - fput(file); 911 + path_noexec(&file->f_path)) 914 912 return ERR_PTR(-EACCES); 915 - } 916 913 917 - return file; 914 + err = deny_write_access(file); 915 + if (err) 916 + return ERR_PTR(err); 917 + 918 + return no_free_ptr(file); 918 919 } 919 920 920 921 /** ··· 926 923 * 927 924 * Returns ERR_PTR on failure or allocated struct file on success. 928 925 * 929 - * As this is a wrapper for the internal do_open_execat(). Also see 926 + * As this is a wrapper for the internal do_open_execat(), callers 927 + * must call allow_write_access() before fput() on release. Also see 930 928 * do_close_execat(). 931 929 */ 932 930 struct file *open_exec(const char *name) ··· 1469 1465 /* Matches do_open_execat() */ 1470 1466 static void do_close_execat(struct file *file) 1471 1467 { 1472 - if (file) 1473 - fput(file); 1468 + if (!file) 1469 + return; 1470 + allow_write_access(file); 1471 + fput(file); 1474 1472 } 1475 1473 1476 1474 static void free_bprm(struct linux_binprm *bprm) ··· 1797 1791 bprm->file = bprm->interpreter; 1798 1792 bprm->interpreter = NULL; 1799 1793 1794 + allow_write_access(exec); 1800 1795 if (unlikely(bprm->have_execfd)) { 1801 1796 if (bprm->executable) { 1802 1797 fput(exec);
+23 -3
kernel/fork.c
··· 621 621 622 622 exe_file = get_mm_exe_file(oldmm); 623 623 RCU_INIT_POINTER(mm->exe_file, exe_file); 624 + /* 625 + * We depend on the oldmm having properly denied write access to the 626 + * exe_file already. 627 + */ 628 + if (exe_file && deny_write_access(exe_file)) 629 + pr_warn_once("deny_write_access() failed in %s\n", __func__); 624 630 } 625 631 626 632 #ifdef CONFIG_MMU ··· 1419 1413 */ 1420 1414 old_exe_file = rcu_dereference_raw(mm->exe_file); 1421 1415 1422 - if (new_exe_file) 1416 + if (new_exe_file) { 1417 + /* 1418 + * We expect the caller (i.e., sys_execve) to already denied 1419 + * write access, so this is unlikely to fail. 1420 + */ 1421 + if (unlikely(deny_write_access(new_exe_file))) 1422 + return -EACCES; 1423 1423 get_file(new_exe_file); 1424 + } 1424 1425 rcu_assign_pointer(mm->exe_file, new_exe_file); 1425 - if (old_exe_file) 1426 + if (old_exe_file) { 1427 + allow_write_access(old_exe_file); 1426 1428 fput(old_exe_file); 1429 + } 1427 1430 return 0; 1428 1431 } 1429 1432 ··· 1471 1456 return ret; 1472 1457 } 1473 1458 1459 + ret = deny_write_access(new_exe_file); 1460 + if (ret) 1461 + return -EACCES; 1474 1462 get_file(new_exe_file); 1475 1463 1476 1464 /* set the new file */ ··· 1482 1464 rcu_assign_pointer(mm->exe_file, new_exe_file); 1483 1465 mmap_write_unlock(mm); 1484 1466 1485 - if (old_exe_file) 1467 + if (old_exe_file) { 1468 + allow_write_access(old_exe_file); 1486 1469 fput(old_exe_file); 1470 + } 1487 1471 return 0; 1488 1472 } 1489 1473