Skip to content

Commit 27c4f67

Browse files
hfreudeVasily Gorbik
authored andcommitted
s390/zcrypt: Introduce Failure Injection feature
Introduce a way to specify additional debug flags with an crpyto request to be able to trigger certain failures within the zcrypt device drivers and/or ap core code. This failure injection possibility is only enabled with a kernel debug build CONFIG_ZCRYPT_DEBUG) and should never be available on a regular kernel running in production environment. Details: * The ioctl(ICARSAMODEXPO) get's a struct ica_rsa_modexpo. If the leftmost bit of the 32 bit unsigned int inputdatalength field is set, the uppermost 16 bits are separated and used as debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. * The ioctl(ICARSACRT) get's a struct ica_rsa_modexpo_crt. If the leftmost bit of the 32 bit unsigned int inputdatalength field is set, the uppermost 16 bits are separated and used als debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. * The ioctl(ZSECSENDCPRB) used to send CCA CPRBs get's a struct ica_xcRB. If the leftmost bit of the 32 bit unsigned int status field is set, the uppermost 16 bits of this field are used as debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. * The ioctl(ZSENDEP11CPRB) used to send EP11 CPRBs get's a struct ep11_urb. If the leftmost bit of the 64 bit unsigned int req_len field is set, the uppermost 16 bits of this field are used as debug flag value. The process is checked to have the CAP_SYS_ADMIN capability enabled or EPERM is returned. So it is possible to send an additional 16 bit value to the zcrypt API to be used to carry a failure injection command which may trigger special behavior within the zcrypt API and layers below. This 16 bit value is for the rest of the test referred as 'fi command' for Failure Injection. The lower 8 bits of the fi command construct a numerical argument in the range of 1-255 and is the 'fi action' to be performed with the request or the resulting reply: * 0x00 (all requests): No failure injection action but flags may be provided which may affect the processing of the request or reply. * 0x01 (only CCA CPRBs): The CPRB's agent_ID field is set to 'FF'. This results in an reply code 0x90 (Transport-Protocol Failure). * 0x02 (only CCA CPRBs): After the APQN to send to has been chosen, the domain field within the CPRB is overwritten with value 99 to enforce an reply with RY 0x8A. * 0x03 (all requests): At NQAP invocation the invalid qid value 0xFF00 is used causing an response code of 0x01 (AP queue not valid). The upper 8 bits of the fi command may carry bit flags which may influence the processing of an request or response: * 0x01: No retry. If this bit is set, the usual loop in the zcrypt API which retries an CPRB up to 10 times when the lower layers return with EAGAIN is abandoned after the first attempt to send the CPRB. * 0x02: Toggle special. Toggles the special bit on this request. This should result in an reply code RY~0x41 and result in an ioctl failure with errno EINVAL. This failure injection possibilities may get some further extensions in the future. As of now this is a starting point for Continuous Test and Integration to trigger some failures and watch for the reaction of the ap bus and zcrypt device driver code. Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 3730f53 commit 27c4f67

6 files changed

Lines changed: 151 additions & 3 deletions

File tree

