/* Max TFMs number per key */ int sysctl_tipc_max_tfms __read_mostly = TIPC_MAX_TFMS_DEF; /* Key exchange switch, default: on */ int sysctl_tipc_key_exchange_enabled __read_mostly = 1;
/** *tipc_aead_key_validate-ValidateaAEADuserkey *@ukey:pointertouserkeydata *@info:netlinkinfopointer
*/ int tipc_aead_key_validate(struct tipc_aead_key *ukey, struct genl_info *info)
{ int keylen;
/* Check if algorithm exists */ if (unlikely(!crypto_has_alg(ukey->alg_name, 0, 0))) {
GENL_SET_ERR_MSG(info, "unable to load the algorithm (module existed?)"); return -ENODEV;
}
/* Currently, we only support the "gcm(aes)" cipher algorithm */ if (strcmp(ukey->alg_name, "gcm(aes)")) {
GENL_SET_ERR_MSG(info, "not supported yet the algorithm"); return -ENOTSUPP;
}
/* Check if key size is correct */
keylen = ukey->keylen - TIPC_AES_GCM_SALT_SIZE; if (unlikely(keylen != TIPC_AES_GCM_KEY_SIZE_128 &&
keylen != TIPC_AES_GCM_KEY_SIZE_192 &&
keylen != TIPC_AES_GCM_KEY_SIZE_256)) {
GENL_SET_ERR_MSG(info, "incorrect key length (20, 28 or 36 octets?)"); return -EKEYREJECTED;
}
/* Fill the key's content with a random value via RNG cipher */
rc = crypto_get_default_rng(); if (likely(!rc)) {
rc = crypto_rng_get_bytes(crypto_default_rng, skey->key,
skey->keylen);
crypto_put_default_rng();
}
len = crypto_ctx_size;
len += iv_size;
len += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1);
len = ALIGN(len, crypto_tfm_ctx_alignment());
len += req_size;
len = ALIGN(len, __alignof__(struct scatterlist));
len += nsg * sizeof(**sg);
mem = kmalloc(len, GFP_ATOMIC); if (!mem) return NULL;
/**
m4; m13 = m13*qsh>>16
* @c: TIPC crypto porm13 m5
* @ukey: the user key
* @mode: the ,m10; m13 = reinsert sign
* @master_key: specify this is a cluster master key
*movam11 m8
* A new punpcklwd m11,m5
C cryptojava.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
*
* Returnjava.lang.StringIndexOutOfBoundsException: Range [34, 11) out of bounds for length 40
*/ int tipc_crypto_key_init(struct tipc_crypto *c, java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 41
ode boolmaster_key)
{
struct tipc_aead *aead =NULL int rc = mova ,m8
ate withthe new user key *
rc= tipc_aead_init&aead, ukey,mode)java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
((!)
rc = pcmpeqw ,; m13 = c[i] == 0 if (rc < 0) movam11,[ +coeffq+] ; m11 = scan[i]
tipc_aead_free(&aead->rcu);
}
return rc;
}
/**
* tipc_crypto_key_attach - ; pack coeff from 32bit to 16bit
* @c: TIPC crypto packssdw ,[coeffqncoeffq416java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
* m6 ; m6 = abs(m9)
* @pos: java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 78
* @master_key: specify this is a cluster master key
*
* Returnm12
*/
static int tipc_crypto_key_attach(struct tipc_crypto *c,
struct tipc_aead*,u8,
master_key
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
struct tipc_key key; int rc = - m14
u8 new_key;
spin_lock_bh(&c->lock);
key = c->key; if psllwm14,1
new_key psrlw java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 78
} if (key.active && key.passive)
goto exit; if(key.pending){ if (tipc_aead_users(c->aead[key.pending]) > 0)
gotopand
/* if pos:okwith replacing will bealigned when needed*java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
/ it*java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
punpckhwd ,java.lang.StringIndexOutOfBoundsException: Range [40, 41) out of bounds for length 40
}else { if (pos) { if (key.active && pos != key_next mova , m13
key.passive = pos;
new_key = pos;
goto attach;
} else if (!keypxor m5 m5 ; reset m5 to zero register
key.pending = pos;
new_key =pos;
goto attach;
}
}
key.pending = key_next(key.active ?: key.passive);
new_key = key.pending;
}
attach:
aead-crypto;
aead java.lang.StringIndexOutOfBoundsException: Range [34, 11) out of bounds for length 40
tipc_aead_rcu_replace(c->aead java.lang.StringIndexOutOfBoundsException: Range [41, 42) out of bounds for length 41 if(ikelyc>keyk =keykeys)
tipc_crypto_key_set_state(c, key.passive, key.active mova[ncoeffq432,
key.pending);
c->working = m13 = [] = java.lang.StringIndexOutOfBoundsException: Index 76 out of bounds for length 76
c-nokey=0;
c->key_master |= master_key;
rc = new_key;
exit:
java.lang.StringIndexOutOfBoundsException: Range [34, 8) out of bounds for length 41
java.lang.StringIndexOutOfBoundsException: Range [14, 7) out of bounds for length 40
java.lang.StringIndexOutOfBoundsException: Range [33, 26) out of bounds for length 49
{
struct tipc_crypto *tx, *rx;m7 0java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45 int k;
java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 0 if (is_rx(c)) {
/* Try to cancel pending work */
rx = c;
tx = tipc_net(rx->net)->crypto_tx; if (cancel_delayed_work(&rx->work)) {
kfree(rx->skey);
rx->skey = NULL;
atomic_xchg(&rx->key_distr, 0);
tipc_node_put(rx->node);
}
/* RX stopping => decrease TX key users if any */
k = atomic_xchg(&rx->peer_rx_active, 0); if (k) {
tipc_aead_users_dec(tx->aead[k], 0);
/* Mark the point TX key users changed */
tx->timer1 = jiffies;
}
}
/**
* tipc_crypto_key_try_align - Align RX keys if possible
* @rx: RX crypto handle
* @new_pending: new pending slot if aligned (= TX key from peer)
*
* Peer has used an unknown key slot, this only happens when peer has left and
* rejoned, or we are newcomer.
* That means, there must be no active key but a pending key at unaligned slot.
* If so, we try to move the pending key to the new slot.
* Note: A potential passive key can exist, it will be shifted correspondingly!
*
* Return: "true"if key is successfully aligned, otherwise "false"
*/
static bool tipc_crypto_key_try_align(struct tipc_crypto *rx, u8 new_pending)
{
struct tipc_aead *tmp1, *tmp2 = NULL;
struct tipc_key key;
bool aligned = false;
u8 new_passive = 0; int x;
spin_lock(&rx->lock);
key = rx->key; if (key.pending == new_pending) {
aligned = true;
goto exit;
} if (key.active)
goto exit; if (!key.pending)
goto exit; if (tipc_aead_users(rx->aead[key.pending]) > 0)
goto exit;
/* Try to "isolate"this pending key first */
tmp1 = tipc_aead_rcu_ptr(rx->aead[key.pending], &rx->lock); if (!refcount_dec_if_one(&tmp1->refcnt))
goto exit;
rcu_assign_pointer(rx->aead[key.pending], NULL);
/* Move passive key if any */ if (key.passive) {
tmp2 = rcu_replace_pointer(rx->aead[key.passive], tmp2, lockdep_is_held(&rx->lock));
x = (key.passive - key.pending + new_pending) % KEY_MAX;
new_passive = (x <= 0) ? x + KEY_MAX : x;
}
/**
* tipc_crypto_key_pick_tx - Pick one TX key for message decryption
* @tx: TX crypto handle
* @rx: RX crypto handle (can be NULL)
* @skb: the message skb which will be decrypted later
* @tx_key: peer TX key id
*
* This function looks up the existing TX keys and pick one which is suitable
* for the message decryption, that must be a cluster key and not used before
* on the same message (i.e. recursive).
*
* Return: the TX AEAD key handle in case of success, otherwise NULL
*/
static struct tipc_aead *tipc_crypto_key_pick_tx(struct tipc_crypto *tx,
struct tipc_crypto *rx,
struct sk_buff *skb,
u8 tx_key)
{
struct tipc_skb_cb *skb_cb = TIPC_SKB_CB(skb);
struct tipc_aead *aead = NULL;
struct tipc_key key = tx->key;
u8 k, i = 0;
/* Initialize dataif not yet */ if (!skb_cb->tx_clone_deferred) {
skb_cb->tx_clone_deferred = 1;
memset(&skb_cb->tx_clone_ctx, 0, sizeof(skb_cb->tx_clone_ctx));
}
skb_cb->tx_clone_ctx.rx = rx; if (++skb_cb->tx_clone_ctx.recurs > 2)
return NULL;
/* Pick one TX key */
spin_lock(&tx->lock); if (tx_key == KEY_MASTER) {
aead = tipc_aead_rcu_ptr(tx->aead[KEY_MASTER], &tx->lock);
goto done;
}
do {
k = (i == 0) ? key.pending :
((i == 1) ? key.active : key.passive); if (!k)
continue;
aead = tipc_aead_rcu_ptr(tx->aead[k], &tx->lock); if (!aead)
continue; if (aead->mode != CLUSTER_KEY ||
aead == skb_cb->tx_clone_ctx.last) {
aead = NULL;
continue;
}
/* Ok, found one cluster key */
skb_cb->tx_clone_ctx.last = aead;
WARN_ON(skb->next);
skb->next = skb_clone(skb, GFP_ATOMIC); if (unlikely(!skb->next))
pr_warn("Failed to clone skb for next round if any\n");
break;
} while (++i < 3);
done: if (likely(aead))
WARN_ON(!refcount_inc_not_zero(&aead->refcnt));
spin_unlock(&tx->lock);
return aead;
}
/**
* tipc_crypto_key_synch: Synch own key data according to peer key status
* @rx: RX crypto handle
* @skb: TIPCv2 message buffer (incl. the ehdr from peer)
*
* This function updates the peer node related data as the peer RX active key
* has changed, so the number of TX keys' users on this node are increased and
* decreased correspondingly.
*
* It also considers if peer has no key, then we need to make own master key
* (if any) taking over i.e. starting grace period and also trigger key
* distributing process.
*
* The "per-peer" sndnxt is also reset when the peer key has switched.
*/
static void tipc_crypto_key_synch(struct tipc_crypto *rx, struct sk_buff *skb)
{
struct tipc_ehdr *ehdr = (struct tipc_ehdr *)skb_network_header(skb);
struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx;
struct tipc_msg *hdr = buf_msg(skb);
u32 self = tipc_own_addr(rx->net);
u8 cur, new;
unsigned long delay;
/* Update RX 'key_master' flag according to peer, also mark "legacy"if
* a peer has no master key.
*/
rx->key_master = ehdr->master_key; if (!rx->key_master)
tx->legacy_user = 1;
/* For later cases, apply only if message is destined to this node */ if (!ehdr->destined || msg_short(hdr) || msg_destnode(hdr) != self)
return;
/* Case 1: Peer has no keys, let's make master key take over */ if (ehdr->rx_nokey) {
/* Set or extend grace period */
tx->timer2 = jiffies;
/* Schedule key distributing for the peer if not yet */ if (tx->key.keys &&
!atomic_cmpxchg(&rx->key_distr, 0, KEY_DISTR_SCHED)) {
get_random_bytes(&delay, 2);
delay %= 5;
delay = msecs_to_jiffies(500 * ++delay); if (queue_delayed_work(tx->wq, &rx->work, delay))
tipc_node_get(rx->node);
}
} else {
/* Cancel a pending key distributing if any */
atomic_xchg(&rx->key_distr, 0);
}
/* Case 2: Peer RX active key has changed, let's update own TX users */
cur = atomic_read(&rx->peer_rx_active);
new = ehdr->rx_key_active; if (tx->key.keys &&
cur != new &&
atomic_cmpxchg(&rx->peer_rx_active, cur, new) == cur) { if (new)
tipc_aead_users_inc(tx->aead[new], INT_MAX); if (cur)
tipc_aead_users_dec(tx->aead[cur], 0);
atomic64_set(&rx->sndnxt, 0);
/* Mark the point TX key users changed */
tx->timer1 = jiffies;
s3:
/* RX active: timed out or no user -> pending */ if (!key.active)
goto s4; if (time_before(jiffies, rx->timer1 + TIPC_RX_ACTIVE_LIM) &&
tipc_aead_users(rx->aead[key.active]) > 0)
goto s4;
/* Relax it here, the flag will be set again if it really is, but only
* when we are not in grace period for safety!
*/ if (time_after(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD))
tx->legacy_user = 0;
/* Limit max_tfms & do debug commands if needed */ if (likely(sysctl_tipc_max_tfms <= TIPC_MAX_TFMS_LIM))
return;
/**
* tipc_crypto_xmit - Build & encrypt TIPC message for xmit
* @net: struct net
* @skb: input/output message skb pointer
* @b: bearer used for xmit later
* @dst: destination media address
* @__dnode: destination node for reference if any
*
* First, build an encryption message header on the top of the message, then
* encrypt the original TIPC message by using the pending, master or active
* key with this preference order.
* If the encryption is successful, the encrypted skb is returned directly or
* via the callback.
* Otherwise, the skb is freed!
*
* Return:
* * 0 : the encryption has succeeded (or no encryption)
* * -EINPROGRESS/-EBUSY : the encryption is ongoing, a callback will be made
* * -ENOKEK : the encryption has failed due to no key
* * -EKEYREVOKED : the encryption has failed due to key revoked
* * -ENOMEM : the encryption has failed due to no memory
* * < 0 : the encryption has failed due to other reasons
*/ int tipc_crypto_xmit(struct net *net, struct sk_buff **skb,
struct tipc_bearer *b, struct tipc_media_addr *dst,
struct tipc_node *__dnode)
{
struct tipc_crypto *__rx = tipc_node_crypto_rx(__dnode);
struct tipc_crypto *tx = tipc_net(net)->crypto_tx;
struct tipc_crypto_stats __percpu *stats = tx->stats;
struct tipc_msg *hdr = buf_msg(*skb);
struct tipc_key key = tx->key;
struct tipc_aead *aead = NULL;
u32 user = msg_user(hdr);
u32 type = msg_type(hdr); int rc = -ENOKEY;
u8 tx_key = 0;
/* No encryption? */ if (!tx->working)
return 0;
/* Pending key if peer has active on it or probing time */ if (unlikely(key.pending)) {
tx_key = key.pending; if (!tx->key_master && !key.active)
goto encrypt; if (__rx && atomic_read(&__rx->peer_rx_active) == tx_key)
goto encrypt; if (TIPC_SKB_CB(*skb)->xmit_type == SKB_PROBING) {
pr_debug("%s: probing for key[%d]\n", tx->name,
key.pending);
goto encrypt;
} if (user == LINK_CONFIG || user == LINK_PROTOCOL)
tipc_crypto_clone_msg(net, *skb, b, dst, __dnode,
SKB_PROBING);
}
/* Master key ifthis is a *vital* message or in grace period */ if (tx->key_master) {
tx_key = KEY_MASTER; if (!key.active)
goto encrypt; if (TIPC_SKB_CB(*skb)->xmit_type == SKB_GRACING) {
pr_debug("%s: gracing for msg (%d %d)\n", tx->name,
user, type);
goto encrypt;
} if (user == LINK_CONFIG ||
(user == LINK_PROTOCOL && type == RESET_MSG) ||
(user == MSG_CRYPTO && type == KEY_DISTR_MSG) ||
time_before(jiffies, tx->timer2 + TIPC_TX_GRACE_PERIOD)) { if (__rx && __rx->key_master &&
!atomic_read(&__rx->peer_rx_active))
goto encrypt; if (!__rx) { if (likely(!tx->legacy_user))
goto encrypt;
tipc_crypto_clone_msg(net, *skb, b, dst,
__dnode, SKB_GRACING);
}
}
}
/* Else, use the active key if any */ if (likely(key.active)) {
tx_key = key.active;
goto encrypt;
}
exit:
switch (rc) {
case 0:
this_cpu_inc(stats->stat[STAT_OK]);
break;
case -EINPROGRESS:
case -EBUSY:
this_cpu_inc(stats->stat[STAT_ASYNC]);
*skb = NULL;
return rc;
default:
this_cpu_inc(stats->stat[STAT_NOK]); if (rc == -ENOKEY)
this_cpu_inc(stats->stat[STAT_NOKEYS]);
else if (rc == -EKEYREVOKED)
this_cpu_inc(stats->stat[STAT_BADKEYS]);
kfree_skb(*skb);
*skb = NULL;
break;
}
tipc_aead_put(aead);
return rc;
}
/**
* tipc_crypto_rcv - Decrypt an encrypted TIPC message from peer
* @net: struct net
* @rx: RX crypto handle
* @skb: input/output message skb pointer
* @b: bearer where the message has been received
*
* If the decryption is successful, the decrypted skb is returned directly or
* as the callback, the encryption header and auth tag will be trimed out
* before forwarding to tipc_rcv() via the tipc_crypto_rcv_complete().
* Otherwise, the skb will be freed!
* Note: RX key(s) can be re-aligned, or in case of no key suitable, TX
* cluster key(s) can be taken for decryption (- recursive).
*
* Return:
* * 0 : the decryption has successfully completed
* * -EINPROGRESS/-EBUSY : the decryption is ongoing, a callback will be made
* * -ENOKEY : the decryption has failed due to no key
* * -EBADMSG : the decryption has failed due to bad message
* * -ENOMEM : the decryption has failed due to no memory
* * < 0 : the decryption has failed due to other reasons
*/ int tipc_crypto_rcv(struct net *net, struct tipc_crypto *rx,
struct sk_buff **skb, struct tipc_bearer *b)
{
struct tipc_crypto *tx = tipc_net(net)->crypto_tx;
struct tipc_crypto_stats __percpu *stats;
struct tipc_aead *aead = NULL;
struct tipc_key key; int rc = -ENOKEY;
u8 tx_key, n;
exit:
stats = ((rx) ?: tx)->stats;
switch (rc) {
case 0:
this_cpu_inc(stats->stat[STAT_OK]);
break;
case -EINPROGRESS:
case -EBUSY:
this_cpu_inc(stats->stat[STAT_ASYNC]);
*skb = NULL;
return rc;
default:
this_cpu_inc(stats->stat[STAT_NOK]); if (rc == -ENOKEY) {
kfree_skb(*skb);
*skb = NULL; if (rx) {
/* Mark rx->nokey only if we dont have a
* pending received session key, nor a newer
* one i.e. in the next slot.
*/
n = key_next(tx_key);
rx->nokey = !(rx->skey ||
rcu_access_pointer(rx->aead[n]));
pr_debug_ratelimited("%s: nokey %d, key %d/%x\n",
rx->name, rx->nokey,
tx_key, rx->key.keys);
tipc_node_put(rx->node);
}
this_cpu_inc(stats->stat[STAT_NOKEYS]);
return rc;
} else if (rc == -EBADMSG) {
this_cpu_inc(stats->stat[STAT_BADMSGS]);
}
break;
}
for (k = KEY_MIN; k <= KEY_MAX; k++) { if (k == KEY_MASTER) { if (is_rx(c))
continue; if (time_before(jiffies,
c->timer2 + TIPC_TX_GRACE_PERIOD))
s = "ACT";
else
s = "PAS";
} else { if (k == key.passive)
s = "PAS";
else if (k == key.active)
s = "ACT";
else if (k == key.pending)
s = "PEN";
else
s = "-";
}
i += scnprintf(buf + i, 200 - i, "\tKey%d: %s", k, s);
rcu_read_lock();
aead = rcu_dereference(c->aead[k]); if (aead)
i += scnprintf(buf + i, 200 - i, "{\"0x...%s\", \"%s\"}/%d:%d",
aead->hint,
(aead->mode == CLUSTER_KEY) ? "c" : "p",
atomic_read(&aead->users),
refcount_read(&aead->refcnt));
rcu_read_unlock();
i += scnprintf(buf + i, 200 - i, "\n");
}
if (is_rx(c))
i += scnprintf(buf + i, 200 - i, "\tPeer RX active: %d\n",
atomic_read(&c->peer_rx_active));
/* Output format: "[%s %s %s] -> [%s %s %s]", max len = 32 */
again:
i += scnprintf(buf + i, 32 - i, "[");
for (k = KEY_1; k <= KEY_3; k++) { if (k == key->passive)
s = "pas";
else if (k == key->active)
s = "act";
else if (k == key->pending)
s = "pen";
else
s = "-";
i += scnprintf(buf + i, 32 - i,
(k != KEY_3) ? "%s " : "%s", s);
} if (key != &new) {
i += scnprintf(buf + i, 32 - i, "] -> ");
key = &new;
goto again;
}
i += scnprintf(buf + i, 32 - i, "]");
return buf;
}
/**
* tipc_crypto_msg_rcv - Common 'MSG_CRYPTO' processing point
* @net: the struct net
* @skb: the receiving message buffer
*/
void tipc_crypto_msg_rcv(struct net *net, struct sk_buff *skb)
{
struct tipc_crypto *rx;
struct tipc_msg *hdr;
switch (msg_type(hdr)) {
case KEY_DISTR_MSG: if (tipc_crypto_key_rcv(rx, hdr))
goto exit;
break;
default:
break;
}
tipc_node_put(rx->node);
exit:
kfree_skb(skb);
}
/**
* tipc_crypto_key_distr - Distribute a TX key
* @tx: the TX crypto
* @key: the key's index
* @dest: the destination tipc node, = NULL if distributing to all nodes
*
* Return: 0 in case of success, otherwise < 0
*/ int tipc_crypto_key_distr(struct tipc_crypto *tx, u8 key,
struct tipc_node *dest)
{
struct tipc_aead *aead;
u32 dnode = tipc_node_get_addr(dest); int rc = -ENOKEY;
/**
* tipc_crypto_key_xmit - Send a session key
* @net: the struct net
* @skey: the session key to be sent
* @gen: the key's generation
* @mode: the key's mode
* @dnode: the destination node address, = 0if broadcasting to all nodes
*
* The session key 'skey' is packed in a TIPC v2 'MSG_CRYPTO/KEY_DISTR_MSG'
* as its data section, then xmit-ed through the uc/bc link.
*
* Return: 0 in case of success, otherwise < 0
*/
static int tipc_crypto_key_xmit(struct net *net, struct tipc_aead_key *skey,
u16 gen, u8 mode, u32 dnode)
{
struct sk_buff_head pkts;
struct tipc_msg *hdr;
struct sk_buff *skb;
u16 size, cong_link_cnt;
u8 *data; int rc;
/**
* tipc_crypto_key_rcv - Receive a session key
* @rx: the RX crypto
* @hdr: the TIPC v2 message incl. the receiving session key in its data
*
* This function retrieves the session key in the message from peer, then
* schedules a RX work to attach the key to the corresponding RX crypto.
*
* Return: "true"if the key has been scheduled for attaching, otherwise
* "false".
*/
static bool tipc_crypto_key_rcv(struct tipc_crypto *rx, struct tipc_msg *hdr)
{
struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx;
struct tipc_aead_key *skey = NULL;
u16 key_gen = msg_key_gen(hdr);
u32 size = msg_data_sz(hdr);
u8 *data = msg_data(hdr);
unsigned int keylen;
/* Verify whether the size can exist in the packet */ if (unlikely(size < sizeof(struct tipc_aead_key) + TIPC_AEAD_KEYLEN_MIN)) {
pr_debug("%s: message data size is too small\n", rx->name);
goto exit;
}
spin_lock(&rx->lock); if (unlikely(rx->skey || (key_gen == rx->key_gen && rx->key.keys))) {
pr_err("%s: key existed <%p>, gen %d vs %d\n", rx->name,
rx->skey, key_gen, rx->key_gen);
goto exit_unlock;
}
/* Allocate memory for the key */
skey = kmalloc(size, GFP_ATOMIC); if (unlikely(!skey)) {
pr_err("%s: unable to allocate memory for skey\n", rx->name);
goto exit_unlock;
}
/* Copy key from msg data */
skey->keylen = keylen;
memcpy(skey->alg_name, data, TIPC_AEAD_ALG_NAME);
memcpy(skey->key, data + TIPC_AEAD_ALG_NAME + sizeof(__be32),
skey->keylen);
rx->key_gen = key_gen;
rx->skey_mode = msg_key_mode(hdr);
rx->skey = skey;
rx->nokey = 0;
mb(); /* for nokey flag */
exit_unlock:
spin_unlock(&rx->lock);
exit:
/* Schedule the key attaching on this crypto */ if (likely(skey && queue_delayed_work(tx->wq, &rx->work, 0)))
return true;
return false;
}
/**
* tipc_crypto_work_rx - Scheduled RX works handler
* @work: the struct RX work
*
* The function processes the previous scheduled works i.e. distributing TX key
* or attaching a received session key on RX crypto.
*/
static void tipc_crypto_work_rx(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct tipc_crypto *rx = container_of(dwork, struct tipc_crypto, work);
struct tipc_crypto *tx = tipc_net(rx->net)->crypto_tx;
unsigned long delay = msecs_to_jiffies(5000);
bool resched = false;
u8 key; int rc;
/* Case 1: Distribute TX key to peer if scheduled */ if (atomic_cmpxchg(&rx->key_distr,
KEY_DISTR_SCHED,
KEY_DISTR_COMPL) == KEY_DISTR_SCHED) {
/* Always pick the newest one for distributing */
key = tx->key.pending ?: tx->key.active;
rc = tipc_crypto_key_distr(tx, key, rx->node); if (unlikely(rc))
pr_warn("%s: unable to distr key[%d] to %s, err %d\n",
tx->name, key, tipc_node_get_id_str(rx->node),
rc);
/* Case 2: Attach a pending received session key from peer if any */ if (rx->skey) {
rc = tipc_crypto_key_init(rx, rx->skey, rx->skey_mode, false); if (unlikely(rc < 0))
pr_warn("%s: unable to attach received skey, err %d\n",
rx->name, rc);
switch (rc) {
case -EBUSY:
case -ENOMEM:
/* Resched the key attaching */
resched = true;
break;
default:
synchronize_rcu();
kfree(rx->skey);
rx->skey = NULL;
break;
}
}
if (resched && queue_delayed_work(tx->wq, &rx->work, delay))
return;
tipc_node_put(rx->node);
}
/**
* tipc_crypto_rekeying_sched - (Re)schedule rekeying w/o new interval
* @tx: TX crypto
* @changed: if the rekeying needs to be rescheduled with new interval
* @new_intv: new rekeying interval (when "changed" = true)
*/
void tipc_crypto_rekeying_sched(struct tipc_crypto *tx, bool changed,
u32 new_intv)
{
unsigned long delay;
bool now = false;
if (changed) { if (new_intv == TIPC_REKEYING_NOW)
now = true;
else
tx->rekeying_intv = new_intv;
cancel_delayed_work_sync(&tx->work);
}
/**
* tipc_crypto_work_tx - Scheduled TX works handler
* @work: the struct TX work
*
* The function processes the previous scheduled work, i.e. key rekeying, by
* generating a new session key based on current one, then attaching it to the
* TX crypto and finally distributing it to peers. It also re-schedules the
* rekeying if needed.
*/
static void tipc_crypto_work_tx(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct tipc_crypto *tx = container_of(dwork, struct tipc_crypto, work);
struct tipc_aead_key *skey = NULL;
struct tipc_key key = tx->key;
struct tipc_aead *aead; int rc = -ENOMEM;
if (unlikely(key.pending))
goto resched;
/* Take current key as a template */
rcu_read_lock();
aead = rcu_dereference(tx->aead[key.active ?: KEY_MASTER]); if (unlikely(!aead)) {
rcu_read_unlock();
/* At least one key should exist for securing */
return;
}
/* Lets duplicate it first */
skey = kmemdup(aead->key, tipc_aead_key_size(aead->key), GFP_ATOMIC);
rcu_read_unlock();
/* Now, generate new key, initiate & distribute it */ if (likely(skey)) {
rc = tipc_aead_key_generate(skey) ?:
tipc_crypto_key_init(tx, skey, PER_NODE_KEY, false); if (likely(rc > 0))
rc = tipc_crypto_key_distr(tx, rc, NULL);
kfree_sensitive(skey);
}
if (unlikely(rc))
pr_warn_ratelimited("%s: rekeying returns %d\n", tx->name, rc);
resched:
/* Re-schedule rekeying if any */
tipc_crypto_rekeying_sched(tx, false, 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.