On Thu, Nov 11, 2021 at 03:21:45PM +0100, Alexander Bluhm wrote:
> On Thu, Nov 11, 2021 at 12:09:41PM +0300, Vitaliy Makkoveev wrote:
> > Can I propose to commit this diff before? It reorders soclose() to
> > destroy PCB before `so_q0' and `so_q' cleanup.
> 
> OK bluhm@
> 
> > Also the tool to test the diff:
> 
> What happens when you run the tool with the current code?  Does the
> kernel crash?  Are there some inconsistencies that userland could
> detect?
> 
> If yes, we could convert it to a regress test.
> 

All fine with the current code. I wrote this to check that nothing
changes with the diff.

> bluhm
> 
> > #include <sys/types.h>
> > #include <sys/socket.h>
> > #include <sys/un.h>
> > #include <stdio.h>
> > #include <stdlib.h>
> > #include <err.h>
> > #include <pthread.h>
> > #include <string.h>
> > #include <unistd.h>
> > 
> > #include <arpa/inet.h>
> > #include <netinet/in.h>
> > 
> > #define NTHR (10)
> > #define NCONNECT (10)
> > #define NACCEPT ((NTHR * NCONNECT) / 2)
> > 
> > static void *
> > thr_conn(void *arg)
> > {
> >     struct sockaddr_storage *ss = arg;
> >     int s[NCONNECT];
> >     size_t hd = 0, tl = 0;
> > 
> >     while (1) {
> >             if ((s[hd] = socket(ss->ss_family, SOCK_STREAM, 0)) < 0)
> >                     continue;
> > 
> >             if (connect(s[hd], (struct sockaddr *)ss, ss->ss_len) < 0) {
> >                     close(s[hd]);
> >                     continue;
> >             }
> > 
> >             if ((hd = (hd + 1) % NCONNECT) == tl) {
> >                     close(s[tl]);
> >                     tl = (tl + 1) % NCONNECT;
> >             }
> >     }
> > 
> >     return NULL;
> > }
> > 
> > static void
> > usage(void)
> > {
> >     extern char *__progname;
> > 
> >     fprintf(stderr, "Usage %s: unix | inet | inet6\n", __progname);
> >     exit(1);
> > }
> > 
> > int
> > main(int argc, char *argv[])
> > {
> >     struct sockaddr_storage ss;
> >     size_t i;
> >     int s;
> > 
> >     if (argc != 2) {
> >             usage();
> >     }
> > 
> >     memset(&ss, 0, sizeof(ss));
> > 
> >     if (strcmp(argv[1], "unix") == 0) {
> >             struct sockaddr_un *sun;
> > 
> >             sun = (struct sockaddr_un *)&ss;
> >             sun->sun_len = sizeof(*sun);
> >             sun->sun_family = AF_UNIX;
> >             snprintf(sun->sun_path, sizeof(sun->sun_path) - 1,
> >                     "/tmp/socket%d", getpid());
> >     } else if (strcmp(argv[1], "inet") == 0) {
> >             struct sockaddr_in *sin;
> > 
> >             sin = (struct sockaddr_in *)&ss;
> >             sin->sin_len = sizeof(*sin);
> >             sin->sin_family = AF_INET;
> >             sin->sin_port = htons(10000+(getpid()%10000));
> >             if (inet_pton(AF_INET, "127.0.0.1", &sin->sin_addr) <= 0)
> >                     errx(1, "inet_pton()");
> >     } else if (strcmp(argv[1], "inet6") == 0) {
> >             struct sockaddr_in6 *sin6;
> > 
> >             sin6 = (struct sockaddr_in6 *)&ss;
> >             sin6->sin6_len = sizeof(*sin6);
> >             sin6->sin6_family = AF_INET6;
> >             sin6->sin6_port = htons(10000+(getpid()%10000));
> >             if (inet_pton(AF_INET6, "::1", &sin6->sin6_addr) <= 0)
> >                     errx(1, "inet_pton()");
> >     } else
> >             usage();
> > 
> >     for (i = 0; i < NTHR; ++i) {
> >             pthread_t thr;
> >             int error;
> > 
> >             if ((error = pthread_create(&thr, NULL, thr_conn, &ss)))
> >                     errc(1, error, "pthread_create()");
> >     }
> > 
> >     while(1) {
> >             int conns[NACCEPT];
> > 
> >             if ((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
> >                     err(1, "socket()");
> > 
> >             if (ss.ss_family == AF_UNIX) {
> >                     struct sockaddr_un *sun = (struct sockaddr_un *)&ss;
> >                     unlink(sun->sun_path);
> >             } else {
> >                     int opt = 1;
> > 
> >                     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
> >                         &opt, sizeof(opt)) < 0)
> >                             err(1, "setsockopt()");
> >             }
> > 
> >             if (bind(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
> >                     err(1, "bind()");
> > 
> >             if (listen(s, 10) < 0)
> >                     err(1, "listen()");
> > 
> >             for(i=0; i < NACCEPT; ++i) {
> >                     if ((conns[i] = accept(s, NULL, NULL)) < 0)
> >                             err(1, "accept()");
> >             }
> > 
> >             close(s);
> > 
> >             for(i=0; i < NACCEPT; ++i) {
> >                     close(conns[i]);
> >             }
> >     }
> > 
> >     return 0;
> > }
> > 
> > Index: sys/kern/uipc_socket.c
> > ===================================================================
> > RCS file: /cvs/src/sys/kern/uipc_socket.c,v
> > retrieving revision 1.267
> > diff -u -p -r1.267 uipc_socket.c
> > --- sys/kern/uipc_socket.c  24 Oct 2021 07:02:47 -0000      1.267
> > +++ sys/kern/uipc_socket.c  11 Nov 2021 08:56:17 -0000
> > @@ -322,19 +322,9 @@ soclose(struct socket *so, int flags)
> >     s = solock(so);
> >     /* Revoke async IO early. There is a final revocation in sofree(). */
> >     sigio_free(&so->so_sigio);
> > -   if (so->so_options & SO_ACCEPTCONN) {
> > -           while ((so2 = TAILQ_FIRST(&so->so_q0)) != NULL) {
> > -                   (void) soqremque(so2, 0);
> > -                   (void) soabort(so2);
> > -           }
> > -           while ((so2 = TAILQ_FIRST(&so->so_q)) != NULL) {
> > -                   (void) soqremque(so2, 1);
> > -                   (void) soabort(so2);
> > -           }
> > -   }
> > -   if (so->so_pcb == NULL)
> > -           goto discard;
> >     if (so->so_state & SS_ISCONNECTED) {
> > +           if (so->so_pcb == NULL)
> > +                   goto discard;
> >             if ((so->so_state & SS_ISDISCONNECTING) == 0) {
> >                     error = sodisconnect(so);
> >                     if (error)
> > @@ -360,6 +350,16 @@ drop:
> >             error2 = (*so->so_proto->pr_detach)(so);
> >             if (error == 0)
> >                     error = error2;
> > +   }
> > +   if (so->so_options & SO_ACCEPTCONN) {
> > +           while ((so2 = TAILQ_FIRST(&so->so_q0)) != NULL) {
> > +                   (void) soqremque(so2, 0);
> > +                   (void) soabort(so2);
> > +           }
> > +           while ((so2 = TAILQ_FIRST(&so->so_q)) != NULL) {
> > +                   (void) soqremque(so2, 1);
> > +                   (void) soabort(so2);
> > +           }
> >     }
> >  discard:
> >     if (so->so_state & SS_NOFDREF)

Reply via email to