diff options
author | Hugh Dickins <hugh@veritas.com> | 2007-05-25 19:39:17 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-25 20:37:46 -0400 |
commit | f4d43bd579f13219ffd3cae48432eab5bbac2d6f (patch) | |
tree | b3376f267b2e519506633d0bdf73b8cb6d90a981 | |
parent | 1ea0975875294964853209927feccdf6bc8cf5f9 (diff) |
fix compat console unimap regression
Why is it that since the 2f1a2ccb9c0de632ab07193becf5f7121794f6ae console
UTF-8 fixes went into 2.6.22-rc1, the PowerMac G5 shows only inverse video
question marks for the text on tty2-6? whereas tty1 is fine, and so is x86.
No fault of that patch: by removing the old fallback behaviour, it reveals
that 32-bit setfont running on 64-bit kernels has only really worked on
the current console, the rest getting faked by that inadequate fallback.
Bring the compat do_unimap_ioctl into line with the main one: PIO_UNIMAP
and GIO_UNIMAP apply to the specified tty, not redirected to fg_console.
Use the same checks, and most particularly, remember to check access_ok:
con_set_unimap and con_get_unimap are using __get_user and __put_user.
And the compat vt_check should ask for the same capability as the main
one, CAP_SYS_TTY_CONFIG rather than CAP_SYS_ADMIN. Added in vt_ioctl's
vc_cons_allocated check for safety, though failure may well be impossible.
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/compat_ioctl.c | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 65643def3182..6b44cdc96fac 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -1194,6 +1194,7 @@ static int vt_check(struct file *file) | |||
1194 | { | 1194 | { |
1195 | struct tty_struct *tty; | 1195 | struct tty_struct *tty; |
1196 | struct inode *inode = file->f_path.dentry->d_inode; | 1196 | struct inode *inode = file->f_path.dentry->d_inode; |
1197 | struct vc_data *vc; | ||
1197 | 1198 | ||
1198 | if (file->f_op->ioctl != tty_ioctl) | 1199 | if (file->f_op->ioctl != tty_ioctl) |
1199 | return -EINVAL; | 1200 | return -EINVAL; |
@@ -1204,12 +1205,16 @@ static int vt_check(struct file *file) | |||
1204 | 1205 | ||
1205 | if (tty->driver->ioctl != vt_ioctl) | 1206 | if (tty->driver->ioctl != vt_ioctl) |
1206 | return -EINVAL; | 1207 | return -EINVAL; |
1207 | 1208 | ||
1209 | vc = (struct vc_data *)tty->driver_data; | ||
1210 | if (!vc_cons_allocated(vc->vc_num)) /* impossible? */ | ||
1211 | return -ENOIOCTLCMD; | ||
1212 | |||
1208 | /* | 1213 | /* |
1209 | * To have permissions to do most of the vt ioctls, we either have | 1214 | * To have permissions to do most of the vt ioctls, we either have |
1210 | * to be the owner of the tty, or super-user. | 1215 | * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. |
1211 | */ | 1216 | */ |
1212 | if (current->signal->tty == tty || capable(CAP_SYS_ADMIN)) | 1217 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) |
1213 | return 1; | 1218 | return 1; |
1214 | return 0; | 1219 | return 0; |
1215 | } | 1220 | } |
@@ -1310,16 +1315,28 @@ static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg, | |||
1310 | struct unimapdesc32 tmp; | 1315 | struct unimapdesc32 tmp; |
1311 | struct unimapdesc32 __user *user_ud = compat_ptr(arg); | 1316 | struct unimapdesc32 __user *user_ud = compat_ptr(arg); |
1312 | int perm = vt_check(file); | 1317 | int perm = vt_check(file); |
1313 | 1318 | struct vc_data *vc; | |
1314 | if (perm < 0) return perm; | 1319 | |
1320 | if (perm < 0) | ||
1321 | return perm; | ||
1315 | if (copy_from_user(&tmp, user_ud, sizeof tmp)) | 1322 | if (copy_from_user(&tmp, user_ud, sizeof tmp)) |
1316 | return -EFAULT; | 1323 | return -EFAULT; |
1324 | if (tmp.entries) | ||
1325 | if (!access_ok(VERIFY_WRITE, compat_ptr(tmp.entries), | ||
1326 | tmp.entry_ct*sizeof(struct unipair))) | ||
1327 | return -EFAULT; | ||
1328 | vc = ((struct tty_struct *)file->private_data)->driver_data; | ||
1317 | switch (cmd) { | 1329 | switch (cmd) { |
1318 | case PIO_UNIMAP: | 1330 | case PIO_UNIMAP: |
1319 | if (!perm) return -EPERM; | 1331 | if (!perm) |
1320 | return con_set_unimap(vc_cons[fg_console].d, tmp.entry_ct, compat_ptr(tmp.entries)); | 1332 | return -EPERM; |
1333 | return con_set_unimap(vc, tmp.entry_ct, | ||
1334 | compat_ptr(tmp.entries)); | ||
1321 | case GIO_UNIMAP: | 1335 | case GIO_UNIMAP: |
1322 | return con_get_unimap(vc_cons[fg_console].d, tmp.entry_ct, &(user_ud->entry_ct), compat_ptr(tmp.entries)); | 1336 | if (!perm && fg_console != vc->vc_num) |
1337 | return -EPERM; | ||
1338 | return con_get_unimap(vc, tmp.entry_ct, &(user_ud->entry_ct), | ||
1339 | compat_ptr(tmp.entries)); | ||
1323 | } | 1340 | } |
1324 | return 0; | 1341 | return 0; |
1325 | } | 1342 | } |