Skip to content

Commit c2a49fe

Browse files
mranostaygregkh
authored andcommitted
pps: fix padding issue with PPS_FETCH for ioctl_compat
Issue is that x86 32-bit aligns to 4-bytes instead of 8-bytes so this patchset works around the issue and corrects the data returned in pps_fdata_compat. Acked-by: Rodolfo Giometti <[email protected]> Signed-off-by: Matt Ranostay <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2ac6665 commit c2a49fe

File tree

2 files changed

+98
-31
lines changed

2 files changed

+98
-31
lines changed

drivers/pps/pps.c

Lines changed: 79 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,43 @@ static int pps_cdev_fasync(int fd, struct file *file, int on)
6464
return fasync_helper(fd, file, on, &pps->async_queue);
6565
}
6666

67+
static int pps_cdev_pps_fetch(struct pps_device *pps, struct pps_fdata *fdata)
68+
{
69+
unsigned int ev = pps->last_ev;
70+
int err = 0;
71+
72+
/* Manage the timeout */
73+
if (fdata->timeout.flags & PPS_TIME_INVALID)
74+
err = wait_event_interruptible(pps->queue,
75+
ev != pps->last_ev);
76+
else {
77+
unsigned long ticks;
78+
79+
dev_dbg(pps->dev, "timeout %lld.%09d\n",
80+
(long long) fdata->timeout.sec,
81+
fdata->timeout.nsec);
82+
ticks = fdata->timeout.sec * HZ;
83+
ticks += fdata->timeout.nsec / (NSEC_PER_SEC / HZ);
84+
85+
if (ticks != 0) {
86+
err = wait_event_interruptible_timeout(
87+
pps->queue,
88+
ev != pps->last_ev,
89+
ticks);
90+
if (err == 0)
91+
return -ETIMEDOUT;
92+
}
93+
}
94+
95+
/* Check for pending signals */
96+
if (err == -ERESTARTSYS) {
97+
dev_dbg(pps->dev, "pending signal caught\n");
98+
return -EINTR;
99+
}
100+
101+
return 0;
102+
}
103+
67104
static long pps_cdev_ioctl(struct file *file,
68105
unsigned int cmd, unsigned long arg)
69106
{
@@ -144,44 +181,16 @@ static long pps_cdev_ioctl(struct file *file,
144181

145182
case PPS_FETCH: {
146183
struct pps_fdata fdata;
147-
unsigned int ev;
148184

149185
dev_dbg(pps->dev, "PPS_FETCH\n");
150186

151187
err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
152188
if (err)
153189
return -EFAULT;
154190

155-
ev = pps->last_ev;
156-
157-
/* Manage the timeout */
158-
if (fdata.timeout.flags & PPS_TIME_INVALID)
159-
err = wait_event_interruptible(pps->queue,
160-
ev != pps->last_ev);
161-
else {
162-
unsigned long ticks;
163-
164-
dev_dbg(pps->dev, "timeout %lld.%09d\n",
165-
(long long) fdata.timeout.sec,
166-
fdata.timeout.nsec);
167-
ticks = fdata.timeout.sec * HZ;
168-
ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ);
169-
170-
if (ticks != 0) {
171-
err = wait_event_interruptible_timeout(
172-
pps->queue,
173-
ev != pps->last_ev,
174-
ticks);
175-
if (err == 0)
176-
return -ETIMEDOUT;
177-
}
178-
}
179-
180-
/* Check for pending signals */
181-
if (err == -ERESTARTSYS) {
182-
dev_dbg(pps->dev, "pending signal caught\n");
183-
return -EINTR;
184-
}
191+
err = pps_cdev_pps_fetch(pps, &fdata);
192+
if (err)
193+
return err;
185194

186195
/* Return the fetched timestamp */
187196
spin_lock_irq(&pps->lock);
@@ -246,8 +255,47 @@ static long pps_cdev_ioctl(struct file *file,
246255
static long pps_cdev_compat_ioctl(struct file *file,
247256
unsigned int cmd, unsigned long arg)
248257
{
258+
struct pps_device *pps = file->private_data;
259+
void __user *uarg = (void __user *) arg;
260+
249261
cmd = _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(void *));
250262

263+
if (cmd == PPS_FETCH) {
264+
struct pps_fdata_compat compat;
265+
struct pps_fdata fdata;
266+
int err;
267+
268+
dev_dbg(pps->dev, "PPS_FETCH\n");
269+
270+
err = copy_from_user(&compat, uarg, sizeof(struct pps_fdata_compat));
271+
if (err)
272+
return -EFAULT;
273+
274+
memcpy(&fdata.timeout, &compat.timeout,
275+
sizeof(struct pps_ktime_compat));
276+
277+
err = pps_cdev_pps_fetch(pps, &fdata);
278+
if (err)
279+
return err;
280+
281+
/* Return the fetched timestamp */
282+
spin_lock_irq(&pps->lock);
283+
284+
compat.info.assert_sequence = pps->assert_sequence;
285+
compat.info.clear_sequence = pps->clear_sequence;
286+
compat.info.current_mode = pps->current_mode;
287+
288+
memcpy(&compat.info.assert_tu, &pps->assert_tu,
289+
sizeof(struct pps_ktime_compat));
290+
memcpy(&compat.info.clear_tu, &pps->clear_tu,
291+
sizeof(struct pps_ktime_compat));
292+
293+
spin_unlock_irq(&pps->lock);
294+
295+
return copy_to_user(uarg, &compat,
296+
sizeof(struct pps_fdata_compat)) ? -EFAULT : 0;
297+
}
298+
251299
return pps_cdev_ioctl(file, cmd, arg);
252300
}
253301
#else

include/uapi/linux/pps.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ struct pps_ktime {
5555
__s32 nsec;
5656
__u32 flags;
5757
};
58+
59+
struct pps_ktime_compat {
60+
__s64 sec;
61+
__s32 nsec;
62+
__u32 flags;
63+
} __attribute__((packed, aligned(4)));
5864
#define PPS_TIME_INVALID (1<<0) /* used to specify timeout==NULL */
5965

6066
struct pps_kinfo {
@@ -65,6 +71,14 @@ struct pps_kinfo {
6571
int current_mode; /* current mode bits */
6672
};
6773

74+
struct pps_kinfo_compat {
75+
__u32 assert_sequence; /* seq. num. of assert event */
76+
__u32 clear_sequence; /* seq. num. of clear event */
77+
struct pps_ktime_compat assert_tu; /* time of assert event */
78+
struct pps_ktime_compat clear_tu; /* time of clear event */
79+
int current_mode; /* current mode bits */
80+
};
81+
6882
struct pps_kparams {
6983
int api_version; /* API version # */
7084
int mode; /* mode bits */
@@ -114,6 +128,11 @@ struct pps_fdata {
114128
struct pps_ktime timeout;
115129
};
116130

131+
struct pps_fdata_compat {
132+
struct pps_kinfo_compat info;
133+
struct pps_ktime_compat timeout;
134+
};
135+
117136
struct pps_bind_args {
118137
int tsformat; /* format of time stamps */
119138
int edge; /* selected event type */

0 commit comments

Comments
 (0)