diff mbox series

[v4,4/4] fanotify,audit: deliver fan_info as a hex-encoded string

Message ID 2d8159cec4392029dabfc39b55ac5fbd0faa9fbd.1659996830.git.rgb@redhat.com (mailing list archive)
State New, archived
Headers show
Series fanotify: Allow user space to pass back additional audit info | expand

Commit Message

Richard Guy Briggs Aug. 9, 2022, 5:22 p.m. UTC
Currently the only type of fanotify info that is defined is an audit
rule number, but convert it to hex encoding to future-proof the field.

Sample record:
  type=FANOTIFY msg=audit(1659730979.839:284): resp=1 fan_type=0 fan_info=3F

Suggested-by: Paul Moore <paul@paul-moore.com>
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 kernel/auditsc.c | 28 +++++++++++++++++++++-------
 1 file changed, 21 insertions(+), 7 deletions(-)

Comments

Steve Grubb Aug. 10, 2022, 7:15 p.m. UTC | #1
Hell Richard,

On Tuesday, August 9, 2022 1:22:55 PM EDT Richard Guy Briggs wrote:
> Currently the only type of fanotify info that is defined is an audit
> rule number, but convert it to hex encoding to future-proof the field.
> 
> Sample record:
>   type=FANOTIFY msg=audit(1659730979.839:284): resp=1 fan_type=0
> fan_info=3F

I compiled a new kernel and run old user space on this. The above event is 
exactly what I see in my audit logs. Why the fan_info=3F? I really would have 
expected 0. What if the actual rule number was 63? I think this will work 
better to leave everything 0 with old user space.

-Steve
 
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> ---
>  kernel/auditsc.c | 28 +++++++++++++++++++++-------
>  1 file changed, 21 insertions(+), 7 deletions(-)
> 
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index f000fec52360..0f747015c577 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2908,22 +2908,36 @@ void __audit_fanotify(u32 response, size_t len,
> char *buf)
> 
>  	if (!(len && buf)) {
>  		audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -			  "resp=%u fan_type=0 fan_info=?", response);
> +			  "resp=%u fan_type=0 fan_info=3F", response); /* "?" 
*/
>  		return;
>  	}
>  	while (c >= sizeof(struct fanotify_response_info_header)) {
> +		struct audit_context *ctx = audit_context();
> +		struct audit_buffer *ab;
> +
>  		friar = (struct fanotify_response_info_audit_rule *)buf;
>  		switch (friar->hdr.type) {
>  		case FAN_RESPONSE_INFO_AUDIT_RULE:
>  			if (friar->hdr.len < sizeof(*friar)) {
> -				audit_log(audit_context(), GFP_KERNEL, 
AUDIT_FANOTIFY,
> -					  "resp=%u fan_type=%u 
fan_info=(incomplete)",
> -					  response, friar->hdr.type);
> +				ab = audit_log_start(ctx, GFP_KERNEL, 
AUDIT_FANOTIFY);
> +				if (ab) {
> +					audit_log_format(ab, "resp=%u fan_type=%u 
fan_info=",
> +							 response, friar-
>hdr.type);
> +#define INCOMPLETE "(incomplete)"
> +					audit_log_n_hex(ab, INCOMPLETE, 
sizeof(INCOMPLETE));
> +					audit_log_end(ab);
> +				}
>  				return;
>  			}
> -			audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -				  "resp=%u fan_type=%u fan_info=%u",
> -				  response, friar->hdr.type, friar->audit_rule);
> +			ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> +			if (ab) {
> +				audit_log_format(ab, "resp=%u fan_type=%u 
fan_info=",
> +						 response, friar->hdr.type);
> +				audit_log_n_hex(ab, (char *)&friar->audit_rule,
> +						sizeof(friar->audit_rule));
> +				audit_log_end(ab);
> +
> +			}
>  		}
>  		c -= friar->hdr.len;
>  		ib += friar->hdr.len;
Richard Guy Briggs Aug. 11, 2022, 2:23 a.m. UTC | #2
On 2022-08-10 15:15, Steve Grubb wrote:
> Hell Richard,

That's quite an introduction!  ;-)

