Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread David Taylor

On Tue, 16 Jul 2002, David Taylor wrote:

Bah, ignore me, it appears you've already admitted your post was rather
less than clear :)

-- 
David Taylor
[EMAIL PROTECTED]
"The future just ain't what it used to be"

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread David Taylor

On Mon, 15 Jul 2002, Terry Lambert wrote:
> Thomas Moestl wrote:
> > > He's making the valid point that for:
> > >
> > >   struct foo *fee;
> > >
> > > It's possible that:
> > >
> > >   sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))
> > 
> > No, I do not. In fact, the opposite:
> > 
> > sizeof(struct foo) = (((char *)&fee[1]) - ((char *)&fee[0]))
> > 
> > _must_ always be true

> Reread my second to last paragraph.  I'm saying the same thing
> that you are.  


How can you possibly be saying the same thing, when you are saying the
exact opposite (You: A != B may be true, Thomas: A == B must be true)?

You're saying:

sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))

which would imply that end-padding is not included in sizeof(struct foo),
when it must be, otherwise malloc(n * sizeof(struct foo)) would not
allocate enough memory for an array of n elements of struct foo.

-- 
David Taylor
[EMAIL PROTECTED]
"The future just ain't what it used to be"

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Terry Lambert

Richard Tobin wrote:
> It is not a valid point that it's possible that
> 
>   sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> because it isn't possible.  It must be the case that
> 
>   sizeof(struct foo) == (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> If that's what you meant, you seem to be saying the opposite.

I guess I should have been clearer; reading it again, it's clearly
a double entendre on my part.  Sorry for the confusion it caused.

> > and that inter-structure padding depends on ordering of elements
> 
> Yes, though it isn't "inter-structure" padding, it's padding that
> is part of the structure.

Yes, because the compiler can't know that a pointer will not have
arithmatic done on it, because it can't know whether the element
it points to is the first in a series, or only a single element.
This is the source of the confusion in the size test that was
broken in the case that started this thread.


> > (for a good example of this, see the struct direct name element
> > reference macro, which is also padding independent).
> 
> Not sure which macro you mean here, since there are several variants
> of it which work in different ways.  The one in dirent.h (I'm looking
> at 4.6 here) subtracts from sizeof, while the one in ufs/dir.h uses
> &(0->d_name) which is equivalent to offsetof.

This is the one (n.b: there didn't used to be an "offsetof").


> > Basically, end-padding happens because arrays of structures need to
> > have their first element properly aligned, so there is a pad added
> > after each element to ensure that the following element starts on
> > an alignment boundary.
> 
> The point is that there isn't a pad *after* each element.  The pad is
> part of the element, and is there regardless of whether the structure
> is in an array.  Again, if that's what you meant you seem to be saying
> the opposite!

I think I just used ambiguous language in the initial part, and that
threw off everything after it.  Like the SNL joke "You can't put too
much water in a nuclear reactor".

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Richard Tobin

> If everyone could read the text past my example of bad math, so
> that they could know it was an intentional example of bad math,
> live would be beautiful.  8-).

I did read past it, and I just read it again, and I can't make it come
out any way other than it did the first time.

You said:

> He's making the valid point that for:
> 
> struct foo *fee;
> 
> It's possible that:
> 
> sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> because of end-padding, which is not accounted for in arrays,

It is not a valid point that it's possible that

  sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))

because it isn't possible.  It must be the case that

  sizeof(struct foo) == (((char *)&fee[1]) - ((char *)&fee[0]))

If that's what you meant, you seem to be saying the opposite.

> and that inter-structure padding depends on ordering of elements

Yes, though it isn't "inter-structure" padding, it's padding that
is part of the structure.

> (for a good example of this, see the struct direct name element
> reference macro, which is also padding independent).

Not sure which macro you mean here, since there are several variants
of it which work in different ways.  The one in dirent.h (I'm looking
at 4.6 here) subtracts from sizeof, while the one in ufs/dir.h uses
&(0->d_name) which is equivalent to offsetof.

> Basically, end-padding happens because arrays of structures need to
> have their first element properly aligned, so there is a pad added
> after each element to ensure that the following element starts on
> an alignment boundary.