drivers/s390/crypto/ap_bus.h

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,20 +200,45 @@ struct ap_queue {
200200

201201
typedef enum ap_sm_wait (ap_func_t)(struct ap_queue *queue);
202202

203+
/* failure injection cmd struct */
204+
struct ap_fi {
205+
union {
206+
u16 cmd; /* fi flags + action */
207+
struct {
208+
u8 flags; /* fi flags only */
209+
u8 action; /* fi action only */
210+
};
211+
};
212+
};
213+
214+
/* all currently known fi actions */
215+
enum ap_fi_actions {
216+
AP_FI_ACTION_CCA_AGENT_FF = 0x01,
217+
AP_FI_ACTION_CCA_DOM_INVAL = 0x02,
218+
AP_FI_ACTION_NQAP_QID_INVAL = 0x03,
219+
};
220+
221+
/* all currently known fi flags */
222+
enum ap_fi_flags {
223+
AP_FI_FLAG_NO_RETRY = 0x01,
224+
AP_FI_FLAG_TOGGLE_SPECIAL = 0x02,
225+
};
226+
203227
struct ap_message {
204228
struct list_head list; /* Request queueing. */
205229
unsigned long long psmid; /* Message id. */
206230
void *msg; /* Pointer to message buffer. */
207231
unsigned int len; /* Message length. */
208-
u32 flags; /* Flags, see AP_MSG_FLAG_xxx */
232+
u16 flags; /* Flags, see AP_MSG_FLAG_xxx */
233+
struct ap_fi fi; /* Failure Injection cmd */
209234
int rc; /* Return code for this message */
210235
void *private; /* ap driver private pointer. */
211236
/* receive is called from tasklet context */
212237
void (*receive)(struct ap_queue *, struct ap_message *,
213238
struct ap_message *);
214239
};
215240

216-
#define AP_MSG_FLAG_SPECIAL (1 << 16) /* flag msg as 'special' with NQAP */
241+
#define AP_MSG_FLAG_SPECIAL 1 /* flag msg as 'special' with NQAP */
217242

218243
/**
219244
* ap_init_message() - Initialize ap_message.

drivers/s390/crypto/ap_queue.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,20 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq)
214214
{
215215
struct ap_queue_status status;
216216
struct ap_message *ap_msg;
217+
ap_qid_t qid = aq->qid;
217218

218219
if (aq->requestq_count <= 0)
219220
return AP_SM_WAIT_NONE;
220221
/* Start the next request on the queue. */
221222
ap_msg = list_entry(aq->requestq.next, struct ap_message, list);
222-
status = __ap_send(aq->qid, ap_msg->psmid,
223+
#ifdef CONFIG_ZCRYPT_DEBUG
224+
if (ap_msg->fi.action == AP_FI_ACTION_NQAP_QID_INVAL) {
225+
AP_DBF_WARN("%s fi cmd 0x%04x: forcing invalid qid 0xFF00\n",
226+
__func__, ap_msg->fi.cmd);
227+
qid = 0xFF00;
228+
}
229+
#endif
230+
status = __ap_send(qid, ap_msg->psmid,
223231
ap_msg->msg, ap_msg->len,
224232
ap_msg->flags & AP_MSG_FLAG_SPECIAL);
225233
switch (status.response_code) {

drivers/s390/crypto/zcrypt_api.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <linux/debugfs.h>
2626
#include <linux/cdev.h>
2727
#include <linux/ctype.h>
28+
#include <linux/capability.h>
2829
#include <asm/debug.h>
2930

3031
#define CREATE_TRACE_POINTS
@@ -645,6 +646,11 @@ static long zcrypt_rsa_modexpo(struct ap_perms *perms,
645646

646647
ap_init_message(&ap_msg);
647648

649+
#ifdef CONFIG_ZCRYPT_DEBUG
650+
if (tr && tr->fi.cmd)
651+
ap_msg.fi.cmd = tr->fi.cmd;
652+
#endif
653+
648654
if (mex->outputdatalength < mex->inputdatalength) {
649655
func_code = 0;
650656
rc = -EINVAL;
@@ -748,6 +754,11 @@ static long zcrypt_rsa_crt(struct ap_perms *perms,
748754

749755
ap_init_message(&ap_msg);
750756

757+
#ifdef CONFIG_ZCRYPT_DEBUG
758+
if (tr && tr->fi.cmd)
759+
ap_msg.fi.cmd = tr->fi.cmd;
760+
#endif
761+
751762
if (crt->outputdatalength < crt->inputdatalength) {
752763
func_code = 0;
753764
rc = -EINVAL;
@@ -852,6 +863,17 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
852863

853864
xcRB->status = 0;
854865
ap_init_message(&ap_msg);
866+
867+
#ifdef CONFIG_ZCRYPT_DEBUG
868+
if (tr && tr->fi.cmd)
869+
ap_msg.fi.cmd = tr->fi.cmd;
870+
if (tr && tr->fi.action == AP_FI_ACTION_CCA_AGENT_FF) {
871+
ZCRYPT_DBF_WARN("%s fi cmd 0x%04x: forcing invalid agent_ID 'FF'\n",
872+
__func__, tr->fi.cmd);
873+
xcRB->agent_ID = 0x4646;
874+
}
875+
#endif
876+
855877
rc = get_cprb_fc(userspace, xcRB, &ap_msg, &func_code, &domain);
856878
if (rc)
857879
goto out;
@@ -927,6 +949,14 @@ static long _zcrypt_send_cprb(bool userspace, struct ap_perms *perms,
927949
if (*domain == AUTOSEL_DOM)
928950
*domain = AP_QID_QUEUE(qid);
929951

952+
#ifdef CONFIG_ZCRYPT_DEBUG
953+
if (tr && tr->fi.action == AP_FI_ACTION_CCA_DOM_INVAL) {
954+
ZCRYPT_DBF_WARN("%s fi cmd 0x%04x: forcing invalid domain\n",
955+
__func__, tr->fi.cmd);
956+
*domain = 99;
957+
}
958+
#endif
959+
930960
rc = pref_zq->ops->send_cprb(userspace, pref_zq, xcRB, &ap_msg);
931961

932962
spin_lock(&zcrypt_list_lock);
@@ -995,6 +1025,11 @@ static long _zcrypt_send_ep11_cprb(bool userspace, struct ap_perms *perms,
9951025

9961026
ap_init_message(&ap_msg);
9971027

1028+
#ifdef CONFIG_ZCRYPT_DEBUG
1029+
if (tr && tr->fi.cmd)
1030+
ap_msg.fi.cmd = tr->fi.cmd;
1031+
#endif
1032+
9981033
target_num = (unsigned short) xcrb->targets_num;
9991034

10001035
/* empty list indicates autoselect (all available targets) */
@@ -1377,10 +1412,24 @@ static int icarsamodexpo_ioctl(struct ap_perms *perms, unsigned long arg)
13771412
memset(&tr, 0, sizeof(tr));
13781413
if (copy_from_user(&mex, umex, sizeof(mex)))
13791414
return -EFAULT;
1415+
1416+
#ifdef CONFIG_ZCRYPT_DEBUG
1417+
if (mex.inputdatalength & (1U << 31)) {
1418+
if (!capable(CAP_SYS_ADMIN))
1419+
return -EPERM;
1420+
tr.fi.cmd = (u16)(mex.inputdatalength >> 16);
1421+
}
1422+
mex.inputdatalength &= 0x0000FFFF;
1423+
#endif
1424+
13801425
do {
13811426
rc = zcrypt_rsa_modexpo(perms, &tr, &mex);
13821427
if (rc == -EAGAIN)
13831428
tr.again_counter++;
1429+
#ifdef CONFIG_ZCRYPT_DEBUG
1430+
if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY))
1431+
break;
1432+
#endif
13841433
} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
13851434
/* on failure: retry once again after a requested rescan */
13861435
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
@@ -1406,10 +1455,24 @@ static int icarsacrt_ioctl(struct ap_perms *perms, unsigned long arg)
14061455
memset(&tr, 0, sizeof(tr));
14071456
if (copy_from_user(&crt, ucrt, sizeof(crt)))
14081457
return -EFAULT;
1458+
1459+
#ifdef CONFIG_ZCRYPT_DEBUG
1460+
if (crt.inputdatalength & (1U << 31)) {
1461+
if (!capable(CAP_SYS_ADMIN))
1462+
return -EPERM;
1463+
tr.fi.cmd = (u16)(crt.inputdatalength >> 16);
1464+
}
1465+
crt.inputdatalength &= 0x0000FFFF;
1466+
#endif
1467+
14091468
do {
14101469
rc = zcrypt_rsa_crt(perms, &tr, &crt);
14111470
if (rc == -EAGAIN)
14121471
tr.again_counter++;
1472+
#ifdef CONFIG_ZCRYPT_DEBUG
1473+
if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY))
1474+
break;
1475+
#endif
14131476
} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
14141477
/* on failure: retry once again after a requested rescan */
14151478
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
@@ -1435,10 +1498,24 @@ static int zsecsendcprb_ioctl(struct ap_perms *perms, unsigned long arg)
14351498
memset(&tr, 0, sizeof(tr));
14361499
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
14371500
return -EFAULT;
1501+
1502+
#ifdef CONFIG_ZCRYPT_DEBUG
1503+
if (xcRB.status & (1U << 31)) {
1504+
if (!capable(CAP_SYS_ADMIN))
1505+
return -EPERM;
1506+
tr.fi.cmd = (u16)(xcRB.status >> 16);
1507+
}
1508+
xcRB.status &= 0x0000FFFF;
1509+
#endif
1510+
14381511
do {
14391512
rc = _zcrypt_send_cprb(true, perms, &tr, &xcRB);
14401513
if (rc == -EAGAIN)
14411514
tr.again_counter++;
1515+
#ifdef CONFIG_ZCRYPT_DEBUG
1516+
if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY))
1517+
break;
1518+
#endif
14421519
} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
14431520
/* on failure: retry once again after a requested rescan */
14441521
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
@@ -1465,10 +1542,24 @@ static int zsendep11cprb_ioctl(struct ap_perms *perms, unsigned long arg)
14651542
memset(&tr, 0, sizeof(tr));
14661543
if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
14671544
return -EFAULT;
1545+
1546+
#ifdef CONFIG_ZCRYPT_DEBUG
1547+
if (xcrb.req_len & (1ULL << 63)) {
1548+
if (!capable(CAP_SYS_ADMIN))
1549+
return -EPERM;
1550+
tr.fi.cmd = (u16)(xcrb.req_len >> 48);
1551+
}
1552+
xcrb.req_len &= 0x0000FFFFFFFFFFFFULL;
1553+
#endif
1554+
14681555
do {
14691556
rc = _zcrypt_send_ep11_cprb(true, perms, &tr, &xcrb);
14701557
if (rc == -EAGAIN)
14711558
tr.again_counter++;
1559+
#ifdef CONFIG_ZCRYPT_DEBUG
1560+
if (rc == -EAGAIN && (tr.fi.flags & AP_FI_FLAG_NO_RETRY))
1561+
break;
1562+
#endif
14721563
} while (rc == -EAGAIN && tr.again_counter < TRACK_AGAIN_MAX);
14731564
/* on failure: retry once again after a requested rescan */
14741565
if ((rc == -ENODEV) && (zcrypt_process_rescan()))

drivers/s390/crypto/zcrypt_api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ struct zcrypt_track {
6060
int again_counter; /* retry attempts counter */
6161
int last_qid; /* last qid used */
6262
int last_rc; /* last return code */
63+
#ifdef CONFIG_ZCRYPT_DEBUG
64+
struct ap_fi fi; /* failure injection cmd */
65+
#endif
6366
};
6467

6568
/* defines related to message tracking */

drivers/s390/crypto/zcrypt_msgtype50.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,12 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq,
246246
copy_from_user(exp, mex->b_key, mod_len) ||
247247
copy_from_user(inp, mex->inputdata, mod_len))
248248
return -EFAULT;
249+
250+
#ifdef CONFIG_ZCRYPT_DEBUG
251+
if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL)
252+
ap_msg->flags ^= AP_MSG_FLAG_SPECIAL;
253+
#endif
254+
249255
return 0;
250256
}
251257

