All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mehmet Kayaalp <mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
To: ima-devel
	<linux-ima-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
Cc: Mehmet Kayaalp
	<mkayaalp-4hyTIkVWTs8LubxHQvXPfYdd74u8MsAO@public.gmane.org>,
	Mehmet Kayaalp
	<mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>,
	Yuqiong Sun
	<sunyuqiong1988-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
	containers
	<containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org>,
	linux-kernel
	<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
	David Safford <david.safford-JJi787mZWgc@public.gmane.org>,
	linux-security-module
	<linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>
Subject: [RFC PATCH 2/5] ima: Add ns_status for storing namespaced iint data
Date: Thu, 20 Jul 2017 18:50:30 -0400	[thread overview]
Message-ID: <20170720225033.21298-3-mkayaalp__13889.0939103023$1500591316$gmane$org@linux.vnet.ibm.com> (raw)
In-Reply-To: <20170720225033.21298-1-mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>

This patch adds an rbtree to the IMA namespace structure that stores a
namespaced version of iint->flags in ns_status struct. Similar to the
integrity_iint_cache, both the iint ns_struct are looked up using the
inode pointer value. The lookup, allocate, and insertion code is also
similar, except ns_struct is not free'd when the inode is free'd.
Instead, the lookup verifies the i_ino and i_generation fields are also a
match. A lazy clean up of the rbtree that removes free'd inodes could be
implemented to reclaim the invalid entries.

Signed-off-by: Mehmet Kayaalp <mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
---
 include/linux/ima.h             |   3 +
 security/integrity/ima/ima.h    |  16 ++++++
 security/integrity/ima/ima_ns.c | 120 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 139 insertions(+)

diff --git a/include/linux/ima.h b/include/linux/ima.h
index 11e4841..3fdf56f 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -111,6 +111,9 @@ struct ima_namespace {
 	struct user_namespace *user_ns;
 	struct ns_common ns;
 	struct ima_namespace *parent;
+	struct rb_root ns_status_tree;
+	rwlock_t ns_status_lock;
+	struct kmem_cache *ns_status_cache;
 };
 
 extern struct ima_namespace init_ima_ns;
diff --git a/security/integrity/ima/ima.h b/security/integrity/ima/ima.h
index 8a8234a..5ab769a 100644
--- a/security/integrity/ima/ima.h
+++ b/security/integrity/ima/ima.h
@@ -128,6 +128,14 @@ static inline void ima_load_kexec_buffer(void) {}
  */
 extern bool ima_canonical_fmt;
 
+struct ns_status {
+	struct rb_node rb_node;
+	struct inode *inode;
+	ino_t i_ino;
+	u32 i_generation;
+	unsigned long flags;
+};
+
 /* Internal IMA function definitions */
 int ima_init(void);
 int ima_fs_init(void);
