aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2016-03-22 19:03:59 -0400
committerTakashi Iwai <tiwai@suse.de>2016-03-23 03:06:16 -0400
commit91d2178e26fdc806f33063f9df5904a48e3b6aeb (patch)
treebba54fcb578a5fc30a8b4f953cf2e98d628786da
parentc64c1437afb14ebc900e40910f31ffb20bf652ad (diff)
ALSA: timer: fix gparams ioctl compatibility for different architectures
'struct snd_timer_gparams' includes some members with 'unsigned long', therefore its size differs depending on data models of architecture. As a result, x86/x32 applications fail to execute ioctl(2) with SNDRV_TIMER_GPARAMS command on x86_64 machine. This commit fixes this bug by adding a pair of structure and ioctl command for the compatibility. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/core/timer.c20
-rw-r--r--sound/core/timer_compat.c30
2 files changed, 42 insertions, 8 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c
index aa1b15c155d1..ea4d999113ef 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -1502,17 +1502,13 @@ static int snd_timer_user_ginfo(struct file *file,
1502 return err; 1502 return err;
1503} 1503}
1504 1504
1505static int snd_timer_user_gparams(struct file *file, 1505static int timer_set_gparams(struct snd_timer_gparams *gparams)
1506 struct snd_timer_gparams __user *_gparams)
1507{ 1506{
1508 struct snd_timer_gparams gparams;
1509 struct snd_timer *t; 1507 struct snd_timer *t;
1510 int err; 1508 int err;
1511 1509
1512 if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
1513 return -EFAULT;
1514 mutex_lock(&register_mutex); 1510 mutex_lock(&register_mutex);
1515 t = snd_timer_find(&gparams.tid); 1511 t = snd_timer_find(&gparams->tid);
1516 if (!t) { 1512 if (!t) {
1517 err = -ENODEV; 1513 err = -ENODEV;
1518 goto _error; 1514 goto _error;
@@ -1525,12 +1521,22 @@ static int snd_timer_user_gparams(struct file *file,
1525 err = -ENOSYS; 1521 err = -ENOSYS;
1526 goto _error; 1522 goto _error;
1527 } 1523 }
1528 err = t->hw.set_period(t, gparams.period_num, gparams.period_den); 1524 err = t->hw.set_period(t, gparams->period_num, gparams->period_den);
1529_error: 1525_error:
1530 mutex_unlock(&register_mutex); 1526 mutex_unlock(&register_mutex);
1531 return err; 1527 return err;
1532} 1528}
1533 1529
1530static int snd_timer_user_gparams(struct file *file,
1531 struct snd_timer_gparams __user *_gparams)
1532{
1533 struct snd_timer_gparams gparams;
1534
1535 if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
1536 return -EFAULT;
1537 return timer_set_gparams(&gparams);
1538}
1539
1534static int snd_timer_user_gstatus(struct file *file, 1540static int snd_timer_user_gstatus(struct file *file,
1535 struct snd_timer_gstatus __user *_gstatus) 1541 struct snd_timer_gstatus __user *_gstatus)
1536{ 1542{
diff --git a/sound/core/timer_compat.c b/sound/core/timer_compat.c
index 2e908225d754..6a437eb66115 100644
--- a/sound/core/timer_compat.c
+++ b/sound/core/timer_compat.c
@@ -22,6 +22,19 @@
22 22
23#include <linux/compat.h> 23#include <linux/compat.h>
24 24
25/*
26 * ILP32/LP64 has different size for 'long' type. Additionally, the size
27 * of storage alignment differs depending on architectures. Here, '__packed'
28 * qualifier is used so that the size of this structure is multiple of 4 and
29 * it fits to any architectures with 32 bit storage alignment.
30 */
31struct snd_timer_gparams32 {
32 struct snd_timer_id tid;
33 u32 period_num;
34 u32 period_den;
35 unsigned char reserved[32];
36} __packed;
37
25struct snd_timer_info32 { 38struct snd_timer_info32 {
26 u32 flags; 39 u32 flags;
27 s32 card; 40 s32 card;
@@ -32,6 +45,19 @@ struct snd_timer_info32 {
32 unsigned char reserved[64]; 45 unsigned char reserved[64];
33}; 46};
34 47
48static int snd_timer_user_gparams_compat(struct file *file,
49 struct snd_timer_gparams32 __user *user)
50{
51 struct snd_timer_gparams gparams;
52
53 if (copy_from_user(&gparams.tid, &user->tid, sizeof(gparams.tid)) ||
54 get_user(gparams.period_num, &user->period_num) ||
55 get_user(gparams.period_den, &user->period_den))
56 return -EFAULT;
57
58 return timer_set_gparams(&gparams);
59}
60
35static int snd_timer_user_info_compat(struct file *file, 61static int snd_timer_user_info_compat(struct file *file,
36 struct snd_timer_info32 __user *_info) 62 struct snd_timer_info32 __user *_info)
37{ 63{
@@ -99,6 +125,7 @@ static int snd_timer_user_status_compat(struct file *file,
99 */ 125 */
100 126
101enum { 127enum {
128 SNDRV_TIMER_IOCTL_GPARAMS32 = _IOW('T', 0x04, struct snd_timer_gparams32),
102 SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32), 129 SNDRV_TIMER_IOCTL_INFO32 = _IOR('T', 0x11, struct snd_timer_info32),
103 SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32), 130 SNDRV_TIMER_IOCTL_STATUS32 = _IOW('T', 0x14, struct snd_timer_status32),
104#ifdef CONFIG_X86_X32 131#ifdef CONFIG_X86_X32
@@ -114,7 +141,6 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
114 case SNDRV_TIMER_IOCTL_PVERSION: 141 case SNDRV_TIMER_IOCTL_PVERSION:
115 case SNDRV_TIMER_IOCTL_TREAD: 142 case SNDRV_TIMER_IOCTL_TREAD:
116 case SNDRV_TIMER_IOCTL_GINFO: 143 case SNDRV_TIMER_IOCTL_GINFO:
117 case SNDRV_TIMER_IOCTL_GPARAMS:
118 case SNDRV_TIMER_IOCTL_GSTATUS: 144 case SNDRV_TIMER_IOCTL_GSTATUS:
119 case SNDRV_TIMER_IOCTL_SELECT: 145 case SNDRV_TIMER_IOCTL_SELECT:
120 case SNDRV_TIMER_IOCTL_PARAMS: 146 case SNDRV_TIMER_IOCTL_PARAMS:
@@ -128,6 +154,8 @@ static long snd_timer_user_ioctl_compat(struct file *file, unsigned int cmd, uns
128 case SNDRV_TIMER_IOCTL_PAUSE_OLD: 154 case SNDRV_TIMER_IOCTL_PAUSE_OLD:
129 case SNDRV_TIMER_IOCTL_NEXT_DEVICE: 155 case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
130 return snd_timer_user_ioctl(file, cmd, (unsigned long)argp); 156 return snd_timer_user_ioctl(file, cmd, (unsigned long)argp);
157 case SNDRV_TIMER_IOCTL_GPARAMS32:
158 return snd_timer_user_gparams_compat(file, argp);
131 case SNDRV_TIMER_IOCTL_INFO32: 159 case SNDRV_TIMER_IOCTL_INFO32:
132 return snd_timer_user_info_compat(file, argp); 160 return snd_timer_user_info_compat(file, argp);
133 case SNDRV_TIMER_IOCTL_STATUS32: 161 case SNDRV_TIMER_IOCTL_STATUS32: