From patchwork Wed Dec 21 23:15:06 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Micka=C3=ABl_Sala=C3=BCn?= X-Patchwork-Id: 9483915 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 08B56600CA for ; Wed, 21 Dec 2016 23:16:57 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EE6272849B for ; Wed, 21 Dec 2016 23:16:56 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E2B43284A5; Wed, 21 Dec 2016 23:16:56 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6A2912849B for ; Wed, 21 Dec 2016 23:16:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1764175AbcLUXQy (ORCPT ); Wed, 21 Dec 2016 18:16:54 -0500 Received: from smtp-sh2.infomaniak.ch ([128.65.195.6]:50831 "EHLO smtp-sh2.infomaniak.ch" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1758551AbcLUXQm (ORCPT ); Wed, 21 Dec 2016 18:16:42 -0500 Received: from smtp5.infomaniak.ch (smtp5.infomaniak.ch [83.166.132.18]) by smtp-sh.infomaniak.ch (8.14.5/8.14.5) with ESMTP id uBLNFg4J005328 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Thu, 22 Dec 2016 00:15:42 +0100 Received: from localhost (ns3096276.ip-94-23-54.eu [94.23.54.103]) (authenticated bits=0) by smtp5.infomaniak.ch (8.14.5/8.14.5) with ESMTP id uBLNFX60051021; Thu, 22 Dec 2016 00:15:34 +0100 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= To: linux-kernel@vger.kernel.org Cc: Alexander Viro , Andreas Gruenbacher , Andy Lutomirski , Casey Schaufler , Dmitry Kasatkin , Eric Paris , James Morris , John Johansen , Kees Cook , Kentaro Takeda , Mimi Zohar , Paul Moore , "Serge E . Hallyn" , Stephen Smalley , Tetsuo Handa , Vivek Goyal , linux-fsdevel@vger.kernel.org, linux-security-module@vger.kernel.org, =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Subject: [PATCH v1] security: Add a new hook: inode_touch_atime Date: Thu, 22 Dec 2016 00:15:06 +0100 Message-Id: <20161221231506.19800-1-mic@digikod.net> X-Mailer: git-send-email 2.11.0 MIME-Version: 1.0 X-Antivirus: Dr.Web (R) for Unix mail servers drweb plugin ver.6.0.2.8 X-Antivirus-Code: 0x100000 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP Add a new LSM hook named inode_touch_atime which is needed to deny indirect update of extended file attributes (i.e. access time) which are not catched by the inode_setattr hook. By creating a new hook instead of calling inode_setattr, we avoid to simulate a useless struct iattr. This hook allows to create read-only environments as with read-only mount points. It can also take care of anonymous inodes. Signed-off-by: Mickaël Salaün Cc: Alexander Viro Cc: Andy Lutomirski Cc: Casey Schaufler Cc: Dmitry Kasatkin Cc: Eric Paris Cc: James Morris Cc: John Johansen Cc: Kees Cook Cc: Kentaro Takeda Cc: Mimi Zohar Cc: Paul Moore Cc: Serge E. Hallyn Cc: Stephen Smalley Cc: Tetsuo Handa --- fs/inode.c | 5 ++++- include/linux/lsm_hooks.h | 8 ++++++++ include/linux/security.h | 8 ++++++++ security/security.c | 9 +++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/fs/inode.c b/fs/inode.c index 88110fd0b282..8e7519196942 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1706,6 +1706,10 @@ void touch_atime(const struct path *path) if (!__atime_needs_update(path, inode, false)) return; + now = current_time(inode); + if (security_inode_touch_atime(path, &now)) + return; + if (!sb_start_write_trylock(inode->i_sb)) return; @@ -1720,7 +1724,6 @@ void touch_atime(const struct path *path) * We may also fail on filesystems that have the ability to make parts * of the fs read only, e.g. subvolumes in Btrfs. */ - now = current_time(inode); update_time(inode, &now, S_ATIME); __mnt_drop_write(mnt); skip_update: diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 558adfa5c8a8..e77051715e6b 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -428,6 +428,11 @@ * security module does not know about attribute or a negative error code * to abort the copy up. Note that the caller is responsible for reading * and writing the xattrs as this hook is merely a filter. + * @inode_touch_atime: + * Check permission before updating access time. + * @path contains the path structure for the file. + * @ts contains the current time. + * Return 0 if permission is granted. * * Security hooks for file operations * @@ -1458,6 +1463,8 @@ union security_list_options { void (*inode_getsecid)(struct inode *inode, u32 *secid); int (*inode_copy_up)(struct dentry *src, struct cred **new); int (*inode_copy_up_xattr)(const char *name); + int (*inode_touch_atime)(const struct path *path, + const struct timespec *ts); int (*file_permission)(struct file *file, int mask); int (*file_alloc_security)(struct file *file); @@ -1731,6 +1738,7 @@ struct security_hook_heads { struct list_head inode_getsecid; struct list_head inode_copy_up; struct list_head inode_copy_up_xattr; + struct list_head inode_touch_atime; struct list_head file_permission; struct list_head file_alloc_security; struct list_head file_free_security; diff --git a/include/linux/security.h b/include/linux/security.h index c2125e9093e8..619f44c290a5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -30,6 +30,7 @@ #include #include #include +#include struct linux_binprm; struct cred; @@ -288,6 +289,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer void security_inode_getsecid(struct inode *inode, u32 *secid); int security_inode_copy_up(struct dentry *src, struct cred **new); int security_inode_copy_up_xattr(const char *name); +int security_inode_touch_atime(const struct path *path, const struct timespec *ts); int security_file_permission(struct file *file, int mask); int security_file_alloc(struct file *file); void security_file_free(struct file *file); @@ -781,6 +783,12 @@ static inline int security_inode_copy_up_xattr(const char *name) return -EOPNOTSUPP; } +static inline int security_inode_touch_atime(const struct path *path, const + struct timespec *ts) +{ + return 0; +} + static inline int security_file_permission(struct file *file, int mask) { return 0; diff --git a/security/security.c b/security/security.c index f825304f04a7..cd093c4b4115 100644 --- a/security/security.c +++ b/security/security.c @@ -769,6 +769,13 @@ int security_inode_copy_up_xattr(const char *name) } EXPORT_SYMBOL(security_inode_copy_up_xattr); +int security_inode_touch_atime(const struct path *path, + const struct timespec *ts) +{ + return call_int_hook(inode_touch_atime, 0, path, ts); +} +EXPORT_SYMBOL(security_inode_touch_atime); + int security_file_permission(struct file *file, int mask) { int ret; @@ -1711,6 +1718,8 @@ struct security_hook_heads security_hook_heads = { LIST_HEAD_INIT(security_hook_heads.inode_copy_up), .inode_copy_up_xattr = LIST_HEAD_INIT(security_hook_heads.inode_copy_up_xattr), + .inode_touch_atime = + LIST_HEAD_INIT(security_hook_heads.inode_touch_atime), .file_permission = LIST_HEAD_INIT(security_hook_heads.file_permission), .file_alloc_security =