Fixes CAN-2004 security reports 1016, 1017, and 1068
authorMarc Fiuczynski <mef@cs.princeton.edu>
Wed, 19 Jan 2005 22:42:27 +0000 (22:42 +0000)
committerMarc Fiuczynski <mef@cs.princeton.edu>
Wed, 19 Jan 2005 22:42:27 +0000 (22:42 +0000)
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_edgeport.h
include/linux/socket.h
include/net/af_unix.h
net/core/scm.c
net/unix/af_unix.c

index e727628..87f99a3 100644 (file)
@@ -479,7 +479,7 @@ static void get_boot_desc           (struct edgeport_serial *edge_serial);
 static void load_application_firmware  (struct edgeport_serial *edge_serial);
 
 
-static void unicode_to_ascii           (char *string, short *unicode, int unicode_size);
+static void unicode_to_ascii           (char *string, __le16 *unicode, int unicode_size);
 
 
 
@@ -504,7 +504,7 @@ static void update_edgeport_E2PROM (struct edgeport_serial *edge_serial)
        __u32 BootNewVer;
        __u8 BootMajorVersion;                  
        __u8 BootMinorVersion;                  
-       __u16 BootBuildNumber;
+       __le16 BootBuildNumber;
        __u8 *BootImage;      
        __u32 BootSize;
        struct edge_firmware_image_record *record;
@@ -653,7 +653,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
 
        memset (product_info, 0, sizeof(struct edgeport_product_info));
 
-       product_info->ProductId         = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_GENERATION_2);
+       product_info->ProductId         = (__u16)(edge_serial->serial->dev->descriptor.idProduct & ~ION_DEVICE_ID_80251_NETCHIP);
        product_info->NumPorts          = edge_serial->manuf_descriptor.NumPorts;
        product_info->ProdInfoVer       = 0;
 
@@ -669,7 +669,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
        memcpy(product_info->ManufactureDescDate, edge_serial->manuf_descriptor.DescDate, sizeof(edge_serial->manuf_descriptor.DescDate));
 
        // check if this is 2nd generation hardware
-       if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_GENERATION_2) {
+       if (edge_serial->serial->dev->descriptor.idProduct & ION_DEVICE_ID_80251_NETCHIP) {
                product_info->FirmwareMajorVersion      = OperationalCodeImageVersion_GEN2.MajorVersion;
                product_info->FirmwareMinorVersion      = OperationalCodeImageVersion_GEN2.MinorVersion;
                product_info->FirmwareBuildNumber       = cpu_to_le16(OperationalCodeImageVersion_GEN2.BuildNumber);
@@ -900,12 +900,7 @@ static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs)
 
        if (tty && edge_port->open) {
                /* let the tty driver wakeup if it has a special write_wakeup function */
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) {
-                       (tty->ldisc.write_wakeup)(tty);
-               }
-
-               /* tell the tty driver that something has changed */
-               wake_up_interruptible(&tty->write_wait);
+               tty_wakeup(tty);
        }
 
        // Release the Write URB
@@ -1389,7 +1384,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial, struct edge
        //      to bother queueing a write. If it's too small, say a few bytes,
        //      it's better to wait for more credits so we can do a larger
        //      write.
