The seq read of ve.sysfs_permissions walks every sysfs node and calls kernfs_perms_shown(), which feeds kn->ve_perms_map to kmapset_lookup() and reads ->default_value with no NULL check.
A node can have a NULL ve_perms_map. kernfs_get_ve_perms() returns void and only sets the map when kmapset_new() works, so if that alloc fails the node keeps a NULL map for good. And until the rwsem fix in the next patch, the walk ran under the wrong root lock and did not serialise against kernfs_add_one(), so it could also hit a node that was linked into the tree but did not have its map set yet. Either way kernfs_perms_shown() then dereferences NULL: BUG: kernel NULL pointer dereference, address: 0000000000000020 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page Oops: 0000 [#1] SMP NOPTI CPU: 82 UID: 0 PID: 10796 Comm: cat ve: 0 Tainted: G W 12.7 PREEMPT(full) RIP: 0010:kmapset_lookup+0x4/0x40 RDX: 0000000000000000 RSI: ff2eb351033adf88 RDI: 0000000000000000 CR2: 0000000000000020 CR3: 0000000c09658001 CR4: 0000000000f71ef0 Call Trace: <TASK> ? kernfs_perms_start+0x60/0xd0 ? page_fault_oops+0xbb/0x110 ? exc_page_fault+0x8e/0x100 ? asm_exc_page_fault+0x26/0x30 ? kmapset_lookup+0x4/0x40 kernfs_perms_start+0x60/0xd0 kernfs_seq_start+0x74/0x110 seq_read_iter+0xfe/0x480 vfs_read+0x29f/0x370 ksys_read+0x73/0xf0 do_syscall_64+0x92/0x180 entry_SYSCALL_64_after_hwframe+0x76/0x7e </TASK> Return false for such nodes. kernfs_perms_show() only ever sees nodes that kernfs_perms_shown() accepted, so guarding it here is enough. https://virtuozzo.atlassian.net/browse/VSTOR-136541 Fixes: 008aa8b6ff0b ("ve/kernfs: add new interface to control per-VE nodes visibility") Signed-off-by: Mirian Shilakadze <[email protected]> --- fs/kernfs/ve.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/kernfs/ve.c b/fs/kernfs/ve.c index beaa278b014e..f357ebb907f1 100644 --- a/fs/kernfs/ve.c +++ b/fs/kernfs/ve.c @@ -146,6 +146,8 @@ static struct kernfs_node *kernfs_next_recursive(struct kernfs_node *kn) static bool kernfs_perms_shown(struct ve_struct *ve, struct kernfs_node *kn, struct kmapset_key *key) { + if (!kn->ve_perms_map) + return false; if (ve_is_super(ve)) return kn->ve_perms_map->default_value != 0; return kmapset_lookup(kn->ve_perms_map, key) != NULL; -- 2.43.0 _______________________________________________ Devel mailing list [email protected] https://lists.openvz.org/mailman/listinfo/devel