The point is that there isn't a pad *after* each element.  The pad is
part of the element, and is there regardless of whether the structure
is in an array.  Again, if that's what you meant you seem to be saying
the opposite!

-- Richard

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Terry Lambert

Richard Tobin wrote:
> Er, no, that's not right.  Otherwise

[ ... ]

If everyone could read the text past my example of bad math, so
that they could know it was an intentional example of bad math,
live would be beautiful.  8-).

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Terry Lambert

Peter Edwards wrote:
> > He's making the valid point that for:
> >
> > struct foo *fee;
> >
> > It's possible that:
> >
> > sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> Wouldn't that mean
> 
> .. struct X *xarr = malloc(sizeof (struct X) * arrayLen);
> 
> wouldn't produce a useable array of struct X of length arrayLen?
> That can't be right.

No, it doesn't mean that, because there *is* end padding in the
size calculation.  That's kind of the whole point of this thread.

In the directory entry example, the last element is a d_name[1]
that's an overlay array that's much longer than it appears (it
is always at least 4 bytes).  This is because it's meant to work
with other than C99 (which permits an array with a declared size
of 0).  It's necessary for the code to know the offset of the
start of that elemenet from the start of the structure, and that
offset is *NOT* "sizeof(struct) - 1", as you would naievely believe,
as if there were no end padding, because the total size of the
structure is not always going to be evenly divisible by the number
of bytes between alignment boundaries.

Does this make more sense?!?

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Terry Lambert

Thomas Moestl wrote:
> > He's making the valid point that for:
> >
> >   struct foo *fee;
> >
> > It's possible that:
> >
> >   sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> No, I do not. In fact, the opposite:
> 
> sizeof(struct foo) = (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> _must_ always be true, since it is legal to compute the size of
> storage needed for an n-element array of struct foo by using
> (sizeof(struct foo) * n).
> 
> My point was that, because of the above, any padding that might be
> required between the first and last member of two struct foo's
> immediately following each other must be _included_ in struct foo,
> after the last element.

Reread my second to last paragraph.  I'm saying the same thing
that you are.  In my third to last paragrap, I pointed to an
example for directory entries that ensures end-pad independence
(I wrote that code).

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Mike Barcroft

Thomas Moestl <[EMAIL PROTECTED]> writes:
> Oh, right, that's related: the kernel checks for a minimum size of the
> passed data on two occasions, first in sooptcopyin(), and then again
> in check_ipfw_struct().
> It the size to be at least sizeof(struct ip_fw), however for
> structures containing just one action (like the one for the command
> above) this is again too much in the 64-bit case because of the
> padding. Can you please try the attached patch (against the CVS
> version)?

Yes, this version works.

%%%
bowie# ipfw show
00100  0  0 allow ip from me to 192.168.3.1
00200  5484 allow udp from me to 192.168.3.13
00300  0  0 allow tcp from me to 192.168.3.0/24 established
00400  0  0 deny ip from me to 192.168.3.0/24
00500  9734 allow ip from any to any
65535  0  0 deny ip from any to any
%%%

Best regards,
Mike Barcroft

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Luigi Rizzo

ok, convincing explaination, thanks!

I will review the code and try to implement a proper fix,
not the workaround that I put in.

cheers
luigi


To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Richard Tobin

>   struct foo *fee;
> 
> It's possible that:
> 
>   sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))
> 
> because of end-padding, which is not accounted for in arrays,

Er, no, that's not right.  Otherwise 

  fee = malloc(n * sizeof(struct foo))

wouldn't work.

C89 says:

  There may also be unnamed padding at the end of a structure or union,
  as necessary to achieve the proper alignment were the structure or
  union to be an element of an array.

And:

  the result [of sizeof] is the total number of bytes in such an object,
  including internal and trailing padding.

So if a struct needs padding in an array, it has it even when it isn't
in an array.

-- Richard

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Peter Edwards

Hi,

> He's making the valid point that for:
>
> struct foo *fee;
>
> It's possible that:
>
> sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))

Wouldn't that mean

.. struct X *xarr = malloc(sizeof (struct X) * arrayLen);

