From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-3.3 required=3.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 578D5C4727C for ; Tue, 29 Sep 2020 18:18:15 +0000 (UTC) Received: from shelob.surriel.com (shelob.surriel.com [96.67.55.147]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 62F83208B8 for ; Tue, 29 Sep 2020 18:18:14 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (1024-bit key) header.d=gmx.net header.i=@gmx.net header.b="j9aUBpz5" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 62F83208B8 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=gmx.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=kernelnewbies-bounces@kernelnewbies.org Received: from localhost ([::1] helo=shelob.surriel.com) by shelob.surriel.com with esmtp (Exim 4.94) (envelope-from ) id 1kNKBw-0007Rk-Fa; Tue, 29 Sep 2020 14:17:32 -0400 Received: from mout.gmx.net ([212.227.15.18]) by shelob.surriel.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94) (envelope-from ) id 1kLqKI-0001ug-D0 for kernelnewbies@kernelnewbies.org; Fri, 25 Sep 2020 12:12:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=gmx.net; s=badeba3b8450; t=1601050319; bh=Mn2gmBg0kOTkwKErQjTVQ6hjw4QjirgHxMw3S+828QE=; h=X-UI-Sender-Class:Date:From:To:Cc:Subject; b=j9aUBpz52GUhDTp8020ZZUnftbuZ5K6N8CxyqH3JisxM4nWZwOix3tfxkk5/TwChE DYku2Kw2+eYwcQAeM9GQJHeKYg3GH5RgS6U9d9DLnDFofjyIlHjeXAGspm4wg6z2Re Xr/PgWd9uxdr0OVeU/ozQGXtZ2vRSp0fT4xXbpU0= X-UI-Sender-Class: 01bb95c1-4bf8-414a-932a-4f6e2808ef9c Received: from ubuntu ([79.150.73.70]) by mail.gmx.com (mrgmx004 [212.227.17.184]) with ESMTPSA (Nemesis) id 1MqJqD-1kqWFw2Qt9-00nQpb; Fri, 25 Sep 2020 18:11:59 +0200 Date: Fri, 25 Sep 2020 18:11:42 +0200 From: John Wood To: kernelnewbies@kernelnewbies.org Subject: Read the "real_parent" field of task_struct Message-ID: <20200925161142.GA2857@ubuntu> MIME-Version: 1.0 Content-Disposition: inline X-Provags-ID: V03:K1:3LAW1WGS1fw0zkG9S/N8FyfZv2J+hY/WCgWw8cwvU1ZKrEDse8I sci8fshoh86LiwDZiBSw1YukH+CNqXpbgbJkeNtbXU2zG4bwBwxLLappfAmAPbUK/V5j8J5 sAvwCT71DxdLEB6yQm5LmTfVrdIGoBVu4kn9tuMqcc8b8a95BMpXcWomniK38UCgzqblpas O5wS1LRs5sKJdhWKJAIOg== X-UI-Out-Filterresults: notjunk:1;V03:K0:JlkYg3zDwYc=:voqbK2dcJq6Yp8doTzMf17 jy4pnw/dsWnra5vuWI6NsmKCryGyE/wz7niaw7v+vNGqy4IaELGRcJjhmABzQAwc4gw14wm5E Hvnr2G8a/S2n1NemAE2HeheMocmMaZ/ifX3wVheDmFmVgGiMW+xAZ5SqUZa+cEWRKvLSequms VRzeTSeLmILTYExKqRnsI875OuZhhfwkduSCzA01ZE1XeE4CbeygEA7m5EDGGSqp2IX+aIOc8 6ykza1YNG7mzVYTNUQoBo4DI2CQafAOFbbRtLmWzuj6LdpGRn2hyiQaJtxe84jKx4U+z0B2KN fOOMTsYb3ifp6V3F/SCwEdZ9YXGhoXzw5ikJFbCIDq5YuuyndhZvVxvR0kCBPcNHpbozZPQAj R+LcLvNn1YArZx3wEsb84FGWASRSAdvSYQxDfVnhgyKUrA3YzrHRh3Kl3Nhvb94Iyv6zhIr3A 86j7AFQoM4Xo6hvpIaXfS47zOOU8+ljkYiFeXgaS9T6RafGB18yPZzzch0p9uGcdxJYo+v49y NQhPK3u/qagMxKm0eLZ1HUloOtc/8xFO2e4rfqDdSqOO9Hx6M3eLlHo1xdGcpYke6zCcGO87p c7mE5Psh6sTg0yMfg5MxF4YGmmz2n+ZKSdjrdzK/JAAz0ebdj5GiJCYtUXbq+INNBoAygppQv /TzI06NjYMjaIYk9RvAA/KTtFhymQHhazfBKZ3bGiezEgxIXEp9pIjoBDZH0ZyFk2+rJTsq6X IIh3vgA2Ynm7w3DCAT+8Ql8SQAcMLbIbCMur0TNQITaHGWtWT7whfCHX4rscXuBciNJDt8D9K sT4e+2a/L4HXfutbKhlmsGy0HQ3fkvzDlAeZqK3n8BdYZ+RH0GwVaP7nqa1MmUZpQZGE+yhFw kd+ykx7pm5pBF+FspkbY6o2a8SD2Zv8gLFoOJXPaYdKUVZmnZTu/bcAKNhT+xVZTu64ZhsHPp Ex8g2efUJ1jUHDERUMe76B48QO/ekC30iTaD2wcgTpMUDyWmDaIY1qKYVVjqNkm5wGBKb3IhW opNUBaNbhrO57lt7dcKUqi+mdyfwwwUgO6JLsfu4YBCa0M18IrdCOGSseD7qeHD4aAGzu6yiV o5fYMcK8ZQpBsg1u7qXfV/g8p6JLQFnYG/CKxD0c48VlaV736WAo2n5txId7kVxG5bvHisW/O M7E+fb8/eN1sh6rUv6S4e/NjXvR2RtUjr5yn6CwB+KiBldMptZtqwu8H3XjmVRGw4RsYBiYy+ DYYifRhhrwLj4OkIi9eTKskbMCGuRVHfh9YiZnw== X-Mailman-Approved-At: Tue, 29 Sep 2020 14:17:21 -0400 Cc: John Wood X-BeenThere: kernelnewbies@kernelnewbies.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: Learn about the Linux kernel List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: kernelnewbies-bounces@kernelnewbies.org Hi, I'm working in a LSM that uses the task_alloc hook to do some work. This hook needs to check the "real_parent" field hold by the task_struct structure. I'm very confused since navigating the source code I see many different ways to access this field. I don't understand why every method is used in each case. So I don't know how to implement this access in my LSM in a secure way. The real_parent field is defined in the task_struct structure as: struct task_struct __rcu *real_parent; So, as far I can understand this pointer uses the "Read Copy Update" feature. Below I show some examples of different access: -------------------------------------------------------------------------- Example 1 -------------------------------------------------------------------------- void proc_fork_connector(struct task_struct *task) { [...] rcu_read_lock(); parent = rcu_dereference(task->real_parent); ev->event_data.fork.parent_pid = parent->pid; ev->event_data.fork.parent_tgid = parent->tgid; rcu_read_unlock(); [...] } Here to access the real_parent field the code uses rcu_dereference inside the rcu_read_lock/rcu_read_unlock block. -------------------------------------------------------------------------- Example 2 -------------------------------------------------------------------------- static struct pid * get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos) { [...] read_lock(&tasklist_lock); [...] if (task && task->real_parent == start && !(list_empty(&task->sibling))) { [...] read_unlock(&tasklist_lock); [...] } Here to access the real_parent field the code reads the pointer directly inside the read_lock/read_unlock block. No rcu block needed? Why is not used the rcu_dereference function? -------------------------------------------------------------------------- Example 3 -------------------------------------------------------------------------- struct task_struct init_task __aligned(L1_CACHE_BYTES) = { [...] .real_parent = &init_task, .parent = &init_task, [...] RCU_POINTER_INITIALIZER(real_cred, &init_cred), RCU_POINTER_INITIALIZER(cred, &init_cred), [...] }; Here the initialization is directly. If the pointer is declared __rcu, the assigment to the real_parent should be with RCU_POINTER_INITIALIZER macro? -------------------------------------------------------------------------- Example 4 -------------------------------------------------------------------------- static void forget_original_parent(struct task_struct *father, struct list_head *dead) { [...] RCU_INIT_POINTER(t->real_parent, reaper); [...] } Here the initialization uses the RCU_INIT_POINTER macro. It's not directly. -------------------------------------------------------------------------- Example 5 -------------------------------------------------------------------------- SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) { [...] rcu_read_lock(); /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM */ write_lock_irq(&tasklist_lock); [...] if (same_thread_group(p->real_parent, group_leader)) { [...] write_unlock_irq(&tasklist_lock); rcu_read_unlock(); [...] } Here to access the real_parent field the code reads the pointer directly inside the write_lock_irq/write_unlock_irq block nested in a rcu_read_lock/ rcu_read_unlock block. -------------------------------------------------------------------------- Example 6 -------------------------------------------------------------------------- long keyctl_session_to_parent(void) { [...] rcu_read_lock(); write_lock_irq(&tasklist_lock); [...] parent = rcu_dereference_protected(me->real_parent, lockdep_is_held(&tasklist_lock)); [...] write_unlock_irq(&tasklist_lock); rcu_read_unlock(); [...] } But here to access the real_parent field the code uses rcu_dereference_* inside the write_lock_irq/write_unlock_irq block nested in a rcu_read_lock/ rcu_read_unlock block. The nested blocks are the sames that in the example 5 but the access is not directly, it uses rcu_dereference_*. Why? Extracted from the documentation: [1] The variant rcu_dereference_protected() can be used outside of an RCU read-side critical section as long as the usage is protected by locks acquired by the update-side code. This variant avoids the lockdep warning that would happen when using (for example) rcu_dereference() without rcu_read_lock() protection. Using rcu_dereference_protected() also has the advantage of permitting compiler optimizations that rcu_dereference() must prohibit. The rcu_dereference_protected() variant takes a lockdep expression to indicate which locks must be acquired by the caller. If the indicated protection is not provided, a lockdep splat is emitted. Moreover, why the rcu_dereference_protected is used under a rcu block? There are more examples but are similars to the ones showed. So my question is how to read the "real_parent" field correctly. If I can understand all the above examples I think I will have the knowledge to implement my LSM in a correct way. Any help that points me to the right direction will be greatly apreciated. Some rules to know when and why use a method or another are welcome. Thanks in advance. Regards, John Wood _______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org https://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies