This patch prevents an OOPS when you pass a NULL buffer address
to recvfrom().  The __copy_user() was not protecting a stq with an
exception
table entry so when it chewed on a bad address the kernel did an OOPS
instead of properly handling the fault.

Attached is:  1.) the one-line kernel patch,  2.) the server that passes
the
NULL buffer to recvfrom(), and 3.) the client that sends junk to the
server.

To recreate the problem run the server in the background then run the
client.  The server will OOPS without the patch.


Larry Woodman
http://www.missioncriticallinux.com


diff -u --recursive linux-2.3.99-pre3.vanilla/arch/alpha/lib/copy_user.S 
linux/arch/alpha/lib/copy_user.S
--- linux-2.3.99-pre3.vanilla/arch/alpha/lib/copy_user.S        Fri Apr 30 11:22:19 
1999
+++ linux/arch/alpha/lib/copy_user.S    Mon Apr 27 08:11:24 2020
@@ -80,7 +80,7 @@
        extql $3,$7,$3
        extqh $2,$7,$1
        bis $3,$1,$1
-       stq $1,0($6)
+       EXO( stq $1,0($6) )
        addq $7,8,$7
        subq $0,8,$0
        addq $6,8,$6
#include <unistd.h> 
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <errno.h> 
#include <getopt.h>

#define BUFLEN  8192

/* defaults */
int     port = 1300;

main()
{
        int                     sock, bytes;
        struct sockaddr_in      s;
        char                    *buf[BUFLEN];

        sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (sock < 0) {
                perror("socket");
                exit(1);
        }
        bzero((void*)&s, sizeof(s));
        s.sin_family = AF_INET; 
        s.sin_port = htons(port);
        s.sin_addr.s_addr = INADDR_ANY;

        if (bind(sock, (struct sockaddr*)&s, sizeof(s)) < 0) {
                perror("bind");
                exit(2);
        }
        if ((bytes = recvfrom(sock, NULL, BUFLEN, 0, NULL, NULL)) < 0) {
                perror("recvfrom");
                exit(4);
        }  
        printf("recvfrom returned %d bytes\n", bytes);

        exit(0);        
        

}

#include <unistd.h> 
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <errno.h> 
#include <getopt.h>

#define BUFLEN  8192

/* defaults */
int     port = 1300;
char    *buf = "abcdefghijklmnopqrstuvwxyz";

main()
{
        int                     sock, bytes;
        struct sockaddr_in      to;

        sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (sock < 0) {
                perror("socket");
                exit(1);
        }
        bzero((void*)&to, sizeof(to));
        to.sin_family = AF_INET; 
        to.sin_port = htons(port);
        to.sin_addr.s_addr = inet_addr("127.0.0.1");

        if ((bytes = sendto(sock, buf, strlen(buf), 0, &to, sizeof(to))) < 0) {
                perror("sendto");
                exit(4);
        }  
        printf("sendto returned %d bytes\n", bytes);

        exit(0);        
}

Reply via email to