@@ -293,11 +301,19 @@ static inline int ima_read_xattr(struct dentry *dentry,
 
 #ifdef CONFIG_IMA_NS
 int ima_ns_init(void);
+struct ns_status *ima_get_ns_status(struct ima_namespace *ns,
+				    struct inode *inode);
 #else
 static inline int ima_ns_init(void)
 {
 	return 0;
 }
+
+static inline struct ns_status *ima_get_ns_status(struct ima_namespace *ns,
+						  struct inode *inode)
+{
+	return NULL;
+}
 #endif /* CONFIG_IMA_NS */
 
 /* LSM based policy rules require audit */
diff --git a/security/integrity/ima/ima_ns.c b/security/integrity/ima/ima_ns.c
index 383217b..5ec5a4b 100644
--- a/security/integrity/ima/ima_ns.c
+++ b/security/integrity/ima/ima_ns.c
@@ -20,6 +20,9 @@ static void get_ima_ns(struct ima_namespace *ns);
 
 int ima_init_namespace(struct ima_namespace *ns)
 {
+	ns->ns_status_tree = RB_ROOT;
+	rwlock_init(&ns->ns_status_lock);
+	ns->ns_status_cache = KMEM_CACHE(ns_status, SLAB_PANIC);
 	return 0;
 }
 
@@ -98,10 +101,24 @@ struct ima_namespace *copy_ima(unsigned long flags,
 	return new_ns;
 }
 
+static void free_ns_status_cache(struct ima_namespace *ns)
+{
+	struct ns_status *status, *next;
+
+	write_lock(&ns->ns_status_lock);
+	rbtree_postorder_for_each_entry_safe(status, next,
+					     &ns->ns_status_tree, rb_node)
+		kmem_cache_free(ns->ns_status_cache, status);
+	ns->ns_status_tree = RB_ROOT;
+	write_unlock(&ns->ns_status_lock);
+	kmem_cache_destroy(ns->ns_status_cache);
+}
+
 static void destroy_ima_ns(struct ima_namespace *ns)
 {
 	put_user_ns(ns->user_ns);
 	ns_free_inum(&ns->ns);
+	free_ns_status_cache(ns);
 	kfree(ns);
 }
 
@@ -181,3 +198,106 @@ struct ima_namespace init_ima_ns = {
 	.parent = NULL,
 };
 EXPORT_SYMBOL(init_ima_ns);
+
+/*
+ * __ima_ns_status_find - return the ns_status associated with an inode
+ */
+static struct ns_status *__ima_ns_status_find(struct ima_namespace *ns,
+					      struct inode *inode)
+{
+	struct ns_status *status;
+	struct rb_node *n = ns->ns_status_tree.rb_node;
+
+	while (n) {
+		status = rb_entry(n, struct ns_status, rb_node);
+
+		if (inode < status->inode)
+			n = n->rb_left;
+		else if (inode->i_ino > status->i_ino)
+			n = n->rb_right;
+		else
+			break;
+	}
+	if (!n)
+		return NULL;
+
+	return status;
+}
+
+/*
+ * ima_ns_status_find - return the ns_status associated with an inode
+ */
+static struct ns_status *ima_ns_status_find(struct ima_namespace *ns,
+					    struct inode *inode)
+{
+	struct ns_status *status;
+
+	read_lock(&ns->ns_status_lock);
+	status = __ima_ns_status_find(ns, inode);
+	read_unlock(&ns->ns_status_lock);
+
+	return status;
+}
+
+void insert_ns_status(struct ima_namespace *ns, struct inode *inode,
+		      struct ns_status *status)
+{
+	struct rb_node **p;
+	struct rb_node *node, *parent = NULL;
+	struct ns_status *test_status;
+
+	p = &ns->ns_status_tree.rb_node;
+	while (*p) {
+		parent = *p;
+		test_status = rb_entry(parent, struct ns_status, rb_node);
+		if (inode < test_status->inode)
+			p = &(*p)->rb_left;
+		else
+			p = &(*p)->rb_right;
+	}
+	node = &status->rb_node;
+	rb_link_node(node, parent, p);
+	rb_insert_color(node, &ns->ns_status_tree);
+}
+
+struct ns_status *ima_get_ns_status(struct ima_namespace *ns,
+				    struct inode *inode)
+{
+	struct ns_status *status;
+	int skip_insert = 0;
+
+	status = ima_ns_status_find(ns, inode);
+	if (status) {
+		/*
+		 * Unlike integrity_iint_cache we are not free'ing the
+		 * ns_status data when the inode is free'd. So, in addition to
+		 * checking the inode pointer, we need to make sure the
+		 * (i_generation, i_ino) pair matches as well. In the future
+		 * we might want to add support for lazily walking the rbtree
+		 * to clean it up.
+		 */
+		if (inode->i_ino == status->i_ino &&
+		    inode->i_generation == status->i_generation)
+			return status;
+
+		/* Same inode number is reused, overwrite the ns_status */
+		skip_insert = 1;
+	} else {
+		status = kmem_cache_alloc(ns->ns_status_cache, GFP_NOFS);
+		if (!status)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	write_lock(&ns->ns_status_lock);
+
+	if (!skip_insert)
+		insert_ns_status(ns, inode, status);
+
+	status->inode = inode;
+	status->i_ino = inode->i_ino;
+	status->i_generation = inode->i_generation;
+	status->flags = 0UL;
+	write_unlock(&ns->ns_status_lock);
+
+	return status;
+}
-- 
2.9.4

  parent reply	other threads:[~2017-07-20 22:50 UTC|newest]

Thread overview: 131+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-20 22:50 [RFC PATCH 0/5] ima: namespacing IMA audit messages Mehmet Kayaalp
2017-07-20 22:50 ` Mehmet Kayaalp
2017-07-20 22:50 ` [RFC PATCH 1/5] ima: extend clone() with IMA namespace support Mehmet Kayaalp
2017-07-20 22:50   ` Mehmet Kayaalp
     [not found]   ` <20170720225033.21298-2-mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-25 17:53     ` Serge E. Hallyn
2017-07-25 17:53       ` Serge E. Hallyn
2017-07-25 17:53       ` Serge E. Hallyn
     [not found]       ` <20170725175317.GA727-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2017-07-25 18:49         ` James Bottomley
2017-07-25 18:49       ` James Bottomley
2017-07-25 18:49         ` James Bottomley
     [not found]         ` <1501008554.3689.30.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2017-07-25 19:04           ` Serge E. Hallyn
2017-07-25 19:04             ` Serge E. Hallyn
2017-07-25 19:04             ` Serge E. Hallyn
2017-07-25 19:08             ` James Bottomley
2017-07-25 19:08               ` James Bottomley
2017-07-25 19:48               ` Mimi Zohar
2017-07-25 19:48                 ` Mimi Zohar
     [not found]                 ` <1501012082.27413.17.camel-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-25 20:11                   ` Stefan Berger
2017-07-25 20:11                     ` Stefan Berger
2017-07-25 20:11                     ` Stefan Berger
     [not found]                     ` <645db815-7773-e351-5db7-89f38cd88c3d-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-25 20:46                       ` Serge E. Hallyn
2017-07-25 20:46                         ` Serge E. Hallyn
2017-07-25 20:46                         ` Serge E. Hallyn
     [not found]                         ` <20170725204622.GA4969-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2017-07-25 20:57                           ` Mimi Zohar
2017-07-25 20:57                             ` Mimi Zohar
2017-07-25 20:57                             ` Mimi Zohar
     [not found]                             ` <1501016277.27413.50.camel-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-25 21:08                               ` Serge E. Hallyn
2017-07-25 21:08                             ` Serge E. Hallyn
2017-07-25 21:08                               ` Serge E. Hallyn
     [not found]                               ` <20170725210801.GA5628-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2017-07-25 21:28                                 ` Mimi Zohar
2017-07-25 21:28                                   ` Mimi Zohar
2017-07-25 21:28                                   ` Mimi Zohar
     [not found]                                   ` <1501018134.27413.66.camel-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-27 12:51                                     ` [Linux-ima-devel] " Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 12:51                                       ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 12:51                                       ` Magalhaes, Guilherme (Brazil R&D-CL)
     [not found]                                       ` <TU4PR84MB03021F7FDF1B89ECAA8F7FFFFFBE0-cn0wsXH2uUebani3oaRudNicc1VoeDReZmpNikb/MY7jO8Y7rvWZVA@public.gmane.org>
2017-07-27 14:39                                         ` Mimi Zohar
2017-07-27 14:39                                       ` Mimi Zohar
2017-07-27 14:39                                         ` Mimi Zohar
     [not found]                                         ` <1501166369.28419.171.camel-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-27 17:18                                           ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-28 14:19                                           ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 17:18                                         ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 17:18                                           ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 17:49                                           ` Stefan Berger
2017-07-27 17:49                                             ` Stefan Berger
     [not found]                                             ` <3c3d8594-9958-5f53-ec0b-f33c36967f95-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-27 19:39                                               ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 19:39                                             ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 19:39                                               ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-27 20:51                                               ` Stefan Berger
2017-07-27 20:51                                                 ` Stefan Berger
     [not found]                                               ` <TU4PR84MB030243E7071B5A7455334886FFBE0-cn0wsXH2uUebani3oaRudNicc1VoeDReZmpNikb/MY7jO8Y7rvWZVA@public.gmane.org>
2017-07-27 20:51                                                 ` Stefan Berger
     [not found]                                           ` <TU4PR84MB03025AD26718A173FB3E3F94FFBE0-cn0wsXH2uUebani3oaRudNicc1VoeDReZmpNikb/MY7jO8Y7rvWZVA@public.gmane.org>
2017-07-27 17:49                                             ` Stefan Berger
2017-07-28 14:19                                         ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-28 14:19                                           ` Magalhaes, Guilherme (Brazil R&D-CL)
2017-07-31 11:31                                           ` Mimi Zohar
2017-07-31 11:31                                             ` Mimi Zohar
     [not found]                                           ` <TU4PR84MB03025BC4B8DEC44A0D63A298FFBF0-cn0wsXH2uUebani3oaRudNicc1VoeDReZmpNikb/MY7jO8Y7rvWZVA@public.gmane.org>
2017-07-31 11:31                                             ` Mimi Zohar
2017-07-25 21:35                           ` Stefan Berger
2017-07-25 21:35                             ` Stefan Berger
2017-07-25 21:35                             ` Stefan Berger
2018-03-08 14:04                           ` Stefan Berger
2018-03-08 14:04                         ` Stefan Berger
2018-03-08 14:04                           ` Stefan Berger
     [not found]                           ` <97839865-b0ab-8e5d-114e-0603ef2edf6f-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2018-03-09  2:59                             ` Serge E. Hallyn
2018-03-09  2:59                           ` Serge E. Hallyn
2018-03-09  2:59                             ` Serge E. Hallyn
     [not found]                             ` <20180309025942.GA15295-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2018-03-09 13:52                               ` Stefan Berger
2018-03-09 13:52                                 ` Stefan Berger
2018-03-09 13:52                                 ` Stefan Berger
     [not found]                                 ` <ec137677-34f8-df91-0d1c-6c6d6c951496-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2018-03-11 22:58                                   ` James Morris
2018-03-11 22:58                                 ` James Morris
2018-03-11 22:58                                   ` James Morris
     [not found]                                   ` <alpine.LRH.2.21.1803120953310.26512-gx6/JNMH7DfYtjvyW6yDsg@public.gmane.org>
2018-03-13 18:02                                     ` Stefan Berger
2018-03-13 18:02                                       ` Stefan Berger
2018-03-13 18:02                                       ` Stefan Berger
     [not found]                                       ` <c39350db-046f-ea70-15e4-210884548b1e-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2018-03-13 21:51                                         ` James Morris
2018-03-13 21:51                                           ` James Morris
2018-03-13 21:51                                           ` James Morris
2017-07-25 20:31                   ` James Bottomley
2017-07-25 20:31                 ` James Bottomley
2017-07-25 20:31                   ` James Bottomley
     [not found]                   ` <1501014695.3689.41.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2017-07-25 20:47                     ` Mimi Zohar
2017-07-25 20:47                       ` Mimi Zohar
2017-07-25 20:47                       ` Mimi Zohar
     [not found]               ` <1501009739.3689.33.camel-d9PhHud1JfjCXq6kfMZ53/egYHeGw8Jk@public.gmane.org>
2017-07-25 19:48                 ` Mimi Zohar
     [not found]             ` <20170725190406.GA1883-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2017-07-25 19:08               ` James Bottomley
2018-03-08 13:39     ` Stefan Berger
2018-03-08 13:39   ` Stefan Berger
2018-03-08 13:39     ` Stefan Berger
     [not found]     ` <2fac8414-6957-1fce-6b40-ad4b687ca83c-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2018-03-08 20:19       ` Serge E. Hallyn
2018-03-08 20:19     ` Serge E. Hallyn
2018-03-08 20:19       ` Serge E. Hallyn
     [not found]       ` <20180308201931.GA6462-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2018-03-08 22:53         ` Stefan Berger
2018-03-08 23:31           ` Serge E. Hallyn
2018-03-08 23:31             ` Serge E. Hallyn
     [not found]           ` <a6ef5679-6aef-21de-7cdb-48e8af83f874-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2018-03-08 23:31             ` Serge E. Hallyn
     [not found] ` <20170720225033.21298-1-mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-20 22:50   ` Mehmet Kayaalp
2017-07-20 22:50   ` Mehmet Kayaalp [this message]
2017-07-20 22:50   ` [RFC PATCH 3/5] ima: mamespace audit status flags Mehmet Kayaalp
2017-07-20 22:50   ` [RFC PATCH 4/5] ima: differentiate auditing policy rules from "audit" actions Mehmet Kayaalp
2017-07-20 22:50     ` Mehmet Kayaalp
2017-07-20 22:50     ` Mehmet Kayaalp
2017-07-20 22:50   ` [RFC PATCH 5/5] ima: Add ns_mnt, dev, ino fields to IMA audit measurement msgs Mehmet Kayaalp
2017-07-20 22:50 ` [RFC PATCH 2/5] ima: Add ns_status for storing namespaced iint data Mehmet Kayaalp
2017-07-20 22:50   ` Mehmet Kayaalp
     [not found]   ` <20170720225033.21298-3-mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-25 19:43     ` Serge E. Hallyn
2017-07-25 19:43       ` Serge E. Hallyn
2017-07-25 19:43       ` Serge E. Hallyn
     [not found]       ` <20170725194315.GA2397-7LNsyQBKDXoIagZqoN9o3w@public.gmane.org>
2017-07-25 20:15         ` Mimi Zohar
2017-07-25 20:15           ` Mimi Zohar
2017-07-25 20:15           ` Mimi Zohar
     [not found]           ` <1501013725.27413.27.camel-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-07-25 20:25             ` Stefan Berger
2017-07-25 20:25               ` Stefan Berger
2017-07-25 20:25               ` Stefan Berger
2017-07-25 20:49             ` Serge E. Hallyn
2017-07-25 20:49               ` Serge E. Hallyn
2017-07-25 20:49               ` Serge E. Hallyn
2017-08-11 15:00     ` Stefan Berger
2017-08-11 15:00   ` Stefan Berger
2017-08-11 15:00     ` Stefan Berger
2017-07-20 22:50 ` [RFC PATCH 3/5] ima: mamespace audit status flags Mehmet Kayaalp
2017-07-20 22:50   ` Mehmet Kayaalp
     [not found]   ` <20170720225033.21298-4-mkayaalp-23VcF4HTsmIX0ybBhKVfKdBPR1lH4CV8@public.gmane.org>
2017-08-01 17:17     ` Tycho Andersen via Containers
2017-08-01 17:17   ` Tycho Andersen
2017-08-01 17:17     ` Tycho Andersen
2017-08-01 17:25     ` Mehmet Kayaalp
2017-08-01 17:25       ` Mehmet Kayaalp
2017-08-02 21:48       ` Tycho Andersen
2017-08-02 21:48         ` Tycho Andersen
2017-08-01 17:25     ` Mehmet Kayaalp
2017-07-20 22:50 ` [RFC PATCH 5/5] ima: Add ns_mnt, dev, ino fields to IMA audit measurement msgs Mehmet Kayaalp
2017-07-20 22:50   ` Mehmet Kayaalp

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='20170720225033.21298-3-mkayaalp__13889.0939103023$1500591316$gmane$org@linux.vnet.ibm.com' \
    --to=mkayaalp-23vcf4htsmix0ybbhkvfkdbpr1lh4cv8@public.gmane.org \
    --cc=containers-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org \
    --cc=david.safford-JJi787mZWgc@public.gmane.org \
    --cc=linux-ima-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
    --cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=linux-security-module-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=mkayaalp-4hyTIkVWTs8LubxHQvXPfYdd74u8MsAO@public.gmane.org \
    --cc=sunyuqiong1988-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.