From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.1 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SIGNED_OFF_BY,SPF_HELO_NONE, SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 46041C433E0 for ; Tue, 19 May 2020 18:14:17 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id 1D8B320674 for ; Tue, 19 May 2020 18:14:15 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="aDw1q/Gc" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 1D8B320674 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=linux.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 9051480007; Tue, 19 May 2020 14:14:15 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 8DB6A900002; Tue, 19 May 2020 14:14:15 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7CB6480007; Tue, 19 May 2020 14:14:15 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0041.hostedemail.com [216.40.44.41]) by kanga.kvack.org (Postfix) with ESMTP id 605E5900002 for ; Tue, 19 May 2020 14:14:15 -0400 (EDT) Received: from smtpin27.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay03.hostedemail.com (Postfix) with ESMTP id 25904824556B for ; Tue, 19 May 2020 18:14:15 +0000 (UTC) X-FDA: 76834268070.27.corn37_7fbf08c3b35a X-HE-Tag: corn37_7fbf08c3b35a X-Filterd-Recvd-Size: 8724 Received: from mail-wm1-f66.google.com (mail-wm1-f66.google.com [209.85.128.66]) by imf44.hostedemail.com (Postfix) with ESMTP for ; Tue, 19 May 2020 18:14:14 +0000 (UTC) Received: by mail-wm1-f66.google.com with SMTP id u1so206155wmn.3 for ; Tue, 19 May 2020 11:14:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:date:from:to:cc:subject:message-id:mail-followup-to :mime-version:content-disposition:user-agent; bh=Smbnh/HjJZfXW9umDTUlih066PFtxdapl55+liTkPwU=; b=aDw1q/Gcg/iKskACjlVFyCLUCG7c7zqmH32bqk8M1zWcKSzmtRuNo9w3BCn0wKWsjL AnyO3xoCyLsf8Z3YX7yykH4AXXIE5jJBgBnxOWWVWC+3jbal211Cy9p0XfM43vXfujG4 3VcVe+Q/UgcclgL0x5PHCog6v9iWU+ELVwCd+IKXGLFHpqahv2ReoXSbEhasm5iOzALt hKFCaQKfogF6F8WskDDf0vWICcYHdARKj0Bz2lXc5otMmr4NHcpJ+8mOeRK2s0G0HIVn KKAYICIqXJqkIrqzh9bvNkYZuSGO1VXcmZwGtJKZTxQ41KexhZ45pIrHGOp94wYAHf1t Qo8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:from:to:cc:subject:message-id :mail-followup-to:mime-version:content-disposition:user-agent; bh=Smbnh/HjJZfXW9umDTUlih066PFtxdapl55+liTkPwU=; b=hSYecH5am5XRhc1/1esvBhi/2yhBcJUsmCZ8p35TbTluCmwdnAXfKSHDTE+JTV5Wl1 LggJbqWrD7qw9DFXQOOmqCOSI3GHacgwnD5wnwKsiyAFWPrDmuaAYF2TjZZa+7ZMh1lq sQMvA8LgP84FhoIpuLO31MG+KzzbzcJMnI23tsT5+HSjrV86zzG46Jhm6gFEQ9Ha34v6 3spZkd+D3xE0RabSjGB1CCHtGbvvI/Vgse79wFULiqyTAMsBZOKy+YXIerQ5vv4jlr3N 6kCbmkL7CID6CPKM5MbbzSqF2FivqlWe41BkXlQroDevxK3qpK6tdjupMcMzsGO1AHxO 29ug== X-Gm-Message-State: AOAM533D1NsJvocjFyNYgEyz66g4tSAEHqs1do/OVaB3VMbEqsqohXSD IIrsGfCqTggUFLWBHrwzfLk= X-Google-Smtp-Source: ABdhPJwtwcBxa1z6T7T+kmhD2d0HQ+Omb3d13a8dvsF60CkMyXrE0dYCYUK7i1sDzO1JsSZN1YcYYQ== X-Received: by 2002:a1c:7e03:: with SMTP id z3mr670958wmc.88.1589912053600; Tue, 19 May 2020 11:14:13 -0700 (PDT) Received: from dumbo ([185.220.101.209]) by smtp.gmail.com with ESMTPSA id s8sm265465wrg.34.2020.05.19.11.14.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 19 May 2020 11:14:12 -0700 (PDT) Received: from cavok by dumbo with local (Exim 4.92) (envelope-from ) id 1jb6kk-0004L5-Q7; Tue, 19 May 2020 20:14:10 +0200 Date: Tue, 19 May 2020 20:14:10 +0200 From: Domenico Andreoli To: "Rafael J. Wysocki" , "Darrick J. Wong" Cc: Pavel Machek , Christoph Hellwig , viro@zeniv.linux.org.uk, tytso@mit.edu, len.brown@intel.com, linux-pm@vger.kernel.org, linux-mm@kvack.org, linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Domenico Andreoli Subject: [PATCH v2] PM: hibernate: restrict writes to the resume device Message-ID: <20200519181410.GA1963@dumbo> Mail-Followup-To: "Rafael J. Wysocki" , "Darrick J. Wong" , Pavel Machek , Christoph Hellwig , viro@zeniv.linux.org.uk, tytso@mit.edu, len.brown@intel.com, linux-pm@vger.kernel.org, linux-mm@kvack.org, linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.10.1 (2018-07-13) X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: From: Domenico Andreoli Hibernation via snapshot device requires write permission to the swap block device, the one that more often (but not necessarily) is used to store the hibernation image. With this patch, such permissions are granted iff: 1) snapshot device config option is enabled 2) swap partition is used as resume device In other circumstances the swap device is not writable from userspace. In order to achieve this, every write attempt to a swap device is checked against the device configured as part of the uswsusp API [0] using a pointer to the inode struct in memory. If the swap device being written was not configured for resuming, the write request is denied. NOTE: this implementation works only for swap block devices, where the inode configured by swapon (which sets S_SWAPFILE) is the same used by SNAPSHOT_SET_SWAP_AREA. In case of swap file, SNAPSHOT_SET_SWAP_AREA indeed receives the inode of the block device containing the filesystem where the swap file is located (+ offset in it) which is never passed to swapon and then has not set S_SWAPFILE. As result, the swap file itself (as a file) has never an option to be written from userspace. Instead it remains writable if accessed directly from the containing block device, which is always writeable from root. [0] Documentation/power/userland-swsusp.rst v2: - rename is_hibernate_snapshot_dev() to is_hibernate_resume_dev() - fix description so to correctly refer to the resume device Signed-off-by: Domenico Andreoli Cc: "Rafael J. Wysocki" Cc: Pavel Machek Cc: Darrick J. Wong Cc: Christoph Hellwig Cc: viro@zeniv.linux.org.uk Cc: tytso@mit.edu Cc: len.brown@intel.com Cc: linux-pm@vger.kernel.org Cc: linux-mm@kvack.org Cc: linux-xfs@vger.kernel.org Cc: linux-fsdevel@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- fs/block_dev.c | 3 +-- include/linux/suspend.h | 6 ++++++ kernel/power/user.c | 14 +++++++++++++- 3 files changed, 20 insertions(+), 3 deletions(-) Index: b/include/linux/suspend.h =================================================================== --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -466,6 +466,12 @@ static inline bool system_entering_hiber static inline bool hibernation_available(void) { return false; } #endif /* CONFIG_HIBERNATION */ +#ifdef CONFIG_HIBERNATION_SNAPSHOT_DEV +int is_hibernate_resume_dev(const struct inode *); +#else +static inline int is_hibernate_resume_dev(const struct inode *i) { return 0; } +#endif + /* Hibernation and suspend events */ #define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ #define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ Index: b/kernel/power/user.c =================================================================== --- a/kernel/power/user.c +++ b/kernel/power/user.c @@ -35,8 +35,14 @@ static struct snapshot_data { bool ready; bool platform_support; bool free_bitmaps; + struct inode *bd_inode; } snapshot_state; +int is_hibernate_resume_dev(const struct inode *bd_inode) +{ + return hibernation_available() && snapshot_state.bd_inode == bd_inode; +} + static int snapshot_open(struct inode *inode, struct file *filp) { struct snapshot_data *data; @@ -95,6 +101,7 @@ static int snapshot_open(struct inode *i data->frozen = false; data->ready = false; data->platform_support = false; + data->bd_inode = NULL; Unlock: unlock_system_sleep(); @@ -110,6 +117,7 @@ static int snapshot_release(struct inode swsusp_free(); data = filp->private_data; + data->bd_inode = NULL; free_all_swap_pages(data->swap); if (data->frozen) { pm_restore_gfp_mask(); @@ -202,6 +210,7 @@ struct compat_resume_swap_area { static int snapshot_set_swap_area(struct snapshot_data *data, void __user *argp) { + struct block_device *bdev; sector_t offset; dev_t swdev; @@ -232,9 +241,12 @@ static int snapshot_set_swap_area(struct data->swap = -1; return -EINVAL; } - data->swap = swap_type_of(swdev, offset, NULL); + data->swap = swap_type_of(swdev, offset, &bdev); if (data->swap < 0) return -ENODEV; + + data->bd_inode = bdev->bd_inode; + bdput(bdev); return 0; } Index: b/fs/block_dev.c =================================================================== --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -2023,8 +2023,7 @@ ssize_t blkdev_write_iter(struct kiocb * if (bdev_read_only(I_BDEV(bd_inode))) return -EPERM; - /* uswsusp needs write permission to the swap */ - if (IS_SWAPFILE(bd_inode) && !hibernation_available()) + if (IS_SWAPFILE(bd_inode) && !is_hibernate_resume_dev(bd_inode)) return -ETXTBSY; if (!iov_iter_count(from)) -- rsa4096: 3B10 0CA1 8674 ACBA B4FE FCD2 CE5B CF17 9960 DE13 ed25519: FFB4 0CC3 7F2E 091D F7DA 356E CC79 2832 ED38 CB05