| From 09c1e8dd0c18948fa8cdcee5d7666d99061ee07e Mon Sep 17 00:00:00 2001 |
| From: Harald Freudenberger <freude@linux.ibm.com> |
| Date: Fri, 20 Dec 2019 16:02:54 +0100 |
| Subject: [PATCH] s390/zcrypt: fix card and queue total counter wrap |
| |
| commit fcd98d4002539f1e381916fc1b6648938c1eac76 upstream. |
| |
| The internal statistic counters for the total number of |
| requests processed per card and per queue used integers. So they do |
| wrap after a rather huge amount of crypto requests processed. This |
| patch introduces uint64 counters which should hold much longer but |
| still may wrap. The sysfs attributes request_count for card and queue |
| also used only %ld and now display the counter value with %llu. |
| |
| This is not a security relevant fix. The int overflow which happened |
| is not in any way exploitable as a security breach. |
| |
| Signed-off-by: Harald Freudenberger <freude@linux.ibm.com> |
| Signed-off-by: Vasily Gorbik <gor@linux.ibm.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h |
| index 10f8024f03cb..36a3bfada3e4 100644 |
| --- a/drivers/s390/crypto/ap_bus.h |
| +++ b/drivers/s390/crypto/ap_bus.h |
| @@ -161,7 +161,7 @@ struct ap_card { |
| unsigned int functions; /* AP device function bitfield. */ |
| int queue_depth; /* AP queue depth.*/ |
| int id; /* AP card number. */ |
| - atomic_t total_request_count; /* # requests ever for this AP device.*/ |
| + atomic64_t total_request_count; /* # requests ever for this AP device.*/ |
| }; |
| |
| #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) |
| @@ -178,7 +178,7 @@ struct ap_queue { |
| enum ap_state state; /* State of the AP device. */ |
| int pendingq_count; /* # requests on pendingq list. */ |
| int requestq_count; /* # requests on requestq list. */ |
| - int total_request_count; /* # requests ever for this AP device.*/ |
| + u64 total_request_count; /* # requests ever for this AP device.*/ |
| int request_timeout; /* Request timeout in jiffies. */ |
| struct timer_list timeout; /* Timer for request timeouts. */ |
| struct list_head pendingq; /* List of message sent to AP queue. */ |
| diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c |
| index 63b4cc6cd7e5..e85bfca1ed16 100644 |
| --- a/drivers/s390/crypto/ap_card.c |
| +++ b/drivers/s390/crypto/ap_card.c |
| @@ -63,13 +63,13 @@ static ssize_t request_count_show(struct device *dev, |
| char *buf) |
| { |
| struct ap_card *ac = to_ap_card(dev); |
| - unsigned int req_cnt; |
| + u64 req_cnt; |
| |
| req_cnt = 0; |
| spin_lock_bh(&ap_list_lock); |
| - req_cnt = atomic_read(&ac->total_request_count); |
| + req_cnt = atomic64_read(&ac->total_request_count); |
| spin_unlock_bh(&ap_list_lock); |
| - return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); |
| + return snprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); |
| } |
| |
| static ssize_t request_count_store(struct device *dev, |
| @@ -83,7 +83,7 @@ static ssize_t request_count_store(struct device *dev, |
| for_each_ap_queue(aq, ac) |
| aq->total_request_count = 0; |
| spin_unlock_bh(&ap_list_lock); |
| - atomic_set(&ac->total_request_count, 0); |
| + atomic64_set(&ac->total_request_count, 0); |
| |
| return count; |
| } |
| diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c |
| index a3f8d2512698..4d3a31b9e14d 100644 |
| --- a/drivers/s390/crypto/ap_queue.c |
| +++ b/drivers/s390/crypto/ap_queue.c |
| @@ -478,12 +478,12 @@ static ssize_t request_count_show(struct device *dev, |
| char *buf) |
| { |
| struct ap_queue *aq = to_ap_queue(dev); |
| - unsigned int req_cnt; |
| + u64 req_cnt; |
| |
| spin_lock_bh(&aq->lock); |
| req_cnt = aq->total_request_count; |
| spin_unlock_bh(&aq->lock); |
| - return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); |
| + return snprintf(buf, PAGE_SIZE, "%llu\n", req_cnt); |
| } |
| |
| static ssize_t request_count_store(struct device *dev, |
| @@ -675,7 +675,7 @@ void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) |
| list_add_tail(&ap_msg->list, &aq->requestq); |
| aq->requestq_count++; |
| aq->total_request_count++; |
| - atomic_inc(&aq->card->total_request_count); |
| + atomic64_inc(&aq->card->total_request_count); |
| /* Send/receive as many request from the queue as possible. */ |
| ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL)); |
| spin_unlock_bh(&aq->lock); |
| diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c |
| index 35a0e9569239..71e20fb6a1af 100644 |
| --- a/drivers/s390/crypto/zcrypt_api.c |
| +++ b/drivers/s390/crypto/zcrypt_api.c |
| @@ -622,8 +622,8 @@ static inline bool zcrypt_card_compare(struct zcrypt_card *zc, |
| weight += atomic_read(&zc->load); |
| pref_weight += atomic_read(&pref_zc->load); |
| if (weight == pref_weight) |
| - return atomic_read(&zc->card->total_request_count) > |
| - atomic_read(&pref_zc->card->total_request_count); |
| + return atomic64_read(&zc->card->total_request_count) > |
| + atomic64_read(&pref_zc->card->total_request_count); |
| return weight > pref_weight; |
| } |
| |
| @@ -1205,11 +1205,12 @@ static void zcrypt_qdepth_mask(char qdepth[], size_t max_adapters) |
| spin_unlock(&zcrypt_list_lock); |
| } |
| |
| -static void zcrypt_perdev_reqcnt(int reqcnt[], size_t max_adapters) |
| +static void zcrypt_perdev_reqcnt(u32 reqcnt[], size_t max_adapters) |
| { |
| struct zcrypt_card *zc; |
| struct zcrypt_queue *zq; |
| int card; |
| + u64 cnt; |
| |
| memset(reqcnt, 0, sizeof(int) * max_adapters); |
| spin_lock(&zcrypt_list_lock); |
| @@ -1221,8 +1222,9 @@ static void zcrypt_perdev_reqcnt(int reqcnt[], size_t max_adapters) |
| || card >= max_adapters) |
| continue; |
| spin_lock(&zq->queue->lock); |
| - reqcnt[card] = zq->queue->total_request_count; |
| + cnt = zq->queue->total_request_count; |
| spin_unlock(&zq->queue->lock); |
| + reqcnt[card] = (cnt < UINT_MAX) ? (u32) cnt : UINT_MAX; |
| } |
| } |
| local_bh_enable(); |
| @@ -1400,9 +1402,9 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, |
| return 0; |
| } |
| case ZCRYPT_PERDEV_REQCNT: { |
| - int *reqcnt; |
| + u32 *reqcnt; |
| |
| - reqcnt = kcalloc(AP_DEVICES, sizeof(int), GFP_KERNEL); |
| + reqcnt = kcalloc(AP_DEVICES, sizeof(u32), GFP_KERNEL); |
| if (!reqcnt) |
| return -ENOMEM; |
| zcrypt_perdev_reqcnt(reqcnt, AP_DEVICES); |
| @@ -1459,7 +1461,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, |
| } |
| case Z90STAT_PERDEV_REQCNT: { |
| /* the old ioctl supports only 64 adapters */ |
| - int reqcnt[MAX_ZDEV_CARDIDS]; |
| + u32 reqcnt[MAX_ZDEV_CARDIDS]; |
| |
| zcrypt_perdev_reqcnt(reqcnt, MAX_ZDEV_CARDIDS); |
| if (copy_to_user((int __user *) arg, reqcnt, sizeof(reqcnt))) |
| -- |
| 2.7.4 |
| |