Received: by 2002:a05:6a10:af89:0:0:0:0 with SMTP id iu9csp5537701pxb; Wed, 26 Jan 2022 14:27:53 -0800 (PST) X-Google-Smtp-Source: ABdhPJz5Otbs/+yEwuqmb7sL9ZrmHpTTj+mhz3EjpGpe4XcEiMZrwlgzNPwahMCoVp+eN+zxo8Zw X-Received: by 2002:a05:6402:528a:: with SMTP id en10mr991338edb.209.1643236073596; Wed, 26 Jan 2022 14:27:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1643236073; cv=none; d=google.com; s=arc-20160816; b=SoTsC5QJ0kSMETe4ZJvXo8VVG+XscsVFSHOsdYlxaByCY9+BYNAYHfJqvuIAio+cpC MN6XzFN6D1HqHnFs4pQ0NpljrWaKbxECKpcy/QqroF8rm87KyQiSHFLt8hDDMtnzgZzI NC9iYDCXZfhLlmPrJNjviL6a2bmp9Edetlwvoh1qFJy33AZKuA8N4Wwo2hTaJcQRWuKF qYXk94Fe8o8wHt9eGLvQFT7gRQtSBlA9Cct+mZGhJ6OWwSlVu/wcKEnqdelxP6czoha6 rPRL0GynJnAXomvPuin61O2RA7IAvaj8y/qgYBCTc7mQADQwKuMJUrHQqLItgtNVkHDA f/PA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:to:from :dkim-signature; bh=5WscGeHykgFKvtNA2a3xQVpoktH8d9hYnkzSqx4X754=; b=CUmQD+7AgCL+23h1q0ezJ8vVPrNCQOXgqqPYSqIvWxksulwp+fkoAKOiTH200H2Weo vNPgOMkH/o7ZEjCCIqExiXMItv6us0NHuJ0htt4w8yUOjX2aMLCwdQ5HmkOI29dbHOiD 62hNEra0xp32HVCz9ySzbEULMRqxYe9sOA8RU2qLm9vlkV3VKv9WADQ930MQiB/qHmU5 dDEHjsku+fo5dxoStySJnw7l1iPSFftWGHp/5mCPcogs9INWpsKYiPtD7ryrFH8dWlGu NbGMMj9cQe4K7vpodOOxynoBkhVg6xwZCEo+b9ePsx1CI25iPrJeXXT4oBmDqNeNoueX uZtA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@soleen.com header.s=google header.b=c5KOiDhI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d25si279495ejo.289.2022.01.26.14.27.28; Wed, 26 Jan 2022 14:27:53 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@soleen.com header.s=google header.b=c5KOiDhI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238337AbiAZSej (ORCPT + 99 others); Wed, 26 Jan 2022 13:34:39 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60120 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238302AbiAZSee (ORCPT ); Wed, 26 Jan 2022 13:34:34 -0500 Received: from mail-qv1-xf2d.google.com (mail-qv1-xf2d.google.com [IPv6:2607:f8b0:4864:20::f2d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D4D81C06161C for ; Wed, 26 Jan 2022 10:34:33 -0800 (PST) Received: by mail-qv1-xf2d.google.com with SMTP id o9so581009qvy.13 for ; Wed, 26 Jan 2022 10:34:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=5WscGeHykgFKvtNA2a3xQVpoktH8d9hYnkzSqx4X754=; b=c5KOiDhIQTjr76e99jrvXjP+zQIipG3qWrlyoBFSGPZvpXa3a24bsABSirLKilejPC HkTjj42IFw8t4AGBMUZWfJ7deIiZuar7QUetQ8j4b4ofpD9nqn3+4cZ+Qs8vY95+vQF3 0YiNinlkA9NmsHXyZHGsJIIXnG2UIJ6XjZZ7qxMufoPDrAK4ntjA7Duo9NfAdnsNtZjp s/Q8JPMpXFQvDIwl2QI3Apz9+P5MxV3P6qHkV3oq9kortiYH97cGqcZNdyBFGhEUXVIX TdnOrdrUYAxm1YWbVGQ0v05o4Zwi7U4IYlcDrSNMwEf1C1RR/aG//gsOJJPFR3WepWN6 bd7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5WscGeHykgFKvtNA2a3xQVpoktH8d9hYnkzSqx4X754=; b=kQLoE3TR3fVpzSs0sPBC6pKvtgGYuhm6E7xkrfuT0TYPD0FC6zm431flpHy43nBTVk afsR4oV6L+km3lKYf/Qd7wA3IAw9ULC6zwmQ3cZOjVy6NMnqDhUbQ5vKq0iqiuf26A8x 2l6tPNhKHEdeVb+/MyGX0ZSJQmSPb4m4xXzvEZ62iJ6SI43ZHcBMqV3H8tZG7EtTwYbc ej30J7/P4YIdO266pgg/DCd26Ii1f3EEvl5dvJs9iy6gbLALXHQpWXcvXJ7G8HhZMjFm 2QaBP97mbLM99cldmuSB/iMaGdWOhISz7SY13kOt10zxfcdxVncqmqg0vO141SByQ+Ju 6mSw== X-Gm-Message-State: AOAM5306Jsm22FA2juqyqrfpR7MH+A+isTBd/T5c2ip0eKDb5weGqzav rVMbnWt/Ub+is3smGwORWkDKEg== X-Received: by 2002:a05:6214:2b06:: with SMTP id jx6mr15297174qvb.117.1643222072958; Wed, 26 Jan 2022 10:34:32 -0800 (PST) Received: from soleen.c.googlers.com.com (189.216.85.34.bc.googleusercontent.com. [34.85.216.189]) by smtp.gmail.com with ESMTPSA id u17sm35886qki.12.2022.01.26.10.34.32 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Jan 2022 10:34:32 -0800 (PST) From: Pasha Tatashin To: pasha.tatashin@soleen.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-m68k@lists.linux-m68k.org, anshuman.khandual@arm.com, willy@infradead.org, akpm@linux-foundation.org, william.kucharski@oracle.com, mike.kravetz@oracle.com, vbabka@suse.cz, geert@linux-m68k.org, schmitzmic@gmail.com, rostedt@goodmis.org, mingo@redhat.com, hannes@cmpxchg.org, guro@fb.com, songmuchun@bytedance.com, weixugc@google.com, gthelen@google.com, rientjes@google.com, pjt@google.com, hughd@google.com Subject: [PATCH v3 1/9] mm: add overflow and underflow checks for page->_refcount Date: Wed, 26 Jan 2022 18:34:21 +0000 Message-Id: <20220126183429.1840447-2-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.35.0.rc0.227.g00780c9af4-goog In-Reply-To: <20220126183429.1840447-1-pasha.tatashin@soleen.com> References: <20220126183429.1840447-1-pasha.tatashin@soleen.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The problems with page->_refcount are hard to debug, because usually when they are detected, the damage has occurred a long time ago. Yet, the problems with invalid page refcount may be catastrophic and lead to memory corruptions. Reduce the scope of when the _refcount problems manifest themselves by adding checks for underflows and overflows into functions that modify _refcount. Use atomic_fetch_* functions to get the old values of the _refcount, and use it to check for overflow/underflow. Signed-off-by: Pasha Tatashin --- include/linux/page_ref.h | 59 +++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h index 2e677e6ad09f..fe4864f7f69c 100644 --- a/include/linux/page_ref.h +++ b/include/linux/page_ref.h @@ -117,7 +117,10 @@ static inline void init_page_count(struct page *page) static inline void page_ref_add(struct page *page, int nr) { - atomic_add(nr, &page->_refcount); + int old_val = atomic_fetch_add(nr, &page->_refcount); + int new_val = old_val + nr; + + VM_BUG_ON_PAGE((unsigned int)new_val < (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod)) __page_ref_mod(page, nr); } @@ -129,7 +132,10 @@ static inline void folio_ref_add(struct folio *folio, int nr) static inline void page_ref_sub(struct page *page, int nr) { - atomic_sub(nr, &page->_refcount); + int old_val = atomic_fetch_sub(nr, &page->_refcount); + int new_val = old_val - nr; + + VM_BUG_ON_PAGE((unsigned int)new_val > (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod)) __page_ref_mod(page, -nr); } @@ -141,11 +147,13 @@ static inline void folio_ref_sub(struct folio *folio, int nr) static inline int page_ref_sub_return(struct page *page, int nr) { - int ret = atomic_sub_return(nr, &page->_refcount); + int old_val = atomic_fetch_sub(nr, &page->_refcount); + int new_val = old_val - nr; + VM_BUG_ON_PAGE((unsigned int)new_val > (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod_and_return)) - __page_ref_mod_and_return(page, -nr, ret); - return ret; + __page_ref_mod_and_return(page, -nr, new_val); + return new_val; } static inline int folio_ref_sub_return(struct folio *folio, int nr) @@ -155,7 +163,10 @@ static inline int folio_ref_sub_return(struct folio *folio, int nr) static inline void page_ref_inc(struct page *page) { - atomic_inc(&page->_refcount); + int old_val = atomic_fetch_inc(&page->_refcount); + int new_val = old_val + 1; + + VM_BUG_ON_PAGE((unsigned int)new_val < (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod)) __page_ref_mod(page, 1); } @@ -167,7 +178,10 @@ static inline void folio_ref_inc(struct folio *folio) static inline void page_ref_dec(struct page *page) { - atomic_dec(&page->_refcount); + int old_val = atomic_fetch_dec(&page->_refcount); + int new_val = old_val - 1; + + VM_BUG_ON_PAGE((unsigned int)new_val > (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod)) __page_ref_mod(page, -1); } @@ -179,8 +193,11 @@ static inline void folio_ref_dec(struct folio *folio) static inline int page_ref_sub_and_test(struct page *page, int nr) { - int ret = atomic_sub_and_test(nr, &page->_refcount); + int old_val = atomic_fetch_sub(nr, &page->_refcount); + int new_val = old_val - nr; + int ret = new_val == 0; + VM_BUG_ON_PAGE((unsigned int)new_val > (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod_and_test)) __page_ref_mod_and_test(page, -nr, ret); return ret; @@ -193,11 +210,13 @@ static inline int folio_ref_sub_and_test(struct folio *folio, int nr) static inline int page_ref_inc_return(struct page *page) { - int ret = atomic_inc_return(&page->_refcount); + int old_val = atomic_fetch_inc(&page->_refcount); + int new_val = old_val + 1; + VM_BUG_ON_PAGE((unsigned int)new_val < (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod_and_return)) - __page_ref_mod_and_return(page, 1, ret); - return ret; + __page_ref_mod_and_return(page, 1, new_val); + return new_val; } static inline int folio_ref_inc_return(struct folio *folio) @@ -207,8 +226,11 @@ static inline int folio_ref_inc_return(struct folio *folio) static inline int page_ref_dec_and_test(struct page *page) { - int ret = atomic_dec_and_test(&page->_refcount); + int old_val = atomic_fetch_dec(&page->_refcount); + int new_val = old_val - 1; + int ret = new_val == 0; + VM_BUG_ON_PAGE((unsigned int)new_val > (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod_and_test)) __page_ref_mod_and_test(page, -1, ret); return ret; @@ -221,11 +243,13 @@ static inline int folio_ref_dec_and_test(struct folio *folio) static inline int page_ref_dec_return(struct page *page) { - int ret = atomic_dec_return(&page->_refcount); + int old_val = atomic_fetch_dec(&page->_refcount); + int new_val = old_val - 1; + VM_BUG_ON_PAGE((unsigned int)new_val > (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod_and_return)) - __page_ref_mod_and_return(page, -1, ret); - return ret; + __page_ref_mod_and_return(page, -1, new_val); + return new_val; } static inline int folio_ref_dec_return(struct folio *folio) @@ -235,8 +259,11 @@ static inline int folio_ref_dec_return(struct folio *folio) static inline bool page_ref_add_unless(struct page *page, int nr, int u) { - bool ret = atomic_add_unless(&page->_refcount, nr, u); + int old_val = atomic_fetch_add_unless(&page->_refcount, nr, u); + int new_val = old_val + nr; + int ret = old_val != u; + VM_BUG_ON_PAGE(ret && (unsigned int)new_val < (unsigned int)old_val, page); if (page_ref_tracepoint_active(page_ref_mod_unless)) __page_ref_mod_unless(page, nr, ret); return ret; -- 2.35.0.rc0.227.g00780c9af4-goog