From nobody Sat Jul 25 17:33:40 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0361131986C for ; Wed, 15 Jul 2026 13:53:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123594; cv=none; b=X0Ujn0AgJzuJYyEC8GtRxhbhXHlQyVGFoobhDkYQA/IJ6l6d7ERvMgmP2WzSZTY+jkdut7lHY/xV1PT9KkMgfoB9AGbjD9l+ThAkGYPy6K968OGdbvGbt9kksHsZ+mk7cfeKJmLoKZzNDSH0DFHxxib+4HnD5w3S2D2sHJ+2qic= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123594; c=relaxed/simple; bh=w6Sp86eHEMVoVOxdFnIDhhVPOr3sGlq3VH2c/w0u1E8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RvDbjBW/CsOby+6mxRSqYTVtNUrfkRdkE8RlR/hP1+MDRbO5Yq2lYesJ/XJ14OMTBSX3Z2trf8IhEs7cILWl6Q/fNqGsBqVLwxHRSWFNgycHlaA5hb8gVat727trFMr8dEn1s0c9I0y21kSweRjVhTNHOtqyxr6qPqmexEhhryk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=X3FjBoq/; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="X3FjBoq/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1784123592; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=hwk64BpXBFsCzUAEimbym6phg6u2yD1wC5895sqxBoY=; b=X3FjBoq/gNFA9UfUd8MF4fXzIre7S3AtQa7oHhn5gVitIO4NzI0cRmTDB8bMuLBlfMeZkG rpkFmA275Yt7K77+OOiwD3M/e4JnxiKJkis8t/3Us4tCk4wRVWkJkVmqqFXuv0BbqUXMLV ycPUKoLEWdeku6dWvOG3MbTzaOXd7z0= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-612-C1O3IunOPQ2UzB98WnBWjQ-1; Wed, 15 Jul 2026 09:53:06 -0400 X-MC-Unique: C1O3IunOPQ2UzB98WnBWjQ-1 X-Mimecast-MFC-AGG-ID: C1O3IunOPQ2UzB98WnBWjQ_1784123583 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C4B5D180065C; Wed, 15 Jul 2026 13:53:02 +0000 (UTC) Received: from ashelat-thinkpadp1gen5.boston.csb (unknown [10.22.80.235]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0B71D1956089; Wed, 15 Jul 2026 13:53:00 +0000 (UTC) From: Anubhav Shelat To: rostedt@goodmis.org, acme@kernel.org, peterz@infradead.org, Masami Hiramatsu , Mathieu Desnoyers , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: linux-perf-users@vger.kernel.org, Anubhav Shelat Subject: [PATCH v5 1/5] eventfs: define event fields before directory creation Date: Wed, 15 Jul 2026 09:52:22 -0400 Message-ID: <20260715135231.338535-3-ashelat@redhat.com> In-Reply-To: <20260715135231.338535-2-ashelat@redhat.com> References: <20260715135231.338535-2-ashelat@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Move the event_define_fields() call in event_create_dir() before the eventfs directory creation. Previously, a failure after directory creation wouldn't clean up eventfs_inode because the error path didn't call eventfs_remove_dir(). This eliminates the need to clean up the eventfs directories if event_define_fields() fails. Signed-off-by: Anubhav Shelat --- kernel/trace/trace_events.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index c46e623e7e0d..ddb6932a3ee7 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -3190,6 +3190,13 @@ event_create_dir(struct eventfs_inode *parent, struc= t trace_event_file *file) if (WARN_ON_ONCE(strcmp(call->class->system, TRACE_SYSTEM) =3D=3D 0)) return -ENODEV; =20 + ret =3D event_define_fields(call); + if (ret < 0) { + pr_warn("Could not initialize trace point events/%s\n", + trace_event_name(call)); + return ret; + } + e_events =3D event_subsystem_dir(tr, call->class->system, file, parent); if (!e_events) return -ENOMEM; @@ -3208,12 +3215,6 @@ event_create_dir(struct eventfs_inode *parent, struc= t trace_event_file *file) =20 file->ei =3D ei; =20 - ret =3D event_define_fields(call); - if (ret < 0) { - pr_warn("Could not initialize trace point events/%s\n", name); - return ret; - } - /* Gets decremented on freeing of the "enable" file */ event_file_get(file); =20 --=20 2.54.0 From nobody Sat Jul 25 17:33:40 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 885923126DF for ; Wed, 15 Jul 2026 13:53:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123595; cv=none; b=d/VVt9I3zBYhstQ8h//q5PJteVesLsn+neHBoUhOZqK0eV+WW3lABz7b1g2sewpsZFuRk3VmyjgqYkqqy6iV4272XR/Yf3KenwHNPq+RsGxIgHjas6ZiBMIizY7Sw992DmY5JF/5g789C16CkQ0YRppRMDLTag5HnuoQFRR/924= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123595; c=relaxed/simple; bh=c7Ux3Y4oBKWCT3MZoygJWIz84lJaLHkZAtdLU06/qn4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pY+Nt9jGJySAySFC8TpcXxwkpAkhy0+g8ACCpFKrBWXIlg3d8aTOk0xy2FhPP5vjC6YWFI7o9ghe0SSGJ6rPMsbsHvZe5n9KMhk7bWHT9DX1Kc2g1Htlk2nH39X1hL6qLZq4Edvt5EtkGPR6Vll7iJNxHBCrIKEO3zwfLs5UEw0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=TgT2O+9A; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="TgT2O+9A" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1784123592; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=wUIQVFWz/6HX0LXQ2LfuttAZGzqa1laC8h1PL/eYtC0=; b=TgT2O+9AbU6OfxCcRXJMRPoyvoJVkPn9JExi+P46SN8wo2Xycv+5jAmftbLQPtaeUCnPJo z7jhvzP4zUrnat1vT80NB8K1b4kx+CdEwzFZlrT6Op7J0/OiDNlRCX3TAJYKBKV7fpeCXw apXNIhSzwnqF8FVQf5x9WxONyph1Icc= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-54-DQPCm83kNf233xB0k5e_iw-1; Wed, 15 Jul 2026 09:53:09 -0400 X-MC-Unique: DQPCm83kNf233xB0k5e_iw-1 X-Mimecast-MFC-AGG-ID: DQPCm83kNf233xB0k5e_iw_1784123587 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 8D3D01800673; Wed, 15 Jul 2026 13:53:06 +0000 (UTC) Received: from ashelat-thinkpadp1gen5.boston.csb (unknown [10.22.80.235]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 257281956089; Wed, 15 Jul 2026 13:53:03 +0000 (UTC) From: Anubhav Shelat To: rostedt@goodmis.org, acme@kernel.org, peterz@infradead.org, Masami Hiramatsu , Mathieu Desnoyers , Shivank Garg , Ackerley Tng , Fuad Tabba , Christian Brauner , Sean Christopherson , Anubhav Shelat , linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: linux-perf-users@vger.kernel.org Subject: [PATCH v5 2/5] tracefs: add read-only eventfs filesystem at /sys/kernel/events Date: Wed, 15 Jul 2026 09:52:23 -0400 Message-ID: <20260715135231.338535-4-ashelat@redhat.com> In-Reply-To: <20260715135231.338535-2-ashelat@redhat.com> References: <20260715135231.338535-2-ashelat@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" Introduce a new read-only pseudo-filesystem "eventfs" mounted at /sys/kernel/events that exposes trace event format and id files (mode 0444) to unprivileged users. This allows tools like perf to discover event formats without requiring access to the full tracefs/debugfs mount. The eventfs filesystem reuses the existing eventfs_inode lazy-lookup infrastructure. A new set of super_operations (eventfs_ro_super_operations) shares the tracefs inode allocator so that eventfs_get_inode() and get_tracefs() work on the RO superblock. The superblock is manually initialized to ensure the root inode is allocated with tracefs_alloc_inode, allowing the root to serve directly as the events directory without another events subdirectory. Each qualifying event gets a subsystem directory containing format and id files. The top-level events directory also exposes header_page and header_event. Similar to tracefs, a change will need to be made in systemd to mount this filesystem automatically. Assisted-by: CLAUDE:claude-opus-4 Apogee Signed-off-by: Anubhav Shelat --- fs/tracefs/event_inode.c | 61 +++++++++++++++++++++++ fs/tracefs/inode.c | 95 +++++++++++++++++++++++++++++++++++- fs/tracefs/internal.h | 3 ++ include/linux/trace_events.h | 1 + include/linux/tracefs.h | 4 ++ include/uapi/linux/magic.h | 1 + kernel/trace/trace.h | 2 + kernel/trace/trace_events.c | 87 +++++++++++++++++++++++++++++++++ 8 files changed, 252 insertions(+), 2 deletions(-) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 39c7a34531e8..fd6f63ec3ce0 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -812,6 +812,67 @@ struct eventfs_inode *eventfs_create_events_dir(const = char *name, struct dentry return ERR_PTR(-ENOMEM); } =20 +/** + * eventfs_create_events_dir_ro - create a read-only events directory + * @name: The name of the top level directory to create. + * @entries: A list of entries that represent the files under this directo= ry + * @size: The number of @entries + * @data: The default data to pass to the files (an entry may override it). + * + * This function configures the eventfs filesystem root as a read-only + * trace event directory using the existing eventfs_inode lazy-lookup + * infrastructure. + * + * See eventfs_create_dir() for use of @entries. + */ +struct eventfs_inode *eventfs_create_events_dir_ro(const char *name, + const struct eventfs_entry *entries, + int size, void *data) +{ + struct dentry *dentry; + struct eventfs_root_inode *rei; + struct eventfs_inode *ei; + struct tracefs_inode *ti; + struct inode *inode; + + dentry =3D eventfs_ro_get_root(); + if (IS_ERR(dentry)) + return ERR_CAST(dentry); + + inode =3D d_inode(dentry); + + ei =3D alloc_root_ei(name); + if (!ei) + goto fail; + + rei =3D get_root_inode(ei); + rei->events_dir =3D dentry; + + ei->entries =3D entries; + ei->nr_entries =3D size; + ei->data =3D data; + + INIT_LIST_HEAD(&ei->children); + INIT_LIST_HEAD(&ei->list); + + ti =3D get_tracefs(inode); + ti->flags |=3D TRACEFS_EVENT_INODE; + ti->private =3D ei; + + inode->i_op =3D &eventfs_dir_inode_operations; + inode->i_fop =3D &eventfs_file_operations; + + dentry->d_fsdata =3D get_ei(ei); + + return ei; + + fail: + cleanup_ei(ei); + dput(dentry); + eventfs_ro_put_root(); + return ERR_PTR(-ENOMEM); +} + /** * eventfs_remove_rec - remove eventfs dir or file from list * @ei: eventfs_inode to be removed. diff --git a/fs/tracefs/inode.c b/fs/tracefs/inode.c index f3d6188a3b7b..fd064d79d940 100644 --- a/fs/tracefs/inode.c +++ b/fs/tracefs/inode.c @@ -30,6 +30,9 @@ static struct vfsmount *tracefs_mount; static int tracefs_mount_count; static bool tracefs_registered; =20 +static struct vfsmount *eventfs_ro_mount; +static int eventfs_ro_mount_count; + /* * Keep track of all tracefs_inodes in order to update their * flags if necessary on a remount. @@ -423,6 +426,14 @@ static const struct super_operations tracefs_super_ope= rations =3D { .show_options =3D tracefs_show_options, }; =20 +static const struct super_operations eventfs_ro_super_operations =3D { + .alloc_inode =3D tracefs_alloc_inode, + .free_inode =3D tracefs_free_inode, + .destroy_inode =3D tracefs_destroy_inode, + .drop_inode =3D tracefs_drop_inode, + .statfs =3D simple_statfs, +}; + /* * It would be cleaner if eventfs had its own dentry ops. * @@ -523,6 +534,79 @@ static struct file_system_type trace_fs_type =3D { }; MODULE_ALIAS_FS("tracefs"); =20 +static int eventfs_ro_fill_super(struct super_block *sb, struct fs_context= *fc) +{ + struct inode *inode; + struct dentry *root; + + sb->s_blocksize =3D PAGE_SIZE; + sb->s_blocksize_bits =3D PAGE_SHIFT; + sb->s_magic =3D EVENTFS_SUPER_MAGIC; + sb->s_op =3D &eventfs_ro_super_operations; + sb->s_time_gran =3D 1; + sb->s_flags |=3D SB_RDONLY; + + inode =3D new_inode(sb); + if (!inode) + return -ENOMEM; + + inode->i_ino =3D 1; + inode->i_mode =3D S_IFDIR | 0555; + simple_inode_init_ts(inode); + inode->i_op =3D &simple_dir_inode_operations; + inode->i_fop =3D &simple_dir_operations; + set_nlink(inode, 2); + + set_default_d_op(sb, &tracefs_dentry_operations); + + root =3D d_make_root(inode); + if (!root) + return -ENOMEM; + + sb->s_root =3D root; + + return 0; +} + +static int eventfs_ro_get_tree(struct fs_context *fc) +{ + return get_tree_single(fc, eventfs_ro_fill_super); +} + +static const struct fs_context_operations eventfs_ro_context_ops =3D { + .get_tree =3D eventfs_ro_get_tree, +}; + +static int eventfs_ro_init_fs_context(struct fs_context *fc) +{ + fc->ops =3D &eventfs_ro_context_ops; + return 0; +} + +static struct file_system_type eventfs_ro_fs_type =3D { + .owner =3D THIS_MODULE, + .name =3D "eventfs", + .init_fs_context =3D eventfs_ro_init_fs_context, + .kill_sb =3D kill_anon_super, +}; + +struct dentry *eventfs_ro_get_root(void) +{ + int error; + + error =3D simple_pin_fs(&eventfs_ro_fs_type, &eventfs_ro_mount, + &eventfs_ro_mount_count); + if (error) + return ERR_PTR(error); + + return dget(eventfs_ro_mount->mnt_root); +} + +void eventfs_ro_put_root(void) +{ + simple_release_fs(&eventfs_ro_mount, &eventfs_ro_mount_count); +} + struct dentry *tracefs_start_creating(const char *name, struct dentry *par= ent) { struct dentry *dentry; @@ -801,8 +885,15 @@ static int __init tracefs_init(void) return -EINVAL; =20 retval =3D register_filesystem(&trace_fs_type); - if (!retval) - tracefs_registered =3D true; + if (retval) + return retval; + tracefs_registered =3D true; + + retval =3D sysfs_create_mount_point(kernel_kobj, "events"); + if (retval) + return retval; + + retval =3D register_filesystem(&eventfs_ro_fs_type); =20 return retval; } diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index a4a7f8431aff..0440413f959b 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -73,6 +73,9 @@ struct dentry *tracefs_end_creating(struct dentry *dentry= ); struct dentry *tracefs_failed_creating(struct dentry *dentry); struct inode *tracefs_get_inode(struct super_block *sb); =20 +struct dentry *eventfs_ro_get_root(void); +void eventfs_ro_put_root(void); + void eventfs_remount(struct tracefs_inode *ti, bool update_uid, bool updat= e_gid); void eventfs_d_release(struct dentry *dentry); =20 diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h index 308c76b57d13..957695fbb015 100644 --- a/include/linux/trace_events.h +++ b/include/linux/trace_events.h @@ -648,6 +648,7 @@ struct trace_event_file { struct trace_event_call *event_call; struct event_filter __rcu *filter; struct eventfs_inode *ei; + struct eventfs_inode *ei_ro; struct trace_array *tr; struct trace_subsystem_dir *system; struct list_head triggers; diff --git a/include/linux/tracefs.h b/include/linux/tracefs.h index bc354d340046..c175efc51d20 100644 --- a/include/linux/tracefs.h +++ b/include/linux/tracefs.h @@ -87,6 +87,10 @@ struct eventfs_inode *eventfs_create_dir(const char *nam= e, struct eventfs_inode const struct eventfs_entry *entries, int size, void *data); =20 +struct eventfs_inode *eventfs_create_events_dir_ro(const char *name, + const struct eventfs_entry *entries, + int size, void *data); + void eventfs_remove_events_dir(struct eventfs_inode *ei); void eventfs_remove_dir(struct eventfs_inode *ei); =20 diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 4f2da935a76c..7cf8f1a1ae38 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -75,6 +75,7 @@ #define STACK_END_MAGIC 0x57AC6E9D =20 #define TRACEFS_MAGIC 0x74726163 +#define EVENTFS_SUPER_MAGIC 0x65766673 =20 #define V9FS_MAGIC 0x01021997 =20 diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 80fe152af1dd..00c35aaa5069 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -416,6 +416,7 @@ struct trace_array { struct dentry *options; struct dentry *percpu_dir; struct eventfs_inode *event_dir; + struct eventfs_inode *event_dir_ro; struct trace_options *topts; struct list_head systems; struct list_head events; @@ -1604,6 +1605,7 @@ struct trace_subsystem_dir { struct event_subsystem *subsystem; struct trace_array *tr; struct eventfs_inode *ei; + struct eventfs_inode *ei_ro; int ref_count; int nr_events; }; diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index ddb6932a3ee7..9662cb24a92c 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1279,6 +1279,7 @@ static void remove_subsystem(struct trace_subsystem_d= ir *dir) =20 if (!--dir->nr_events) { eventfs_remove_dir(dir->ei); + eventfs_remove_dir(dir->ei_ro); list_del(&dir->list); __put_system_dir(dir); } @@ -1308,6 +1309,7 @@ void event_file_put(struct trace_event_file *file) static void remove_event_file_dir(struct trace_event_file *file) { eventfs_remove_dir(file->ei); + eventfs_remove_dir(file->ei_ro); list_del(&file->list); remove_subsystem(file->system); free_event_filter(file->filter); @@ -2986,6 +2988,7 @@ event_subsystem_dir(struct trace_array *tr, const cha= r *name, } =20 dir->ei =3D ei; + dir->ei_ro =3D NULL; dir->tr =3D tr; dir->ref_count =3D 1; dir->nr_events =3D 1; @@ -3126,6 +3129,33 @@ static void event_release(const char *name, void *da= ta) event_file_put(file); } =20 +static int event_callback_ro(const char *name, umode_t *mode, void **data, + const struct file_operations **fops) +{ + int ret =3D event_callback(name, mode, data, fops); + + /* Skip writable entries in the read-only tree */ + if (ret && (*mode & 0222)) + return 0; + if (ret) + *mode =3D 0444; + return ret; +} + +static struct eventfs_entry event_entries_ro[] =3D { + { + .name =3D "format", + .callback =3D event_callback_ro, + .release =3D event_release, + }, +#ifdef CONFIG_PERF_EVENTS + { + .name =3D "id", + .callback =3D event_callback_ro, + }, +#endif +}; + static int event_create_dir(struct eventfs_inode *parent, struct trace_event_file *fi= le) { @@ -3218,6 +3248,28 @@ event_create_dir(struct eventfs_inode *parent, struc= t trace_event_file *file) /* Gets decremented on freeing of the "enable" file */ event_file_get(file); =20 + /* Create read only eventfs directory */ + if (!(call->flags & TRACE_EVENT_FL_DYNAMIC) && + !IS_ERR_OR_NULL(tr->event_dir_ro)) { + struct trace_subsystem_dir *sdir =3D file->system; + + if (!sdir->ei_ro) { + sdir->ei_ro =3D eventfs_create_dir(call->class->system, + tr->event_dir_ro, NULL, 0, sdir); + if (IS_ERR(sdir->ei_ro)) + sdir->ei_ro =3D NULL; + } + if (sdir->ei_ro) { + file->ei_ro =3D eventfs_create_dir(name, sdir->ei_ro, + event_entries_ro, + ARRAY_SIZE(event_entries_ro), file); + if (IS_ERR(file->ei_ro)) + file->ei_ro =3D NULL; + else + event_file_get(file); + } + } + return 0; } =20 @@ -4539,10 +4591,35 @@ static int events_callback(const char *name, umode_= t *mode, void **data, return 1; } =20 +static int events_callback_ro(const char *name, umode_t *mode, void **data, + const struct file_operations **fops) +{ + int ret =3D events_callback(name, mode, data, fops); + + /* Skip writable entries in the read-only tree */ + if (ret && (*mode & 0222)) + return 0; + if (ret) + *mode =3D 0444; + return ret; +} + +static struct eventfs_entry events_entries_ro[] =3D { + { + .name =3D "header_page", + .callback =3D events_callback_ro, + }, + { + .name =3D "header_event", + .callback =3D events_callback_ro, + }, +}; + /* Expects to have event_mutex held when called */ static int create_event_toplevel_files(struct dentry *parent, struct trace_array *tr) { + static bool event_dir_ro_created; struct eventfs_inode *e_events; struct dentry *entry; int nr_entries; @@ -4596,6 +4673,16 @@ create_event_toplevel_files(struct dentry *parent, s= truct trace_array *tr) =20 tr->event_dir =3D e_events; =20 + if (!event_dir_ro_created && (tr->flags & TRACE_ARRAY_FL_GLOBAL)) { + tr->event_dir_ro =3D eventfs_create_events_dir_ro( + "events", events_entries_ro, + ARRAY_SIZE(events_entries_ro), tr); + if (IS_ERR(tr->event_dir_ro)) + tr->event_dir_ro =3D NULL; + else + event_dir_ro_created =3D true; + } + return 0; } =20 --=20 2.54.0 From nobody Sat Jul 25 17:33:40 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 417BF31A575 for ; Wed, 15 Jul 2026 13:53:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123602; cv=none; b=O6gDfqTFPZerBDqY1PB5ocDbgSvCvdopZoDCsz2hTmE2Ukxsly4FZD6XwIy8gjZ2YgaLfLx7x7eW7dxGRGm/m5ZwpvV6PC69VCp6tJTCaPFsGphWv5kfDEirUuQBQ8FBKkemoW5xVWgPipFgsYelmgj+1DLz0wx72oWGF+FeN80= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123602; c=relaxed/simple; bh=O3ivOgmDRBqcXIeMODoLr5igdL7mEEZYikJ+jhp/gfU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Ri2FsUkmHDs1Xz8836L+EHTEMsTedsnoaps1baKVD6PooqnQCX6FrYgPPahcyDkPUOPtaOIFDgkv+b6Exovl6z7QcOlHWDI+FIua43GrUzgLeoZ3MC/SWuHMCaYu/Vx6X+HvGQ2m9nIl4jI0QEa9XAzWg4lCa95asXJSBVPDsJM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=iqu0dGzM; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="iqu0dGzM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1784123600; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rBXa+CtLSxnyksrkUXGGy3/jtRSwHraEoQaUzzqjDvk=; b=iqu0dGzMZQiEHj5JvCZTVl45YQSFN4e4Ohz0wvo2JfqwebCyeVJYXlm4CwEkBnaEtxeEbY DFC1WzFnRPg23rIC+dUxScluT/YprV0RxcfYukjdqfzOlhKMlGEBUMR3dUgomCgsAjbfI+ j40wq8mXkRSonkkv2jN7I/iDLp6aykQ= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-73-2-WIypeINMSHPUU3M9hhWg-1; Wed, 15 Jul 2026 09:53:16 -0400 X-MC-Unique: 2-WIypeINMSHPUU3M9hhWg-1 X-Mimecast-MFC-AGG-ID: 2-WIypeINMSHPUU3M9hhWg_1784123594 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 00B3018001F2; Wed, 15 Jul 2026 13:53:14 +0000 (UTC) Received: from ashelat-thinkpadp1gen5.boston.csb (unknown [10.22.80.235]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C884D1956089; Wed, 15 Jul 2026 13:53:10 +0000 (UTC) From: Anubhav Shelat To: rostedt@goodmis.org, acme@kernel.org, peterz@infradead.org, Ingo Molnar , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , Anubhav Shelat , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org Cc: linux-trace-kernel@vger.kernel.org Subject: [PATCH v5 3/5] perf tools: fall back to eventfs for unprivileged event discovery Date: Wed, 15 Jul 2026 09:52:24 -0400 Message-ID: <20260715135231.338535-5-ashelat@redhat.com> In-Reply-To: <20260715135231.338535-2-ashelat@redhat.com> References: <20260715135231.338535-2-ashelat@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" When tracefs events are not readable by unprivileged users, fall back to /sys/kernel/events (the read-only eventfs mount) for tracepoint format and id file discovery. This allows perf trace to work for unprivileged users on kernels that expose the eventfs filesystem. The fallback is transparent: get_events_file() tries the tracefs path first and only switches to eventfs when access() fails. On kernels without eventfs, the existing error path is preserved. Assisted-by: CLAUDE:claude-opus-4 Apogee Signed-off-by: Anubhav Shelat --- tools/lib/api/fs/fs.c | 10 ++++++ tools/lib/api/fs/fs.h | 1 + tools/lib/api/fs/tracing_path.c | 52 ++++++++++++++++++++++++++---- tools/lib/api/fs/tracing_path.h | 1 + tools/perf/util/tp_pmu.c | 5 +-- tools/perf/util/trace-event-info.c | 19 ++++++----- 6 files changed, 71 insertions(+), 17 deletions(-) diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index cbd8eab0d1df..abc3581a9703 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -46,6 +46,10 @@ #define BPF_FS_MAGIC 0xcafe4a11 #endif =20 +#ifndef EVENTFS_SUPER_MAGIC +#define EVENTFS_SUPER_MAGIC 0x65766673 +#endif + static const char * const sysfs__known_mountpoints[] =3D { "/sys", 0, @@ -88,6 +92,11 @@ static const char * const bpf_fs__known_mountpoints[] = =3D { 0, }; =20 +static const char * const eventfs__known_mountpoints[] =3D { + "/sys/kernel/events", + 0, +}; + struct fs { const char * const name; const char * const * const mounts; @@ -150,6 +159,7 @@ FS(debugfs, debugfs, DEBUGFS); FS(tracefs, tracefs, TRACEFS); FS(hugetlbfs, hugetlbfs, HUGETLBFS); FS(bpf_fs, bpf, BPF_FS); +FS(eventfs, eventfs, EVENTFS_SUPER); =20 static bool fs__read_mounts(struct fs *fs) { diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index aa222ca30311..57790c93f80e 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h @@ -36,6 +36,7 @@ FS(debugfs) FS(tracefs) FS(hugetlbfs) FS(bpf_fs) +FS(eventfs) =20 #undef FS =20 diff --git a/tools/lib/api/fs/tracing_path.c b/tools/lib/api/fs/tracing_pat= h.c index 834fd64c7130..de4ed7c61415 100644 --- a/tools/lib/api/fs/tracing_path.c +++ b/tools/lib/api/fs/tracing_path.c @@ -3,6 +3,8 @@ # define _GNU_SOURCE #endif =20 +#include +#include #include #include #include @@ -80,13 +82,46 @@ void put_tracing_file(char *file) free(file); } =20 +char *get_events_dir(void) +{ + const char *eventfs; + char *path; + int saved_errno; + + path =3D get_tracing_file("events"); + if (path && faccessat(AT_FDCWD, path, R_OK, AT_EACCESS) =3D=3D 0) + return path; + + saved_errno =3D errno; + put_tracing_file(path); + + eventfs =3D eventfs__mount(); + if (eventfs && faccessat(AT_FDCWD, eventfs, R_OK, AT_EACCESS) =3D=3D 0 && + eventfs__configured()) + return strdup(eventfs); + + /* + * Prefer EACCES over other errors: it tells the user that events + * exist but are not accessible, which is more actionable than + * ENOENT from a missing filesystem. + */ + if (errno !=3D EACCES) + errno =3D saved_errno; + return NULL; +} + char *get_events_file(const char *name) { - char *file; + char *dir, *file; =20 - if (asprintf(&file, "%s/events/%s", tracing_path_mount(), name) < 0) + dir =3D get_events_dir(); + if (!dir) return NULL; =20 + if (asprintf(&file, "%s/%s", dir, name) < 0) + file =3D NULL; + + free(dir); return file; } =20 @@ -97,8 +132,8 @@ void put_events_file(char *file) =20 DIR *tracing_events__opendir(void) { + char *path =3D get_events_dir(); DIR *dir =3D NULL; - char *path =3D get_tracing_file("events"); =20 if (path) { dir =3D opendir(path); @@ -110,7 +145,7 @@ DIR *tracing_events__opendir(void) =20 int tracing_events__scandir_alphasort(struct dirent ***namelist) { - char *path =3D get_tracing_file("events"); + char *path =3D get_events_dir(); int ret; =20 if (!path) { @@ -121,6 +156,9 @@ int tracing_events__scandir_alphasort(struct dirent ***= namelist) ret =3D scandir(path, namelist, NULL, alphasort); put_events_file(path); =20 + if (ret < 0) + *namelist =3D NULL; + return ret; } =20 @@ -162,12 +200,12 @@ int tracing_path__strerror_open_tp(int err, char *buf= , size_t size, "Hint:\tIs the debugfs/tracefs filesystem mounted?\n" "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); break; - case EACCES: { + case EACCES: snprintf(buf, size, "Error:\tNo permissions to read %s/events/%s\n" - "Hint:\tTry 'sudo mount -o remount,mode=3D755 %s'\n", + "Hint:\tTry 'sudo mount -o remount,mode=3D755 %s'\n" + "Hint:\tOr check if /sys/kernel/events is available\n", tracing_path, filename, tracing_path_mount()); - } break; default: snprintf(buf, size, "%s", str_error_r(err, sbuf, sizeof(sbuf))); diff --git a/tools/lib/api/fs/tracing_path.h b/tools/lib/api/fs/tracing_pat= h.h index fc6347c11deb..a93befb38f80 100644 --- a/tools/lib/api/fs/tracing_path.h +++ b/tools/lib/api/fs/tracing_path.h @@ -14,6 +14,7 @@ const char *tracing_path_mount(void); char *get_tracing_file(const char *name); void put_tracing_file(char *file); =20 +char *get_events_dir(void); char *get_events_file(const char *name); void put_events_file(char *file); =20 diff --git a/tools/perf/util/tp_pmu.c b/tools/perf/util/tp_pmu.c index c2be8c9f9084..4f45bd816945 100644 --- a/tools/perf/util/tp_pmu.c +++ b/tools/perf/util/tp_pmu.c @@ -6,6 +6,7 @@ #include #include #include +#include #include =20 int tp_pmu__id(const char *sys, const char *name) @@ -15,7 +16,7 @@ int tp_pmu__id(const char *sys, const char *name) int id, err; =20 if (!tp_dir) - return -1; + return -errno; =20 scnprintf(path, PATH_MAX, "%s/%s/id", tp_dir, name); put_events_file(tp_dir); @@ -66,7 +67,7 @@ int tp_pmu__for_each_tp_sys(void *state, tp_sys_callback = cb) struct io_dirent64 *events_ent; struct io_dir events_dir; int ret =3D 0; - char *events_dir_path =3D get_tracing_file("events"); + char *events_dir_path =3D get_events_dir(); =20 if (!events_dir_path) return -errno; diff --git a/tools/perf/util/trace-event-info.c b/tools/perf/util/trace-eve= nt-info.c index 45774722f249..643451d2c08d 100644 --- a/tools/perf/util/trace-event-info.c +++ b/tools/perf/util/trace-event-info.c @@ -92,8 +92,9 @@ static int record_header_files(void) int err =3D -EIO; =20 if (!path) { + err =3D -errno; pr_debug("can't get tracing/events/header_page"); - return -ENOMEM; + return err; } =20 if (stat(path, &st) < 0) { @@ -115,8 +116,8 @@ static int record_header_files(void) =20 path =3D get_events_file("header_event"); if (!path) { + err =3D -errno; pr_debug("can't get tracing/events/header_event"); - err =3D -ENOMEM; goto out; } =20 @@ -228,13 +229,14 @@ static int record_ftrace_files(struct tracepoint_path= *tps) =20 path =3D get_events_file("ftrace"); if (!path) { + ret =3D -errno; pr_debug("can't get tracing/events/ftrace"); - return -ENOMEM; + return ret; } =20 ret =3D copy_event_system(path, tps); =20 - put_tracing_file(path); + put_events_file(path); =20 return ret; } @@ -256,15 +258,16 @@ static int record_event_files(struct tracepoint_path = *tps) struct stat st; char *path; char *sys; - DIR *dir; + DIR *dir =3D NULL; int count =3D 0; int ret; int err; =20 - path =3D get_tracing_file("events"); + path =3D get_events_dir(); if (!path) { + err =3D -errno; pr_debug("can't get tracing/events"); - return -ENOMEM; + goto out; } =20 dir =3D opendir(path); @@ -315,7 +318,7 @@ static int record_event_files(struct tracepoint_path *t= ps) out: if (dir) closedir(dir); - put_tracing_file(path); + put_events_file(path); =20 return err; } --=20 2.54.0 From nobody Sat Jul 25 17:33:40 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B4FD2322B9F for ; Wed, 15 Jul 2026 13:53:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123607; cv=none; b=sjftRAZQtvnuvIf/oP7kM/HlekX/Z0oZ/yUY0Jxetb2EfpH+8r+9gJYXZ3Gl+YrEmMcXdpTbA3c9w4sXbfljtHvUNWE0PXfoUKdIR19FU3Y6kItMxyv85gC6VLsjzG1rLs1+k0Atz3NezJXj4rPOn6AD0KmXVXzrt92yqxYu7ck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123607; c=relaxed/simple; bh=3kWygXnKCpjuIn/qC6W/3zq25IIgInfjEvKuW8zdE90=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=d+0m9fjdAX7BAqJCsB8iI72ZSxx4C4ecKg3mo+X475MV+A59HFE5FSaEekgsSi/T41P+ZUC+sQXK4P53Lr/0BnPaATE4eJiCgYxG3nbDQU+0jnuXdepmg/0IVp33VpFJt1lnKJ2qacC+PLi34DKmZuv6B6cZjKGFAjut3GtnJ9o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=cw5rGz/x; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="cw5rGz/x" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1784123604; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=epfFDK7uRA/mihPB8RJRezIjGoE7O366kYFSAw99Blg=; b=cw5rGz/xmC8ZJqHntUL1sRAZxd0gQsrbAn3/RHNnYfPjwxhy+M1JML2zFfM3OSt+WDr6EP BEz44adSef3fDZrsQKpi9puC9Jq5Z+75aVPmmeSt42HbiPSoYmpr2uQDWj8Sy/5cNeTXk2 v8Z5PgtA42tKDQ8CPfvA8M/2NV1iucE= Received: from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-583-QRc_5vW_PVadmInA_PA87w-1; Wed, 15 Jul 2026 09:53:20 -0400 X-MC-Unique: QRc_5vW_PVadmInA_PA87w-1 X-Mimecast-MFC-AGG-ID: QRc_5vW_PVadmInA_PA87w_1784123598 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B42E71800358; Wed, 15 Jul 2026 13:53:17 +0000 (UTC) Received: from ashelat-thinkpadp1gen5.boston.csb (unknown [10.22.80.235]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id F10021956086; Wed, 15 Jul 2026 13:53:14 +0000 (UTC) From: Anubhav Shelat To: rostedt@goodmis.org, acme@kernel.org, peterz@infradead.org, Ingo Molnar , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , Thomas Falcon , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org Cc: linux-trace-kernel@vger.kernel.org, Anubhav Shelat Subject: [PATCH v5 4/5] perf evsel: don't set PERF_SAMPLE_IP for unprivileged tracepoints Date: Wed, 15 Jul 2026 09:52:25 -0400 Message-ID: <20260715135231.338535-6-ashelat@redhat.com> In-Reply-To: <20260715135231.338535-2-ashelat@redhat.com> References: <20260715135231.338535-2-ashelat@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Content-Type: text/plain; charset="utf-8" For tracepoint events the IP is a static kernel address. It doesn't vary by sample and provides no useful information for unprivileged users. Skipping setting PERF_SAMPLE_IP for unprivileged tracepoints avoids exposing a kernel address that reveals the KASLR base offset. Make an exception for uprobes, which are registered as PERF_TYPE_TRACEPOINT, because the IP is important for their functionality and is a safe userspace address. Detect them with __probe_ip (entry) and __probe_ret_ip (return) using evsel__field(). Assisted-by: CLAUDE:claude-opus-4 Apogee Signed-off-by: Anubhav Shelat --- tools/perf/util/evsel.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index ea9fa04429f0..1d85e5503cf3 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1571,7 +1571,19 @@ void evsel__config(struct evsel *evsel, const struct= record_opts *opts, attr->write_backward =3D opts->overwrite ? 1 : 0; attr->read_format =3D PERF_FORMAT_LOST; =20 - evsel__set_sample_bit(evsel, IP); + /* + * Don't set PERF_SAMPLE_IP for unprivileged kernel tracepoints to + * avoid exposing kernel addresses. Uprobes expose only userspace + * addresses so they're safe. Detect both entry and return uprobes. + */ + if (attr->type !=3D PERF_TYPE_TRACEPOINT || perf_event_paranoid_check(1) +#ifdef HAVE_LIBTRACEEVENT + || evsel__field(evsel, "__probe_ip") + || evsel__field(evsel, "__probe_ret_ip") +#endif + ) + evsel__set_sample_bit(evsel, IP); + evsel__set_sample_bit(evsel, TID); =20 if (evsel->sample_read) { --=20 2.54.0 From nobody Sat Jul 25 17:33:40 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 99280328B7B for ; Wed, 15 Jul 2026 13:53:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123610; cv=none; b=AUBFwk77mWrp0UN5i5ObWWOoYJ9D/wBBY8XeOoHrQDaO422gzczrE8IeIdprAi6F9mlZ9kczfzBmCRbsCXyZoQFXN0VaU7hJIazB1QpAXH36B1fHLGFcgRg2OvCsBuU6mPKZ3zoBUtCiGV7zeOMRo1frHXQE2vpwAN+QJLYvRag= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784123610; c=relaxed/simple; bh=5ZugrS/XkaD0h/4ZRtq6FyU9FkKZDK9GPMwpyXNA5Rw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=nlKfUWUorYVbMZ1xfPQNIP5X1ik0pMnGasYKUyss/mBqSnN+Xf8ibeAY8kQ605Vt2zrxRY/Ukn8wXZ7vvOW4lIh64FMybgoUzTjuUPJl2Ivs34F0FaMuoBjUw+QlTV8qGs9VRpxUzrTsI7XAmLt8xgdQrYm+WsJgBycWIWakHWE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=A5fb1kc/; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="A5fb1kc/" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1784123607; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=LvmLOXpC1CRK/A3/t0yO20cykVDTPKJzzMQZeRym+Ns=; b=A5fb1kc/G4P/hLSLshxdoHaXVKH8qJ7jLMyhI79LbzD9se+CFaogm7U+ugv/YICfy6uNGi 8jCsPsEkKYUDOEYfaIAHloqwtJyxU3EW/8jxF6otFmDkHRkdG9QTsJkdIXuVjU6rBW7VCr Wr4dBSqZ6cPJh09v6c69lm9prJLJ1fk= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-328-vVvQ4nMhMeauDqWgIyhMJA-1; Wed, 15 Jul 2026 09:53:23 -0400 X-MC-Unique: vVvQ4nMhMeauDqWgIyhMJA-1 X-Mimecast-MFC-AGG-ID: vVvQ4nMhMeauDqWgIyhMJA_1784123600 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A8BDE18002CC; Wed, 15 Jul 2026 13:53:20 +0000 (UTC) Received: from ashelat-thinkpadp1gen5.boston.csb (unknown [10.22.80.235]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 3A07B195608E; Wed, 15 Jul 2026 13:53:18 +0000 (UTC) From: Anubhav Shelat To: rostedt@goodmis.org, acme@kernel.org, peterz@infradead.org, Ingo Molnar , Namhyung Kim , Mark Rutland , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , Masami Hiramatsu , Mathieu Desnoyers , linux-perf-users@vger.kernel.org, linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: Anubhav Shelat Subject: [PATCH v5 5/5] perf: enable unprivileged syscall tracing with perf trace Date: Wed, 15 Jul 2026 09:52:26 -0400 Message-ID: <20260715135231.338535-7-ashelat@redhat.com> In-Reply-To: <20260715135231.338535-2-ashelat@redhat.com> References: <20260715135231.338535-2-ashelat@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 Allow unprivileged users to trace their own processes' syscalls using perf trace, similar to strace without the overhead of ptrace(). Currently, perf trace requires CAP_PERFMON or paranoid level =E2=89=A4 1 ev= en though the kernel has existing infrastructure (TRACE_EVENT_FL_CAP_ANY) designed to mark syscall tracepoints as safe for unprivileged access. To fix this: 1. Loosen the condition in perf_event_open() which requires privileges for all events with exclude_kernel=3D0. This allows perf_event_open() to bypass the paranoid check for task-attached tracepoint events. Ensure that sample types which can expose kernel addresses to unprivileged users are blocked. Ensure the PERF_SECURITY_KERNEL LSM hook is preserved. 2. Add a check to perf_trace_event_perm() to block PERF_SAMPLE_IP on kernel tracepoints for unprivileged users to prevent KASLR bypass. We do this here rather than in kaddr_leak because perf_trace_event_perm() can distinguish between kernel tracepoints and uprobe tracepoints, where the IP is a safe user space address and is necessary for uprobe functionality. 3. Restrict pure counting events (no PERF_SAMPLE_RAW) to TRACE_EVENT_FL_CAP_ANY tracepoints preventing unprivileged users from counting internal kernel tracepoints while preserving current behavior for exclude_kernel=3D1 events. Example usage after this change: $ perf trace ls # works as unprivileged user $ perf trace # system-wide, still requires privileges $ perf trace -p 1234 # requires ptrace permission on pid 1234 Assisted-by: CLAUDE:claude-opus-4 Apogee Signed-off-by: Anubhav Shelat --- kernel/events/core.c | 28 +++++++++++++++++++++++++--- kernel/trace/trace_event_perf.c | 28 +++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 4 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 954c36e28101..48bfff07ae02 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -13910,9 +13910,31 @@ SYSCALL_DEFINE5(perf_event_open, return err; =20 if (!attr.exclude_kernel) { - err =3D perf_allow_kernel(); - if (err) - return err; + bool tp_bypass =3D false; + + /* Check unprivileged tracepoints */ + if (attr.type =3D=3D PERF_TYPE_TRACEPOINT && pid !=3D -1) { + /* + * Block sample types that expose kernel addresses to + * prevent KASLR bypass + */ + u64 kaddr_leak =3D PERF_SAMPLE_CALLCHAIN | + PERF_SAMPLE_BRANCH_STACK | + PERF_SAMPLE_ADDR | + PERF_SAMPLE_REGS_INTR; + + tp_bypass =3D !(attr.sample_type & kaddr_leak); + } + + if (!tp_bypass) { + err =3D perf_allow_kernel(); + if (err) + return err; + } else { + err =3D security_perf_event_open(PERF_SECURITY_KERNEL); + if (err) + return err; + } } =20 if (attr.namespaces) { diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_per= f.c index 5b272856e5ab..a264154b460e 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -24,6 +24,16 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / size= of(unsigned long)]) /* Count the events in use (per event id, not per instance) */ static int total_ref_count; =20 +/* Check if perf tracepoint is restricted for unprivileged users */ +static bool perf_tp_is_restricted(struct perf_event *p_event) +{ + if (p_event->attr.exclude_kernel) + return false; + if (sysctl_perf_event_paranoid <=3D 1 || perfmon_capable()) + return false; + return true; +} + static int perf_trace_event_perm(struct trace_event_call *tp_event, struct perf_event *p_event) { @@ -72,9 +82,25 @@ static int perf_trace_event_perm(struct trace_event_call= *tp_event, return -EINVAL; } =20 + /* + * PERF_SAMPLE_IP on kernel tracepoints exposes a kernel text + * address, weakening KASLR. Block for unprivileged users unless + * the tracepoint is a uprobe (userspace IP, safe to expose). + */ + if ((p_event->attr.sample_type & PERF_SAMPLE_IP) && + !(tp_event->flags & TRACE_EVENT_FL_UPROBE) && + perf_tp_is_restricted(p_event)) + return -EACCES; + /* No tracing, just counting, so no obvious leak */ - if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) + if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) { + /* Prevent unprivileged users from counting kernel tracepoints */ + if (perf_tp_is_restricted(p_event) && + !(p_event->attach_state =3D=3D PERF_ATTACH_TASK && + (tp_event->flags & TRACE_EVENT_FL_CAP_ANY))) + return -EACCES; return 0; + } =20 /* Some events are ok to be traced by non-root users... */ if (p_event->attach_state =3D=3D PERF_ATTACH_TASK) { --=20 2.54.0