> On Tuesday, August 9, 2022 1:22:55 PM EDT Richard Guy Briggs wrote:
> > Currently the only type of fanotify info that is defined is an audit
> > rule number, but convert it to hex encoding to future-proof the field.
> > 
> > Sample record:
> >   type=FANOTIFY msg=audit(1659730979.839:284): resp=1 fan_type=0
> > fan_info=3F
> 
> I compiled a new kernel and run old user space on this. The above event is 
> exactly what I see in my audit logs. Why the fan_info=3F? I really would have 
> expected 0. What if the actual rule number was 63? I think this will work 
> better to leave everything 0 with old user space.

Well, if it is to be consistently hex encoded, that corresponds to "?"
if it is to be interpreted as a string.  Since the fan_type is 0,
fan_info would be invalid, so a value of 0 would be entirely reasonable,
hex encoded to fan_info=00.  It could also be hex encoded to the string
"(none)".  If you wanted "0" for fan_type=FAN_RESPONSE_INFO_AUDIT_RULE,
that would be fan_info=30 if it were interpreted as a string, or
arguably 3F for an integer of rule (decimal) 63.  Ultimately, fan_type
should determine how fan_info's hex encoded value should be interpreted.

But ultimately, the point of this patch is to hex encode the fan_info
field value.

> -Steve
>  
> > Suggested-by: Paul Moore <paul@paul-moore.com>
> > Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > ---
> >  kernel/auditsc.c | 28 +++++++++++++++++++++-------
> >  1 file changed, 21 insertions(+), 7 deletions(-)
> > 
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index f000fec52360..0f747015c577 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2908,22 +2908,36 @@ void __audit_fanotify(u32 response, size_t len,
> > char *buf)
> > 
> >  	if (!(len && buf)) {
> >  		audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> > -			  "resp=%u fan_type=0 fan_info=?", response);
> > +			  "resp=%u fan_type=0 fan_info=3F", response); /* "?" */
> >  		return;
> >  	}
> >  	while (c >= sizeof(struct fanotify_response_info_header)) {
> > +		struct audit_context *ctx = audit_context();
> > +		struct audit_buffer *ab;
> > +
> >  		friar = (struct fanotify_response_info_audit_rule *)buf;
> >  		switch (friar->hdr.type) {
> >  		case FAN_RESPONSE_INFO_AUDIT_RULE:
> >  			if (friar->hdr.len < sizeof(*friar)) {
> > -				audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> > -					  "resp=%u fan_type=%u fan_info=(incomplete)",
> > -					  response, friar->hdr.type);
> > +				ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> > +				if (ab) {
> > +					audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> > +							 response, friar-
> >hdr.type);
> > +#define INCOMPLETE "(incomplete)"
> > +					audit_log_n_hex(ab, INCOMPLETE, sizeof(INCOMPLETE));
> > +					audit_log_end(ab);
> > +				}
> >  				return;
> >  			}
> > -			audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> > -				  "resp=%u fan_type=%u fan_info=%u",
> > -				  response, friar->hdr.type, friar->audit_rule);
> > +			ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> > +			if (ab) {
> > +				audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> > +						 response, friar->hdr.type);
> > +				audit_log_n_hex(ab, (char *)&friar->audit_rule,
> > +						sizeof(friar->audit_rule));
> > +				audit_log_end(ab);
> > +
> > +			}
> >  		}
> >  		c -= friar->hdr.len;
> >  		ib += friar->hdr.len;
> 
> 
> 
> 

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635
Steve Grubb Aug. 15, 2022, 9:15 p.m. UTC | #3
Hello Richard,

On Wednesday, August 10, 2022 10:23:49 PM EDT Richard Guy Briggs wrote:
> > I compiled a new kernel and run old user space on this. The above event
> > is
> > exactly what I see in my audit logs. Why the fan_info=3F? I really would
> > have expected 0. What if the actual rule number was 63? I think this
> > will work better to leave everything 0 with old user space.
> 
> Well, if it is to be consistently hex encoded, that corresponds to "?"

I suppose this OK.

