lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20140509191914.GA7286@jtriplet-mobl1>
Date:	Fri, 9 May 2014 12:19:16 -0700
From:	Josh Triplett <josh@...htriplett.org>
To:	Arnd Bergmann <arnd@...db.de>,
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
	akpm@...ux-foundation.org, linux-kernel@...r.kernel.org,
	linux-api@...r.kernel.org
Subject: [PATCH] drivers/char/mem.c: Add /dev/ioports, supporting 16-bit and
 32-bit ports

/dev/port only supports reading and writing 8-bit ports; multi-byte
operations on /dev/port will just operate on multiple successive 8-bit
ports.

Add a new device, /dev/ioports, which supports reading and writing
16-bit and 32-bit ports.  This makes it possible to perform arbitrary
I/O port operations cleanly from privileged userspace processes, without
using iopl or ioperm.

Signed-off-by: Josh Triplett <josh@...htriplett.org>
---

Written after encountering yet another out-of-tree omnibus "do arbitrary
I/O for test purposes" driver; this one's main reason for existence was
the inability to operate on 16-bit and 32-bit I/O ports.  Let's get a
proper interface into the kernel, to make such drivers obsolete.

I've also written a corresponding manpage patch, which I'll submit as a
reply to this one.

 drivers/char/mem.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 77 insertions(+), 2 deletions(-)

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 917403f..84e0526 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -35,6 +35,7 @@
 #endif
 
 #define DEVPORT_MINOR	4
+#define DEVIOPORTS_MINOR	12
 
 static inline unsigned long size_inside_page(unsigned long start,
 					     unsigned long size)
@@ -584,6 +585,69 @@ static ssize_t write_port(struct file *file, const char __user *buf,
 	*ppos = i;
 	return tmp-buf;
 }
+
+static ssize_t read_ioports(struct file *file, char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long port = *ppos;
+
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+	if (port > 65535)
+		return 0;
+	switch (count) {
+	case 1:
+		if (__put_user(inb(port), buf) < 0)
+			return -EFAULT;
+		return 1;
+	case 2:
+		if (__put_user(inw(port), buf) < 0)
+			return -EFAULT;
+		return 2;
+	case 4:
+		if (__put_user(inl(port), buf) < 0)
+			return -EFAULT;
+		return 4;
+	default:
+		return -EINVAL;
+	}
+}
+
+static ssize_t write_ioports(struct file *file, const char __user *buf,
+			     size_t count, loff_t *ppos)
+{
+	unsigned long port = *ppos;
+
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;
+	if (port > 65535)
+		return 0;
+	switch (count) {
+	case 1: {
+		u8 b;
+		if (__get_user(b, buf))
+			return -EFAULT;
+		outb(b, port);
+		return 1;
+	}
+	case 2: {
+		u16 w;
+		if (__get_user(w, buf))
+			return -EFAULT;
+		outw(w, port);
+		return 2;
+	}
+	case 4: {
+		u32 l;
+		if (__get_user(l, buf))
+			return -EFAULT;
+		outl(l, port);
+		return 4;
+	}
+	default:
+		return -EINVAL;
+	}
+}
 #endif
 
 static ssize_t read_null(struct file *file, char __user *buf,
@@ -779,6 +843,13 @@ static const struct file_operations port_fops = {
 	.write		= write_port,
 	.open		= open_port,
 };
+
+static const struct file_operations ioports_fops = {
+	.llseek		= memory_lseek,
+	.read		= read_ioports,
+	.write		= write_ioports,
+	.open		= open_port,
+};
 #endif
 
 static const struct file_operations zero_fops = {
@@ -827,6 +898,9 @@ static const struct memdev {
 #ifdef CONFIG_PRINTK
 	[11] = { "kmsg", 0644, &kmsg_fops, NULL },
 #endif
+#ifdef CONFIG_DEVPORT
+	 [12] = { "ioports", 0, &ioports_fops, NULL },
+#endif
 };
 
 static int memory_open(struct inode *inode, struct file *filp)
@@ -892,9 +966,10 @@ static int __init chr_dev_init(void)
 			continue;
 
 		/*
-		 * Create /dev/port?
+		 * Create /dev/port and /dev/ioports?
 		 */
-		if ((minor == DEVPORT_MINOR) && !arch_has_dev_port())
+		if ((minor == DEVPORT_MINOR || minor == DEVIOPORTS_MINOR)
+		    && !arch_has_dev_port())
 			continue;
 
 		device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
-- 
2.0.0.rc2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