From: Dmitry Kasatkin <d.kasatkin@samsung.com>
To: linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org,
viro@zeniv.linux.org.uk, linux-security-module@vger.kernel.org,
zohar@linux.vnet.ibm.com, jmorris@namei.org
Cc: dmitry.kasatkin@gmail.com, Dmitry Kasatkin <d.kasatkin@samsung.com>
Subject: Re: [PATCH 1/2] ima: hooks for directory integrity protection
Date: Wed, 11 Dec 2013 14:57:21 +0000 [thread overview]
Message-ID: <52A87D51.9060606@samsung.com> (raw)
In-Reply-To: <d9de3562c23e4ac8f59d6eb16c12e303f42c8855.1384806012.git.d.kasatkin@samsung.com>
On 18/11/13 20:24, Dmitry Kasatkin wrote:
> Both IMA-appraisal and EVM protect the integrity of regular files.
> IMA protects file data integrity, while EVM protects the file meta-data
> integrity, such as file attributes and extended attributes. This patch
> set adds hooks for offline directory integrity protection.
>
> An inode itself does not have any file name associated with it. The
> association of the file name to inode is done via directory entries.
> On a running system, mandatory and/or discretionary access control prevent
> unprivileged file deletion, file name change, or hardlink creation.
> In an offline attack, without these protections, the association between
> a file name and an inode is unprotected. Files can be deleted, renamed
> or moved from one directory to another one. In all of these cases,
> the integrity of the file data and metadata is good.
>
> To prevent such attacks, it is necessary to protect integrity of directory
> content.
>
> This patch adds 2 new hooks for directory integrity protection:
> ima_dir_check() and ima_dir_update().
>
> ima_dir_check() is called to verify integrity of the the directory during
> the initial path lookup.
>
> ima_dir_update() is called from several places in namei.c, when the directory
> content is changing, for updating the directory hash.
>
> Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
> ---
> fs/namei.c | 42 ++++++++++++++++++++++++++++++++++++---
> fs/open.c | 6 ++++++
> include/linux/ima.h | 23 +++++++++++++++++++++
> net/unix/af_unix.c | 2 ++
> security/integrity/ima/ima_main.c | 3 +++
> 5 files changed, 73 insertions(+), 3 deletions(-)
>
> diff --git a/fs/namei.c b/fs/namei.c
> index 645268f..d0e1821 100644
> --- a/fs/namei.c
> +++ b/fs/namei.c
> @@ -1469,16 +1469,33 @@ static int lookup_slow(struct nameidata *nd, struct path *path)
> return 0;
> }
>
> +static inline int may_lookup_ima(struct nameidata *nd, int err)
> +{
> + if (err)
> + return err;
> + err = ima_dir_check(&nd->path, MAY_EXEC|MAY_NOT_BLOCK);
> + if (err != -ECHILD)
> + return err;
> + if (unlazy_walk(nd, NULL))
> + return -ECHILD;
> + return ima_dir_check(&nd->path, MAY_EXEC);
> +}
> +
> static inline int may_lookup(struct nameidata *nd)
> {
> + int err = 0;
> +
> if (nd->flags & LOOKUP_RCU) {
> - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
> + err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK);
> if (err != -ECHILD)
> - return err;
> + return may_lookup_ima(nd, err);
> if (unlazy_walk(nd, NULL))
> return -ECHILD;
> }
> - return inode_permission(nd->inode, MAY_EXEC);
> + err = inode_permission(nd->inode, MAY_EXEC);
> + if (err)
> + return err;
> + return ima_dir_check(&nd->path, MAY_EXEC);
> }
>
> static inline int handle_dots(struct nameidata *nd, int type)
> @@ -2956,6 +2973,8 @@ retry_lookup:
> }
> mutex_lock(&dir->d_inode->i_mutex);
> error = lookup_open(nd, path, file, op, got_write, opened);
> + if (error >= 0 && (*opened & FILE_CREATED))
> + ima_dir_update(&nd->path, NULL);
> mutex_unlock(&dir->d_inode->i_mutex);
>
> if (error <= 0) {
> @@ -3454,6 +3473,8 @@ retry:
> error = vfs_mknod(path.dentry->d_inode,dentry,mode,0);
> break;
> }
> + if (!error)
> + ima_dir_update(&path, dentry);
> out:
> done_path_create(&path, dentry);
> if (retry_estale(error, lookup_flags)) {
> @@ -3510,6 +3531,8 @@ retry:
> error = security_path_mkdir(&path, dentry, mode);
> if (!error)
> error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
> + if (!error)
> + ima_dir_update(&path, dentry);
> done_path_create(&path, dentry);
> if (retry_estale(error, lookup_flags)) {
> lookup_flags |= LOOKUP_REVAL;
> @@ -3626,6 +3649,8 @@ retry:
> if (error)
> goto exit3;
> error = vfs_rmdir(nd.path.dentry->d_inode, dentry);
> + if (!error)
> + ima_dir_update(&nd.path, NULL);
> exit3:
> dput(dentry);
> exit2:
> @@ -3721,6 +3746,8 @@ retry:
> if (error)
> goto exit2;
> error = vfs_unlink(nd.path.dentry->d_inode, dentry);
> + if (!error)
> + ima_dir_update(&nd.path, NULL);
> exit2:
> dput(dentry);
> }
> @@ -3801,6 +3828,8 @@ retry:
> error = security_path_symlink(&path, dentry, from->name);
> if (!error)
> error = vfs_symlink(path.dentry->d_inode, dentry, from->name);
> + if (!error)
> + ima_dir_update(&path, dentry);
> done_path_create(&path, dentry);
> if (retry_estale(error, lookup_flags)) {
> lookup_flags |= LOOKUP_REVAL;
> @@ -3919,6 +3948,8 @@ retry:
> if (error)
> goto out_dput;
> error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
> + if (!error)
> + ima_dir_update(&new_path, NULL);
> out_dput:
> done_path_create(&new_path, new_dentry);
> if (retry_estale(error, how)) {
> @@ -4171,6 +4202,11 @@ retry:
> goto exit5;
> error = vfs_rename(old_dir->d_inode, old_dentry,
> new_dir->d_inode, new_dentry);
> + if (!error) {
> + ima_dir_update(&oldnd.path, NULL);
> + if (!path_equal(&oldnd.path, &newnd.path))
> + ima_dir_update(&newnd.path, NULL);
> + }
> exit5:
> dput(new_dentry);
> exit4:
> diff --git a/fs/open.c b/fs/open.c
> index d420331..021e2c5 100644
> --- a/fs/open.c
> +++ b/fs/open.c
> @@ -390,6 +390,9 @@ retry:
> error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
> if (error)
> goto dput_and_out;
> + error = ima_dir_check(&path, MAY_EXEC);
> + if (error)
> + goto dput_and_out;
>
> set_fs_pwd(current->fs, &path);
>
> @@ -420,6 +423,9 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd)
> goto out_putf;
>
> error = inode_permission(inode, MAY_EXEC | MAY_CHDIR);
> + if (error)
> + goto out_putf;
> + error = ima_dir_check(&f.file->f_path, MAY_EXEC);
> if (!error)
> set_fs_pwd(current->fs, &f.file->f_path);
> out_putf:
> diff --git a/include/linux/ima.h b/include/linux/ima.h
> index 1b7f268..e33035e 100644
> --- a/include/linux/ima.h
> +++ b/include/linux/ima.h
> @@ -73,4 +73,27 @@ static inline int ima_inode_removexattr(struct dentry *dentry,
> return 0;
> }
> #endif /* CONFIG_IMA_APPRAISE */
> +
> +#ifdef CONFIG_IMA_APPRAISE_DIRECTORIES
> +extern int ima_dir_check(struct path *dir, int mask);
> +extern int ima_special_check(struct file *file, int mask);
> +extern void ima_dir_update(struct path *dir, struct dentry *dentry);
> +#else
> +static inline int ima_dir_check(struct path *dir, int mask)
> +{
> + return 0;
> +}
> +
> +static inline int ima_special_check(struct file *file, int mask)
> +{
> + return 0;
> +}
> +
> +static inline void ima_dir_update(struct path *dir, struct dentry *dentry)
> +{
> + return;
> +}
> +
> +#endif /* CONFIG_IMA_APPRAISE_DIRECTORIES */
> +
> #endif /* _LINUX_IMA_H */
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 86de99a..6230a50 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -115,6 +115,7 @@
> #include <net/checksum.h>
> #include <linux/security.h>
> #include <linux/freezer.h>
> +#include <linux/ima.h>
>
> struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE];
> EXPORT_SYMBOL_GPL(unix_socket_table);
> @@ -841,6 +842,7 @@ static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
> if (!err) {
> res->mnt = mntget(path.mnt);
> res->dentry = dget(dentry);
> + ima_dir_update(&path, dentry);
> }
> }
> done_path_create(&path, dentry);
> diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
> index 6c12811..18d76d8 100644
> --- a/security/integrity/ima/ima_main.c
> +++ b/security/integrity/ima/ima_main.c
> @@ -300,6 +300,9 @@ int ima_bprm_check(struct linux_binprm *bprm)
> */
> int ima_file_check(struct file *file, int mask)
> {
> + if (!S_ISREG(file->f_dentry->d_inode->i_mode))
> + return ima_special_check(file, mask);
> +
> ima_rdwr_violation_check(file);
> return process_measurement(file, NULL,
> mask & (MAY_READ | MAY_WRITE | MAY_EXEC),
Hi Al,
Are you OK with the hooks?
If so can you please ack or discuss the patch?
- Dmitry
next prev parent reply other threads:[~2013-12-11 14:57 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-18 20:24 [PATCH 0/2] ima: directory integrity appraisal Dmitry Kasatkin
2013-11-18 20:24 ` [PATCH 1/2] ima: hooks for directory integrity protection Dmitry Kasatkin
2013-12-11 14:57 ` Dmitry Kasatkin [this message]
2013-12-12 13:39 ` Mimi Zohar
2013-12-23 8:54 ` Dmitry Kasatkin
2013-12-23 11:45 ` Mimi Zohar
2013-11-18 20:24 ` [PATCH 2/2] ima: directory integrity protection implementation Dmitry Kasatkin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52A87D51.9060606@samsung.com \
--to=d.kasatkin@samsung.com \
--cc=dmitry.kasatkin@gmail.com \
--cc=jmorris@namei.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=zohar@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.