mac80211: allow writing TX PN in debugfs

For certain tests, for example replay detection, it can be useful
to be able to influence/set the PN used in outgoing packets. Make
it possible to change the TX PN in debugfs.

For now, this doesn't support TKIP since I haven't needed it, but
there's no reason it couldn't be added if necessary.

Note that this must be used very carefully: it could, for example,
be used to make "valid replays" where the PN reuse happens on a
different TID. This couldn't be done by an attacker since the TID
is protected as part of the AAD.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2015-09-23 10:42:28 +02:00
parent 416eb9fc29
commit d0a77c6569

View File

@ -2,6 +2,7 @@
* Copyright 2003-2005 Devicescape Software, Inc. * Copyright 2003-2005 Devicescape Software, Inc.
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net> * Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
* Copyright (C) 2015 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
@ -34,6 +35,14 @@ static const struct file_operations key_ ##name## _ops = { \
.llseek = generic_file_llseek, \ .llseek = generic_file_llseek, \
} }
#define KEY_OPS_W(name) \
static const struct file_operations key_ ##name## _ops = { \
.read = key_##name##_read, \
.write = key_##name##_write, \
.open = simple_open, \
.llseek = generic_file_llseek, \
}
#define KEY_FILE(name, format) \ #define KEY_FILE(name, format) \
KEY_READ_##format(name) \ KEY_READ_##format(name) \
KEY_OPS(name) KEY_OPS(name)
@ -74,6 +83,41 @@ static ssize_t key_algorithm_read(struct file *file,
} }
KEY_OPS(algorithm); KEY_OPS(algorithm);
static ssize_t key_tx_spec_write(struct file *file, const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct ieee80211_key *key = file->private_data;
u64 pn;
int ret;
switch (key->conf.cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
return -EINVAL;
case WLAN_CIPHER_SUITE_TKIP:
/* not supported yet */
return -EOPNOTSUPP;
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
ret = kstrtou64_from_user(userbuf, count, 16, &pn);
if (ret)
return ret;
/* PN is a 48-bit counter */
if (pn >= (1ULL << 48))
return -ERANGE;
atomic64_set(&key->conf.tx_pn, pn);
return count;
default:
return 0;
}
}
static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf, static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
@ -110,7 +154,7 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
} }
return simple_read_from_buffer(userbuf, count, ppos, buf, len); return simple_read_from_buffer(userbuf, count, ppos, buf, len);
} }
KEY_OPS(tx_spec); KEY_OPS_W(tx_spec);
static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf, static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
@ -278,6 +322,9 @@ KEY_OPS(key);
#define DEBUGFS_ADD(name) \ #define DEBUGFS_ADD(name) \
debugfs_create_file(#name, 0400, key->debugfs.dir, \ debugfs_create_file(#name, 0400, key->debugfs.dir, \
key, &key_##name##_ops); key, &key_##name##_ops);
#define DEBUGFS_ADD_W(name) \
debugfs_create_file(#name, 0600, key->debugfs.dir, \
key, &key_##name##_ops);
void ieee80211_debugfs_key_add(struct ieee80211_key *key) void ieee80211_debugfs_key_add(struct ieee80211_key *key)
{ {
@ -310,7 +357,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key)
DEBUGFS_ADD(keyidx); DEBUGFS_ADD(keyidx);
DEBUGFS_ADD(hw_key_idx); DEBUGFS_ADD(hw_key_idx);
DEBUGFS_ADD(algorithm); DEBUGFS_ADD(algorithm);
DEBUGFS_ADD(tx_spec); DEBUGFS_ADD_W(tx_spec);
DEBUGFS_ADD(rx_spec); DEBUGFS_ADD(rx_spec);
DEBUGFS_ADD(replays); DEBUGFS_ADD(replays);
DEBUGFS_ADD(icverrors); DEBUGFS_ADD(icverrors);