wouldn't produce a useable array of struct X of length arrayLen?
That can't be right.

-- 
Peter Edwards.

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Thomas Moestl

On Mon, 2002/07/15 at 04:24:33 -0700, Terry Lambert wrote:
> Luigi Rizzo wrote:
> > sorry but all this just does not make sense to me.
> > 
> > sizeof(foo) should give the same result irrespective of
> > where you use it.
> > 
> > Perhaps the best thing would be to put a
> > 
> > printf("struct ip_fw has size %d\n", sizeof(struct ip_fw));
> > 
> > both in ipfw2.c and somewhere in ip_fw2.c and see if there is
> > a mismatch between the two numbers.
> 
> I have to assume that what didn't make sense was that his patch
> worked?  8-).
> 
> He's making the valid point that for:
> 
>   struct foo *fee;
> 
> It's possible that:
> 
>   sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))

No, I do not. In fact, the opposite:

sizeof(struct foo) = (((char *)&fee[1]) - ((char *)&fee[0]))

_must_ always be true, since it is legal to compute the size of
storage needed for an n-element array of struct foo by using
(sizeof(struct foo) * n).

My point was that, because of the above, any padding that might be
required between the first and last member of two struct foo's
immediately following each other must be _included_ in struct foo,
after the last element.

- thomas

-- 
Thomas Moestl <[EMAIL PROTECTED]> http://www.tu-bs.de/~y0015675/
  <[EMAIL PROTECTED]> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Thomas Moestl

On Mon, 2002/07/15 at 04:00:08 -0700, Luigi Rizzo wrote:
> sorry but all this just does not make sense to me.
> 
> sizeof(foo) should give the same result irrespective of
> where you use it.

OK, let me rephrase it: as I explained before, struct ip_fw has padding
after 'cmd' (the last member) to ensure that arrays can be built from
it safely, so that the first member will always be properly
aligned.
Since the first members must/should be aligned on an 8-bit boundary on
64-bit platforms, this means that sizeof(struct ip_fw) must be a
multiple of 8, the size of the padding is 4 bytes (unless the
situation is changed by reordering structure members). This can easily
be checked on a 64-bit platform. The following program fragment:

struct ip_fw f;

printf("sizeof(ip_fw) = %d\n", (int)sizeof(f));
printf("offsetof(ip_fw, cmd) = %d\n", (int)offsetof(struct ip_fw, cmd));
printf("sizeof(ip_fw.cmd) = %d\n", (int)sizeof(f.cmd));

Produces this output on sparc64:

sizeof(ip_fw) = 56
offsetof(ip_fw, cmd) = 48
sizeof(ip_fw.cmd) = 4

This illustrates that indeed, padding is appended after 'cmd'.

In the (userland) ipfw2.c, you basically do the following:

ipfw_insn *dst; /* sizeof(ipfw_insn) = 4 */

dst = (ipfw_insn *)rule->cmd;
/* Write n instructions and increase dst accordingly. */
rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
i = (void *)dst - (void *)rule;

if (getsockopt(s, IPPROTO_IP, IP_FW_ADD, rule, &i) == -1)
err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");

Let's consider the case where only one instruction was added. In this
case, dst was incremented once and points directly after cmd, so i is
52 on a 64-bit platform.
However, sizeof(struct ip_fw) is 56 because the aformentioned 4 bytes
of padding following 'cmd', so i < sizeof(struct ip_fw). This explains
why rules with just one instruction would not work properly in this
case with just my first patch. 
Likewise, when adding more rules, the second one will be added to the
memory location directly following 'cmd'. If padding is present, the
second instruction will write into it. The size of the total structure
will thus not be properly computed by the old RULESIZE macro:

#define RULESIZE(rule)  (sizeof(struct ip_fw) + \
((struct ip_fw *)(rule))->cmd_len * 4 - 4)

The '- 4' is meant to subtract the size of the cmd, which is accounted
for in cmd_len. Still, you are counting the padding twice, once in the
sizeof() and once in cmd_len.

