selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH testsuite] tests/sctp: fix setting of the SCTP_EVENTS sockopt
@ 2020-02-24 12:47 Ondrej Mosnacek
  2020-02-24 15:23 ` Richard Haines
  0 siblings, 1 reply; 3+ messages in thread
From: Ondrej Mosnacek @ 2020-02-24 12:47 UTC (permalink / raw)
  To: selinux

First, the setting of SCTP_EVENTS socket option in sctp_server.c is
completely wrong -- it assumes little-endian byte order and uses a plain
int instead of the dedicated sctp_event_subscribe struct.

Second, the usage in sctp_peeloff_server.c is correct, but it may lead
to errors when the SCTP header definitions are newer than what the
kernel supports. In such case the size of struct sctp_event_subscribe
may be higher than the kernel's version and the setsockopt(2) may fail
with -EINVAL due to the 'optlen > sizeof(struct sctp_event_subscribe)'
check in net/sctp/socket.c:sctp_setsockopt_events().

To fix this, introduce a common function that does what the
sctp_peeloff_server's set_subscr_events() did, but also truncates the
optlen to only those fields that we use.

Fixes: c38b57ffdac4 ("selinux-testsuite: Add SCTP test support")
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
---
 tests/sctp/sctp_common.c         | 20 ++++++++++++++++++++
 tests/sctp/sctp_common.h         |  1 +
 tests/sctp/sctp_peeloff_server.c | 28 ++++++++--------------------
 tests/sctp/sctp_server.c         |  2 +-
 4 files changed, 30 insertions(+), 21 deletions(-)

diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c
index 100ab22..089af2a 100644
--- a/tests/sctp/sctp_common.c
+++ b/tests/sctp/sctp_common.c
@@ -1,5 +1,8 @@
 #include "sctp_common.h"
 
+#define member_size(type, member) sizeof(((type *)0)->member)
+#define sizeof_up_to(type, member) (offsetof(type, member) + member_size(type, member))
+
 void print_context(int fd, char *text)
 {
 	char *context;
@@ -99,3 +102,20 @@ void print_ip_option(int fd, bool ipv4, char *text)
 		printf("%s No IP Options set\n", text);
 	}
 }
+
+int set_subscr_events(int fd, int data_io, int association)
+{
+	struct sctp_event_subscribe subscr_events;
+
+	memset(&subscr_events, 0, sizeof(subscr_events));
+	subscr_events.sctp_data_io_event = data_io;
+	subscr_events.sctp_association_event = association;
+
+	/*
+	 * Truncate optlen to just the fields we touch to avoid errors when
+	 * the uapi headers are newer than the running kernel.
+	 */
+	return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &subscr_events,
+			  sizeof_up_to(struct sctp_event_subscribe,
+				       sctp_association_event));
+}
diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h
index d5c1397..351ee37 100644
--- a/tests/sctp/sctp_common.h
+++ b/tests/sctp/sctp_common.h
@@ -25,3 +25,4 @@ void print_context(int fd, char *text);
 void print_addr_info(struct sockaddr *sin, char *text);
 char *get_ip_option(int fd, bool ipv4, socklen_t *opt_len);
 void print_ip_option(int fd, bool ipv4, char *text);
+int set_subscr_events(int fd, int data_io, int association);
diff --git a/tests/sctp/sctp_peeloff_server.c b/tests/sctp/sctp_peeloff_server.c
index 4a5110a..093c6c0 100644
--- a/tests/sctp/sctp_peeloff_server.c
+++ b/tests/sctp/sctp_peeloff_server.c
@@ -16,24 +16,6 @@ static void usage(char *progname)
 	exit(1);
 }
 
-static void set_subscr_events(int fd, int value)
-{
-	int result;
-	struct sctp_event_subscribe subscr_events;
-
-	memset(&subscr_events, 0, sizeof(subscr_events));
-	subscr_events.sctp_association_event = value;
-	/* subscr_events.sctp_data_io_event = value; */
-
-	result = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
-			    &subscr_events, sizeof(subscr_events));
-	if (result < 0) {
-		perror("Server setsockopt: SCTP_EVENTS");
-		close(fd);
-		exit(1);
-	}
-}
-
 static sctp_assoc_t handle_event(void *buf)
 {
 	union sctp_notification *snp = buf;
@@ -166,7 +148,13 @@ int main(int argc, char **argv)
 	}
 
 	do {
-		set_subscr_events(sock, 1); /* Get assoc_id for sctp_peeloff() */
+		/* Get assoc_id for sctp_peeloff() */
+		result = set_subscr_events(sock, 0, 1);
+		if (result < 0) {
+			perror("Server setsockopt: SCTP_EVENTS");
+			close(sock);
+			exit(1);
+		}
 		sinlen = sizeof(sin);
 		flags = 0;
 
@@ -192,7 +180,7 @@ int main(int argc, char **argv)
 				exit(1);
 			}
 			/* No more notifications */
-			set_subscr_events(sock, 0);
+			set_subscr_events(sock, 0, 0);
 
 			peeloff_sk = sctp_peeloff(sock, assoc_id);
 			if (peeloff_sk < 0) {
diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c
index 4659ed1..7f2cd20 100644
--- a/tests/sctp/sctp_server.c
+++ b/tests/sctp/sctp_server.c
@@ -134,7 +134,7 @@ int main(int argc, char **argv)
 	}
 
 	/* Enables sctp_data_io_events for sctp_recvmsg(3) for assoc_id. */
-	result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on, sizeof(on));
+	result = set_subscr_events(sock, on, 0);
 	if (result < 0) {
 		perror("Server setsockopt: SCTP_EVENTS");
 		close(sock);
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH testsuite] tests/sctp: fix setting of the SCTP_EVENTS sockopt
  2020-02-24 12:47 [PATCH testsuite] tests/sctp: fix setting of the SCTP_EVENTS sockopt Ondrej Mosnacek
@ 2020-02-24 15:23 ` Richard Haines
  2020-02-24 15:48   ` Ondrej Mosnacek
  0 siblings, 1 reply; 3+ messages in thread
From: Richard Haines @ 2020-02-24 15:23 UTC (permalink / raw)
  To: Ondrej Mosnacek, selinux

On Mon, 2020-02-24 at 13:47 +0100, Ondrej Mosnacek wrote:
> First, the setting of SCTP_EVENTS socket option in sctp_server.c is
> completely wrong -- it assumes little-endian byte order and uses a
> plain
> int instead of the dedicated sctp_event_subscribe struct.
> 
> Second, the usage in sctp_peeloff_server.c is correct, but it may
> lead
> to errors when the SCTP header definitions are newer than what the
> kernel supports. In such case the size of struct sctp_event_subscribe
> may be higher than the kernel's version and the setsockopt(2) may
> fail
> with -EINVAL due to the 'optlen > sizeof(struct
> sctp_event_subscribe)'
> check in net/sctp/socket.c:sctp_setsockopt_events().
> 
> To fix this, introduce a common function that does what the
> sctp_peeloff_server's set_subscr_events() did, but also truncates the
> optlen to only those fields that we use.

Thanks for fixing these problems. How did the problems come to light,
just via the header file changes or some tests failing on a certain
kernel ?

> 
> Fixes: c38b57ffdac4 ("selinux-testsuite: Add SCTP test support")
> Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> ---
>  tests/sctp/sctp_common.c         | 20 ++++++++++++++++++++
>  tests/sctp/sctp_common.h         |  1 +
>  tests/sctp/sctp_peeloff_server.c | 28 ++++++++--------------------
>  tests/sctp/sctp_server.c         |  2 +-
>  4 files changed, 30 insertions(+), 21 deletions(-)
> 
> diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c
> index 100ab22..089af2a 100644
> --- a/tests/sctp/sctp_common.c
> +++ b/tests/sctp/sctp_common.c
> @@ -1,5 +1,8 @@
>  #include "sctp_common.h"
>  
> +#define member_size(type, member) sizeof(((type *)0)->member)
> +#define sizeof_up_to(type, member) (offsetof(type, member) +
> member_size(type, member))
> +
>  void print_context(int fd, char *text)
>  {
>  	char *context;
> @@ -99,3 +102,20 @@ void print_ip_option(int fd, bool ipv4, char
> *text)
>  		printf("%s No IP Options set\n", text);
>  	}
>  }
> +
> +int set_subscr_events(int fd, int data_io, int association)
> +{
> +	struct sctp_event_subscribe subscr_events;
> +
> +	memset(&subscr_events, 0, sizeof(subscr_events));
> +	subscr_events.sctp_data_io_event = data_io;
> +	subscr_events.sctp_association_event = association;
> +
> +	/*
> +	 * Truncate optlen to just the fields we touch to avoid errors
> when
> +	 * the uapi headers are newer than the running kernel.
> +	 */
> +	return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
> &subscr_events,
> +			  sizeof_up_to(struct sctp_event_subscribe,
> +				       sctp_association_event));
> +}
> diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h
> index d5c1397..351ee37 100644
> --- a/tests/sctp/sctp_common.h
> +++ b/tests/sctp/sctp_common.h
> @@ -25,3 +25,4 @@ void print_context(int fd, char *text);
>  void print_addr_info(struct sockaddr *sin, char *text);
>  char *get_ip_option(int fd, bool ipv4, socklen_t *opt_len);
>  void print_ip_option(int fd, bool ipv4, char *text);
> +int set_subscr_events(int fd, int data_io, int association);
> diff --git a/tests/sctp/sctp_peeloff_server.c
> b/tests/sctp/sctp_peeloff_server.c
> index 4a5110a..093c6c0 100644
> --- a/tests/sctp/sctp_peeloff_server.c
> +++ b/tests/sctp/sctp_peeloff_server.c
> @@ -16,24 +16,6 @@ static void usage(char *progname)
>  	exit(1);
>  }
>  
> -static void set_subscr_events(int fd, int value)
> -{
> -	int result;
> -	struct sctp_event_subscribe subscr_events;
> -
> -	memset(&subscr_events, 0, sizeof(subscr_events));
> -	subscr_events.sctp_association_event = value;
> -	/* subscr_events.sctp_data_io_event = value; */
> -
> -	result = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
> -			    &subscr_events, sizeof(subscr_events));
> -	if (result < 0) {
> -		perror("Server setsockopt: SCTP_EVENTS");
> -		close(fd);
> -		exit(1);
> -	}
> -}
> -
>  static sctp_assoc_t handle_event(void *buf)
>  {
>  	union sctp_notification *snp = buf;
> @@ -166,7 +148,13 @@ int main(int argc, char **argv)
>  	}
>  
>  	do {
> -		set_subscr_events(sock, 1); /* Get assoc_id for
> sctp_peeloff() */
> +		/* Get assoc_id for sctp_peeloff() */
> +		result = set_subscr_events(sock, 0, 1);
> +		if (result < 0) {
> +			perror("Server setsockopt: SCTP_EVENTS");
> +			close(sock);
> +			exit(1);
> +		}
>  		sinlen = sizeof(sin);
>  		flags = 0;
>  
> @@ -192,7 +180,7 @@ int main(int argc, char **argv)
>  				exit(1);
>  			}
>  			/* No more notifications */
> -			set_subscr_events(sock, 0);
> +			set_subscr_events(sock, 0, 0);
>  
>  			peeloff_sk = sctp_peeloff(sock, assoc_id);
>  			if (peeloff_sk < 0) {
> diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c
> index 4659ed1..7f2cd20 100644
> --- a/tests/sctp/sctp_server.c
> +++ b/tests/sctp/sctp_server.c
> @@ -134,7 +134,7 @@ int main(int argc, char **argv)
>  	}
>  
>  	/* Enables sctp_data_io_events for sctp_recvmsg(3) for
> assoc_id. */
> -	result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on,
> sizeof(on));
> +	result = set_subscr_events(sock, on, 0);
>  	if (result < 0) {
>  		perror("Server setsockopt: SCTP_EVENTS");
>  		close(sock);


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH testsuite] tests/sctp: fix setting of the SCTP_EVENTS sockopt
  2020-02-24 15:23 ` Richard Haines
