Skip to content

Commit

Permalink
Merge branch 'dynamic-possix-clocks-permission-checks'
Browse files Browse the repository at this point in the history
Wojtek Wasko says:

====================
Permission checks for dynamic POSIX clocks

Dynamic clocks - such as PTP clocks - extend beyond the standard POSIX
clock API by using ioctl calls. While file permissions are enforced for
standard POSIX operations, they are not implemented for ioctl calls,
since the POSIX layer cannot differentiate between calls which modify
the clock's state (like enabling PPS output generation) and those that
don't (such as retrieving the clock's PPS capabilities).

On the other hand, drivers implementing the dynamic clocks lack the
necessary information context to enforce permission checks themselves.

Additionally, POSIX clock layer requires the WRITE permission even for
readonly adjtime() operations before invoking the callback.

Add a struct file pointer to the POSIX clock context and use it to
implement the appropriate permission checks on PTP chardevs. Permit
readonly adjtime() for dynamic clocks. Add a readonly option to testptp.

Changes in v4:
- Allow readonly adjtime() for dynamic clocks, as suggested by Thomas

Changes in v3:
- Reword the log message for commit against posix-clock and fix
  documentation of struct posix_clock_context, as suggested by Thomas

Changes in v2:
- Store file pointer in POSIX clock context rather than fmode in the PTP
  clock's private data, as suggested by Richard.
- Move testptp.c changes into separate patch.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Mar 5, 2025
2 parents f252f23 + 7686864 commit c62e6f0
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 16 deletions.
16 changes: 16 additions & 0 deletions drivers/ptp/ptp_chardev.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,

case PTP_EXTTS_REQUEST:
case PTP_EXTTS_REQUEST2:
if ((pccontext->fp->f_mode & FMODE_WRITE) == 0) {
err = -EACCES;
break;
}
memset(&req, 0, sizeof(req));

if (copy_from_user(&req.extts, (void __user *)arg,
Expand Down Expand Up @@ -246,6 +250,10 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,

case PTP_PEROUT_REQUEST:
case PTP_PEROUT_REQUEST2:
if ((pccontext->fp->f_mode & FMODE_WRITE) == 0) {
err = -EACCES;
break;
}
memset(&req, 0, sizeof(req));

if (copy_from_user(&req.perout, (void __user *)arg,
Expand Down Expand Up @@ -314,6 +322,10 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,

case PTP_ENABLE_PPS:
case PTP_ENABLE_PPS2:
if ((pccontext->fp->f_mode & FMODE_WRITE) == 0) {
err = -EACCES;
break;
}
memset(&req, 0, sizeof(req));

if (!capable(CAP_SYS_TIME))
Expand Down Expand Up @@ -456,6 +468,10 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,

case PTP_PIN_SETFUNC:
case PTP_PIN_SETFUNC2:
if ((pccontext->fp->f_mode & FMODE_WRITE) == 0) {
err = -EACCES;
break;
}
if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) {
err = -EFAULT;
break;
Expand Down
6 changes: 5 additions & 1 deletion include/linux/posix-clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,21 @@ struct posix_clock {
* struct posix_clock_context - represents clock file operations context
*
* @clk: Pointer to the clock
* @fp: Pointer to the file used to open the clock
* @private_clkdata: Pointer to user data
*
* Drivers should use struct posix_clock_context during specific character
* device file operation methods to access the posix clock.
* device file operation methods to access the posix clock. In particular,
* the file pointer can be used to verify correct access mode for ioctl()
* calls.
*
* Drivers can store a private data structure during the open operation
* if they have specific information that is required in other file
* operations.
*/
struct posix_clock_context {
struct posix_clock *clk;
struct file *fp;
void *private_clkdata;
};

Expand Down
3 changes: 2 additions & 1 deletion kernel/time/posix-clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
goto out;
}
pccontext->clk = clk;
pccontext->fp = fp;
if (clk->ops.open) {
err = clk->ops.open(pccontext, fp->f_mode);
if (err) {
Expand Down Expand Up @@ -251,7 +252,7 @@ static int pc_clock_adjtime(clockid_t id, struct __kernel_timex *tx)
if (err)
return err;

if ((cd.fp->f_mode & FMODE_WRITE) == 0) {
if (tx->modes && (cd.fp->f_mode & FMODE_WRITE) == 0) {
err = -EACCES;
goto out;
}
Expand Down
37 changes: 23 additions & 14 deletions tools/testing/selftests/ptp/testptp.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ static void usage(char *progname)
" -H val set output phase to 'val' nanoseconds (requires -p)\n"
" -w val set output pulse width to 'val' nanoseconds (requires -p)\n"
" -P val enable or disable (val=1|0) the system clock PPS\n"
" -r open the ptp clock in readonly mode\n"
" -s set the ptp clock time from the system time\n"
" -S set the system time from the ptp clock time\n"
" -t val shift the ptp clock time by 'val' seconds\n"
Expand Down Expand Up @@ -188,6 +189,7 @@ int main(int argc, char *argv[])
int pin_index = -1, pin_func;
int pps = -1;
int seconds = 0;
int readonly = 0;
int settime = 0;
int channel = -1;
clockid_t ext_clockid = CLOCK_REALTIME;
Expand All @@ -200,7 +202,7 @@ int main(int argc, char *argv[])

progname = strrchr(argv[0], '/');
progname = progname ? 1+progname : argv[0];
while (EOF != (c = getopt(argc, argv, "cd:e:f:F:ghH:i:k:lL:n:o:p:P:sSt:T:w:x:Xy:z"))) {
while (EOF != (c = getopt(argc, argv, "cd:e:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) {
switch (c) {
case 'c':
capabilities = 1;
Expand Down Expand Up @@ -252,6 +254,9 @@ int main(int argc, char *argv[])
case 'P':
pps = atoi(optarg);
break;
case 'r':
readonly = 1;
break;
case 's':
settime = 1;
break;
Expand Down Expand Up @@ -308,7 +313,7 @@ int main(int argc, char *argv[])
}
}

fd = open(device, O_RDWR);
fd = open(device, readonly ? O_RDONLY : O_RDWR);
if (fd < 0) {
fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
return -1;
Expand Down Expand Up @@ -436,14 +441,16 @@ int main(int argc, char *argv[])
}

if (extts) {
memset(&extts_request, 0, sizeof(extts_request));
extts_request.index = index;
extts_request.flags = PTP_ENABLE_FEATURE;
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
perror("PTP_EXTTS_REQUEST");
extts = 0;
} else {
puts("external time stamp request okay");
if (!readonly) {
memset(&extts_request, 0, sizeof(extts_request));
extts_request.index = index;
extts_request.flags = PTP_ENABLE_FEATURE;
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
perror("PTP_EXTTS_REQUEST");
extts = 0;
} else {
puts("external time stamp request okay");
}
}
for (; extts; extts--) {
cnt = read(fd, &event, sizeof(event));
Expand All @@ -455,10 +462,12 @@ int main(int argc, char *argv[])
event.t.sec, event.t.nsec);
fflush(stdout);
}
/* Disable the feature again. */
extts_request.flags = 0;
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
perror("PTP_EXTTS_REQUEST");
if (!readonly) {
/* Disable the feature again. */
extts_request.flags = 0;
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
perror("PTP_EXTTS_REQUEST");
}
}
}

Expand Down

0 comments on commit c62e6f0

Please sign in to comment.