> if it is to be interpreted as a string.  Since the fan_type is 0,
> fan_info would be invalid, so a value of 0 would be entirely reasonable,
> hex encoded to fan_info=00.  It could also be hex encoded to the string
> "(none)".  If you wanted "0" for fan_type=FAN_RESPONSE_INFO_AUDIT_RULE,
> that would be fan_info=30 if it were interpreted as a string, or
> arguably 3F for an integer of rule (decimal) 63.  Ultimately, fan_type
> should determine how fan_info's hex encoded value should be interpreted.
> 
> But ultimately, the point of this patch is to hex encode the fan_info
> field value.

Just one last update, I have been able to test the patches with the user 
space application and it appears to be working from the PoV of what is sent 
is what's in the audit logs. I'm not sure how picky old kernels are wrt the 
size of what's sent. But an unpatched 5.19 kernel seems to accept the larger 
size response and do the right thing.

-Steve
Paul Moore Aug. 16, 2022, 12:31 a.m. UTC | #4
On Tue, Aug 9, 2022 at 1:23 PM Richard Guy Briggs <rgb@redhat.com> wrote:
>
> Currently the only type of fanotify info that is defined is an audit
> rule number, but convert it to hex encoding to future-proof the field.
>
> Sample record:
>   type=FANOTIFY msg=audit(1659730979.839:284): resp=1 fan_type=0 fan_info=3F
>
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> ---
>  kernel/auditsc.c | 28 +++++++++++++++++++++-------
>  1 file changed, 21 insertions(+), 7 deletions(-)

This needs to be squashed with patch 3/4; it's a user visible change
so we don't want someone backporting 3/4 without 4/4, especially when
it is part of the same patchset.

> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index f000fec52360..0f747015c577 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2908,22 +2908,36 @@ void __audit_fanotify(u32 response, size_t len, char *buf)
>
>         if (!(len && buf)) {
>                 audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -                         "resp=%u fan_type=0 fan_info=?", response);
> +                         "resp=%u fan_type=0 fan_info=3F", response); /* "?" */

Please drop the trailing comment, it's not necessary and it makes the
code messier.

>                 return;
>         }
>         while (c >= sizeof(struct fanotify_response_info_header)) {
> +               struct audit_context *ctx = audit_context();
> +               struct audit_buffer *ab;
> +
>                 friar = (struct fanotify_response_info_audit_rule *)buf;
>                 switch (friar->hdr.type) {
>                 case FAN_RESPONSE_INFO_AUDIT_RULE:
>                         if (friar->hdr.len < sizeof(*friar)) {
> -                               audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -                                         "resp=%u fan_type=%u fan_info=(incomplete)",
> -                                         response, friar->hdr.type);
> +                               ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> +                               if (ab) {
> +                                       audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> +                                                        response, friar->hdr.type);
> +#define INCOMPLETE "(incomplete)"
> +                                       audit_log_n_hex(ab, INCOMPLETE, sizeof(INCOMPLETE));

Is the distinction between "?" and "(incomplete)" really that
important?  I'm not going to go digging through all of the
audit_log_format() callers to check, but I believe there is precedence
for using "?" not only for when a value is missing, but when it is
bogus as well.

If we are really going to use "(incomplete)" here, let's do a better
job than defining a macro mid-function and only using it in one other
place - the line immediately below the definition.  This is both ugly
and a little silly (especially when one considers that the macro name
is almost exactly the same as the string it replaces.  If we must use
"(incomplete)" here, just ditch the macro; any conceptual arguments
about macros vs literals is largely rendered moot since there is only
one user.

> +                                       audit_log_end(ab);
> +                               }
>                                 return;
>                         }
> -                       audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -                                 "resp=%u fan_type=%u fan_info=%u",
> -                                 response, friar->hdr.type, friar->audit_rule);
> +                       ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> +                       if (ab) {
> +                               audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> +                                                response, friar->hdr.type);
> +                               audit_log_n_hex(ab, (char *)&friar->audit_rule,
> +                                               sizeof(friar->audit_rule));
> +                               audit_log_end(ab);
> +
> +                       }
>                 }
>                 c -= friar->hdr.len;
>                 ib += friar->hdr.len;
> --
> 2.27.0
Steve Grubb Aug. 16, 2022, 1:37 p.m. UTC | #5
Hello Richard,