-       if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits)) {
+       if (edge_port->txCredits < EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(edge_port->maxTxCredits,EDGE_FW_BULK_MAX_PACKET_SIZE)) {
                dbg("%s(%d) Not enough credit - fifo %d TxCredit %d", __FUNCTION__, edge_port->port->number, fifo->count, edge_port->txCredits );
                return;
        }
@@ -2747,12 +2742,15 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio
  *     ASCII range, but it's only for debugging...
  *     NOTE: expects the unicode in LE format
  ****************************************************************************/
-static void unicode_to_ascii (char *string, short *unicode, int unicode_size)
+static void unicode_to_ascii (char *string, __le16 *unicode, int unicode_size)
 {
        int i;
-       for (i = 0; i < unicode_size; ++i) {
+
+       if (unicode_size <= 0)
+               return;
+
+       for (i = 0; i < unicode_size; ++i)
                string[i] = (char)(le16_to_cpu(unicode[i]));
-       }
        string[unicode_size] = 0x00;
 }
 
@@ -3007,9 +3005,6 @@ static void edge_shutdown (struct usb_serial *serial)
 static int __init edgeport_init(void)
 {
        int retval;
-       retval = usb_serial_register(&edgeport_1port_device);
-       if (retval) 
-               goto failed_1port_device_register;
        retval = usb_serial_register(&edgeport_2port_device);
        if (retval)
                goto failed_2port_device_register;
@@ -3031,8 +3026,6 @@ failed_8port_device_register:
 failed_4port_device_register:
        usb_serial_deregister(&edgeport_2port_device);
 failed_2port_device_register:
-       usb_serial_deregister(&edgeport_1port_device);
-failed_1port_device_register:
        return retval;
 }
 
@@ -3045,7 +3038,6 @@ failed_1port_device_register:
 static void __exit edgeport_exit (void)
 {
        usb_deregister (&io_driver);
-       usb_serial_deregister (&edgeport_1port_device);
        usb_serial_deregister (&edgeport_2port_device);
        usb_serial_deregister (&edgeport_4port_device);
        usb_serial_deregister (&edgeport_8port_device);
index 386139d..5112d7a 100644 (file)
@@ -107,11 +107,11 @@ struct edgeport_product_info {
 
        __u8    BootMajorVersion;               /* Boot Firmware version: xx. */
        __u8    BootMinorVersion;               /*                        yy. */
-       __u16   BootBuildNumber;                /*                        zzzz (LE format) */
+       __le16  BootBuildNumber;                /*                        zzzz (LE format) */
 
        __u8    FirmwareMajorVersion;           /* Operational Firmware version:xx. */
        __u8    FirmwareMinorVersion;           /*                              yy. */
-       __u16   FirmwareBuildNumber;            /*                              zzzz (LE format) */
+       __le16  FirmwareBuildNumber;            /*                              zzzz (LE format) */
 
        __u8    ManufactureDescDate[3];         /* MM/DD/YY when descriptor template was compiled */
        __u8    Unused1[1];                     /* Available */
index 602d03b..f30253c 100644 (file)
@@ -90,6 +90,10 @@ struct cmsghdr {
                                  (struct cmsghdr *)(ctl) : \
                                  (struct cmsghdr *)NULL)
 #define CMSG_FIRSTHDR(msg)     __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen)
+#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \
+                            (cmsg)->cmsg_len <= (unsigned long) \
+                            ((mhdr)->msg_controllen - \
+                             ((char *)(cmsg) - (char *)(mhdr)->msg_control)))
 
 /*
  *     This mess will go away with glibc
index 79314ff..621c64f 100644 (file)
@@ -43,16 +43,14 @@ static inline struct sock *first_unix_socket(int *i)
 #define forall_unix_sockets(i, s) \
        for (s = first_unix_socket(&(i)); s; s = next_unix_socket(&(i),(s)))
 
-struct unix_address
-{
+struct unix_address {
        atomic_t        refcnt;
        int             len;
        unsigned        hash;
        struct sockaddr_un name[0];
 };
 
-struct unix_skb_parms
-{
+struct unix_skb_parms {
        struct ucred            creds;          /* Skb credentials      */
        struct scm_fp_list      *fp;            /* Passed files         */
 };
@@ -74,6 +72,7 @@ struct unix_sock {
         struct dentry          *dentry;
         struct vfsmount                *mnt;
         struct semaphore        readsem;
+        struct sock            *peer;
         struct sock            *other;
         struct sock            *gc_tree;
         atomic_t                inflight;
index 3699df3..a2ebf30 100644 (file)
@@ -127,9 +127,7 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
                   for too short ancillary data object at all! Oops.
                   OK, let's add it...
                 */
-               if (cmsg->cmsg_len < sizeof(struct cmsghdr) ||
-                   (unsigned long)(((char*)cmsg - (char*)msg->msg_control)
-                                   + cmsg->cmsg_len) > msg->msg_controllen)
+               if (!CMSG_OK(msg, cmsg))
                        goto error;
 
                if (cmsg->cmsg_level != SOL_SOCKET)
index 08432ce..5deed5c 100644 (file)
@@ -147,7 +147,7 @@ static inline unsigned unix_hash_fold(unsigned hash)
        return hash&(UNIX_HASH_SIZE-1);
 }
 
-#define unix_peer(sk) ((sk)->sk_pair)
+#define unix_peer(sk) (unix_sk(sk)->peer)
 
 static inline int unix_our_peer(struct sock *sk, struct sock *osk)
 {
@@ -483,6 +483,8 @@ static int unix_dgram_recvmsg(struct kiocb *, struct socket *,
                              struct msghdr *, size_t, int);
 static int unix_dgram_connect(struct socket *, struct sockaddr *,
                              int, int);
+static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
+                                 struct msghdr *, size_t);
 
 static struct proto_ops unix_stream_ops = {
        .family =       PF_UNIX,
@@ -541,7 +543,7 @@ static struct proto_ops unix_seqpacket_ops = {
        .shutdown =     unix_shutdown,
        .setsockopt =   sock_no_setsockopt,
        .getsockopt =   sock_no_getsockopt,
-       .sendmsg =      unix_dgram_sendmsg,
+       .sendmsg =      unix_seqpacket_sendmsg,
        .recvmsg =      unix_dgram_recvmsg,
        .mmap =         sock_no_mmap,
        .sendpage =     sock_no_sendpage,
@@ -1378,9 +1380,11 @@ restart:
        if (other->sk_shutdown & RCV_SHUTDOWN)
                goto out_unlock;
 
-       err = security_unix_may_send(sk->sk_socket, other->sk_socket);
-       if (err)
-               goto out_unlock;
+       if (sk->sk_type != SOCK_SEQPACKET) {
+               err = security_unix_may_send(sk->sk_socket, other->sk_socket);
+               if (err)
+                       goto out_unlock;
+       }
 
        if (unix_peer(other) != sk &&
            (skb_queue_len(&other->sk_receive_queue) >
@@ -1530,6 +1534,25 @@ out_err:
        return sent ? : err;
 }
 
+static int unix_seqpacket_sendmsg(struct kiocb *kiocb, struct socket *sock,
+                                 struct msghdr *msg, size_t len)
+{
+       int err;
+       struct sock *sk = sock->sk;
+       
+       err = sock_error(sk);
+       if (err)
+               return err;
+
+       if (sk->sk_state != TCP_ESTABLISHED)
+               return -ENOTCONN;
+
+       if (msg->msg_namelen)
+               msg->msg_namelen = 0;
+
+       return unix_dgram_sendmsg(kiocb, sock, msg, len);
+}
+                                                                                            
 static void unix_copy_addr(struct msghdr *msg, struct sock *sk)
 {
        struct unix_sock *u = unix_sk(sk);
@@ -1559,9 +1582,11 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        msg->msg_namelen = 0;
 
+       down(&u->readsem);
+
        skb = skb_recv_datagram(sk, flags, noblock, &err);
        if (!skb)
-               goto out;
+               goto out_unlock;
 
        wake_up_interruptible(&u->peer_wait);
 
@@ -1611,6 +1636,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
 
 out_free:
        skb_free_datagram(sk,skb);
+out_unlock:
+       up(&u->readsem);
 out:
        return err;
 }