Commit message: V4L/DVB (9624): CVE-2008-5033: fix OOPS on tvaudio when controlling bass/treble

This bug were supposed to be fixed by 5ba2f67afb02c5302b2898949ed6fc3b3d37dcf1,
where a call to NULL happens.

Not all tvaudio chips allow controlling bass/treble. So, the driver
has a table with a flag to indicate if the chip does support it.

Unfortunately, the handling of this logic were broken for a very long
time (probably since the first module version). Due to that, an OOPS
were generated for devices that don't support bass/treble.

This were the resulting OOPS message before the patch, with debug messages
enabled:

tvaudio' 1-005b: VIDIOC_S_CTRL
BUG: unable to handle kernel NULL pointer dereference at 00000000
IP: [<00000000>]
*pde = 22fda067 *pte = 00000000
Oops: 0000 [#1] SMP
Modules linked in: snd_hda_intel snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device
snd_pcm_oss snd_mixer_oss snd_pcm snd_timer snd_hwdep snd soundcore tuner_simple tuner_types tea5767 tuner
tvaudio bttv bridgebnep rfcomm l2cap bluetooth it87 hwmon_vid hwmon fuse sunrpc ipt_REJECT
nf_conntrack_ipv4 iptable_filter ip_tables ip6t_REJECT xt_tcpudp nf_conntrack_ipv6 xt_state nf_conntrack
ip6table_filter ip6_tables x_tables ipv6 dm_mirrordm_multipath dm_mod configfs videodev v4l1_compat
ir_common 8139cp compat_ioctl32 v4l2_common 8139too videobuf_dma_sg videobuf_core mii btcx_risc tveeprom
i915 button snd_page_alloc serio_raw drm pcspkr i2c_algo_bit i2c_i801 i2c_core iTCO_wdt
iTCO_vendor_support sr_mod cdrom sg ata_generic pata_acpi ata_piix libata sd_mod scsi_mod ext3 jbdmbcache
uhci_hcd ohci_hcd ehci_hcd [last unloaded: soundcore]

Pid: 15413, comm: qv4l2 Not tainted (2.6.25.14-108.fc9.i686 #1)
EIP: 0060:[<00000000>] EFLAGS: 00210246 CPU: 0
EIP is at 0x0
EAX: 00008000 EBX: ebd21600 ECX: e2fd9ec4 EDX: 00200046
ESI: f8c0f0c4 EDI: f8c0f0c4 EBP: e2fd9d50 ESP: e2fd9d2c
 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068
Process qv4l2 (pid: 15413, ti=e2fd9000 task=ebe44000 task.ti=e2fd9000)
Stack: f8c0c6ae e2ff2a00 00000d00 e2fd9ec4 ebc4e000 e2fd9d5c f8c0c448 00000000
       f899c12a e2fd9d5c f899c154 e2fd9d68 e2fd9d80 c0560185 e2fd9d88 f8f3e1d8
       f8f3e1dc ebc4e034 f8f3e18c e2fd9ec4 00000000 e2fd9d90 f899c286 c008561c
Call Trace:
 [<f8c0c6ae>] ? chip_command+0x266/0x4b6 [tvaudio]
 [<f8c0c448>] ? chip_command+0x0/0x4b6 [tvaudio]
 [<f899c12a>] ? i2c_cmd+0x0/0x2f [i2c_core]
 [<f899c154>] ? i2c_cmd+0x2a/0x2f [i2c_core]
 [<c0560185>] ? device_for_each_child+0x21/0x49
 [<f899c286>] ? i2c_clients_command+0x1c/0x1e [i2c_core]
 [<f8f283d8>] ? bttv_call_i2c_clients+0x14/0x16 [bttv]
 [<f8f23601>] ? bttv_s_ctrl+0x1bc/0x313 [bttv]
 [<f8f23445>] ? bttv_s_ctrl+0x0/0x313 [bttv]
 [<f8b6096d>] ? __video_do_ioctl+0x1f84/0x3726 [videodev]
 [<c05abb4e>] ? sock_aio_write+0x100/0x10d
 [<c041b23e>] ? kmap_atomic_prot+0x1dd/0x1df
 [<c043a0c9>] ? enqueue_hrtimer+0xc2/0xcd
 [<c04f4fa4>] ? copy_from_user+0x39/0x121
 [<f8b622b9>] ? __video_ioctl2+0x1aa/0x24a [videodev]
 [<c04054fd>] ? do_notify_resume+0x768/0x795
 [<c043c0f7>] ? getnstimeofday+0x34/0xd1
 [<c0437b77>] ? autoremove_wake_function+0x0/0x33
 [<f8b62368>] ? video_ioctl2+0xf/0x13 [videodev]
 [<c048c6f0>] ? vfs_ioctl+0x50/0x69
 [<c048c942>] ? do_vfs_ioctl+0x239/0x24c
 [<c048c995>] ? sys_ioctl+0x40/0x5b
 [<c0405bf2>] ? syscall_call+0x7/0xb
 [<c0620000>] ? cpuid4_cache_sysfs_exit+0x3d/0x69
 =======================
Code:  Bad EIP value.
EIP: [<00000000>] 0x0 SS:ESP 0068:e2fd9d2c

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
CVE: CVE-2008-5033
CWE: CWE-399
Vulnerability description: The chip_command function in drivers/media/video/tvaudio.c in the Linux kernel 2.6.25.x before 2.6.25.19, 2.6.26.x before 2.6.26.7, and 2.6.27.x before 2.6.27.3 allows attackers to cause a denial of service (NULL function pointer dereference and OOPS) via unknown vectors.

Project: linux-2.6

static int chip_command(struct i2c_client *client,
			unsigned int cmd, void *arg)
{
	struct CHIPSTATE *chip = i2c_get_clientdata(client);
	struct CHIPDESC  *desc = chip->desc;

	if (debug > 0) {
		v4l_i2c_print_ioctl(chip->c, cmd);
		printk("\n");
	}

	switch (cmd) {
	case AUDC_SET_RADIO:
		chip->radio = 1;
		chip->watch_stereo = 0;
		/* del_timer(&chip->wt); */
		break;
	/* --- v4l ioctls --- */
	/* take care: bttv does userspace copying, we'll get a
	kernel pointer here... */
	case VIDIOC_QUERYCTRL:
	{
		struct v4l2_queryctrl *qc = arg;

		switch (qc->id) {
			case V4L2_CID_AUDIO_MUTE:
				break;
			case V4L2_CID_AUDIO_VOLUME:
			case V4L2_CID_AUDIO_BALANCE:
				if (!(desc->flags & CHIP_HAS_VOLUME))
					return -EINVAL;
				break;
			case V4L2_CID_AUDIO_BASS:
			case V4L2_CID_AUDIO_TREBLE:
				if (desc->flags & CHIP_HAS_BASSTREBLE)
					return -EINVAL;
				break;
			default:
				return -EINVAL;
		}
		return v4l2_ctrl_query_fill_std(qc);
	}
	case VIDIOC_S_CTRL:
		return tvaudio_set_ctrl(chip, arg);

	case VIDIOC_G_CTRL:
		return tvaudio_get_ctrl(chip, arg);
	case VIDIOC_INT_G_AUDIO_ROUTING:
	{
		struct v4l2_routing *rt = arg;

		rt->input = chip->input;
		rt->output = 0;
		break;
	}
	case VIDIOC_INT_S_AUDIO_ROUTING:
	{
		struct v4l2_routing *rt = arg;

		if (!(desc->flags & CHIP_HAS_INPUTSEL) || rt->input >= 4)
				return -EINVAL;
		/* There are four inputs: tuner, radio, extern and intern. */
		chip->input = rt->input;
		if (chip->muted)
			break;
		chip_write_masked(chip, desc->inputreg,
				desc->inputmap[chip->input], desc->inputmask);
		break;
	}
	case VIDIOC_S_TUNER:
	{
		struct v4l2_tuner *vt = arg;
		int mode = 0;

		if (chip->radio)
			break;
		switch (vt->audmode) {
		case V4L2_TUNER_MODE_MONO:
		case V4L2_TUNER_MODE_STEREO:
		case V4L2_TUNER_MODE_LANG1:
		case V4L2_TUNER_MODE_LANG2:
			mode = vt->audmode;
			break;
		case V4L2_TUNER_MODE_LANG1_LANG2:
			mode = V4L2_TUNER_MODE_STEREO;
			break;
		default:
			return -EINVAL;
		}
		chip->audmode = vt->audmode;

		if (desc->setmode && mode) {
			chip->watch_stereo = 0;
			/* del_timer(&chip->wt); */
			chip->mode = mode;
			desc->setmode(chip, mode);
		}
		break;
	}
	case VIDIOC_G_TUNER:
	{
		struct v4l2_tuner *vt = arg;
		int mode = V4L2_TUNER_MODE_MONO;

		if (chip->radio)
			break;
		vt->audmode = chip->audmode;
		vt->rxsubchans = 0;
		vt->capability = V4L2_TUNER_CAP_STEREO |
			V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;

		if (desc->getmode)
			mode = desc->getmode(chip);

		if (mode & V4L2_TUNER_MODE_MONO)
			vt->rxsubchans |= V4L2_TUNER_SUB_MONO;
		if (mode & V4L2_TUNER_MODE_STEREO)
			vt->rxsubchans |= V4L2_TUNER_SUB_STEREO;
		/* Note: for SAP it should be mono/lang2 or stereo/lang2.
		   When this module is converted fully to v4l2, then this
		   should change for those chips that can detect SAP. */
		if (mode & V4L2_TUNER_MODE_LANG1)
			vt->rxsubchans = V4L2_TUNER_SUB_LANG1 |
					 V4L2_TUNER_SUB_LANG2;
		break;
	}
	case VIDIOC_S_STD:
		chip->radio = 0;
		break;
	case VIDIOC_S_FREQUENCY:
		chip->mode = 0; /* automatic */

		/* For chips that provide getmode and setmode, and doesn't
		   automatically follows the stereo carrier, a kthread is
		   created to set the audio standard. In this case, when then
		   the video channel is changed, tvaudio starts on MONO mode.
		   After waiting for 2 seconds, the kernel thread is called,
		   to follow whatever audio standard is pointed by the
		   audio carrier.
		 */
		if (chip->thread) {
			desc->setmode(chip,V4L2_TUNER_MODE_MONO);
			if (chip->prevmode != V4L2_TUNER_MODE_MONO)
				chip->prevmode = -1; /* reset previous mode */
			mod_timer(&chip->wt, jiffies+msecs_to_jiffies(2000));
		}
		break;

	case VIDIOC_G_CHIP_IDENT:
		return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_TVAUDIO, 0);
	}
	return 0;
}