So, sizeof(struct ip_fw) is no different between userland and kernel,
but the problem is that you don't use sizeof(struct ip_fw) in userland
to compute the sizes (but pointer arithmetic), but you do use it for
the checks in the kernel.

- thomas

-- 
Thomas Moestl <[EMAIL PROTECTED]> http://www.tu-bs.de/~y0015675/
  <[EMAIL PROTECTED]> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Terry Lambert

Luigi Rizzo wrote:
> sorry but all this just does not make sense to me.
> 
> sizeof(foo) should give the same result irrespective of
> where you use it.
> 
> Perhaps the best thing would be to put a
> 
> printf("struct ip_fw has size %d\n", sizeof(struct ip_fw));
> 
> both in ipfw2.c and somewhere in ip_fw2.c and see if there is
> a mismatch between the two numbers.

I have to assume that what didn't make sense was that his patch
worked?  8-).

He's making the valid point that for:

struct foo *fee;

It's possible that:

sizeof(struct foo) != (((char *)&fee[1]) - ((char *)&fee[0]))

because of end-padding, which is not accounted for in arrays,
and that inter-structure padding depends on ordering of elements
(for a good example of this, see the struct direct name element
reference macro, which is also padding independent).

Basically, end-padding happens because arrays of structures need to
have their first element properly aligned, so there is a pad added
after each element to ensure that the following element starts on
an alignment boundary.

I still say that on 486 and higher, the "disallow unaligned access"
bit in the processor control register should be enabled, so your
kernel will panic if you try this.  8-).

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Luigi Rizzo

sorry but all this just does not make sense to me.

sizeof(foo) should give the same result irrespective of
where you use it.

Perhaps the best thing would be to put a

printf("struct ip_fw has size %d\n", sizeof(struct ip_fw));

both in ipfw2.c and somewhere in ip_fw2.c and see if there is
a mismatch between the two numbers.

cheers
luigi

On Mon, Jul 15, 2002 at 12:51:58PM +0200, Thomas Moestl wrote:
> On Sun, 2002/07/14 at 23:08:21 -0400, Mike Barcroft wrote:
> > Thomas Moestl <[EMAIL PROTECTED]> writes:
> > > (Disclaimer: my solution below is untested, so it may all be bogus)
> > 
> > As request, here are the test results.
> > 
> > Most rules work, except my final one:
> > %%%
> > bowie# ipfw add allow all from any to any
> > ipfw: getsockopt(IP_FW_ADD): Invalid argument
> > %%%
> 
> Oh, right, that's related: the kernel checks for a minimum size of the
> passed data on two occasions, first in sooptcopyin(), and then again
> in check_ipfw_struct().
> It the size to be at least sizeof(struct ip_fw), however for
> structures containing just one action (like the one for the command
> above) this is again too much in the 64-bit case because of the
> padding. Can you please try the attached patch (against the CVS
> version)?
> 
>   - thomas
> 
> -- 
> Thomas Moestl <[EMAIL PROTECTED]>   http://www.tu-bs.de/~y0015675/
>   <[EMAIL PROTECTED]>   http://people.FreeBSD.org/~tmm/
> PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C
> 
> Index: ip_fw.h
> ===
> RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
> retrieving revision 1.71
> diff -u -r1.71 ip_fw.h
> --- ip_fw.h   8 Jul 2002 22:39:19 -   1.71
> +++ ip_fw.h   15 Jul 2002 10:48:19 -
> @@ -294,8 +294,9 @@
>  #define ACTION_PTR(rule) \
>   (ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) )
>  
> -#define RULESIZE(rule)  (sizeof(struct ip_fw) + \
> - ((struct ip_fw *)(rule))->cmd_len * 4 - 4)
> +#define  RULESIZE_FROMLEN(len)   (offsetof(struct ip_fw, cmd) + (len) * 4)
> +#define  RULESIZE(rule)  RULESIZE_FROMLEN(((struct ip_fw *)(rule))->cmd_len)
> +#define  RULESIZE_MINRULESIZE_FROMLEN(1)
>  
>  /*
>   * This structure is used as a flow mask and a flow id for various
> Index: ip_fw2.c
> ===
> RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
> retrieving revision 1.4
> diff -u -r1.4 ip_fw2.c
> --- ip_fw2.c  8 Jul 2002 22:46:01 -   1.4
> +++ ip_fw2.c  15 Jul 2002 10:38:09 -
> @@ -2142,7 +2142,7 @@
>   int have_action=0;
>   ipfw_insn *cmd;
>  
> - if (size < sizeof(*rule)) {
> + if (size < RULESIZE_MIN) {
>   printf("ipfw: rule too short\n");
>   return (EINVAL);
>   }
> @@ -2428,7 +2428,7 @@
>   case IP_FW_ADD:
>   rule = (struct ip_fw *)rule_buf; /* XXX do a malloc */
>   error = sooptcopyin(sopt, rule, sizeof(rule_buf),
> - sizeof(struct ip_fw) );
> + RULESIZE_MIN);
>   size = sopt->sopt_valsize;
>   if (error || (error = check_ipfw_struct(rule, size)))
>   break;

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-15 Thread Thomas Moestl

