From: Mimi Zohar <zohar@linux.ibm.com>
To: Goldwyn Rodrigues <rgoldwyn@suse.de>
Cc: Miklos Szeredi <miklos@szeredi.hu>, Fabian Vogt <fvogt@suse.de>,
Ignaz Forster <iforster@suse.de>,
overlayfs <linux-unionfs@vger.kernel.org>,
linux-integrity <linux-integrity@vger.kernel.org>
Subject: Re: PROBLEM: IMA xattrs not written on overlayfs
Date: Fri, 05 Oct 2018 06:33:55 -0400 [thread overview]
Message-ID: <1538735635.3702.423.camel@linux.ibm.com> (raw)
In-Reply-To: <20181005025733.fjlz34pph2hzcsxd@merlin>
On Thu, 2018-10-04 at 21:57 -0500, Goldwyn Rodrigues wrote:
> On 11:52 04/10, Mimi Zohar wrote:
> > On Thu, 2018-10-04 at 00:35 +0200, Miklos Szeredi wrote:
> >
> > > Right, if it's done from last fput() then it's at least not a security hole.
> > >
> > > This hack may work for some filesystems, but as you noticed, it won't
> > > work for overlayfs. And if probably won't work for a number of other
> > > filesystems as well: the fs can assume that f_mode & FMODE_READ will
> > > remain off if it was off at open time.
> > >
> > > The proper way to handle it generally is to open a separate instance
> > > of the same file from IMA with O_RDONLY and use that to calculate the
> > > hash. There's really no point in reusing the same file and hacking
> > > the f_mode bits.
> >
> > Is there an appropriate low level kernel call for creating a new file
> > descriptor that would be appropriate? dentry_open(), like the call in
> > file_clone_open(), has a lot of overhead, including the LSM calls.
> > Calculating the file hash always needs to work.
> >
>
> Mimi,
>
> I have formulated a patch which is working for me on overlayfs. I am
> using dentry_open(), which I agree may have overhead. While this
> opens up the possibility of using it for files opened with O_DIRECT
> which may end up getting the file into pagecache.
>
> Subject: [PATCH] Open new file instance O_RDONLY to calculate hash
>
> Using the open struct file to calculate the hash does not work
> with overlayfs, because the real struct file is hidden behind the
> overlays struct file. So, any file->f_mode manipulations are not
> reflected on the real struct file. So, open the file again, read and
> calculate the hash.
>
> As a byproduct, we can remove all instance of f_mode manipulations
> and can work with O_DIRECT as well.
>
> Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
By "overhead", I didn't mean it from a performance perspective, but
was concerned about the dentry_open() failing. If "dentry_open" fails
for any reason, the file hash will not be re-calculated, causing
future file opens to fail. Missing is the test for dentry_open()
failure.
By removing the "read" check, re-opening the file is now for all
files, not just those opened without "read". From a testing
perspective, it will catch problems faster, but ...
I've had a patch queued that removes the O_DIRECT test, but haven't
had a chance to test it on ALL filesystems. I would probably re-open
the file with the original flags, plus read, as much as possible.
Mimi
>
> diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
> index 7e7e7e7c250a..87e5fedc2162 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -210,7 +210,7 @@ static int ima_calc_file_hash_atfm(struct file *file,
> {
> loff_t i_size, offset;
> char *rbuf[2] = { NULL, };
> - int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0;
> + int rc, rbuf_len, active = 0, ahash_rc = 0;
> struct ahash_request *req;
> struct scatterlist sg[1];
> struct crypto_wait wait;
> @@ -257,11 +257,6 @@ static int ima_calc_file_hash_atfm(struct file *file,
> &rbuf_size[1], 0);
> }
>
> - if (!(file->f_mode & FMODE_READ)) {
> - file->f_mode |= FMODE_READ;
> - read = 1;
> - }
> -
> for (offset = 0; offset < i_size; offset += rbuf_len) {
> if (!rbuf[1] && offset) {
> /* Not using two buffers, and it is not the first
> @@ -300,8 +295,6 @@ static int ima_calc_file_hash_atfm(struct file *file,
> /* wait for the last update request to complete */
> rc = ahash_wait(ahash_rc, &wait);
> out3:
> - if (read)
> - file->f_mode &= ~FMODE_READ;
> ima_free_pages(rbuf[0], rbuf_size[0]);
> ima_free_pages(rbuf[1], rbuf_size[1]);
> out2:
> @@ -336,7 +329,7 @@ static int ima_calc_file_hash_tfm(struct file *file,
> {
> loff_t i_size, offset = 0;
> char *rbuf;
> - int rc, read = 0;
> + int rc;
> SHASH_DESC_ON_STACK(shash, tfm);
>
> shash->tfm = tfm;
> @@ -357,11 +350,6 @@ static int ima_calc_file_hash_tfm(struct file *file,
> if (!rbuf)
> return -ENOMEM;
>
> - if (!(file->f_mode & FMODE_READ)) {
> - file->f_mode |= FMODE_READ;
> - read = 1;
> - }
> -
> while (offset < i_size) {
> int rbuf_len;
>
> @@ -378,8 +366,6 @@ static int ima_calc_file_hash_tfm(struct file *file,
> if (rc)
> break;
> }
> - if (read)
> - file->f_mode &= ~FMODE_READ;
> kfree(rbuf);
> out:
> if (!rc)
> @@ -420,26 +406,21 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
> {
> loff_t i_size;
> int rc;
> + struct file *f = dentry_open(&file->f_path, O_LARGEFILE | O_RDONLY,
> + current_cred());
>
> - /*
> - * For consistency, fail file's opened with the O_DIRECT flag on
> - * filesystems mounted with/without DAX option.
> - */
> - if (file->f_flags & O_DIRECT) {
> - hash->length = hash_digest_size[ima_hash_algo];
> - hash->algo = ima_hash_algo;
> - return -EINVAL;
> - }
> -
> - i_size = i_size_read(file_inode(file));
> + i_size = i_size_read(file_inode(f));
>
> if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
> - rc = ima_calc_file_ahash(file, hash);
> + rc = ima_calc_file_ahash(f, hash);
> if (!rc)
> - return 0;
> + goto out;
> }
>
> - return ima_calc_file_shash(file, hash);
> + rc = ima_calc_file_shash(f, hash);
> +out:
> + fput(f);
> + return rc;
> }
>
> /*
>
WARNING: multiple messages have this Message-ID (diff)
From: Mimi Zohar <zohar@linux.ibm.com>
To: Goldwyn Rodrigues <rgoldwyn@suse.de>
Cc: Miklos Szeredi <miklos@szeredi.hu>, Fabian Vogt <fvogt@suse.de>,
Ignaz Forster <iforster@suse.de>,
overlayfs <linux-unionfs@vger.kernel.org>,
linux-integrity <linux-integrity@vger.kernel.org>
Subject: Re: PROBLEM: IMA xattrs not written on overlayfs
Date: Fri, 05 Oct 2018 06:33:55 -0400 [thread overview]
Message-ID: <1538735635.3702.423.camel@linux.ibm.com> (raw)
In-Reply-To: <20181005025733.fjlz34pph2hzcsxd@merlin>
On Thu, 2018-10-04 at 21:57 -0500, Goldwyn Rodrigues wrote:
> On 11:52 04/10, Mimi Zohar wrote:
> > On Thu, 2018-10-04 at 00:35 +0200, Miklos Szeredi wrote:
> >
> > > Right, if it's done from last fput() then it's at least not a security hole.
> > >
> > > This hack may work for some filesystems, but as you noticed, it won't
> > > work for overlayfs. And if probably won't work for a number of other
> > > filesystems as well: the fs can assume that f_mode & FMODE_READ will
> > > remain off if it was off at open time.
> > >
> > > The proper way to handle it generally is to open a separate instance
> > > of the same file from IMA with O_RDONLY and use that to calculate the
> > > hash. There's really no point in reusing the same file and hacking
> > > the f_mode bits.
> >
> > Is there an appropriate low level kernel call for creating a new file
> > descriptor that would be appropriate? dentry_open(), like the call in
> > file_clone_open(), has a lot of overhead, including the LSM calls.
> > Calculating the file hash always needs to work.
> >
>
> Mimi,
>
> I have formulated a patch which is working for me on overlayfs. I am
> using dentry_open(), which I agree may have overhead. While this
> opens up the possibility of using it for files opened with O_DIRECT
> which may end up getting the file into pagecache.
>
> Subject: [PATCH] Open new file instance O_RDONLY to calculate hash
>
> Using the open struct file to calculate the hash does not work
> with overlayfs, because the real struct file is hidden behind the
> overlays struct file. So, any file->f_mode manipulations are not
> reflected on the real struct file. So, open the file again, read and
> calculate the hash.
>
> As a byproduct, we can remove all instance of f_mode manipulations
> and can work with O_DIRECT as well.
>
> Signed-off-by: Goldwyn Rodrigues <rgoldwyn@suse.com>
By "overhead", I didn't mean it from a performance perspective, but
was concerned about the dentry_open() failing. If "dentry_open" fails
for any reason, the file hash will not be re-calculated, causing
future file opens to fail. Missing is the test for dentry_open()
failure.
By removing the "read" check, re-opening the file is now for all
files, not just those opened without "read". From a testing
perspective, it will catch problems faster, but ...
I've had a patch queued that removes the O_DIRECT test, but haven't
had a chance to test it on ALL filesystems. I would probably re-open
the file with the original flags, plus read, as much as possible.
Mimi
>
> diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c
> index 7e7e7e7c250a..87e5fedc2162 100644
> --- a/security/integrity/ima/ima_crypto.c
> +++ b/security/integrity/ima/ima_crypto.c
> @@ -210,7 +210,7 @@ static int ima_calc_file_hash_atfm(struct file *file,
> {
> loff_t i_size, offset;
> char *rbuf[2] = { NULL, };
> - int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0;
> + int rc, rbuf_len, active = 0, ahash_rc = 0;
> struct ahash_request *req;
> struct scatterlist sg[1];
> struct crypto_wait wait;
> @@ -257,11 +257,6 @@ static int ima_calc_file_hash_atfm(struct file *file,
> &rbuf_size[1], 0);
> }
>
> - if (!(file->f_mode & FMODE_READ)) {
> - file->f_mode |= FMODE_READ;
> - read = 1;
> - }
> -
> for (offset = 0; offset < i_size; offset += rbuf_len) {
> if (!rbuf[1] && offset) {
> /* Not using two buffers, and it is not the first
> @@ -300,8 +295,6 @@ static int ima_calc_file_hash_atfm(struct file *file,
> /* wait for the last update request to complete */
> rc = ahash_wait(ahash_rc, &wait);
> out3:
> - if (read)
> - file->f_mode &= ~FMODE_READ;
> ima_free_pages(rbuf[0], rbuf_size[0]);
> ima_free_pages(rbuf[1], rbuf_size[1]);
> out2:
> @@ -336,7 +329,7 @@ static int ima_calc_file_hash_tfm(struct file *file,
> {
> loff_t i_size, offset = 0;
> char *rbuf;
> - int rc, read = 0;
> + int rc;
> SHASH_DESC_ON_STACK(shash, tfm);
>
> shash->tfm = tfm;
> @@ -357,11 +350,6 @@ static int ima_calc_file_hash_tfm(struct file *file,
> if (!rbuf)
> return -ENOMEM;
>
> - if (!(file->f_mode & FMODE_READ)) {
> - file->f_mode |= FMODE_READ;
> - read = 1;
> - }
> -
> while (offset < i_size) {
> int rbuf_len;
>
> @@ -378,8 +366,6 @@ static int ima_calc_file_hash_tfm(struct file *file,
> if (rc)
> break;
> }
> - if (read)
> - file->f_mode &= ~FMODE_READ;
> kfree(rbuf);
> out:
> if (!rc)
> @@ -420,26 +406,21 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
> {
> loff_t i_size;
> int rc;
> + struct file *f = dentry_open(&file->f_path, O_LARGEFILE | O_RDONLY,
> + current_cred());
>
> - /*
> - * For consistency, fail file's opened with the O_DIRECT flag on
> - * filesystems mounted with/without DAX option.
> - */
> - if (file->f_flags & O_DIRECT) {
> - hash->length = hash_digest_size[ima_hash_algo];
> - hash->algo = ima_hash_algo;
> - return -EINVAL;
> - }
> -
> - i_size = i_size_read(file_inode(file));
> + i_size = i_size_read(file_inode(f));
>
> if (ima_ahash_minsize && i_size >= ima_ahash_minsize) {
> - rc = ima_calc_file_ahash(file, hash);
> + rc = ima_calc_file_ahash(f, hash);
> if (!rc)
> - return 0;
> + goto out;
> }
>
> - return ima_calc_file_shash(file, hash);
> + rc = ima_calc_file_shash(f, hash);
> +out:
> + fput(f);
> + return rc;
> }
>
> /*
>
next prev parent reply other threads:[~2018-10-05 17:32 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-07 16:49 PROBLEM: IMA xattrs not written on overlayfs Ignaz Forster
2018-09-07 18:45 ` Mimi Zohar
2018-09-10 9:17 ` Ignaz Forster
2018-09-28 16:54 ` Mimi Zohar
2018-09-28 18:24 ` Ignaz Forster
2018-09-28 18:24 ` Ignaz Forster
2018-09-28 19:06 ` Mimi Zohar
2018-09-28 19:06 ` Mimi Zohar
2018-09-28 19:37 ` Fabian Vogt
2018-10-01 9:05 ` Miklos Szeredi
2018-10-03 21:18 ` Mimi Zohar
2018-10-03 21:18 ` Mimi Zohar
2018-10-03 22:35 ` Miklos Szeredi
2018-10-04 15:52 ` Mimi Zohar
2018-10-04 15:52 ` Mimi Zohar
2018-10-05 2:57 ` Goldwyn Rodrigues
2018-10-05 10:33 ` Mimi Zohar [this message]
2018-10-05 10:33 ` Mimi Zohar
2018-10-05 17:30 ` Goldwyn Rodrigues
2018-10-05 17:30 ` Goldwyn Rodrigues
2018-10-05 17:30 ` Goldwyn Rodrigues
2018-10-07 8:22 ` Amir Goldstein
2018-10-08 12:54 ` Mimi Zohar
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=1538735635.3702.423.camel@linux.ibm.com \
--to=zohar@linux.ibm.com \
--cc=fvogt@suse.de \
--cc=iforster@suse.de \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=miklos@szeredi.hu \
--cc=rgoldwyn@suse.de \
/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.