Although I have it working, I have some comments below that might improve
things.

On Tuesday, August 9, 2022 1:22:55 PM EDT Richard Guy Briggs wrote:
> Currently the only type of fanotify info that is defined is an audit
> rule number, but convert it to hex encoding to future-proof the field.
> 
> Sample record:
>   type=FANOTIFY msg=audit(1659730979.839:284): resp=1 fan_type=0
> fan_info=3F
> 
> Suggested-by: Paul Moore <paul@paul-moore.com>
> Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> ---
>  kernel/auditsc.c | 28 +++++++++++++++++++++-------
>  1 file changed, 21 insertions(+), 7 deletions(-)
> 
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index f000fec52360..0f747015c577 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -2908,22 +2908,36 @@ void __audit_fanotify(u32 response, size_t len,
> char *buf)
> 
>  	if (!(len && buf)) {
>  		audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -			  "resp=%u fan_type=0 fan_info=?", response);
> +			  "resp=%u fan_type=0 fan_info=3F", response); /* "?" */
>  		return;
>  	}
>  	while (c >= sizeof(struct fanotify_response_info_header)) {
> +		struct audit_context *ctx = audit_context();
> +		struct audit_buffer *ab;
> +
>  		friar = (struct fanotify_response_info_audit_rule *)buf;
>  		switch (friar->hdr.type) {
>  		case FAN_RESPONSE_INFO_AUDIT_RULE:
>  			if (friar->hdr.len < sizeof(*friar)) {
> -				audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -					  "resp=%u fan_type=%u fan_info=(incomplete)",
> -					  response, friar->hdr.type);
> +				ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> +				if (ab) {
> +					audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> +							 response, friar->hdr.type);
> +#define INCOMPLETE "(incomplete)"
> +					audit_log_n_hex(ab, INCOMPLETE, sizeof(INCOMPLETE));
> +					audit_log_end(ab);
> +				}
>  				return;
>  			}
> -			audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> -				  "resp=%u fan_type=%u fan_info=%u",
> -				  response, friar->hdr.type, friar->audit_rule);
> +			ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> +			if (ab) {
> +				audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> +						 response, friar->hdr.type);
> +				audit_log_n_hex(ab, (char *)&friar->audit_rule,
> +						sizeof(friar->audit_rule));

One thing to point out, the structure has a member audit_rule. It is
probably better to call it rule_number. This is because it has nothing to
do with any actual audit rule. It is a rule number meant to be recorded by
the audit system.

Also, that member is a __u32 type. Hex encoding that directly gives back a
__u32 when decoded - which is a bit unexpected since everything else is
strings. It would be better to convert the u32 to a base 10 string and then
hex encode that. A buffer of 12 bytes should be sufficient.

Thanks,
-Steve