On Sun, 2002/07/14 at 23:08:21 -0400, Mike Barcroft wrote:
> Thomas Moestl <[EMAIL PROTECTED]> writes:
> > (Disclaimer: my solution below is untested, so it may all be bogus)
> 
> As request, here are the test results.
> 
> Most rules work, except my final one:
> %%%
> bowie# ipfw add allow all from any to any
> ipfw: getsockopt(IP_FW_ADD): Invalid argument
> %%%

Oh, right, that's related: the kernel checks for a minimum size of the
passed data on two occasions, first in sooptcopyin(), and then again
in check_ipfw_struct().
It the size to be at least sizeof(struct ip_fw), however for
structures containing just one action (like the one for the command
above) this is again too much in the 64-bit case because of the
padding. Can you please try the attached patch (against the CVS
version)?

- thomas

-- 
Thomas Moestl <[EMAIL PROTECTED]> http://www.tu-bs.de/~y0015675/
  <[EMAIL PROTECTED]> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

Index: ip_fw.h
===
RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
retrieving revision 1.71
diff -u -r1.71 ip_fw.h
--- ip_fw.h 8 Jul 2002 22:39:19 -   1.71
+++ ip_fw.h 15 Jul 2002 10:48:19 -
@@ -294,8 +294,9 @@
 #define ACTION_PTR(rule)   \
(ipfw_insn *)( (u_int32_t *)((rule)->cmd) + ((rule)->act_ofs) )
 
-#define RULESIZE(rule)  (sizeof(struct ip_fw) + \
-   ((struct ip_fw *)(rule))->cmd_len * 4 - 4)
+#defineRULESIZE_FROMLEN(len)   (offsetof(struct ip_fw, cmd) + (len) * 4)
+#defineRULESIZE(rule)  RULESIZE_FROMLEN(((struct ip_fw *)(rule))->cmd_len)
+#defineRULESIZE_MINRULESIZE_FROMLEN(1)
 
 /*
  * This structure is used as a flow mask and a flow id for various
Index: ip_fw2.c
===
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.4
diff -u -r1.4 ip_fw2.c
--- ip_fw2.c8 Jul 2002 22:46:01 -   1.4
+++ ip_fw2.c15 Jul 2002 10:38:09 -
@@ -2142,7 +2142,7 @@
int have_action=0;
ipfw_insn *cmd;
 
-   if (size < sizeof(*rule)) {
+   if (size < RULESIZE_MIN) {
printf("ipfw: rule too short\n");
return (EINVAL);
}
@@ -2428,7 +2428,7 @@
case IP_FW_ADD:
rule = (struct ip_fw *)rule_buf; /* XXX do a malloc */
error = sooptcopyin(sopt, rule, sizeof(rule_buf),
-   sizeof(struct ip_fw) );
+   RULESIZE_MIN);
size = sopt->sopt_valsize;
if (error || (error = check_ipfw_struct(rule, size)))
break;

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-14 Thread Mike Barcroft

Thomas Moestl <[EMAIL PROTECTED]> writes:
> (Disclaimer: my solution below is untested, so it may all be bogus)

As request, here are the test results.

