Author: jhb
Date: Fri Dec  2 19:02:12 2016
New Revision: 309426
URL: https://svnweb.freebsd.org/changeset/base/309426

Log:
  MFC 303753,308004: Add bounds checking on addresses used with /dev/mem.
  
  303753:
  Don't permit mappings of invalid physical addresses on amd64 via /dev/mem.
  
  308004:
  MFamd64: Add bounds checks on addresses used with /dev/mem.
  
  Reject attempts to read from or memory map offsets in /dev/mem that are
  beyond the maximum-supported physical address of the current CPU.

Modified:
  stable/10/sys/amd64/amd64/mem.c
  stable/10/sys/amd64/include/md_var.h
  stable/10/sys/i386/i386/mem.c
  stable/10/sys/i386/include/md_var.h
Directory Properties:
  stable/10/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/11/sys/amd64/amd64/mem.c
  stable/11/sys/i386/i386/mem.c
  stable/11/sys/x86/include/x86_var.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/10/sys/amd64/amd64/mem.c
==============================================================================
--- stable/10/sys/amd64/amd64/mem.c     Fri Dec  2 18:03:15 2016        
(r309425)
+++ stable/10/sys/amd64/amd64/mem.c     Fri Dec  2 19:02:12 2016        
(r309426)
@@ -140,7 +140,7 @@ memrw(struct cdev *dev, struct uio *uio,
                                error = uiomove((void *)vd, c, uio);
                                break;
                        }
-                       if (v >= (1ULL << cpu_maxphyaddr)) {
+                       if (v > cpu_getmaxphyaddr()) {
                                error = EFAULT;
                                break;
                        }
@@ -168,9 +168,11 @@ int
 memmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
     int prot __unused, vm_memattr_t *memattr __unused)
 {
-       if (dev2unit(dev) == CDEV_MINOR_MEM)
+       if (dev2unit(dev) == CDEV_MINOR_MEM) {
+               if (offset > cpu_getmaxphyaddr())
+                       return (-1);
                *paddr = offset;
-       else if (dev2unit(dev) == CDEV_MINOR_KMEM)
+       } else if (dev2unit(dev) == CDEV_MINOR_KMEM)
                *paddr = vtophys(offset);
        /* else panic! */
        return (0);

Modified: stable/10/sys/amd64/include/md_var.h
==============================================================================
--- stable/10/sys/amd64/include/md_var.h        Fri Dec  2 18:03:15 2016        
(r309425)
+++ stable/10/sys/amd64/include/md_var.h        Fri Dec  2 19:02:12 2016        
(r309426)
@@ -89,6 +89,16 @@ struct       fpreg;
 struct  dbreg;
 struct dumperinfo;
 
+/*
+ * Returns the maximum physical address that can be used with the
+ * current system.
+ */
+static __inline vm_paddr_t
+cpu_getmaxphyaddr(void)
+{
+       return ((1ULL << cpu_maxphyaddr) - 1);
+}
+
 void   *alloc_fpusave(int flags);
 void   amd64_syscall(struct thread *td, int traced);
 void   busdma_swi(void);

Modified: stable/10/sys/i386/i386/mem.c
==============================================================================
--- stable/10/sys/i386/i386/mem.c       Fri Dec  2 18:03:15 2016        
(r309425)
+++ stable/10/sys/i386/i386/mem.c       Fri Dec  2 19:02:12 2016        
(r309426)
@@ -108,8 +108,11 @@ memrw(struct cdev *dev, struct uio *uio,
                        continue;
                }
                if (dev2unit(dev) == CDEV_MINOR_MEM) {
-                       pa = uio->uio_offset;
-                       pa &= ~PAGE_MASK;
+                       if (uio->uio_offset > cpu_getmaxphyaddr()) {
+                               error = EFAULT;
+                               break;
+                       }
+                       pa = trunc_page(uio->uio_offset);
                } else {
                        /*
                         * Extract the physical page since the mapping may
@@ -161,9 +164,11 @@ int
 memmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
     int prot __unused, vm_memattr_t *memattr __unused)
 {
-       if (dev2unit(dev) == CDEV_MINOR_MEM)
+       if (dev2unit(dev) == CDEV_MINOR_MEM) {
+               if (offset > cpu_getmaxphyaddr())
+                       return (-1);
                *paddr = offset;
-       else if (dev2unit(dev) == CDEV_MINOR_KMEM)
+       } else if (dev2unit(dev) == CDEV_MINOR_KMEM)
                *paddr = vtophys(offset);
        /* else panic! */
        return (0);

Modified: stable/10/sys/i386/include/md_var.h
==============================================================================
--- stable/10/sys/i386/include/md_var.h Fri Dec  2 18:03:15 2016        
(r309425)
+++ stable/10/sys/i386/include/md_var.h Fri Dec  2 19:02:12 2016        
(r309426)
@@ -96,6 +96,20 @@ struct  dbreg;
 struct dumperinfo;
 struct segment_descriptor;
 
+/*
+ * Returns the maximum physical address that can be used with the
+ * current system.
+ */
+static __inline vm_paddr_t
+cpu_getmaxphyaddr(void)
+{
+#if !defined(PAE)
+       return (0xffffffff);
+#else
+       return ((1ULL << cpu_maxphyaddr) - 1);
+#endif
+}
+
 void   *alloc_fpusave(int flags);
 void   bcopyb(const void *from, void *to, size_t len);
 void   busdma_swi(void);
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to