mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-28 11:18:45 +07:00
Merge branch 'sctp-add-support-for-some-sctp-auth-APIs-from-RFC6458'
Xin Long says: ==================== sctp: add support for some sctp auth APIs from RFC6458 This patchset mainly adds support for SCTP AUTH Information for sendmsg, described in RFC6458: 5.3.8. SCTP AUTH Information Structure (SCTP_AUTHINFO) and also adds a sockopt described in RFC6458: 8.3.4. Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY) and two types of events for AUTHENTICATION_EVENT described in RFC6458: 6.1.8. SCTP_AUTHENTICATION_EVENT: - SCTP_AUTH_NO_AUTH - SCTP_AUTH_FREE_KEY After this patchset, we have fully support for sctp_sendv in kernel. Note that this patchset won't touch that sctp options merge conflict. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
c292566a77
@ -62,8 +62,10 @@ struct sctp_auth_bytes {
|
|||||||
/* Definition for a shared key, weather endpoint or association */
|
/* Definition for a shared key, weather endpoint or association */
|
||||||
struct sctp_shared_key {
|
struct sctp_shared_key {
|
||||||
struct list_head key_list;
|
struct list_head key_list;
|
||||||
__u16 key_id;
|
|
||||||
struct sctp_auth_bytes *key;
|
struct sctp_auth_bytes *key;
|
||||||
|
refcount_t refcnt;
|
||||||
|
__u16 key_id;
|
||||||
|
__u8 deactivated;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define key_for_each(__key, __list_head) \
|
#define key_for_each(__key, __list_head) \
|
||||||
@ -103,21 +105,22 @@ int sctp_auth_send_cid(enum sctp_cid chunk,
|
|||||||
int sctp_auth_recv_cid(enum sctp_cid chunk,
|
int sctp_auth_recv_cid(enum sctp_cid chunk,
|
||||||
const struct sctp_association *asoc);
|
const struct sctp_association *asoc);
|
||||||
void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb, struct sctp_auth_chunk *auth,
|
||||||
struct sctp_auth_chunk *auth, gfp_t gfp);
|
struct sctp_shared_key *ep_key, gfp_t gfp);
|
||||||
|
void sctp_auth_shkey_release(struct sctp_shared_key *sh_key);
|
||||||
|
void sctp_auth_shkey_hold(struct sctp_shared_key *sh_key);
|
||||||
|
|
||||||
/* API Helpers */
|
/* API Helpers */
|
||||||
int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id);
|
int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id);
|
||||||
int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
|
int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
|
||||||
struct sctp_hmacalgo *hmacs);
|
struct sctp_hmacalgo *hmacs);
|
||||||
int sctp_auth_set_key(struct sctp_endpoint *ep,
|
int sctp_auth_set_key(struct sctp_endpoint *ep, struct sctp_association *asoc,
|
||||||
struct sctp_association *asoc,
|
|
||||||
struct sctp_authkey *auth_key);
|
struct sctp_authkey *auth_key);
|
||||||
int sctp_auth_set_active_key(struct sctp_endpoint *ep,
|
int sctp_auth_set_active_key(struct sctp_endpoint *ep,
|
||||||
struct sctp_association *asoc,
|
struct sctp_association *asoc, __u16 key_id);
|
||||||
__u16 key_id);
|
|
||||||
int sctp_auth_del_key_id(struct sctp_endpoint *ep,
|
int sctp_auth_del_key_id(struct sctp_endpoint *ep,
|
||||||
struct sctp_association *asoc,
|
struct sctp_association *asoc, __u16 key_id);
|
||||||
__u16 key_id);
|
int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
|
||||||
|
struct sctp_association *asoc, __u16 key_id);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -100,6 +100,7 @@ enum sctp_verb {
|
|||||||
SCTP_CMD_SET_SK_ERR, /* Set sk_err */
|
SCTP_CMD_SET_SK_ERR, /* Set sk_err */
|
||||||
SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
|
SCTP_CMD_ASSOC_CHANGE, /* generate and send assoc_change event */
|
||||||
SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
|
SCTP_CMD_ADAPTATION_IND, /* generate and send adaptation event */
|
||||||
|
SCTP_CMD_PEER_NO_AUTH, /* generate and send authentication event */
|
||||||
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
|
SCTP_CMD_ASSOC_SHKEY, /* generate the association shared keys */
|
||||||
SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
|
SCTP_CMD_T1_RETRAN, /* Mark for retransmission after T1 timeout */
|
||||||
SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
|
SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
|
||||||
|
@ -263,7 +263,8 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
|
|||||||
struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
|
struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
|
||||||
__u32 new_cum_tsn, size_t nstreams,
|
__u32 new_cum_tsn, size_t nstreams,
|
||||||
struct sctp_fwdtsn_skip *skiplist);
|
struct sctp_fwdtsn_skip *skiplist);
|
||||||
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc);
|
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
|
||||||
|
__u16 key_id);
|
||||||
struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc,
|
struct sctp_chunk *sctp_make_strreset_req(const struct sctp_association *asoc,
|
||||||
__u16 stream_num, __be16 *stream_list,
|
__u16 stream_num, __be16 *stream_list,
|
||||||
bool out, bool in);
|
bool out, bool in);
|
||||||
|
@ -577,8 +577,12 @@ struct sctp_chunk {
|
|||||||
/* This points to the sk_buff containing the actual data. */
|
/* This points to the sk_buff containing the actual data. */
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
|
||||||
/* In case of GSO packets, this will store the head one */
|
union {
|
||||||
struct sk_buff *head_skb;
|
/* In case of GSO packets, this will store the head one */
|
||||||
|
struct sk_buff *head_skb;
|
||||||
|
/* In case of auth enabled, this will point to the shkey */
|
||||||
|
struct sctp_shared_key *shkey;
|
||||||
|
};
|
||||||
|
|
||||||
/* These are the SCTP headers by reverse order in a packet.
|
/* These are the SCTP headers by reverse order in a packet.
|
||||||
* Note that some of these may happen more than once. In that
|
* Note that some of these may happen more than once. In that
|
||||||
@ -1995,6 +1999,7 @@ struct sctp_association {
|
|||||||
* The current generated assocaition shared key (secret)
|
* The current generated assocaition shared key (secret)
|
||||||
*/
|
*/
|
||||||
struct sctp_auth_bytes *asoc_shared_key;
|
struct sctp_auth_bytes *asoc_shared_key;
|
||||||
|
struct sctp_shared_key *shkey;
|
||||||
|
|
||||||
/* SCTP AUTH: hmac id of the first peer requested algorithm
|
/* SCTP AUTH: hmac id of the first peer requested algorithm
|
||||||
* that we support.
|
* that we support.
|
||||||
@ -2113,6 +2118,7 @@ struct sctp_cmsgs {
|
|||||||
struct sctp_sndrcvinfo *srinfo;
|
struct sctp_sndrcvinfo *srinfo;
|
||||||
struct sctp_sndinfo *sinfo;
|
struct sctp_sndinfo *sinfo;
|
||||||
struct sctp_prinfo *prinfo;
|
struct sctp_prinfo *prinfo;
|
||||||
|
struct sctp_authinfo *authinfo;
|
||||||
struct msghdr *addrs_msg;
|
struct msghdr *addrs_msg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ typedef __s32 sctp_assoc_t;
|
|||||||
#define SCTP_RECVRCVINFO 32
|
#define SCTP_RECVRCVINFO 32
|
||||||
#define SCTP_RECVNXTINFO 33
|
#define SCTP_RECVNXTINFO 33
|
||||||
#define SCTP_DEFAULT_SNDINFO 34
|
#define SCTP_DEFAULT_SNDINFO 34
|
||||||
|
#define SCTP_AUTH_DEACTIVATE_KEY 35
|
||||||
|
|
||||||
/* Internal Socket Options. Some of the sctp library functions are
|
/* Internal Socket Options. Some of the sctp library functions are
|
||||||
* implemented using these socket options.
|
* implemented using these socket options.
|
||||||
@ -273,6 +274,18 @@ struct sctp_prinfo {
|
|||||||
__u32 pr_value;
|
__u32 pr_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO)
|
||||||
|
*
|
||||||
|
* This cmsghdr structure specifies SCTP options for sendmsg().
|
||||||
|
*
|
||||||
|
* cmsg_level cmsg_type cmsg_data[]
|
||||||
|
* ------------ ------------ -------------------
|
||||||
|
* IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo
|
||||||
|
*/
|
||||||
|
struct sctp_authinfo {
|
||||||
|
__u16 auth_keynumber;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sinfo_flags: 16 bits (unsigned integer)
|
* sinfo_flags: 16 bits (unsigned integer)
|
||||||
*
|
*
|
||||||
@ -310,7 +323,7 @@ typedef enum sctp_cmsg_type {
|
|||||||
#define SCTP_NXTINFO SCTP_NXTINFO
|
#define SCTP_NXTINFO SCTP_NXTINFO
|
||||||
SCTP_PRINFO, /* 5.3.7 SCTP PR-SCTP Information Structure */
|
SCTP_PRINFO, /* 5.3.7 SCTP PR-SCTP Information Structure */
|
||||||
#define SCTP_PRINFO SCTP_PRINFO
|
#define SCTP_PRINFO SCTP_PRINFO
|
||||||
SCTP_AUTHINFO, /* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
|
SCTP_AUTHINFO, /* 5.3.8 SCTP AUTH Information Structure */
|
||||||
#define SCTP_AUTHINFO SCTP_AUTHINFO
|
#define SCTP_AUTHINFO SCTP_AUTHINFO
|
||||||
SCTP_DSTADDRV4, /* 5.3.9 SCTP Destination IPv4 Address Structure */
|
SCTP_DSTADDRV4, /* 5.3.9 SCTP Destination IPv4 Address Structure */
|
||||||
#define SCTP_DSTADDRV4 SCTP_DSTADDRV4
|
#define SCTP_DSTADDRV4 SCTP_DSTADDRV4
|
||||||
@ -505,7 +518,12 @@ struct sctp_authkey_event {
|
|||||||
sctp_assoc_t auth_assoc_id;
|
sctp_assoc_t auth_assoc_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { SCTP_AUTH_NEWKEY = 0, };
|
enum {
|
||||||
|
SCTP_AUTH_NEW_KEY,
|
||||||
|
#define SCTP_AUTH_NEWKEY SCTP_AUTH_NEW_KEY /* compatible with before */
|
||||||
|
SCTP_AUTH_FREE_KEY,
|
||||||
|
SCTP_AUTH_NO_AUTH,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 6.1.9. SCTP_SENDER_DRY_EVENT
|
* 6.1.9. SCTP_SENDER_DRY_EVENT
|
||||||
|
148
net/sctp/auth.c
148
net/sctp/auth.c
@ -101,13 +101,14 @@ struct sctp_shared_key *sctp_auth_shkey_create(__u16 key_id, gfp_t gfp)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&new->key_list);
|
INIT_LIST_HEAD(&new->key_list);
|
||||||
|
refcount_set(&new->refcnt, 1);
|
||||||
new->key_id = key_id;
|
new->key_id = key_id;
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the shared key structure */
|
/* Free the shared key structure */
|
||||||
static void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
|
static void sctp_auth_shkey_destroy(struct sctp_shared_key *sh_key)
|
||||||
{
|
{
|
||||||
BUG_ON(!list_empty(&sh_key->key_list));
|
BUG_ON(!list_empty(&sh_key->key_list));
|
||||||
sctp_auth_key_put(sh_key->key);
|
sctp_auth_key_put(sh_key->key);
|
||||||
@ -115,6 +116,17 @@ static void sctp_auth_shkey_free(struct sctp_shared_key *sh_key)
|
|||||||
kfree(sh_key);
|
kfree(sh_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sctp_auth_shkey_release(struct sctp_shared_key *sh_key)
|
||||||
|
{
|
||||||
|
if (refcount_dec_and_test(&sh_key->refcnt))
|
||||||
|
sctp_auth_shkey_destroy(sh_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sctp_auth_shkey_hold(struct sctp_shared_key *sh_key)
|
||||||
|
{
|
||||||
|
refcount_inc(&sh_key->refcnt);
|
||||||
|
}
|
||||||
|
|
||||||
/* Destroy the entire key list. This is done during the
|
/* Destroy the entire key list. This is done during the
|
||||||
* associon and endpoint free process.
|
* associon and endpoint free process.
|
||||||
*/
|
*/
|
||||||
@ -128,7 +140,7 @@ void sctp_auth_destroy_keys(struct list_head *keys)
|
|||||||
|
|
||||||
key_for_each_safe(ep_key, tmp, keys) {
|
key_for_each_safe(ep_key, tmp, keys) {
|
||||||
list_del_init(&ep_key->key_list);
|
list_del_init(&ep_key->key_list);
|
||||||
sctp_auth_shkey_free(ep_key);
|
sctp_auth_shkey_release(ep_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,13 +421,19 @@ int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
|
|||||||
|
|
||||||
sctp_auth_key_put(asoc->asoc_shared_key);
|
sctp_auth_key_put(asoc->asoc_shared_key);
|
||||||
asoc->asoc_shared_key = secret;
|
asoc->asoc_shared_key = secret;
|
||||||
|
asoc->shkey = ep_key;
|
||||||
|
|
||||||
/* Update send queue in case any chunk already in there now
|
/* Update send queue in case any chunk already in there now
|
||||||
* needs authenticating
|
* needs authenticating
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(chunk, &asoc->outqueue.out_chunk_list, list) {
|
list_for_each_entry(chunk, &asoc->outqueue.out_chunk_list, list) {
|
||||||
if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc))
|
if (sctp_auth_send_cid(chunk->chunk_hdr->type, asoc)) {
|
||||||
chunk->auth = 1;
|
chunk->auth = 1;
|
||||||
|
if (!chunk->shkey) {
|
||||||
|
chunk->shkey = asoc->shkey;
|
||||||
|
sctp_auth_shkey_hold(chunk->shkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -431,8 +449,11 @@ struct sctp_shared_key *sctp_auth_get_shkey(
|
|||||||
|
|
||||||
/* First search associations set of endpoint pair shared keys */
|
/* First search associations set of endpoint pair shared keys */
|
||||||
key_for_each(key, &asoc->endpoint_shared_keys) {
|
key_for_each(key, &asoc->endpoint_shared_keys) {
|
||||||
if (key->key_id == key_id)
|
if (key->key_id == key_id) {
|
||||||
return key;
|
if (!key->deactivated)
|
||||||
|
return key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -703,16 +724,15 @@ int sctp_auth_recv_cid(enum sctp_cid chunk, const struct sctp_association *asoc)
|
|||||||
* after the AUTH chunk in the SCTP packet.
|
* after the AUTH chunk in the SCTP packet.
|
||||||
*/
|
*/
|
||||||
void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb, struct sctp_auth_chunk *auth,
|
||||||
struct sctp_auth_chunk *auth,
|
struct sctp_shared_key *ep_key, gfp_t gfp)
|
||||||
gfp_t gfp)
|
|
||||||
{
|
{
|
||||||
struct crypto_shash *tfm;
|
|
||||||
struct sctp_auth_bytes *asoc_key;
|
struct sctp_auth_bytes *asoc_key;
|
||||||
|
struct crypto_shash *tfm;
|
||||||
__u16 key_id, hmac_id;
|
__u16 key_id, hmac_id;
|
||||||
__u8 *digest;
|
|
||||||
unsigned char *end;
|
unsigned char *end;
|
||||||
int free_key = 0;
|
int free_key = 0;
|
||||||
|
__u8 *digest;
|
||||||
|
|
||||||
/* Extract the info we need:
|
/* Extract the info we need:
|
||||||
* - hmac id
|
* - hmac id
|
||||||
@ -724,12 +744,7 @@ void sctp_auth_calculate_hmac(const struct sctp_association *asoc,
|
|||||||
if (key_id == asoc->active_key_id)
|
if (key_id == asoc->active_key_id)
|
||||||
asoc_key = asoc->asoc_shared_key;
|
asoc_key = asoc->asoc_shared_key;
|
||||||
else {
|
else {
|
||||||
struct sctp_shared_key *ep_key;
|
/* ep_key can't be NULL here */
|
||||||
|
|
||||||
ep_key = sctp_auth_get_shkey(asoc, key_id);
|
|
||||||
if (!ep_key)
|
|
||||||
return;
|
|
||||||
|
|
||||||
asoc_key = sctp_auth_asoc_create_secret(asoc, ep_key, gfp);
|
asoc_key = sctp_auth_asoc_create_secret(asoc, ep_key, gfp);
|
||||||
if (!asoc_key)
|
if (!asoc_key)
|
||||||
return;
|
return;
|
||||||
@ -829,7 +844,7 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
|
|||||||
struct sctp_association *asoc,
|
struct sctp_association *asoc,
|
||||||
struct sctp_authkey *auth_key)
|
struct sctp_authkey *auth_key)
|
||||||
{
|
{
|
||||||
struct sctp_shared_key *cur_key = NULL;
|
struct sctp_shared_key *cur_key, *shkey;
|
||||||
struct sctp_auth_bytes *key;
|
struct sctp_auth_bytes *key;
|
||||||
struct list_head *sh_keys;
|
struct list_head *sh_keys;
|
||||||
int replace = 0;
|
int replace = 0;
|
||||||
@ -842,46 +857,34 @@ int sctp_auth_set_key(struct sctp_endpoint *ep,
|
|||||||
else
|
else
|
||||||
sh_keys = &ep->endpoint_shared_keys;
|
sh_keys = &ep->endpoint_shared_keys;
|
||||||
|
|
||||||
key_for_each(cur_key, sh_keys) {
|
key_for_each(shkey, sh_keys) {
|
||||||
if (cur_key->key_id == auth_key->sca_keynumber) {
|
if (shkey->key_id == auth_key->sca_keynumber) {
|
||||||
replace = 1;
|
replace = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we are not replacing a key id, we need to allocate
|
cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, GFP_KERNEL);
|
||||||
* a shared key.
|
if (!cur_key)
|
||||||
*/
|
return -ENOMEM;
|
||||||
if (!replace) {
|
|
||||||
cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!cur_key)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a new key data based on the info passed in */
|
/* Create a new key data based on the info passed in */
|
||||||
key = sctp_auth_create_key(auth_key->sca_keylength, GFP_KERNEL);
|
key = sctp_auth_create_key(auth_key->sca_keylength, GFP_KERNEL);
|
||||||
if (!key)
|
if (!key) {
|
||||||
goto nomem;
|
kfree(cur_key);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylength);
|
memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylength);
|
||||||
|
|
||||||
/* If we are replacing, remove the old keys data from the
|
|
||||||
* key id. If we are adding new key id, add it to the
|
|
||||||
* list.
|
|
||||||
*/
|
|
||||||
if (replace)
|
|
||||||
sctp_auth_key_put(cur_key->key);
|
|
||||||
else
|
|
||||||
list_add(&cur_key->key_list, sh_keys);
|
|
||||||
|
|
||||||
cur_key->key = key;
|
cur_key->key = key;
|
||||||
return 0;
|
|
||||||
nomem:
|
|
||||||
if (!replace)
|
|
||||||
sctp_auth_shkey_free(cur_key);
|
|
||||||
|
|
||||||
return -ENOMEM;
|
if (replace) {
|
||||||
|
list_del_init(&shkey->key_list);
|
||||||
|
sctp_auth_shkey_release(shkey);
|
||||||
|
}
|
||||||
|
list_add(&cur_key->key_list, sh_keys);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sctp_auth_set_active_key(struct sctp_endpoint *ep,
|
int sctp_auth_set_active_key(struct sctp_endpoint *ep,
|
||||||
@ -905,7 +908,7 @@ int sctp_auth_set_active_key(struct sctp_endpoint *ep,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found || key->deactivated)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (asoc) {
|
if (asoc) {
|
||||||
@ -952,7 +955,58 @@ int sctp_auth_del_key_id(struct sctp_endpoint *ep,
|
|||||||
|
|
||||||
/* Delete the shared key */
|
/* Delete the shared key */
|
||||||
list_del_init(&key->key_list);
|
list_del_init(&key->key_list);
|
||||||
sctp_auth_shkey_free(key);
|
sctp_auth_shkey_release(key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sctp_auth_deact_key_id(struct sctp_endpoint *ep,
|
||||||
|
struct sctp_association *asoc, __u16 key_id)
|
||||||
|
{
|
||||||
|
struct sctp_shared_key *key;
|
||||||
|
struct list_head *sh_keys;
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
/* The key identifier MUST NOT be the current active key
|
||||||
|
* The key identifier MUST correst to an existing key
|
||||||
|
*/
|
||||||
|
if (asoc) {
|
||||||
|
if (asoc->active_key_id == key_id)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
sh_keys = &asoc->endpoint_shared_keys;
|
||||||
|
} else {
|
||||||
|
if (ep->active_key_id == key_id)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
sh_keys = &ep->endpoint_shared_keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
key_for_each(key, sh_keys) {
|
||||||
|
if (key->key_id == key_id) {
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* refcnt == 1 and !list_empty mean it's not being used anywhere
|
||||||
|
* and deactivated will be set, so it's time to notify userland
|
||||||
|
* that this shkey can be freed.
|
||||||
|
*/
|
||||||
|
if (asoc && !list_empty(&key->key_list) &&
|
||||||
|
refcount_read(&key->refcnt) == 1) {
|
||||||
|
struct sctp_ulpevent *ev;
|
||||||
|
|
||||||
|
ev = sctp_ulpevent_make_authkey(asoc, key->key_id,
|
||||||
|
SCTP_AUTH_FREE_KEY, GFP_KERNEL);
|
||||||
|
if (ev)
|
||||||
|
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
key->deactivated = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||||||
{
|
{
|
||||||
size_t len, first_len, max_data, remaining;
|
size_t len, first_len, max_data, remaining;
|
||||||
size_t msg_len = iov_iter_count(from);
|
size_t msg_len = iov_iter_count(from);
|
||||||
|
struct sctp_shared_key *shkey = NULL;
|
||||||
struct list_head *pos, *temp;
|
struct list_head *pos, *temp;
|
||||||
struct sctp_chunk *chunk;
|
struct sctp_chunk *chunk;
|
||||||
struct sctp_datamsg *msg;
|
struct sctp_datamsg *msg;
|
||||||
@ -204,6 +205,17 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||||||
if (hmac_desc)
|
if (hmac_desc)
|
||||||
max_data -= SCTP_PAD4(sizeof(struct sctp_auth_chunk) +
|
max_data -= SCTP_PAD4(sizeof(struct sctp_auth_chunk) +
|
||||||
hmac_desc->hmac_len);
|
hmac_desc->hmac_len);
|
||||||
|
|
||||||
|
if (sinfo->sinfo_tsn &&
|
||||||
|
sinfo->sinfo_ssn != asoc->active_key_id) {
|
||||||
|
shkey = sctp_auth_get_shkey(asoc, sinfo->sinfo_ssn);
|
||||||
|
if (!shkey) {
|
||||||
|
err = -EINVAL;
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shkey = asoc->shkey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check what's our max considering the above */
|
/* Check what's our max considering the above */
|
||||||
@ -275,6 +287,8 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto errout_chunk_free;
|
goto errout_chunk_free;
|
||||||
|
|
||||||
|
chunk->shkey = shkey;
|
||||||
|
|
||||||
/* Put the chunk->skb back into the form expected by send. */
|
/* Put the chunk->skb back into the form expected by send. */
|
||||||
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr -
|
__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr -
|
||||||
chunk->skb->data);
|
chunk->skb->data);
|
||||||
|
@ -241,10 +241,13 @@ static enum sctp_xmit sctp_packet_bundle_auth(struct sctp_packet *pkt,
|
|||||||
if (!chunk->auth)
|
if (!chunk->auth)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
auth = sctp_make_auth(asoc);
|
auth = sctp_make_auth(asoc, chunk->shkey->key_id);
|
||||||
if (!auth)
|
if (!auth)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
auth->shkey = chunk->shkey;
|
||||||
|
sctp_auth_shkey_hold(auth->shkey);
|
||||||
|
|
||||||
retval = __sctp_packet_append_chunk(pkt, auth);
|
retval = __sctp_packet_append_chunk(pkt, auth);
|
||||||
|
|
||||||
if (retval != SCTP_XMIT_OK)
|
if (retval != SCTP_XMIT_OK)
|
||||||
@ -490,7 +493,8 @@ static int sctp_packet_pack(struct sctp_packet *packet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auth) {
|
if (auth) {
|
||||||
sctp_auth_calculate_hmac(tp->asoc, nskb, auth, gfp);
|
sctp_auth_calculate_hmac(tp->asoc, nskb, auth,
|
||||||
|
packet->auth->shkey, gfp);
|
||||||
/* free auth if no more chunks, or add it back */
|
/* free auth if no more chunks, or add it back */
|
||||||
if (list_empty(&packet->chunk_list))
|
if (list_empty(&packet->chunk_list))
|
||||||
sctp_chunk_free(packet->auth);
|
sctp_chunk_free(packet->auth);
|
||||||
@ -770,6 +774,16 @@ static enum sctp_xmit sctp_packet_will_fit(struct sctp_packet *packet,
|
|||||||
enum sctp_xmit retval = SCTP_XMIT_OK;
|
enum sctp_xmit retval = SCTP_XMIT_OK;
|
||||||
size_t psize, pmtu, maxsize;
|
size_t psize, pmtu, maxsize;
|
||||||
|
|
||||||
|
/* Don't bundle in this packet if this chunk's auth key doesn't
|
||||||
|
* match other chunks already enqueued on this packet. Also,
|
||||||
|
* don't bundle the chunk with auth key if other chunks in this
|
||||||
|
* packet don't have auth key.
|
||||||
|
*/
|
||||||
|
if ((packet->auth && chunk->shkey != packet->auth->shkey) ||
|
||||||
|
(!packet->auth && chunk->shkey &&
|
||||||
|
chunk->chunk_hdr->type != SCTP_CID_AUTH))
|
||||||
|
return SCTP_XMIT_PMTU_FULL;
|
||||||
|
|
||||||
psize = packet->size;
|
psize = packet->size;
|
||||||
if (packet->transport->asoc)
|
if (packet->transport->asoc)
|
||||||
pmtu = packet->transport->asoc->pathmtu;
|
pmtu = packet->transport->asoc->pathmtu;
|
||||||
|
@ -87,7 +87,28 @@ static void *sctp_addto_chunk_fixed(struct sctp_chunk *, int len,
|
|||||||
/* Control chunk destructor */
|
/* Control chunk destructor */
|
||||||
static void sctp_control_release_owner(struct sk_buff *skb)
|
static void sctp_control_release_owner(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
/*TODO: do memory release */
|
struct sctp_chunk *chunk = skb_shinfo(skb)->destructor_arg;
|
||||||
|
|
||||||
|
if (chunk->shkey) {
|
||||||
|
struct sctp_shared_key *shkey = chunk->shkey;
|
||||||
|
struct sctp_association *asoc = chunk->asoc;
|
||||||
|
|
||||||
|
/* refcnt == 2 and !list_empty mean after this release, it's
|
||||||
|
* not being used anywhere, and it's time to notify userland
|
||||||
|
* that this shkey can be freed if it's been deactivated.
|
||||||
|
*/
|
||||||
|
if (shkey->deactivated && !list_empty(&shkey->key_list) &&
|
||||||
|
refcount_read(&shkey->refcnt) == 2) {
|
||||||
|
struct sctp_ulpevent *ev;
|
||||||
|
|
||||||
|
ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
|
||||||
|
SCTP_AUTH_FREE_KEY,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (ev)
|
||||||
|
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||||
|
}
|
||||||
|
sctp_auth_shkey_release(chunk->shkey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
||||||
@ -102,7 +123,12 @@ static void sctp_control_set_owner_w(struct sctp_chunk *chunk)
|
|||||||
*
|
*
|
||||||
* For now don't do anything for now.
|
* For now don't do anything for now.
|
||||||
*/
|
*/
|
||||||
|
if (chunk->auth) {
|
||||||
|
chunk->shkey = asoc->shkey;
|
||||||
|
sctp_auth_shkey_hold(chunk->shkey);
|
||||||
|
}
|
||||||
skb->sk = asoc ? asoc->base.sk : NULL;
|
skb->sk = asoc ? asoc->base.sk : NULL;
|
||||||
|
skb_shinfo(skb)->destructor_arg = chunk;
|
||||||
skb->destructor = sctp_control_release_owner;
|
skb->destructor = sctp_control_release_owner;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1271,7 +1297,8 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
|
struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc,
|
||||||
|
__u16 key_id)
|
||||||
{
|
{
|
||||||
struct sctp_authhdr auth_hdr;
|
struct sctp_authhdr auth_hdr;
|
||||||
struct sctp_hmac *hmac_desc;
|
struct sctp_hmac *hmac_desc;
|
||||||
@ -1289,7 +1316,7 @@ struct sctp_chunk *sctp_make_auth(const struct sctp_association *asoc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
|
auth_hdr.hmac_id = htons(hmac_desc->hmac_id);
|
||||||
auth_hdr.shkey_id = htons(asoc->active_key_id);
|
auth_hdr.shkey_id = htons(key_id);
|
||||||
|
|
||||||
retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(auth_hdr),
|
retval->subh.auth_hdr = sctp_addto_chunk(retval, sizeof(auth_hdr),
|
||||||
&auth_hdr);
|
&auth_hdr);
|
||||||
|
@ -1049,6 +1049,16 @@ static void sctp_cmd_assoc_change(struct sctp_cmd_seq *commands,
|
|||||||
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sctp_cmd_peer_no_auth(struct sctp_cmd_seq *commands,
|
||||||
|
struct sctp_association *asoc)
|
||||||
|
{
|
||||||
|
struct sctp_ulpevent *ev;
|
||||||
|
|
||||||
|
ev = sctp_ulpevent_make_authkey(asoc, 0, SCTP_AUTH_NO_AUTH, GFP_ATOMIC);
|
||||||
|
if (ev)
|
||||||
|
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||||
|
}
|
||||||
|
|
||||||
/* Helper function to generate an adaptation indication event */
|
/* Helper function to generate an adaptation indication event */
|
||||||
static void sctp_cmd_adaptation_ind(struct sctp_cmd_seq *commands,
|
static void sctp_cmd_adaptation_ind(struct sctp_cmd_seq *commands,
|
||||||
struct sctp_association *asoc)
|
struct sctp_association *asoc)
|
||||||
@ -1755,6 +1765,9 @@ static int sctp_cmd_interpreter(enum sctp_event event_type,
|
|||||||
case SCTP_CMD_ADAPTATION_IND:
|
case SCTP_CMD_ADAPTATION_IND:
|
||||||
sctp_cmd_adaptation_ind(commands, asoc);
|
sctp_cmd_adaptation_ind(commands, asoc);
|
||||||
break;
|
break;
|
||||||
|
case SCTP_CMD_PEER_NO_AUTH:
|
||||||
|
sctp_cmd_peer_no_auth(commands, asoc);
|
||||||
|
break;
|
||||||
|
|
||||||
case SCTP_CMD_ASSOC_SHKEY:
|
case SCTP_CMD_ASSOC_SHKEY:
|
||||||
error = sctp_auth_asoc_init_active_key(asoc,
|
error = sctp_auth_asoc_init_active_key(asoc,
|
||||||
|
@ -659,7 +659,7 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
|
|||||||
void *arg,
|
void *arg,
|
||||||
struct sctp_cmd_seq *commands)
|
struct sctp_cmd_seq *commands)
|
||||||
{
|
{
|
||||||
struct sctp_ulpevent *ev, *ai_ev = NULL;
|
struct sctp_ulpevent *ev, *ai_ev = NULL, *auth_ev = NULL;
|
||||||
struct sctp_association *new_asoc;
|
struct sctp_association *new_asoc;
|
||||||
struct sctp_init_chunk *peer_init;
|
struct sctp_init_chunk *peer_init;
|
||||||
struct sctp_chunk *chunk = arg;
|
struct sctp_chunk *chunk = arg;
|
||||||
@ -820,6 +820,14 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
|
|||||||
goto nomem_aiev;
|
goto nomem_aiev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!new_asoc->peer.auth_capable) {
|
||||||
|
auth_ev = sctp_ulpevent_make_authkey(new_asoc, 0,
|
||||||
|
SCTP_AUTH_NO_AUTH,
|
||||||
|
GFP_ATOMIC);
|
||||||
|
if (!auth_ev)
|
||||||
|
goto nomem_authev;
|
||||||
|
}
|
||||||
|
|
||||||
/* Add all the state machine commands now since we've created
|
/* Add all the state machine commands now since we've created
|
||||||
* everything. This way we don't introduce memory corruptions
|
* everything. This way we don't introduce memory corruptions
|
||||||
* during side-effect processing and correclty count established
|
* during side-effect processing and correclty count established
|
||||||
@ -847,8 +855,14 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net,
|
|||||||
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
||||||
SCTP_ULPEVENT(ai_ev));
|
SCTP_ULPEVENT(ai_ev));
|
||||||
|
|
||||||
|
if (auth_ev)
|
||||||
|
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
||||||
|
SCTP_ULPEVENT(auth_ev));
|
||||||
|
|
||||||
return SCTP_DISPOSITION_CONSUME;
|
return SCTP_DISPOSITION_CONSUME;
|
||||||
|
|
||||||
|
nomem_authev:
|
||||||
|
sctp_ulpevent_free(ai_ev);
|
||||||
nomem_aiev:
|
nomem_aiev:
|
||||||
sctp_ulpevent_free(ev);
|
sctp_ulpevent_free(ev);
|
||||||
nomem_ev:
|
nomem_ev:
|
||||||
@ -953,6 +967,15 @@ enum sctp_disposition sctp_sf_do_5_1E_ca(struct net *net,
|
|||||||
SCTP_ULPEVENT(ev));
|
SCTP_ULPEVENT(ev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!asoc->peer.auth_capable) {
|
||||||
|
ev = sctp_ulpevent_make_authkey(asoc, 0, SCTP_AUTH_NO_AUTH,
|
||||||
|
GFP_ATOMIC);
|
||||||
|
if (!ev)
|
||||||
|
goto nomem;
|
||||||
|
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
||||||
|
SCTP_ULPEVENT(ev));
|
||||||
|
}
|
||||||
|
|
||||||
return SCTP_DISPOSITION_CONSUME;
|
return SCTP_DISPOSITION_CONSUME;
|
||||||
nomem:
|
nomem:
|
||||||
return SCTP_DISPOSITION_NOMEM;
|
return SCTP_DISPOSITION_NOMEM;
|
||||||
@ -1908,6 +1931,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_b(
|
|||||||
if (asoc->peer.adaptation_ind)
|
if (asoc->peer.adaptation_ind)
|
||||||
sctp_add_cmd_sf(commands, SCTP_CMD_ADAPTATION_IND, SCTP_NULL());
|
sctp_add_cmd_sf(commands, SCTP_CMD_ADAPTATION_IND, SCTP_NULL());
|
||||||
|
|
||||||
|
if (!asoc->peer.auth_capable)
|
||||||
|
sctp_add_cmd_sf(commands, SCTP_CMD_PEER_NO_AUTH, SCTP_NULL());
|
||||||
|
|
||||||
return SCTP_DISPOSITION_CONSUME;
|
return SCTP_DISPOSITION_CONSUME;
|
||||||
|
|
||||||
nomem:
|
nomem:
|
||||||
@ -1954,7 +1980,7 @@ static enum sctp_disposition sctp_sf_do_dupcook_d(
|
|||||||
struct sctp_cmd_seq *commands,
|
struct sctp_cmd_seq *commands,
|
||||||
struct sctp_association *new_asoc)
|
struct sctp_association *new_asoc)
|
||||||
{
|
{
|
||||||
struct sctp_ulpevent *ev = NULL, *ai_ev = NULL;
|
struct sctp_ulpevent *ev = NULL, *ai_ev = NULL, *auth_ev = NULL;
|
||||||
struct sctp_chunk *repl;
|
struct sctp_chunk *repl;
|
||||||
|
|
||||||
/* Clarification from Implementor's Guide:
|
/* Clarification from Implementor's Guide:
|
||||||
@ -2001,6 +2027,14 @@ static enum sctp_disposition sctp_sf_do_dupcook_d(
|
|||||||
goto nomem;
|
goto nomem;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!asoc->peer.auth_capable) {
|
||||||
|
auth_ev = sctp_ulpevent_make_authkey(asoc, 0,
|
||||||
|
SCTP_AUTH_NO_AUTH,
|
||||||
|
GFP_ATOMIC);
|
||||||
|
if (!auth_ev)
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repl = sctp_make_cookie_ack(new_asoc, chunk);
|
repl = sctp_make_cookie_ack(new_asoc, chunk);
|
||||||
@ -2015,10 +2049,15 @@ static enum sctp_disposition sctp_sf_do_dupcook_d(
|
|||||||
if (ai_ev)
|
if (ai_ev)
|
||||||
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
||||||
SCTP_ULPEVENT(ai_ev));
|
SCTP_ULPEVENT(ai_ev));
|
||||||
|
if (auth_ev)
|
||||||
|
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
|
||||||
|
SCTP_ULPEVENT(auth_ev));
|
||||||
|
|
||||||
return SCTP_DISPOSITION_CONSUME;
|
return SCTP_DISPOSITION_CONSUME;
|
||||||
|
|
||||||
nomem:
|
nomem:
|
||||||
|
if (auth_ev)
|
||||||
|
sctp_ulpevent_free(auth_ev);
|
||||||
if (ai_ev)
|
if (ai_ev)
|
||||||
sctp_ulpevent_free(ai_ev);
|
sctp_ulpevent_free(ai_ev);
|
||||||
if (ev)
|
if (ev)
|
||||||
@ -4114,6 +4153,7 @@ static enum sctp_ierror sctp_sf_authenticate(
|
|||||||
const union sctp_subtype type,
|
const union sctp_subtype type,
|
||||||
struct sctp_chunk *chunk)
|
struct sctp_chunk *chunk)
|
||||||
{
|
{
|
||||||
|
struct sctp_shared_key *sh_key = NULL;
|
||||||
struct sctp_authhdr *auth_hdr;
|
struct sctp_authhdr *auth_hdr;
|
||||||
__u8 *save_digest, *digest;
|
__u8 *save_digest, *digest;
|
||||||
struct sctp_hmac *hmac;
|
struct sctp_hmac *hmac;
|
||||||
@ -4135,9 +4175,11 @@ static enum sctp_ierror sctp_sf_authenticate(
|
|||||||
* configured
|
* configured
|
||||||
*/
|
*/
|
||||||
key_id = ntohs(auth_hdr->shkey_id);
|
key_id = ntohs(auth_hdr->shkey_id);
|
||||||
if (key_id != asoc->active_key_id && !sctp_auth_get_shkey(asoc, key_id))
|
if (key_id != asoc->active_key_id) {
|
||||||
return SCTP_IERROR_AUTH_BAD_KEYID;
|
sh_key = sctp_auth_get_shkey(asoc, key_id);
|
||||||
|
if (!sh_key)
|
||||||
|
return SCTP_IERROR_AUTH_BAD_KEYID;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure that the length of the signature matches what
|
/* Make sure that the length of the signature matches what
|
||||||
* we expect.
|
* we expect.
|
||||||
@ -4166,7 +4208,7 @@ static enum sctp_ierror sctp_sf_authenticate(
|
|||||||
|
|
||||||
sctp_auth_calculate_hmac(asoc, chunk->skb,
|
sctp_auth_calculate_hmac(asoc, chunk->skb,
|
||||||
(struct sctp_auth_chunk *)chunk->chunk_hdr,
|
(struct sctp_auth_chunk *)chunk->chunk_hdr,
|
||||||
GFP_ATOMIC);
|
sh_key, GFP_ATOMIC);
|
||||||
|
|
||||||
/* Discard the packet if the digests do not match */
|
/* Discard the packet if the digests do not match */
|
||||||
if (memcmp(save_digest, digest, sig_len)) {
|
if (memcmp(save_digest, digest, sig_len)) {
|
||||||
@ -4243,7 +4285,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
|
|||||||
struct sctp_ulpevent *ev;
|
struct sctp_ulpevent *ev;
|
||||||
|
|
||||||
ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id),
|
ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id),
|
||||||
SCTP_AUTH_NEWKEY, GFP_ATOMIC);
|
SCTP_AUTH_NEW_KEY, GFP_ATOMIC);
|
||||||
|
|
||||||
if (!ev)
|
if (!ev)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -156,6 +156,9 @@ static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
|
|||||||
/* The sndbuf space is tracked per association. */
|
/* The sndbuf space is tracked per association. */
|
||||||
sctp_association_hold(asoc);
|
sctp_association_hold(asoc);
|
||||||
|
|
||||||
|
if (chunk->shkey)
|
||||||
|
sctp_auth_shkey_hold(chunk->shkey);
|
||||||
|
|
||||||
skb_set_owner_w(chunk->skb, sk);
|
skb_set_owner_w(chunk->skb, sk);
|
||||||
|
|
||||||
chunk->skb->destructor = sctp_wfree;
|
chunk->skb->destructor = sctp_wfree;
|
||||||
@ -1984,6 +1987,14 @@ static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc,
|
|||||||
|
|
||||||
if (!cmsgs->srinfo && !cmsgs->prinfo)
|
if (!cmsgs->srinfo && !cmsgs->prinfo)
|
||||||
sinfo->sinfo_timetolive = asoc->default_timetolive;
|
sinfo->sinfo_timetolive = asoc->default_timetolive;
|
||||||
|
|
||||||
|
if (cmsgs->authinfo) {
|
||||||
|
/* Reuse sinfo_tsn to indicate that authinfo was set and
|
||||||
|
* sinfo_ssn to save the keyid on tx path.
|
||||||
|
*/
|
||||||
|
sinfo->sinfo_tsn = 1;
|
||||||
|
sinfo->sinfo_ssn = cmsgs->authinfo->auth_keynumber;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
|
static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
|
||||||
@ -3635,6 +3646,33 @@ static int sctp_setsockopt_del_key(struct sock *sk,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8.3.4 Deactivate a Shared Key (SCTP_AUTH_DEACTIVATE_KEY)
|
||||||
|
*
|
||||||
|
* This set option will deactivate a shared secret key.
|
||||||
|
*/
|
||||||
|
static int sctp_setsockopt_deactivate_key(struct sock *sk, char __user *optval,
|
||||||
|
unsigned int optlen)
|
||||||
|
{
|
||||||
|
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
|
||||||
|
struct sctp_authkeyid val;
|
||||||
|
struct sctp_association *asoc;
|
||||||
|
|
||||||
|
if (!ep->auth_enable)
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
if (optlen != sizeof(struct sctp_authkeyid))
|
||||||
|
return -EINVAL;
|
||||||
|
if (copy_from_user(&val, optval, optlen))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
asoc = sctp_id2assoc(sk, val.scact_assoc_id);
|
||||||
|
if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return sctp_auth_deact_key_id(ep, asoc, val.scact_keynumber);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 8.1.23 SCTP_AUTO_ASCONF
|
* 8.1.23 SCTP_AUTO_ASCONF
|
||||||
*
|
*
|
||||||
@ -4227,6 +4265,9 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
|
|||||||
case SCTP_AUTH_DELETE_KEY:
|
case SCTP_AUTH_DELETE_KEY:
|
||||||
retval = sctp_setsockopt_del_key(sk, optval, optlen);
|
retval = sctp_setsockopt_del_key(sk, optval, optlen);
|
||||||
break;
|
break;
|
||||||
|
case SCTP_AUTH_DEACTIVATE_KEY:
|
||||||
|
retval = sctp_setsockopt_deactivate_key(sk, optval, optlen);
|
||||||
|
break;
|
||||||
case SCTP_AUTO_ASCONF:
|
case SCTP_AUTO_ASCONF:
|
||||||
retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
|
retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
|
||||||
break;
|
break;
|
||||||
@ -7201,6 +7242,7 @@ static int sctp_getsockopt(struct sock *sk, int level, int optname,
|
|||||||
case SCTP_AUTH_KEY:
|
case SCTP_AUTH_KEY:
|
||||||
case SCTP_AUTH_CHUNK:
|
case SCTP_AUTH_CHUNK:
|
||||||
case SCTP_AUTH_DELETE_KEY:
|
case SCTP_AUTH_DELETE_KEY:
|
||||||
|
case SCTP_AUTH_DEACTIVATE_KEY:
|
||||||
retval = -EOPNOTSUPP;
|
retval = -EOPNOTSUPP;
|
||||||
break;
|
break;
|
||||||
case SCTP_HMAC_IDENT:
|
case SCTP_HMAC_IDENT:
|
||||||
@ -7871,6 +7913,21 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
|
|||||||
if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
|
if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
|
||||||
cmsgs->prinfo->pr_value = 0;
|
cmsgs->prinfo->pr_value = 0;
|
||||||
break;
|
break;
|
||||||
|
case SCTP_AUTHINFO:
|
||||||
|
/* SCTP Socket API Extension
|
||||||
|
* 5.3.8 SCTP AUTH Information Structure (SCTP_AUTHINFO)
|
||||||
|
*
|
||||||
|
* This cmsghdr structure specifies SCTP options for sendmsg().
|
||||||
|
*
|
||||||
|
* cmsg_level cmsg_type cmsg_data[]
|
||||||
|
* ------------ ------------ ---------------------
|
||||||
|
* IPPROTO_SCTP SCTP_AUTHINFO struct sctp_authinfo
|
||||||
|
*/
|
||||||
|
if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_authinfo)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
cmsgs->authinfo = CMSG_DATA(cmsg);
|
||||||
|
break;
|
||||||
case SCTP_DSTADDRV4:
|
case SCTP_DSTADDRV4:
|
||||||
case SCTP_DSTADDRV6:
|
case SCTP_DSTADDRV6:
|
||||||
/* SCTP Socket API Extension
|
/* SCTP Socket API Extension
|
||||||
@ -8109,6 +8166,26 @@ static void sctp_wfree(struct sk_buff *skb)
|
|||||||
sk->sk_wmem_queued -= skb->truesize;
|
sk->sk_wmem_queued -= skb->truesize;
|
||||||
sk_mem_uncharge(sk, skb->truesize);
|
sk_mem_uncharge(sk, skb->truesize);
|
||||||
|
|
||||||
|
if (chunk->shkey) {
|
||||||
|
struct sctp_shared_key *shkey = chunk->shkey;
|
||||||
|
|
||||||
|
/* refcnt == 2 and !list_empty mean after this release, it's
|
||||||
|
* not being used anywhere, and it's time to notify userland
|
||||||
|
* that this shkey can be freed if it's been deactivated.
|
||||||
|
*/
|
||||||
|
if (shkey->deactivated && !list_empty(&shkey->key_list) &&
|
||||||
|
refcount_read(&shkey->refcnt) == 2) {
|
||||||
|
struct sctp_ulpevent *ev;
|
||||||
|
|
||||||
|
ev = sctp_ulpevent_make_authkey(asoc, shkey->key_id,
|
||||||
|
SCTP_AUTH_FREE_KEY,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (ev)
|
||||||
|
asoc->stream.si->enqueue_event(&asoc->ulpq, ev);
|
||||||
|
}
|
||||||
|
sctp_auth_shkey_release(chunk->shkey);
|
||||||
|
}
|
||||||
|
|
||||||
sock_wfree(skb);
|
sock_wfree(skb);
|
||||||
sctp_wake_up_waiters(sk, asoc);
|
sctp_wake_up_waiters(sk, asoc);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user