Most rules work, except my final one:
%%%
bowie# ipfw add allow all from any to any
ipfw: getsockopt(IP_FW_ADD): Invalid argument
%%%

Here's a list of rules that applied okay:
%%%
ipfw bowie# ipfw show
00100  0  0 allow ip from me to 192.168.3.1
00200  2168 allow udp from me to 192.168.3.13
00300  0  0 allow tcp from me to 192.168.3.0/24 established
00400  0  0 deny ip from me to 192.168.3.0/24
65535  3219 deny ip from any to any
%%%

Best regards,
Mike Barcroft

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-14 Thread Thomas Moestl

On Sun, 2002/07/14 at 13:43:37 -0700, Luigi Rizzo wrote:
> [i am deliberately not trimming the email in case someone wants to
> look at the context]
> 
> i am a bit dubious about your explaination -- it also does not
> explain why the person reporting this problem "fixed" that
> by swapping "timestamp" and "next_rule" in the structure

It does - doing so removes the need for padding before 'next_rule',
because it is properly aligned then. 'timestamp' and 'cmd' are both 4
bytes in size and immediately follow each other, so the total
structure size is a multiple of 8 (48 bytes). Because of that, no
padding after 'cmd' is required, and the effect is gone.

- thomas

-- 
Thomas Moestl <[EMAIL PROTECTED]> http://www.tu-bs.de/~y0015675/
  <[EMAIL PROTECTED]> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-14 Thread Luigi Rizzo

[i am deliberately not trimming the email in case someone wants to
look at the context]

i am a bit dubious about your explaination -- it also does not
explain why the person reporting this problem "fixed" that
by swapping "timestamp" and "next_rule" in the structure

cheers
luigi

On Sun, Jul 14, 2002 at 10:36:42PM +0200, Thomas Moestl wrote:
> On Sun, 2002/07/14 at 01:18:10 -0700, Luigi Rizzo wrote:
> > Hi,
> > the following message seems to suggest that the compiler
> > (the way it is invoked) packs structures differently
> > when building the kernel and userland.
> > 
> > The stize of the structure in question is computed
> > by both kernel and userland app using sizeof(),
> > so there is no assumption on the size of its members,
> > so i believe the only possibility of a mismatch is
> > the one above.
> > 
> > Any ideas ?
> 
> (Disclaimer: my solution below is untested, so it may all be bogus)
> 
> No, you are not accounting for "external" structure padding. Take a
> look: 
> 
>   struct ip_fw {
> struct ip_fw  *next;  /* linked list of rules */
> u_int16_t act_ofs;/* offset of action in 32-bit units */
> u_int16_t cmd_len;/* # of 32-bit words in cmd */
> u_int16_t rulenum;/* rule number  */
> u_int16_t _pad;   /* padding  */
> 
> /* These fields are present in all rules. */
> u_int64_t pcnt;   /* Packet counter   */
> u_int64_t bcnt;   /* Byte counter */
> u_int32_t timestamp;  /* tv_sec of last match */
> 
> struct ip_fw *next_rule;  /* ptr to next rule */
> 
> ipfw_insn cmd[1]; /* storage for commands */
>   };
> 
> On a 64-bit architecture, pointers are obviously 8 bytes in size;
> structure members must or should be on natural borders, depending on
> the architecture.
> So, next_rule will not be on a natural border; 4 bytes of padding will
> be inserted before it. With that, the total structure size would be
> 52.
> The compiler must account for the fact that an array of struct ip_fws
> may be used. For obvious reasons, it can not just insert extra padding
> in the array case; instead, the structure size must be chosen so that
> in this situation, the first member will be on a natural border.
> This results in an extra 4 bytes of "external" padding at the end,
> after the member 'cmd'.
> The macro you use to compute the size in the kernel is:
> 
>   #define RULESIZE(rule)  (sizeof(struct ip_fw) + \
> ((struct ip_fw *)(rule))->cmd_len * 4 - 4)
> 
> In the userland code, you start at &foo.cmd and append data
> directly. This means that the padding will also be used to store
> data, so the '- 4' (= sizeof(foo.cmd)) will not always be enough. The
> following definition of RULESIZE (untested) should fix this:
> 
>   #define RULESIZE(rule)  (offsetof(struct ip_fw, cmd) + \
> ((struct ip_fw *)(rule))->cmd_len * 4)
> 
> It also removes the explicit 4 for sizeof(ipfw_insn).
> 
>   - thomas
> 
> -- 
> Thomas Moestl <[EMAIL PROTECTED]>   http://www.tu-bs.de/~y0015675/
>   <[EMAIL PROTECTED]>   http://people.FreeBSD.org/~tmm/
> PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-14 Thread Thomas Moestl

