From owner-freebsd-audit Sun Jul 28 2:25:46 2002 Delivered-To: freebsd-audit@freebsd.org Received: from mx1.FreeBSD.org (mx1.FreeBSD.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 574F137B400; Sun, 28 Jul 2002 02:25:39 -0700 (PDT) Received: from salmon.maths.tcd.ie (salmon.maths.tcd.ie [134.226.81.11]) by mx1.FreeBSD.org (Postfix) with SMTP id 12BDD43E5E; Sun, 28 Jul 2002 02:25:38 -0700 (PDT) (envelope-from dwmalone@maths.tcd.ie) Received: from walton.maths.tcd.ie by salmon.maths.tcd.ie with SMTP id ; 28 Jul 2002 10:25:37 +0100 (BST) To: audit@freebsd.org Cc: yokota@freebsd.org Subject: Controling keymap changes X-Request-Do: Date: Sun, 28 Jul 2002 10:25:36 +0100 From: David Malone Message-ID: <200207281025.aa05845@salmon.maths.tcd.ie> Sender: owner-freebsd-audit@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG I've had this patch for controling changes to the console keymap in my tree at home for a bit. The idea is to give some control over who can twiddle sensitive bits of the keymap. I provide a sysctl, hw.kbd.keymap_restrict_change, which acts a bit like secure level: >= 1: Only root can change restricted keys (like boot, panic, ...) >= 2: Only root can change restricted keys and regular keys. Regular users still can change accents and function keys. >= 3: Only root can change restricted keys, regular keys and accents. >= 4: Only root can change any of the keymap. Unfortunately, the kbd driver clears the keyboard's accent map if you load a new keymap, which makes the distinction between level 3 and level 4 less useful. David. Index: sys/dev/kbd/kbd.c =================================================================== RCS file: /cvs/FreeBSD-CVS/src/sys/dev/kbd/kbd.c,v retrieving revision 1.28 diff -u -r1.28 kbd.c --- sys/dev/kbd/kbd.c 14 Mar 2002 01:32:22 -0000 1.28 +++ sys/dev/kbd/kbd.c 20 Apr 2002 09:33:47 -0000 @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -70,6 +72,11 @@ static keyboard_switch_t *kbdsw_ini; keyboard_switch_t **kbdsw = &kbdsw_ini; +static int keymap_restrict_change; +SYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); +SYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, + &keymap_restrict_change, 0, "restrict ability to change keymap"); + #define ARRAY_DELTA 4 static int @@ -764,6 +771,11 @@ * functions. */ +static int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); +static int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); +static int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); +static int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); + int genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) { @@ -771,6 +783,7 @@ fkeyarg_t *fkeyp; int s; int i; + int error; s = spltty(); switch (cmd) { @@ -800,6 +813,12 @@ break; case PIO_KEYMAP: /* set keyboard translation table */ #ifndef KBD_DISABLE_KEYMAP_LOAD + error = keymap_change_ok(kbd->kb_keymap, (keymap_t* )arg, + curthread); + if (error != 0) { + splx(s); + return error; + } bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); break; @@ -826,6 +845,12 @@ splx(s); return EINVAL; } + error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], + &keyp->key, curthread); + if (error != 0) { + splx(s); + return error; + } bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], sizeof(keyp->key)); break; @@ -839,6 +864,12 @@ break; case PIO_DEADKEYMAP: /* set accent key translation table */ #ifndef KBD_DISABLE_KEYMAP_LOAD + error = accent_change_ok(kbd->kb_accentmap, + (accentmap_t *)arg, curthread); + if (error != 0) { + splx(s); + return error; + } bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); break; #else @@ -863,6 +894,12 @@ splx(s); return EINVAL; } + error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], + fkeyp, curthread); + if (error != 0) { + splx(s); + return error; + } kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, kbd->kb_fkeytab[fkeyp->keynum].len); @@ -878,6 +915,106 @@ } splx(s); + return 0; +} + +#define RESTRICTED_KEY(key, i) \ + ((key->spcl & (0x80 >> i)) && \ + (key->map[i] == RBT || key->map[i] == SUSP || \ + key->map[i] == STBY || key->map[i] == DBG || \ + key->map[i] == PNC || key->map[i] == HALT || \ + key->map[i] == PDWN)) + +static int +key_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) +{ + int i; + + /* Low keymap_restrict_change means any changes are OK. */ + if (keymap_restrict_change <= 0) + return 0; + + /* High keymap_restrict_change means only root can change the keymap. */ + if (keymap_restrict_change >= 2) { + for (i = 0; i < NUM_STATES; i++) + if (oldkey->map[i] != newkey->map[i]) + return suser(td); + if (oldkey->spcl != newkey->spcl) + return suser(td); + if (oldkey->flgs != newkey->flgs) + return suser(td); + return 0; + } + + /* Otherwise we have to see if any special keys are being changed. */ + for (i = 0; i < NUM_STATES; i++) { + /* + * If either the oldkey or the newkey action is restricted + * then we must make sure that the action doesn't change. + */ + if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) + continue; + if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) + && oldkey->map[i] == newkey->map[i]) + continue; + return suser(td); + } + + return 0; +} + +static int +keymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) +{ + int keycode, error; + + for (keycode = 0; keycode < NUM_KEYS; keycode++) { + if ((error = key_change_ok(&oldmap->key[keycode], + &newmap->key[keycode], td)) != 0) + return error; + } + return 0; +} + +static int +accent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) +{ + struct acc_t *oldacc, *newacc; + int accent, i; + + if (keymap_restrict_change <= 2) + return 0; + + if (oldmap->n_accs != newmap->n_accs) + return suser(td); + + for (accent = 0; accent < oldmap->n_accs; accent++) { + oldacc = &oldmap->acc[accent]; + newacc = &newmap->acc[accent]; + if (oldacc->accchar != newacc->accchar) + return suser(td); + for (i = 0; i < NUM_ACCENTCHARS; ++i) { + if (oldacc->map[i][0] != newacc->map[i][0]) + return suser(td); + if (oldacc->map[i][0] == 0) /* end of table */ + break; + if (oldacc->map[i][1] != newacc->map[i][1]) + return suser(td); + } + } + + return 0; +} + +static int fkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) +{ + if (keymap_restrict_change <= 3) + return 0; + + if (oldkey->len != newkey->flen || + bcmp(oldkey->str, newkey->keydef, oldkey->len != 0)) + return suser(td); + return 0; } To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-audit" in the body of the message