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 <m...@digikod.net> Cc: Alexander Viro <v...@zeniv.linux.org.uk> Cc: Andy Lutomirski <l...@amacapital.net> Cc: Casey Schaufler <ca...@schaufler-ca.com> Cc: Dmitry Kasatkin <dmitry.kasat...@gmail.com> Cc: Eric Paris <epa...@parisplace.org> Cc: James Morris <james.l.mor...@oracle.com> Cc: John Johansen <john.johan...@canonical.com> Cc: Kees Cook <keesc...@chromium.org> Cc: Kentaro Takeda <taked...@nttdata.co.jp> Cc: Mimi Zohar <zo...@linux.vnet.ibm.com> Cc: Paul Moore <p...@paul-moore.com> Cc: Serge E. Hallyn <se...@hallyn.com> Cc: Stephen Smalley <s...@tycho.nsa.gov> Cc: Tetsuo Handa <penguin-ker...@i-love.sakura.ne.jp> --- 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 <linux/string.h> #include <linux/mm.h> #include <linux/fs.h> +#include <linux/time.h> 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 = -- 2.11.0