On Sun, 2002/07/14 at 01:18:10 -0700, Luigi Rizzo wrote:
> Hi,
> the following message seems to suggest that the compiler
> (the way it is invoked) packs structures differently
> when building the kernel and userland.
> 
> The stize of the structure in question is computed
> by both kernel and userland app using sizeof(),
> so there is no assumption on the size of its members,
> so i believe the only possibility of a mismatch is
> the one above.
> 
> Any ideas ?

(Disclaimer: my solution below is untested, so it may all be bogus)

No, you are not accounting for "external" structure padding. Take a
look: 

  struct ip_fw {
  struct ip_fw  *next;  /* linked list of rules */
  u_int16_t act_ofs;/* offset of action in 32-bit units */
  u_int16_t cmd_len;/* # of 32-bit words in cmd */
  u_int16_t rulenum;/* rule number  */
  u_int16_t _pad;   /* padding  */

  /* These fields are present in all rules. */
  u_int64_t pcnt;   /* Packet counter   */
  u_int64_t bcnt;   /* Byte counter */
  u_int32_t timestamp;  /* tv_sec of last match */

  struct ip_fw *next_rule;  /* ptr to next rule */

  ipfw_insn cmd[1]; /* storage for commands */
  };

On a 64-bit architecture, pointers are obviously 8 bytes in size;
structure members must or should be on natural borders, depending on
the architecture.
So, next_rule will not be on a natural border; 4 bytes of padding will
be inserted before it. With that, the total structure size would be
52.
The compiler must account for the fact that an array of struct ip_fws
may be used. For obvious reasons, it can not just insert extra padding
in the array case; instead, the structure size must be chosen so that
in this situation, the first member will be on a natural border.
This results in an extra 4 bytes of "external" padding at the end,
after the member 'cmd'.
The macro you use to compute the size in the kernel is:

  #define RULESIZE(rule)  (sizeof(struct ip_fw) + \
  ((struct ip_fw *)(rule))->cmd_len * 4 - 4)

In the userland code, you start at &foo.cmd and append data
directly. This means that the padding will also be used to store
data, so the '- 4' (= sizeof(foo.cmd)) will not always be enough. The
following definition of RULESIZE (untested) should fix this:

  #define RULESIZE(rule)  (offsetof(struct ip_fw, cmd) + \
  ((struct ip_fw *)(rule))->cmd_len * 4)

It also removes the explicit 4 for sizeof(ipfw_insn).

- thomas

-- 
Thomas Moestl <[EMAIL PROTECTED]> http://www.tu-bs.de/~y0015675/
  <[EMAIL PROTECTED]> http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message



Re: different packing of structs in kernel vs. userland ?

2002-07-14 Thread Terry Lambert

Luigi Rizzo wrote:
> Hi,
> the following message seems to suggest that the compiler
> (the way it is invoked) packs structures differently
> when building the kernel and userland.
> 
> The stize of the structure in question is computed
> by both kernel and userland app using sizeof(),
> so there is no assumption on the size of its members,
> so i believe the only possibility of a mismatch is
> the one above.
> 
> Any ideas ?

Probably a #pragma pack() in scope.

Add one explicitly before and after the structure definition
to force it to be the same in user space and the kernel, e.g.:

#pragma pack(1) /* 1 byte packing */
struct foo {
...
};
#pragma pack()  /* whatever it was before */

The latter is like a "pop" of the former's "push", so you
should be OK, even though it looks like what is happening
is an include of an include file in the wrong place or in
code that has one in scope.

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-current" in the body of the message