@@ -332,6 +338,11 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
332338
copy_from_user(inp, crt->inputdata, mod_len))
333339
return -EFAULT;
334340

341+
#ifdef CONFIG_ZCRYPT_DEBUG
342+
if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL)
343+
ap_msg->flags ^= AP_MSG_FLAG_SPECIAL;
344+
#endif
345+
335346
return 0;
336347
}
337348

drivers/s390/crypto/zcrypt_msgtype6.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,11 @@ static int XCRB_msg_to_type6CPRB_msgX(bool userspace, struct ap_message *ap_msg,
482482
|| memcmp(function_code, "AU", 2) == 0)
483483
ap_msg->flags |= AP_MSG_FLAG_SPECIAL;
484484

485+
#ifdef CONFIG_ZCRYPT_DEBUG
486+
if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL)
487+
ap_msg->flags ^= AP_MSG_FLAG_SPECIAL;
488+
#endif
489+
485490
/* copy data block */
486491
if (xcRB->request_data_length &&
487492
z_copy_from_user(userspace, req_data, xcRB->request_data_address,
@@ -569,6 +574,11 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(bool userspace, struct ap_message *ap
569574
if (msg->cprbx.flags & 0x20)
570575
ap_msg->flags |= AP_MSG_FLAG_SPECIAL;
571576

577+
#ifdef CONFIG_ZCRYPT_DEBUG
578+
if (ap_msg->fi.flags & AP_FI_FLAG_TOGGLE_SPECIAL)
579+
ap_msg->flags ^= AP_MSG_FLAG_SPECIAL;
580+
#endif
581+
572582
return 0;
573583
}
574584

0 commit comments

Comments
 (0)