When the last reference to a file is put from exit_task_work(), the task has already run exit_fs(), so current->fs is NULL. syzbot reported: Unable to handle kernel paging request at virtual address dfff800000000002 KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] Call trace: kasan_mem_to_shadow include/linux/kasan.h:65 [inline] (P) kasan_byte_accessible+0xc/0x1c mm/kasan/generic.c:210 (P) kasan_check_byte include/linux/kasan.h:402 [inline] lock_acquire+0xa4/0x320 kernel/locking/lockdep.c:5916 seqcount_lockdep_reader_access include/linux/seqlock.h:73 [inline] read_seqbegin+0x6c/0x144 include/linux/seqlock.h:838 get_fs_root_rcu fs/d_path.c:244 [inline] d_path+0x224/0x4dc fs/d_path.c:287 audit_log_d_path+0xdc/0x19c kernel/audit.c:2221 audit_log_lsm_data+0xe0/0x12d0 security/lsm_audit.c:199 dump_common_audit_data security/lsm_audit.c:421 [inline] common_lsm_audit+0x1d0/0x290 security/lsm_audit.c:451 smack_log+0x1f4/0x264 security/smack/smack_access.c:400 smk_tskacc+0x210/0x2ac security/smack/smack_access.c:255 smack_file_open+0x1d0/0x230 security/smack/smack_lsm.c:2078 security_file_open+0xec/0x258 security/security.c:2739 do_dentry_open+0x2a8/0xfbc fs/open.c:973 vfs_open+0x44/0x2dc fs/open.c:1101 dentry_open+0x74/0xc0 fs/open.c:1124 ima_calc_file_hash+0x120/0x5cc security/integrity/ima/ima_crypto.c:269 ima_collect_measurement+0x420/0x874 security/integrity/ima/ima_api.c:300 ima_update_xattr+0x160/0x230 security/integrity/ima/ima_appraise.c:617 ima_check_last_writer security/integrity/ima/ima_main.c:227 [inline] ima_file_free+0x40c/0x528 security/integrity/ima/ima_main.c:251 security_file_release+0x84/0x148 security/security.c:2424 __fput+0x2c4/0x74c fs/file_table.c:506 ____fput+0x20/0x30 fs/file_table.c:541 task_work_run+0x1cc/0x25c kernel/task_work.c:233 exit_task_work include/linux/task_work.h:40 [inline] do_exit+0x58c/0x1a74 kernel/exit.c:986 do_group_exit+0x198/0x238 kernel/exit.c:1129 __do_sys_exit_group kernel/exit.c:1140 [inline] __se_sys_exit_group kernel/exit.c:1138 [inline] pid_child_should_wake+0x0/0x104 kernel/exit.c:1138 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline] invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49 el0_svc_common+0x19c/0x23c arch/arm64/kernel/syscall.c:121 do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140 el0_svc+0x60/0x1d8 arch/arm64/kernel/entry-common.c:796 el0t_64_sync_handler+0x44/0x104 arch/arm64/kernel/entry-common.c:815 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:606 d_path() renders a path relative to current->fs->root. After exit_fs() there is no such root, and no substitute root is meaningful: the record's pid/comm describe a task that can no longer name the file, and the file may have been opened by a different task entirely. Falling back to another root would produce a well-formed but misleading path, so report the field as unknown instead, as exe=(null) and name=(null) already do. Handle this in audit_log_lsm_data(), where the meaning of the field is known, for LSM_AUDIT_DATA_PATH (Smack file_open), LSM_AUDIT_DATA_FILE (SELinux file_open), LSM_AUDIT_DATA_IOCTL_OP and the AF_UNIX path in LSM_AUDIT_DATA_NET. Alternative: omit " path=" as it is done for inode in audit_log_lsm_data. Fixes: 4a9d4b024a31 ("switch fput to task_work_add") Reported-by: syzbot+975ace299d6ba2eb1cea@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?extid=975ace299d6ba2eb1cea Signed-off-by: Drif Abdelmalek Mohamed Said --- security/lsm_audit.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 955b2e7b2c8e..5ed505d781bb 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -169,6 +169,15 @@ static inline void print_ipv4_addr(struct audit_buffer *ab, __be32 addr, audit_log_format(ab, " %s=%d", name2, ntohs(port)); } +static inline void audit_log_lsm_path(struct audit_buffer *ab, + const struct path *path) +{ + if (current->fs) + audit_log_d_path(ab, " path=", path); + else + audit_log_format(ab, " path=(null)"); +} + /** * audit_log_lsm_data - helper to log common LSM audit data * @ab : the audit buffer @@ -196,7 +205,7 @@ void audit_log_lsm_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_PATH: { struct inode *inode; - audit_log_d_path(ab, " path=", &a->u.path); + audit_log_lsm_path(ab, &a->u.path); inode = d_backing_inode(a->u.path.dentry); if (inode) { @@ -209,7 +218,7 @@ void audit_log_lsm_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_FILE: { struct inode *inode; - audit_log_d_path(ab, " path=", &a->u.file->f_path); + audit_log_lsm_path(ab, &a->u.file->f_path); inode = file_inode(a->u.file); if (inode) { @@ -222,7 +231,7 @@ void audit_log_lsm_data(struct audit_buffer *ab, case LSM_AUDIT_DATA_IOCTL_OP: { struct inode *inode; - audit_log_d_path(ab, " path=", &a->u.op->path); + audit_log_lsm_path(ab, &a->u.op->path); inode = a->u.op->path.dentry->d_inode; if (inode) { @@ -321,7 +330,7 @@ void audit_log_lsm_data(struct audit_buffer *ab, if (!addr) break; if (u->path.dentry) { - audit_log_d_path(ab, " path=", &u->path); + audit_log_lsm_path(ab, &u->path); break; } len = addr->len-sizeof(short); -- 2.43.0