diff options
author | David Howells <dhowells@redhat.com> | 2017-04-06 05:11:59 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2017-04-06 05:11:59 -0400 |
commit | ef68622da9cc0c4e5202f90093a3a5314e41e9e9 (patch) | |
tree | e1fe504e4a3a217a248689dd28e12f1926b21ad0 /net/rxrpc | |
parent | 84a4c09c38903a92ba670375efea5165949a465b (diff) |
rxrpc: Handle temporary errors better in rxkad security
In the rxkad security module, when we encounter a temporary error (such as
ENOMEM) from which we could conceivably recover, don't abort the
connection, but rather permit retransmission of the relevant packets to
induce a retry.
Note that I'm leaving some places that could be merged together to insert
tracing in the next patch.
Signed-off-by; David Howells <dhowells@redhat.com>
Diffstat (limited to 'net/rxrpc')
-rw-r--r-- | net/rxrpc/rxkad.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 2d5838a3dc24..988903f1dc80 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c | |||
@@ -759,16 +759,14 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, | |||
759 | 759 | ||
760 | _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key)); | 760 | _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key)); |
761 | 761 | ||
762 | if (!conn->params.key) { | 762 | abort_code = RX_PROTOCOL_ERROR; |
763 | _leave(" = -EPROTO [no key]"); | 763 | if (!conn->params.key) |
764 | return -EPROTO; | 764 | goto protocol_error; |
765 | } | ||
766 | 765 | ||
766 | abort_code = RXKADEXPIRED; | ||
767 | ret = key_validate(conn->params.key); | 767 | ret = key_validate(conn->params.key); |
768 | if (ret < 0) { | 768 | if (ret < 0) |
769 | *_abort_code = RXKADEXPIRED; | 769 | goto other_error; |
770 | return ret; | ||
771 | } | ||
772 | 770 | ||
773 | abort_code = RXKADPACKETSHORT; | 771 | abort_code = RXKADPACKETSHORT; |
774 | if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), | 772 | if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), |
@@ -787,8 +785,9 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, | |||
787 | goto protocol_error; | 785 | goto protocol_error; |
788 | 786 | ||
789 | abort_code = RXKADLEVELFAIL; | 787 | abort_code = RXKADLEVELFAIL; |
788 | ret = -EACCES; | ||
790 | if (conn->params.security_level < min_level) | 789 | if (conn->params.security_level < min_level) |
791 | goto protocol_error; | 790 | goto other_error; |
792 | 791 | ||
793 | token = conn->params.key->payload.data[0]; | 792 | token = conn->params.key->payload.data[0]; |
794 | 793 | ||
@@ -815,9 +814,10 @@ static int rxkad_respond_to_challenge(struct rxrpc_connection *conn, | |||
815 | return rxkad_send_response(conn, &sp->hdr, &resp, token->kad); | 814 | return rxkad_send_response(conn, &sp->hdr, &resp, token->kad); |
816 | 815 | ||
817 | protocol_error: | 816 | protocol_error: |
817 | ret = -EPROTO; | ||
818 | other_error: | ||
818 | *_abort_code = abort_code; | 819 | *_abort_code = abort_code; |
819 | _leave(" = -EPROTO [%d]", abort_code); | 820 | return ret; |
820 | return -EPROTO; | ||
821 | } | 821 | } |
822 | 822 | ||
823 | /* | 823 | /* |
@@ -848,10 +848,10 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, | |||
848 | switch (ret) { | 848 | switch (ret) { |
849 | case -EKEYEXPIRED: | 849 | case -EKEYEXPIRED: |
850 | *_abort_code = RXKADEXPIRED; | 850 | *_abort_code = RXKADEXPIRED; |
851 | goto error; | 851 | goto other_error; |
852 | default: | 852 | default: |
853 | *_abort_code = RXKADNOAUTH; | 853 | *_abort_code = RXKADNOAUTH; |
854 | goto error; | 854 | goto other_error; |
855 | } | 855 | } |
856 | } | 856 | } |
857 | 857 | ||
@@ -860,13 +860,11 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, | |||
860 | 860 | ||
861 | memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv)); | 861 | memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv)); |
862 | 862 | ||
863 | ret = -ENOMEM; | ||
863 | req = skcipher_request_alloc(conn->server_key->payload.data[0], | 864 | req = skcipher_request_alloc(conn->server_key->payload.data[0], |
864 | GFP_NOFS); | 865 | GFP_NOFS); |
865 | if (!req) { | 866 | if (!req) |
866 | *_abort_code = RXKADNOAUTH; | 867 | goto temporary_error; |
867 | ret = -ENOMEM; | ||
868 | goto error; | ||
869 | } | ||
870 | 868 | ||
871 | sg_init_one(&sg[0], ticket, ticket_len); | 869 | sg_init_one(&sg[0], ticket, ticket_len); |
872 | skcipher_request_set_callback(req, 0, NULL, NULL); | 870 | skcipher_request_set_callback(req, 0, NULL, NULL); |
@@ -943,13 +941,13 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, | |||
943 | if (issue > now) { | 941 | if (issue > now) { |
944 | *_abort_code = RXKADNOAUTH; | 942 | *_abort_code = RXKADNOAUTH; |
945 | ret = -EKEYREJECTED; | 943 | ret = -EKEYREJECTED; |
946 | goto error; | 944 | goto other_error; |
947 | } | 945 | } |
948 | 946 | ||
949 | if (issue < now - life) { | 947 | if (issue < now - life) { |
950 | *_abort_code = RXKADEXPIRED; | 948 | *_abort_code = RXKADEXPIRED; |
951 | ret = -EKEYEXPIRED; | 949 | ret = -EKEYEXPIRED; |
952 | goto error; | 950 | goto other_error; |
953 | } | 951 | } |
954 | 952 | ||
955 | *_expiry = issue + life; | 953 | *_expiry = issue + life; |
@@ -961,16 +959,15 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, | |||
961 | /* get the service instance name */ | 959 | /* get the service instance name */ |
962 | name = Z(INST_SZ); | 960 | name = Z(INST_SZ); |
963 | _debug("KIV SINST: %s", name); | 961 | _debug("KIV SINST: %s", name); |
964 | 962 | return 0; | |
965 | ret = 0; | ||
966 | error: | ||
967 | _leave(" = %d", ret); | ||
968 | return ret; | ||
969 | 963 | ||
970 | bad_ticket: | 964 | bad_ticket: |
971 | *_abort_code = RXKADBADTICKET; | 965 | *_abort_code = RXKADBADTICKET; |
972 | ret = -EBADMSG; | 966 | ret = -EPROTO; |
973 | goto error; | 967 | other_error: |
968 | return ret; | ||
969 | temporary_error: | ||
970 | return ret; | ||
974 | } | 971 | } |
975 | 972 | ||
976 | /* | 973 | /* |
@@ -1054,9 +1051,10 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, | |||
1054 | goto protocol_error; | 1051 | goto protocol_error; |
1055 | 1052 | ||
1056 | /* extract the kerberos ticket and decrypt and decode it */ | 1053 | /* extract the kerberos ticket and decrypt and decode it */ |
1054 | ret = -ENOMEM; | ||
1057 | ticket = kmalloc(ticket_len, GFP_NOFS); | 1055 | ticket = kmalloc(ticket_len, GFP_NOFS); |
1058 | if (!ticket) | 1056 | if (!ticket) |
1059 | return -ENOMEM; | 1057 | goto temporary_error; |
1060 | 1058 | ||
1061 | abort_code = RXKADPACKETSHORT; | 1059 | abort_code = RXKADPACKETSHORT; |
1062 | if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), | 1060 | if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header), |
@@ -1064,12 +1062,9 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, | |||
1064 | goto protocol_error_free; | 1062 | goto protocol_error_free; |
1065 | 1063 | ||
1066 | ret = rxkad_decrypt_ticket(conn, ticket, ticket_len, &session_key, | 1064 | ret = rxkad_decrypt_ticket(conn, ticket, ticket_len, &session_key, |
1067 | &expiry, &abort_code); | 1065 | &expiry, _abort_code); |
1068 | if (ret < 0) { | 1066 | if (ret < 0) |
1069 | *_abort_code = abort_code; | 1067 | goto temporary_error_free; |
1070 | kfree(ticket); | ||
1071 | return ret; | ||
1072 | } | ||
1073 | 1068 | ||
1074 | /* use the session key from inside the ticket to decrypt the | 1069 | /* use the session key from inside the ticket to decrypt the |
1075 | * response */ | 1070 | * response */ |
@@ -1123,10 +1118,8 @@ static int rxkad_verify_response(struct rxrpc_connection *conn, | |||
1123 | * this the connection security can be handled in exactly the same way | 1118 | * this the connection security can be handled in exactly the same way |
1124 | * as for a client connection */ | 1119 | * as for a client connection */ |
1125 | ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno); | 1120 | ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno); |
1126 | if (ret < 0) { | 1121 | if (ret < 0) |
1127 | kfree(ticket); | 1122 | goto temporary_error_free; |
1128 | return ret; | ||
1129 | } | ||
1130 | 1123 | ||
1131 | kfree(ticket); | 1124 | kfree(ticket); |
1132 | _leave(" = 0"); | 1125 | _leave(" = 0"); |
@@ -1140,6 +1133,15 @@ protocol_error: | |||
1140 | *_abort_code = abort_code; | 1133 | *_abort_code = abort_code; |
1141 | _leave(" = -EPROTO [%d]", abort_code); | 1134 | _leave(" = -EPROTO [%d]", abort_code); |
1142 | return -EPROTO; | 1135 | return -EPROTO; |
1136 | |||
1137 | temporary_error_free: | ||
1138 | kfree(ticket); | ||
1139 | temporary_error: | ||
1140 | /* Ignore the response packet if we got a temporary error such as | ||
1141 | * ENOMEM. We just want to send the challenge again. Note that we | ||
1142 | * also come out this way if the ticket decryption fails. | ||
1143 | */ | ||
1144 | return ret; | ||
1143 | } | 1145 | } |
1144 | 1146 | ||
1145 | /* | 1147 | /* |