V4L/DVB (5163): Add checks for CAP_SYS_ADMIN to VIDIOC_DBG_G_REGISTER

Before, root privileges were only needed to set hardware registers, not
to read them.  On some hardware, reading from the wrong place at the
wrong time can hang the machine.  So, to be consistent, root privileges
are required to read registers on all hardware.

Signed-off-by: Trent Piepho <xyzzy@speakeasy.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 6515b2a..9235777 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -629,15 +629,6 @@
 	/* ioctls to allow direct access to the
 	 * cx25840 registers for testing */
 	case VIDIOC_DBG_G_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-
-		if (reg->i2c_id != I2C_DRIVERID_CX25840)
-			return -EINVAL;
-		reg->val = cx25840_read(client, reg->reg & 0x0fff);
-		break;
-	}
-
 	case VIDIOC_DBG_S_REGISTER:
 	{
 		struct v4l2_register *reg = arg;
@@ -646,7 +637,10 @@
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = cx25840_read(client, reg->reg & 0x0fff);
+		else
+			cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
 		break;
 	}
 #endif
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index bb6aa13..7177721 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1418,15 +1418,6 @@
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_DBG_G_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-
-		if (reg->i2c_id != I2C_DRIVERID_SAA711X)
-			return -EINVAL;
-		reg->val = saa711x_read(client, reg->reg & 0xff);
-		break;
-	}
-
 	case VIDIOC_DBG_S_REGISTER:
 	{
 		struct v4l2_register *reg = arg;
@@ -1435,7 +1426,10 @@
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = saa711x_read(client, reg->reg & 0xff);
+		else
+			saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 304375ad..bd9c4f3 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -615,15 +615,6 @@
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_DBG_G_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-
-		if (reg->i2c_id != I2C_DRIVERID_SAA7127)
-			return -EINVAL;
-		reg->val = saa7127_read(client, reg->reg & 0xff);
-		break;
-	}
-
 	case VIDIOC_DBG_S_REGISTER:
 	{
 		struct v4l2_register *reg = arg;
@@ -632,7 +623,10 @@
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = saa7127_read(client, reg->reg & 0xff);
+		else
+			saa7127_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 65d4389..886b5df 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -951,15 +951,6 @@
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_DBG_G_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-
-		if (reg->i2c_id != I2C_DRIVERID_TVP5150)
-			return -EINVAL;
-		reg->val = tvp5150_read(c, reg->reg & 0xff);
-		break;
-	}
-
 	case VIDIOC_DBG_S_REGISTER:
 	{
 		struct v4l2_register *reg = arg;
@@ -968,7 +959,10 @@
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = tvp5150_read(c, reg->reg & 0xff);
+		else
+			tvp5150_write(c, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index 0eee82b..b3b5fd5 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -163,26 +163,18 @@
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_DBG_G_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-
-		if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
-			return -EINVAL;
-		reg->val = upd64031a_read(client, reg->reg & 0xff);
-		break;
-	}
-
 	case VIDIOC_DBG_S_REGISTER:
 	{
 		struct v4l2_register *reg = arg;
-		u8 addr = reg->reg & 0xff;
-		u8 val = reg->val & 0xff;
 
 		if (reg->i2c_id != I2C_DRIVERID_UPD64031A)
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		upd64031a_write(client, addr, val);
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = upd64031a_read(client, reg->reg & 0xff);
+		else
+			upd64031a_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 3f0eec0..8852903 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -140,26 +140,18 @@
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	case VIDIOC_DBG_G_REGISTER:
-	{
-		struct v4l2_register *reg = arg;
-
-		if (reg->i2c_id != I2C_DRIVERID_UPD64083)
-			return -EINVAL;
-		reg->val = upd64083_read(client, reg->reg & 0xff);
-		break;
-	}
-
 	case VIDIOC_DBG_S_REGISTER:
 	{
 		struct v4l2_register *reg = arg;
-		u8 addr = reg->reg & 0xff;
-		u8 val = reg->val & 0xff;
 
 		if (reg->i2c_id != I2C_DRIVERID_UPD64083)
 			return -EINVAL;
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		upd64083_write(client, addr, val);
+		if (cmd == VIDIOC_DBG_G_REGISTER)
+			reg->val = upd64083_read(client, reg->reg & 0xff);
+		else
+			upd64083_write(client, reg->reg & 0xff, reg->val & 0xff);
 		break;
 	}
 #endif
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index b6fabee..6a61ebc 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -520,25 +520,6 @@
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 		/* ioctls to allow direct acces to the NT100x registers */
 		case VIDIOC_DBG_G_REGISTER:
-		{
-			struct v4l2_register *reg = arg;
-			int errCode;
-
-			if (reg->i2c_id != 0)
-				return -EINVAL;
-			/* NT100x has a 8-bit register space */
-			errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
-			if (errCode < 0) {
-				err("%s: VIDIOC_DBG_G_REGISTER failed: error %d", __FUNCTION__, errCode);
-			}
-			else {
-				reg->val=(unsigned char)errCode;
-				PDEBUG(DBG_IOCTL, "VIDIOC_DBG_G_REGISTER reg=0x%02X, value=0x%02X",
-							(unsigned int)reg->reg, reg->val);
-				errCode = 0; // No error
-			}
-			return errCode;
-		}
 		case VIDIOC_DBG_S_REGISTER:
 		{
 			struct v4l2_register *reg = arg;
@@ -548,15 +529,22 @@
 				return -EINVAL;
 			if (!capable(CAP_SYS_ADMIN))
 				return -EPERM;
-			errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
+			/* NT100x has a 8-bit register space */
+			if (cmd == VIDIOC_DBG_G_REGISTER)
+				errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
+			else
+				errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
 			if (errCode < 0) {
-				err("%s: VIDIOC_DBG_S_REGISTER failed: error %d", __FUNCTION__, errCode);
+				err("%s: VIDIOC_DBG_%c_REGISTER failed: error %d", __FUNCTION__,
+				    cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S', errCode);
+				return errCode;
 			}
-			else {
-				PDEBUG(DBG_IOCTL, "VIDIOC_DBG_S_REGISTER reg=0x%02X, value=0x%02X",
-							(unsigned int)reg->reg, reg->val);
-				errCode = 0;
-			}
+			if (cmd == VIDIOC_DBG_S_REGISTER)
+				reg->val = (u8)errCode;
+
+			PDEBUG(DBG_IOCTL, "VIDIOC_DBG_%c_REGISTER reg=0x%02X, value=0x%02X",
+			       cmd == VIDIOC_DBG_G_REGISTER ? 'G' : 'S',
+			       (unsigned int)reg->reg, reg->val);
 			return 0;
 		}
 #endif
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 764a53b..dc9b1ef 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -1457,7 +1457,9 @@
 	case VIDIOC_DBG_G_REGISTER:
 	{
 		struct v4l2_register *p=arg;
-		if (vfd->vidioc_g_register)
+		if (!capable(CAP_SYS_ADMIN))
+			ret=-EPERM;
+		else if (vfd->vidioc_g_register)
 			ret=vfd->vidioc_g_register(file, fh, p);
 		break;
 	}