@ 2020-02-24 15:48   ` Ondrej Mosnacek
  0 siblings, 0 replies; 3+ messages in thread
From: Ondrej Mosnacek @ 2020-02-24 15:48 UTC (permalink / raw)
  To: Richard Haines; +Cc: SElinux list

On Mon, Feb 24, 2020 at 4:24 PM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> On Mon, 2020-02-24 at 13:47 +0100, Ondrej Mosnacek wrote:
> > First, the setting of SCTP_EVENTS socket option in sctp_server.c is
> > completely wrong -- it assumes little-endian byte order and uses a
> > plain
> > int instead of the dedicated sctp_event_subscribe struct.
> >
> > Second, the usage in sctp_peeloff_server.c is correct, but it may
> > lead
> > to errors when the SCTP header definitions are newer than what the
> > kernel supports. In such case the size of struct sctp_event_subscribe
> > may be higher than the kernel's version and the setsockopt(2) may
> > fail
> > with -EINVAL due to the 'optlen > sizeof(struct
> > sctp_event_subscribe)'
> > check in net/sctp/socket.c:sctp_setsockopt_events().
> >
> > To fix this, introduce a common function that does what the
> > sctp_peeloff_server's set_subscr_events() did, but also truncates the
> > optlen to only those fields that we use.
>
> Thanks for fixing these problems. How did the problems come to light,
> just via the header file changes or some tests failing on a certain
> kernel ?

Apparently, struct sctp_event_subscribe has been extended by a new
field between kernel 5.4 and 5.5 [1] and this caused the error to
appear in CKI testing [2] when Fedora 31 moved to kernel 5.5 (it
installed the tested 5.4 stable rc kernel and booted into it, while
the kernel-headers package stayed at the distro's 5.5 version). The
endianness issue never seemed to have triggered actual failures when
we ran the tests internally on big-endian s390x systems. (I'm
wondering if the SCTP_EVENTS setsockopt() is even needed there...?)

[1] https://github.com/torvalds/linux/blame/master/include/uapi/linux/sctp.h#L623
[2] https://lore.kernel.org/stable/CAFqZXNvnywGVwqJhXcfwpmx2mmu8ajAUOdy0Ny8PvsT=Rg_3Qg@mail.gmail.com/T/

>
> >
> > Fixes: c38b57ffdac4 ("selinux-testsuite: Add SCTP test support")
> > Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
> > ---
> >  tests/sctp/sctp_common.c         | 20 ++++++++++++++++++++
> >  tests/sctp/sctp_common.h         |  1 +
> >  tests/sctp/sctp_peeloff_server.c | 28 ++++++++--------------------
> >  tests/sctp/sctp_server.c         |  2 +-
> >  4 files changed, 30 insertions(+), 21 deletions(-)
> >
> > diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c
> > index 100ab22..089af2a 100644
> > --- a/tests/sctp/sctp_common.c
> > +++ b/tests/sctp/sctp_common.c
> > @@ -1,5 +1,8 @@
> >  #include "sctp_common.h"
> >
> > +#define member_size(type, member) sizeof(((type *)0)->member)
> > +#define sizeof_up_to(type, member) (offsetof(type, member) +
> > member_size(type, member))
> > +
> >  void print_context(int fd, char *text)
> >  {
> >       char *context;
> > @@ -99,3 +102,20 @@ void print_ip_option(int fd, bool ipv4, char
> > *text)
> >               printf("%s No IP Options set\n", text);
> >       }
> >  }
> > +
> > +int set_subscr_events(int fd, int data_io, int association)
> > +{
> > +     struct sctp_event_subscribe subscr_events;
> > +
> > +     memset(&subscr_events, 0, sizeof(subscr_events));
> > +     subscr_events.sctp_data_io_event = data_io;
> > +     subscr_events.sctp_association_event = association;
> > +
> > +     /*
> > +      * Truncate optlen to just the fields we touch to avoid errors
> > when
> > +      * the uapi headers are newer than the running kernel.
> > +      */
> > +     return setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
> > &subscr_events,
> > +                       sizeof_up_to(struct sctp_event_subscribe,
> > +                                    sctp_association_event));
> > +}
> > diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h
> > index d5c1397..351ee37 100644
> > --- a/tests/sctp/sctp_common.h
> > +++ b/tests/sctp/sctp_common.h
> > @@ -25,3 +25,4 @@ void print_context(int fd, char *text);
> >  void print_addr_info(struct sockaddr *sin, char *text);
> >  char *get_ip_option(int fd, bool ipv4, socklen_t *opt_len);
> >  void print_ip_option(int fd, bool ipv4, char *text);
> > +int set_subscr_events(int fd, int data_io, int association);
> > diff --git a/tests/sctp/sctp_peeloff_server.c
> > b/tests/sctp/sctp_peeloff_server.c
> > index 4a5110a..093c6c0 100644
> > --- a/tests/sctp/sctp_peeloff_server.c
> > +++ b/tests/sctp/sctp_peeloff_server.c
> > @@ -16,24 +16,6 @@ static void usage(char *progname)
> >       exit(1);
> >  }
> >
> > -static void set_subscr_events(int fd, int value)
> > -{
> > -     int result;
> > -     struct sctp_event_subscribe subscr_events;
> > -
> > -     memset(&subscr_events, 0, sizeof(subscr_events));
> > -     subscr_events.sctp_association_event = value;
> > -     /* subscr_events.sctp_data_io_event = value; */
> > -
> > -     result = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS,
> > -                         &subscr_events, sizeof(subscr_events));
> > -     if (result < 0) {
> > -             perror("Server setsockopt: SCTP_EVENTS");
> > -             close(fd);
> > -             exit(1);
> > -     }
> > -}
> > -
> >  static sctp_assoc_t handle_event(void *buf)
> >  {
> >       union sctp_notification *snp = buf;
> > @@ -166,7 +148,13 @@ int main(int argc, char **argv)
> >       }
> >
> >       do {
> > -             set_subscr_events(sock, 1); /* Get assoc_id for
> > sctp_peeloff() */
> > +             /* Get assoc_id for sctp_peeloff() */
> > +             result = set_subscr_events(sock, 0, 1);
> > +             if (result < 0) {
> > +                     perror("Server setsockopt: SCTP_EVENTS");
> > +                     close(sock);
> > +                     exit(1);
> > +             }
> >               sinlen = sizeof(sin);
> >               flags = 0;
> >
> > @@ -192,7 +180,7 @@ int main(int argc, char **argv)
> >                               exit(1);
> >                       }
> >                       /* No more notifications */
> > -                     set_subscr_events(sock, 0);
> > +                     set_subscr_events(sock, 0, 0);
> >
> >                       peeloff_sk = sctp_peeloff(sock, assoc_id);
> >                       if (peeloff_sk < 0) {
> > diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c
> > index 4659ed1..7f2cd20 100644
> > --- a/tests/sctp/sctp_server.c
> > +++ b/tests/sctp/sctp_server.c
> > @@ -134,7 +134,7 @@ int main(int argc, char **argv)
> >       }
> >
> >       /* Enables sctp_data_io_events for sctp_recvmsg(3) for
> > assoc_id. */
> > -     result = setsockopt(sock, SOL_SCTP, SCTP_EVENTS, &on,
> > sizeof(on));
> > +     result = set_subscr_events(sock, on, 0);
> >       if (result < 0) {
> >               perror("Server setsockopt: SCTP_EVENTS");
> >               close(sock);
>


-- 
Ondrej Mosnacek <omosnace at redhat dot com>
Software Engineer, Security Technologies
Red Hat, Inc.


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2020-02-24 15:48 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-24 12:47 [PATCH testsuite] tests/sctp: fix setting of the SCTP_EVENTS sockopt Ondrej Mosnacek
2020-02-24 15:23 ` Richard Haines
2020-02-24 15:48   ` Ondrej Mosnacek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).