@@ -76,11 +76,155 @@ static void rxgk_describe_server_key(const struct key *key, struct seq_file *m)
7676 seq_printf (m , ": %s" , krb5 -> name );
7777}
7878
79+ /*
80+ * Handle rekeying the connection when we see our limits overrun or when the
81+ * far side decided to rekey.
82+ *
83+ * Returns a ref on the context if successful or -ESTALE if the key is out of
84+ * date.
85+ */
86+ static struct rxgk_context * rxgk_rekey (struct rxrpc_connection * conn ,
87+ const u16 * specific_key_number )
88+ {
89+ struct rxgk_context * gk , * dead = NULL ;
90+ unsigned int key_number , current_key , mask = ARRAY_SIZE (conn -> rxgk .keys ) - 1 ;
91+ bool crank = false;
92+
93+ _enter ("%d" , specific_key_number ? * specific_key_number : -1 );
94+
95+ mutex_lock (& conn -> security_lock );
96+
97+ current_key = conn -> rxgk .key_number ;
98+ if (!specific_key_number ) {
99+ key_number = current_key ;
100+ } else {
101+ if (* specific_key_number == (u16 )current_key )
102+ key_number = current_key ;
103+ else if (* specific_key_number == (u16 )(current_key - 1 ))
104+ key_number = current_key - 1 ;
105+ else if (* specific_key_number == (u16 )(current_key + 1 ))
106+ goto crank_window ;
107+ else
108+ goto bad_key ;
109+ }
110+
111+ gk = conn -> rxgk .keys [key_number & mask ];
112+ if (!gk )
113+ goto generate_key ;
114+ if (!specific_key_number &&
115+ test_bit (RXGK_TK_NEEDS_REKEY , & gk -> flags ))
116+ goto crank_window ;
117+
118+ grab :
119+ refcount_inc (& gk -> usage );
120+ mutex_unlock (& conn -> security_lock );
121+ rxgk_put (dead );
122+ return gk ;
123+
124+ crank_window :
125+ trace_rxrpc_rxgk_rekey (conn , current_key ,
126+ specific_key_number ? * specific_key_number : -1 );
127+ if (current_key == UINT_MAX )
128+ goto bad_key ;
129+ if (current_key + 1 == UINT_MAX )
130+ set_bit (RXRPC_CONN_DONT_REUSE , & conn -> flags );
131+
132+ key_number = current_key + 1 ;
133+ if (WARN_ON (conn -> rxgk .keys [key_number & mask ]))
134+ goto bad_key ;
135+ crank = true;
136+
137+ generate_key :
138+ gk = conn -> rxgk .keys [current_key & mask ];
139+ gk = rxgk_generate_transport_key (conn , gk -> key , key_number , GFP_NOFS );
140+ if (IS_ERR (gk )) {
141+ mutex_unlock (& conn -> security_lock );
142+ return gk ;
143+ }
144+
145+ write_lock (& conn -> security_use_lock );
146+ if (crank ) {
147+ current_key ++ ;
148+ conn -> rxgk .key_number = current_key ;
149+ dead = conn -> rxgk .keys [(current_key - 2 ) & mask ];
150+ conn -> rxgk .keys [(current_key - 2 ) & mask ] = NULL ;
151+ }
152+ conn -> rxgk .keys [current_key & mask ] = gk ;
153+ write_unlock (& conn -> security_use_lock );
154+ goto grab ;
155+
156+ bad_key :
157+ mutex_unlock (& conn -> security_lock );
158+ return ERR_PTR (- ESTALE );
159+ }
160+
161+ /*
162+ * Get the specified keying context.
163+ *
164+ * Returns a ref on the context if successful or -ESTALE if the key is out of
165+ * date.
166+ */
79167static struct rxgk_context * rxgk_get_key (struct rxrpc_connection * conn ,
80- u16 * specific_key_number )
168+ const u16 * specific_key_number )
81169{
82- refcount_inc (& conn -> rxgk .keys [0 ]-> usage );
83- return conn -> rxgk .keys [0 ];
170+ struct rxgk_context * gk ;
171+ unsigned int key_number , current_key , mask = ARRAY_SIZE (conn -> rxgk .keys ) - 1 ;
172+
173+ _enter ("{%u},%d" ,
174+ conn -> rxgk .key_number , specific_key_number ? * specific_key_number : -1 );
175+
176+ read_lock (& conn -> security_use_lock );
177+
178+ current_key = conn -> rxgk .key_number ;
179+ if (!specific_key_number ) {
180+ key_number = current_key ;
181+ } else {
182+ /* Only the bottom 16 bits of the key number are exposed in the
183+ * header, so we try and keep the upper 16 bits in step. The
184+ * whole 32 bits are used to generate the TK.
185+ */
186+ if (* specific_key_number == (u16 )current_key )
187+ key_number = current_key ;
188+ else if (* specific_key_number == (u16 )(current_key - 1 ))
189+ key_number = current_key - 1 ;
190+ else if (* specific_key_number == (u16 )(current_key + 1 ))
191+ goto rekey ;
192+ else
193+ goto bad_key ;
194+ }
195+
196+ gk = conn -> rxgk .keys [key_number & mask ];
197+ if (!gk )
198+ goto slow_path ;
199+ if (!specific_key_number &&
200+ key_number < UINT_MAX ) {
201+ if (time_after (jiffies , gk -> expiry ) ||
202+ gk -> bytes_remaining < 0 ) {
203+ set_bit (RXGK_TK_NEEDS_REKEY , & gk -> flags );
204+ goto slow_path ;
205+ }
206+
207+ if (test_bit (RXGK_TK_NEEDS_REKEY , & gk -> flags ))
208+ goto slow_path ;
209+ }
210+
211+ refcount_inc (& gk -> usage );
212+ read_unlock (& conn -> security_use_lock );
213+ return gk ;
214+
215+ rekey :
216+ _debug ("rekey" );
217+ if (current_key == UINT_MAX )
218+ goto bad_key ;
219+ gk = conn -> rxgk .keys [current_key & mask ];
220+ if (gk )
221+ set_bit (RXGK_TK_NEEDS_REKEY , & gk -> flags );
222+ slow_path :
223+ read_unlock (& conn -> security_use_lock );
224+ return rxgk_rekey (conn , specific_key_number );
225+ bad_key :
226+ read_unlock (& conn -> security_use_lock );
227+ return ERR_PTR (- ESTALE );
84228}
85229
86230/*
@@ -92,7 +236,8 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
92236 struct rxgk_context * gk ;
93237 int ret ;
94238
95- _enter ("{%d},{%x}" , conn -> debug_id , key_serial (conn -> key ));
239+ _enter ("{%d,%u},{%x}" ,
240+ conn -> debug_id , conn -> rxgk .key_number , key_serial (conn -> key ));
96241
97242 conn -> security_ix = token -> security_index ;
98243 conn -> security_level = token -> rxgk -> level ;
@@ -102,11 +247,12 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
102247 do_div (conn -> rxgk .start_time , 100 );
103248 }
104249
105- gk = rxgk_generate_transport_key (conn , token -> rxgk , 0 , GFP_NOFS );
250+ gk = rxgk_generate_transport_key (conn , token -> rxgk , conn -> rxgk .key_number ,
251+ GFP_NOFS );
106252 if (IS_ERR (gk ))
107253 return PTR_ERR (gk );
108254 conn -> rxgk .enctype = gk -> krb5 -> etype ;
109- conn -> rxgk .keys [0 ] = gk ;
255+ conn -> rxgk .keys [gk -> key_number & 3 ] = gk ;
110256
111257 switch (conn -> security_level ) {
112258 case RXRPC_SECURITY_PLAIN :
0 commit comments