Skip to contentSkip to conversation

speaking of stacks

DISCUSSION jamal 3 participants 6 messages Mar 31, 2008 – Apr 4, 2008

Subsystems (2)
lore
Share & tools
lore

jamal

author
#0 lore raw

All this talk about stacks got me thirsty.
Heres something thats a mystery to me; probably very basic when doing static check analysis (kernel make checkstack)

I have ipsec turned on in the linus git tree kernel and net/xfrm/xfrm_user.c::xfrm_get_policy() shows up as one of the top offenders. Eyeballing reveals that
struct xfrm_policy seems to be the offender
in the else {} after if (p->index) in that function.
That seems understandable - once variable "tmp" is declared it goes on the stack and it is freakin huge.
However, checkstack only seems to catch it if i have the line "memset(&tmp, 0, sizeof(struct xfrm_policy))". If i remove that line - even though tmp is on the stack - checkstack doesnt catch it.

What gives?

----

hadi@lilsol:~$ gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --enable-languages=c,c
++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext
--enable-threads=posix --enable-nls --program-suffix=-4.1
--enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug
--enable-mpfr --with-tune=i686 --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)
-----

Not a gcc guru by far.
Anyone interested, I can send you the .o before and after commenting for your perusal.

cheers,
jamal

maintainer
#1 lore raw

From: jamal <[email protected]>
Date: Mon, 31 Mar 2008 09:15:56 -0400

Quoted 17 lines

All this talk about stacks got me thirsty.
Heres something thats a mystery to me; probably very basic when doing static check analysis (kernel make checkstack)

I have ipsec turned on in the linus git tree kernel and net/xfrm/xfrm_user.c::xfrm_get_policy() shows up as one of the top offenders. Eyeballing reveals that
struct xfrm_policy seems to be the offender
in the else {} after if (p->index) in that function.
That seems understandable - once variable "tmp" is declared it goes on the stack and it is freakin huge.
However, checkstack only seems to catch it if i have the line "memset(&tmp, 0, sizeof(struct xfrm_policy))". If i remove that line - even though tmp is on the stack - checkstack doesnt catch it.

Quoted 1 line

What gives?

You probably have most of the security infrastructure turned off, therefore GCC can see that 'tmp' is basically unused and can therefore be totally eliminated.

The memset() call makes 'tmp' get passed by reference to another function, and thus become used.

This whole song and dance here is for SELINUX to set only the policy->security, so that we can pass that back down into the subsequent xfrm_policy_bysel_ctx().

The thing to do is to rearrange these security layer hooks so that they take a "struct xfrm_sec_ctx **" instead of a full policy pointer.

Then the code would look like:

		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
		struct xfrm_sec_ctx *ctx;

		err = verify_sec_ctx_len(attrs);
		if (err)
			return err;

		if (rt) {
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);

			if ((err = security_xfrm_policy_alloc(&ctx, uctx)))
				return err;
		}
		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx,
					   delete, &err);
		security_xfrm_policy_free(ctx);

And thus the xfrm_policy wouldn't need to be on the stack any longer.

author
#2 lore raw
Quoted 6 lines · David Miller

You probably have most of the security infrastructure turned off, therefore GCC can see that 'tmp' is basically unused and can therefore be totally eliminated.

The memset() call makes 'tmp' get passed by reference to another function, and thus become used.

Indeed, thanks - that resolves the mystery;->

Testing by moving the tmp memseting inside security_xfrm_policy_alloc() so memset is only invoked when CONFIG_SECURITY_NETWORK_XFRM resolves the stack abuse.
BTW, of the top 10 stack abusers _in the kernel_ (should say based on my config) constitute 3-4 spots which are caused by this exact thing. I could send a patch that resolves the issue by moving memset but that would only fix it for people like myself who turn off SELinux.

Quoted 27 lines

This whole song and dance here is for SELINUX to set only the policy->security, so that we can pass that back down into the subsequent xfrm_policy_bysel_ctx().

The thing to do is to rearrange these security layer hooks so that they take a "struct xfrm_sec_ctx **" instead of a full policy pointer.

Then the code would look like:

		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
		struct xfrm_sec_ctx *ctx;

		err = verify_sec_ctx_len(attrs);
		if (err)
			return err;

		if (rt) {
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);

			if ((err = security_xfrm_policy_alloc(&ctx, uctx)))
				return err;
		}
		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx,
					   delete, &err);
		security_xfrm_policy_free(ctx);
Quoted 2 lines

And thus the xfrm_policy wouldn't need to be on the stack any longer.

Yes, that would be cleaner than what i did; i will give the opportunity to the SELinux folks to take a first crack at it with the above approach.

CCing some of the SElinux folks.
Thanks Dave.

cheers,
jamal

#3 lore raw
Quoted 31 lines · jamal
Quoted 27 lines · David Miller

This whole song and dance here is for SELINUX to set only the policy->security, so that we can pass that back down into the subsequent xfrm_policy_bysel_ctx().

The thing to do is to rearrange these security layer hooks so that they take a "struct xfrm_sec_ctx **" instead of a full policy pointer.

Then the code would look like:

		struct nlattr *rt = attrs[XFRMA_SEC_CTX];
		struct xfrm_sec_ctx *ctx;

		err = verify_sec_ctx_len(attrs);
		if (err)
			return err;

		if (rt) {
			struct xfrm_user_sec_ctx *uctx = nla_data(rt);

			if ((err = security_xfrm_policy_alloc(&ctx, uctx)))
				return err;
		}
		xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx,
					   delete, &err);
		security_xfrm_policy_free(ctx);
Quoted 2 lines

And thus the xfrm_policy wouldn't need to be on the stack any longer.

Quoted 6 lines

Yes, that would be cleaner than what i did; i will give the opportunity to the SELinux folks to take a first crack at it with the above approach.

CCing some of the SElinux folks.
Thanks Dave.

Sorry, I've been stuck under a rock for about the past month. Unless somebody is really anxious to do this I'll see if I can whip up an RFC patch and get it out either today or early next week.

Signature · 2 lines
paul moore
linux @ hp
author
#4 lore raw
Quoted 3 lines · Paul Moore

Sorry, I've been stuck under a rock for about the past month. Unless somebody is really anxious to do this I'll see if I can whip up an RFC patch and get it out either today or early next week.

No rush - it is an enhancement not a bug fix. If you need my help let me know.

cheers,
jamal

#5 lore raw
Quoted 7 lines · jamal
Quoted 3 lines · Paul Moore

Sorry, I've been stuck under a rock for about the past month. Unless somebody is really anxious to do this I'll see if I can whip up an RFC patch and get it out either today or early next week.

No rush - it is an enhancement not a bug fix. If you need my help let me know.

It would still be nice to get into 2.6.26 and I figure we only have a few weeks before the merge window opens. I've got a patch cobbled together that does what Dave suggested plus all the other "left as an exercise for the reader" pieces that compiles I just haven't had a chance to test it yet, my test machines are busy testing some other bits right now. You should see from mail from me early next week, review and additional testing is always welcome :)

Signature · 2 lines
paul moore
linux @ hp