diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2016-03-22 19:03:59 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2016-03-23 03:06:16 -0400 |
commit | 91d2178e26fdc806f33063f9df5904a48e3b6aeb (patch) | |
tree | bba54fcb578a5fc30a8b4f953cf2e98d628786da | |
parent | c64c1437afb14ebc900e40910f31ffb20bf652ad (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.c | 20 | ||||
-rw-r--r-- | sound/core/timer_compat.c | 30 |
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 | ||
1505 | static int snd_timer_user_gparams(struct file *file, | 1505 | static 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(®ister_mutex); | 1510 | mutex_lock(®ister_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(®ister_mutex); | 1526 | mutex_unlock(®ister_mutex); |
1531 | return err; | 1527 | return err; |
1532 | } | 1528 | } |
1533 | 1529 | ||
1530 | static 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 | |||
1534 | static int snd_timer_user_gstatus(struct file *file, | 1540 | static 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 | */ | ||
31 | struct 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 | |||
25 | struct snd_timer_info32 { | 38 | struct 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 | ||
48 | static 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 | |||
35 | static int snd_timer_user_info_compat(struct file *file, | 61 | static 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 | ||
101 | enum { | 127 | enum { |
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: |