Re: [PATCH] Use an IDR to allocate apparmor secids

From: John Johansen
Date: Tue Jun 05 2018 - 11:47:56 EST


On 06/05/2018 04:47 AM, Matthew Wilcox wrote:
> On Mon, Jun 04, 2018 at 07:35:24PM -0700, John Johansen wrote:
>> On 06/04/2018 07:27 PM, Matthew Wilcox wrote:
>>> On Mon, Jun 04, 2018 at 06:27:09PM -0700, John Johansen wrote:
>>>> hey Mathew,
>>>>
>>>> I've pulled this into apparmor-next and done the retuning of
>>>> AA_SECID_INVALID a follow on patch. The reworking of the api to
>>>> return the specific error type can wait for another cycle.
>>>
>>> Oh ... here's what I currently have. I decided that AA_SECID_INVALID
>>> wasn't needed.
>>>
>> well not needed in the allocation path, but definitely needed and it
>> needs to be 0.
>>
>> This is for catching some uninitialized or freed and zeroed values.
>> The debug checks aren't in the current version, as they were
>> residing in another debug patch, but I will pull them out into their
>> own patch.
>
> With the IDR, I don't know if you need it for debug.
>
> BUG_ON(label != idr_find(&aa_secids, label->secid))
>
> should do the trick.
>

its not so much the idr as the network and audit structs where the
secid gets used and then security system is asked to convert from
the secid to the secctx.

We need an invalid secid for when conversion result in an error,
partly because the returned error is ignored in some paths (eg. scm)
so we also make sure to have an invalid value.

Having it be zero helps us catch bugs on structs that are zero
but we miss initializing, and also works well with apparmor always
zeroing structs on free.

The debug patch didn't get included yet because the networking
code that make use of the secids hasn't landed yet (they are being
used in the audit path) so the debug patch ends up throwing a
lot of warning for the networking paths.

The patch I am testing on top of your patch is below

---

commit d5de3b1d21687c16df0a75b6309ab8481629a841
Author: John Johansen <john.johansen@xxxxxxxxxxxxx>
Date: Mon Jun 4 19:44:59 2018 -0700

apparmor: cleanup secid map convertion to using idr

The idr convertion didn't handle an error case for when allocating a
mapping fails.

In addition it did not ensure that mappings did not allocate or use a
0 value, which is used as an invalid secid because it allows debug
code to detect when objects have not been correctly initialized or
freed too early.

Signed-off-by: John Johansen <john.johansen@xxxxxxxxxxxxx>

diff --git a/security/apparmor/include/secid.h b/security/apparmor/include/secid.h
index 686de8e50a79..dee6fa3b6081 100644
--- a/security/apparmor/include/secid.h
+++ b/security/apparmor/include/secid.h
@@ -28,8 +28,10 @@ int apparmor_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void apparmor_release_secctx(char *secdata, u32 seclen);


-u32 aa_alloc_secid(struct aa_label *label, gfp_t gfp);
+int aa_alloc_secid(struct aa_label *label, gfp_t gfp);
void aa_free_secid(u32 secid);
void aa_secid_update(u32 secid, struct aa_label *label);

+void aa_secids_init(void);
+
#endif /* __AA_SECID_H */
diff --git a/security/apparmor/label.c b/security/apparmor/label.c
index a17574df611b..ba11bdf9043a 100644
--- a/security/apparmor/label.c
+++ b/security/apparmor/label.c
@@ -407,8 +407,7 @@ bool aa_label_init(struct aa_label *label, int size, gfp_t gfp)
AA_BUG(!label);
AA_BUG(size < 1);

- label->secid = aa_alloc_secid(label, gfp);
- if (label->secid == AA_SECID_INVALID)
+ if (aa_alloc_secid(label, gfp) < 0)
return false;

label->size = size; /* doesn't include null */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index dab5409f2608..9ae7f9339513 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -1546,6 +1546,8 @@ static int __init apparmor_init(void)
return 0;
}

+ aa_secids_init();
+
error = aa_setup_dfa_engine();
if (error) {
AA_ERROR("Unable to setup dfa engine\n");
diff --git a/security/apparmor/secid.c b/security/apparmor/secid.c
index 3ad94b2ffbb2..ad6221e1f25f 100644
--- a/security/apparmor/secid.c
+++ b/security/apparmor/secid.c
@@ -33,6 +33,8 @@
* properly updating/freeing them
*/

+#define AA_FIRST_SECID 1
+
static DEFINE_IDR(aa_secids);
static DEFINE_SPINLOCK(secid_lock);

@@ -120,20 +122,30 @@ void apparmor_release_secctx(char *secdata, u32 seclen)

/**
* aa_alloc_secid - allocate a new secid for a profile
+ * @label: the label to allocate a secid for
+ * @gfp: memory allocation flags
+ *
+ * Returns: 0 with @label->secid initialized
+ * <0 returns error with @label->secid set to AA_SECID_INVALID
*/
-u32 aa_alloc_secid(struct aa_label *label, gfp_t gfp)
+int aa_alloc_secid(struct aa_label *label, gfp_t gfp)
{
unsigned long flags;
- u32 secid;
+ int ret;

idr_preload(gfp);
spin_lock_irqsave(&secid_lock, flags);
- secid = idr_alloc(&aa_secids, label, 0, 0, GFP_ATOMIC);
- /* XXX: Can return -ENOMEM */
+ ret = idr_alloc(&aa_secids, label, 1, 0, GFP_ATOMIC);
spin_unlock_irqrestore(&secid_lock, flags);
idr_preload_end();

- return secid;
+ if (ret < 0) {
+ label->secid = AA_SECID_INVALID;
+ return ret;
+ }
+
+ label->secid = ret;
+ return 0;
}

/**
@@ -148,3 +160,8 @@ void aa_free_secid(u32 secid)
idr_remove(&aa_secids, secid);
spin_unlock_irqrestore(&secid_lock, flags);
}
+
+void aa_secids_init(void)
+{
+ idr_init_base(&aa_secids, AA_FIRST_SECID);
+}