> +				audit_log_end(ab);
> +
> +			}
>  		}
>  		c -= friar->hdr.len;
>  		ib += friar->hdr.len;
Richard Guy Briggs Aug. 19, 2022, 9:42 p.m. UTC | #6
On 2022-08-16 09:37, Steve Grubb wrote:
> Hello Richard,
> 
> Although I have it working, I have some comments below that might improve
> things.
> 
> On Tuesday, August 9, 2022 1:22:55 PM EDT Richard Guy Briggs wrote:
> > Currently the only type of fanotify info that is defined is an audit
> > rule number, but convert it to hex encoding to future-proof the field.
> > 
> > Sample record:
> >   type=FANOTIFY msg=audit(1659730979.839:284): resp=1 fan_type=0
> > fan_info=3F
> > 
> > Suggested-by: Paul Moore <paul@paul-moore.com>
> > Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
> > ---
> >  kernel/auditsc.c | 28 +++++++++++++++++++++-------
> >  1 file changed, 21 insertions(+), 7 deletions(-)
> > 
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index f000fec52360..0f747015c577 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -2908,22 +2908,36 @@ void __audit_fanotify(u32 response, size_t len,
> > char *buf)
> > 
> >  	if (!(len && buf)) {
> >  		audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> > -			  "resp=%u fan_type=0 fan_info=?", response);
> > +			  "resp=%u fan_type=0 fan_info=3F", response); /* "?" */
> >  		return;
> >  	}
> >  	while (c >= sizeof(struct fanotify_response_info_header)) {
> > +		struct audit_context *ctx = audit_context();
> > +		struct audit_buffer *ab;
> > +
> >  		friar = (struct fanotify_response_info_audit_rule *)buf;
> >  		switch (friar->hdr.type) {
> >  		case FAN_RESPONSE_INFO_AUDIT_RULE:
> >  			if (friar->hdr.len < sizeof(*friar)) {
> > -				audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> > -					  "resp=%u fan_type=%u fan_info=(incomplete)",
> > -					  response, friar->hdr.type);
> > +				ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> > +				if (ab) {
> > +					audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> > +							 response, friar->hdr.type);
> > +#define INCOMPLETE "(incomplete)"
> > +					audit_log_n_hex(ab, INCOMPLETE, sizeof(INCOMPLETE));
> > +					audit_log_end(ab);
> > +				}
> >  				return;
> >  			}
> > -			audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
> > -				  "resp=%u fan_type=%u fan_info=%u",
> > -				  response, friar->hdr.type, friar->audit_rule);
> > +			ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
> > +			if (ab) {
> > +				audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
> > +						 response, friar->hdr.type);
> > +				audit_log_n_hex(ab, (char *)&friar->audit_rule,
> > +						sizeof(friar->audit_rule));
> 
> One thing to point out, the structure has a member audit_rule. It is
> probably better to call it rule_number. This is because it has nothing to
> do with any actual audit rule. It is a rule number meant to be recorded by
> the audit system.
> 
> Also, that member is a __u32 type. Hex encoding that directly gives back a
> __u32 when decoded - which is a bit unexpected since everything else is
> strings. It would be better to convert the u32 to a base 10 string and then
> hex encode that. A buffer of 12 bytes should be sufficient.

Sure, these seem reasonable.

> Thanks,
> -Steve
> 
> > +				audit_log_end(ab);
> > +
> > +			}
> >  		}
> >  		c -= friar->hdr.len;
> >  		ib += friar->hdr.len;
> 
> 
> 
> 

- RGB

--
Richard Guy Briggs <rgb@redhat.com>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635
diff mbox series

Patch

diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f000fec52360..0f747015c577 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2908,22 +2908,36 @@  void __audit_fanotify(u32 response, size_t len, char *buf)
 
 	if (!(len && buf)) {
 		audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
-			  "resp=%u fan_type=0 fan_info=?", response);
+			  "resp=%u fan_type=0 fan_info=3F", response); /* "?" */
 		return;
 	}
 	while (c >= sizeof(struct fanotify_response_info_header)) {
+		struct audit_context *ctx = audit_context();
+		struct audit_buffer *ab;
+
 		friar = (struct fanotify_response_info_audit_rule *)buf;
 		switch (friar->hdr.type) {
 		case FAN_RESPONSE_INFO_AUDIT_RULE:
 			if (friar->hdr.len < sizeof(*friar)) {
-				audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
-					  "resp=%u fan_type=%u fan_info=(incomplete)",
-					  response, friar->hdr.type);
+				ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
+				if (ab) {
+					audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
+							 response, friar->hdr.type);
+#define INCOMPLETE "(incomplete)"
+					audit_log_n_hex(ab, INCOMPLETE, sizeof(INCOMPLETE));
+					audit_log_end(ab);
+				}
 				return;
 			}
-			audit_log(audit_context(), GFP_KERNEL, AUDIT_FANOTIFY,
-				  "resp=%u fan_type=%u fan_info=%u",
-				  response, friar->hdr.type, friar->audit_rule);
+			ab = audit_log_start(ctx, GFP_KERNEL, AUDIT_FANOTIFY);
+			if (ab) {
+				audit_log_format(ab, "resp=%u fan_type=%u fan_info=",
+						 response, friar->hdr.type);
+				audit_log_n_hex(ab, (char *)&friar->audit_rule,
+						sizeof(friar->audit_rule));
+				audit_log_end(ab);
+
+			}
 		}
 		c -= friar->hdr.len;
 		ib += friar->hdr.len;