Linux Security Modules development
 help / color / mirror / Atom feed
* Re: [PATCH v8 03/11] proc: move /proc/{self|thread-self} dentries to proc_fs_info
From: Andy Lutomirski @ 2020-02-10 18:23 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Eric W . Biederman,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Linus Torvalds, Oleg Nesterov,
	Solar Designer
In-Reply-To: <20200210150519.538333-4-gladkov.alexey@gmail.com>

On Mon, Feb 10, 2020 at 7:06 AM Alexey Gladkov <gladkov.alexey@gmail.com> wrote:
>
> This is a preparation patch that moves /proc/{self|thread-self} dentries
> to be stored inside procfs fs_info struct instead of making them per pid
> namespace. Since we want to support multiple procfs instances we need to
> make sure that these dentries are also per-superblock instead of
> per-pidns,

The changelog makes perfect sense so far...

> unmounting a private procfs won't clash with other procfs
> mounts.

This doesn't parse as part of the previous sentence.  I'm also not
convinced that this really involves unmounting per se.  Maybe just
delete these words.

^ permalink raw reply

* Re: [PATCH v2] ima: export the measurement list when needed
From: david.safford @ 2020-02-10 18:18 UTC (permalink / raw)
  To: Mimi Zohar, Janne Karhunen, linux-integrity,
	linux-security-module
  Cc: Ken Goldman, monty.wiseman, Amir Goldstein, linux-fsdevel
In-Reply-To: <1580998432.5585.411.camel@linux.ibm.com>

On Thu, 2020-02-06 at 09:13 -0500, Mimi Zohar wrote:
> Hi Janne,
> 
> On Fri, 2020-01-10 at 10:48 +0200, Janne Karhunen wrote:
> > On Wed, Jan 8, 2020 at 1:18 PM Janne Karhunen <janne.karhunen@gmail.com> wrote:
> > > Some systems can end up carrying lots of entries in the ima
> > > measurement list. Since every entry is using a bit of kernel
> > > memory, allow the sysadmin to export the measurement list to
> > > the filesystem to free up some memory.
> > 
> > Hopefully this addressed comments from everyone. The flush event can
> > now be triggered by the admin anytime and unique file names can be
> > used for each flush (log.1, log.2, ...) etc, so getting to the correct
> > item should be easy.
> > 
> > While it can now be argued that since this is an admin-driven event,
> > kernel does not need to write the file. However, the intention is to
> > bring out a second patch a bit later that adds a variable to define
> > the max number of entries to be kept in the kernel memory and
> > workqueue based automatic flushing. In those cases the kernel has to
> > be able to write the file without any help from the admin..
> 
> The implications of exporting and removing records from the IMA-
> measurement list needs to be considered carefully.  Verifying a TPM
> quote will become dependent on knowing where the measurements are
> stored.  The existing measurement list is stored in kernel memory and,
> barring a kernel memory attack, is protected from modification.
>  Before upstreaming this or a similar patch, there needs to be a
> discussion as to how the measurement list will be protected once is it
> exported to userspace.

"Protected" here can mean two different aspects: cryptographically
protected from tampering, which is covered with the TPM_QUOTE, and
availability protected from even accidental deletion, which is what
I suspect you are concerned about. Certainly my original TLV patches
were too flippant about this, as userspace had to be trusted not to
drop any records. In this patch, the kernel writes the data in an
atomic fashion. Either all records are successfully written, or none
are, and an error is returned.

> This patch now attempts to address two very different scenarios.  The
> first scenario is where userspace is requesting exporting and removing
> of the measurement list records.  The other scenario is the kernel
> exporting and removing of the measurement list records.  Conflating
> these two different use cases might not be the right solution, as we
> originally thought.

Actually there are at least four significant use cases: userspace
requested, and kernel initiated, both for running out of memory or
for saving the list prior to a kexec. Exporting everything to a file
prior to kexec can really simplify all the vaious use cases of 
template vs TLV formatted lists across kexec. (Consider a modern
TLV firmware kernel wanting to boot an older kernel that only
understands template formats. How simple it would be for the first
kernel to export its list to a file, and the second kernel keeps
its list in template.)

I have been testing this patch on all of these scenarios, and it
provides a simple, powerful approach for all of them.

> The kernel already exports the IMA measurement list to userspace via a
> securityfs file.  From a userspace perspective, missing is the ability
> of removing N number of records.  In this scenario, userspace would be
> responsible for safely storing the measurements (e.g. blockchain).
>  The kernel would only be responsible for limiting permission, perhaps
> based on a capability, before removing records from the measurement
> list. 

I don't think we want to export 'N' records, as this would
be really hard to understand and coordinate with userspace.
Exporting all or none seems simpler.

> In the kernel usecase, somehow the kernel would need to safely export
> the measurement list, or some portion of the measurement list, to a
> file and then delete that portion.  What protects the exported records
> stored in a file from modification?

Tampering is prevented with the TPM_QUOTE. Accidental deletion is
protected with CAP_SYS_ADMIN. If CAP_SYS_ADMIN is untrusted, you 
have bigger problems, and even then it will be detected.

> Instead of exporting the measurement records, one option as suggested
> by Amir Goldstein, would be to use a vfs_tmpfile() to get an anonymous
> file for backing store.  The existing securityfs measurement lists
> would then read from this private copy of the anonymous file.

This doesn't help in use cases where we really do want to
export to a persistent file, without userspace help.

> I've Cc'ed fsdevel for additional comments/suggestions.
> 
> thanks,
> 
> Mimi
> 


^ permalink raw reply

* Re: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
From: Ken Goldman @ 2020-02-10 18:02 UTC (permalink / raw)
  Cc: linux-crypto@vger.kernel.org, linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <CY4PR0401MB36523805F71721000F188F2FC3190@CY4PR0401MB3652.namprd04.prod.outlook.com>

On 2/10/2020 12:01 PM, Van Leeuwen, Pascal wrote:
> Well, the current specification surely doesn't define anything else and is
> already over a decade old. So what would be the odds that they add a
> different blocksize variant_now_  AND still call that SM3-something?

I just got a note from a cryptographer who said there were discussions 
last year about a future SM3 with 512 bit output.

Given that, why not plan ahead and use sm3-256?  Is there any downside?
Is the cost any more than 4 bytes in some source code?

^ permalink raw reply

* Re: [PATCH v8 07/11] proc: flush task dcache entries from all procfs instances
From: Linus Torvalds @ 2020-02-10 17:46 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Eric W . Biederman,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-8-gladkov.alexey@gmail.com>

On Mon, Feb 10, 2020 at 7:06 AM Alexey Gladkov <gladkov.alexey@gmail.com> wrote:
>
> This allows to flush dcache entries of a task on multiple procfs mounts
> per pid namespace.
>
> The RCU lock is used because the number of reads at the task exit time
> is much larger than the number of procfs mounts.

Ok, this looks better to me than the previous version.

But that may be the "pee-in-the-snow" effect, and I _really_ want
others to take a good look at the whole series.

The right people seem to be cc'd, but this is pretty core, and /proc
has a tendency to cause interesting issues because of how it's
involved in a lot of areas indirectly.

Al, Oleg, Andy, Eric?

             Linus

^ permalink raw reply

* Re: [PATCH 1/2] crypto: rename sm3-256 to sm3 in hash_algo_name
From: Mimi Zohar @ 2020-02-10 17:42 UTC (permalink / raw)
  To: Tianjia Zhang, herbert, davem, dmitry.kasatkin, jmorris, serge,
	ebiggers, Jarkko Sakkinen
  Cc: linux-crypto, linux-integrity, linux-security-module,
	linux-kernel
In-Reply-To: <20200210124440.23929-2-tianjia.zhang@linux.alibaba.com>

[Cc'ing Jarkko]

On Mon, 2020-02-10 at 20:44 +0800, Tianjia Zhang wrote:
> The name sm3-256 is defined in hash_algo_name in hash_info, but the
> algorithm name implemented in sm3_generic.c is sm3, which will cause
> the sm3-256 algorithm to be not found in some application scenarios of
> the hash algorithm, and an ENOENT error will occur. For example,
> IMA, keys, and other subsystems that reference hash_algo_name all use
> the hash algorithm of sm3.
> 
> Signed-off-by: Tianjia Zhang <tianjia.zhang@linux.alibaba.com>

Missing is the "Fixes" tag and Cc'ing the person who upstreamed "sm3-
256" in the first place.

Mimi

> ---
>  crypto/hash_info.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/crypto/hash_info.c b/crypto/hash_info.c
> index c754cb75dd1a..a49ff96bde77 100644
> --- a/crypto/hash_info.c
> +++ b/crypto/hash_info.c
> @@ -26,7 +26,7 @@ const char *const hash_algo_name[HASH_ALGO__LAST] = {
>  	[HASH_ALGO_TGR_128]	= "tgr128",
>  	[HASH_ALGO_TGR_160]	= "tgr160",
>  	[HASH_ALGO_TGR_192]	= "tgr192",
> -	[HASH_ALGO_SM3_256]	= "sm3-256",
> +	[HASH_ALGO_SM3_256]	= "sm3",
>  	[HASH_ALGO_STREEBOG_256] = "streebog256",
>  	[HASH_ALGO_STREEBOG_512] = "streebog512",
>  };


^ permalink raw reply

* Re: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
From: Mimi Zohar @ 2020-02-10 17:39 UTC (permalink / raw)
  To: Van Leeuwen, Pascal, James Bottomley, Ken Goldman, Eric Biggers,
	Tianjia Zhang
  Cc: herbert@gondor.apana.org.au, davem@davemloft.net,
	dmitry.kasatkin@gmail.com, jmorris@namei.org, serge@hallyn.com,
	linux-crypto@vger.kernel.org, linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <CY4PR0401MB36523805F71721000F188F2FC3190@CY4PR0401MB3652.namprd04.prod.outlook.com>

On Mon, 2020-02-10 at 17:01 +0000, Van Leeuwen, Pascal wrote:
> > -----Original Message-----
> > From: linux-crypto-owner@vger.kernel.org <linux-crypto-owner@vger.kernel.org> On Behalf Of James Bottomley
> > Sent: Monday, February 10, 2020 5:40 PM
> > To: Ken Goldman <kgold@linux.ibm.com>; Eric Biggers <ebiggers@kernel.org>; Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
> > Cc: herbert@gondor.apana.org.au; davem@davemloft.net; zohar@linux.ibm.com; dmitry.kasatkin@gmail.com; jmorris@namei.org;
> > serge@hallyn.com; linux-crypto@vger.kernel.org; linux-integrity@vger.kernel.org; linux-security-module@vger.kernel.org; linux-
> > kernel@vger.kernel.org
> > Subject: Re: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
> >
> > <<< External Email >>>
> > CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the
> > sender/sender address and know the content is safe.
> >
> >
> > On Mon, 2020-02-10 at 11:30 -0500, Ken Goldman wrote:
> > > On 2/9/2020 10:17 PM, Eric Biggers wrote:
> > > > According to https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftools.ietf.org%2Fid%2Fdraft-oscca-cfrg-sm3-
> > 01.html&amp;data=01%7C01%7Cpvanleeuwen%40verimatrix.com%7C3a51d0c133dd4b00fd9a08d7ae47d6d6%7Cdcb260f9022d449586
> > 02eae51035a0d0%7C0&amp;sdata=0nQ6tWMdVR5uB0MTCgdMXiOmkvTvGEKDTLcMXdzyZpg%3D&amp;reserved=0
> > > > ,
> > > > SM3 always produces a 256-bit hash value.  E.g., it says:
> > > >
> > > >     "SM3 produces an output hash value of 256 bits long"
> > > >
> > > > and
> > > >
> > > >     "SM3 is a hash function that generates a 256-bit hash value."
> > > >
> > > > I don't see any mention of "SM3-256".
> > > >
> > > > So why not just keep it as "sm3" and change hash_info.c instead?
> > > > Since the name there is currently wrong, no one can be using it
> > > > yet.
> > >
> > > Question:  Is 256 bits fundamental to SM3?
> >
> > No.
> >
> Well, the current specification surely doesn't define anything else and is
> already over a decade old. So what would be the odds that they add a
> different blocksize variant _now_ AND still call that SM3-something?
> 
> > >   Could there ever be a
> > > variant in the future that's e.g., 512 bits?
> >
> > Yes, SM3 like SHA-3 is based on a 512  bit input blocks.  However,
> > what's left of the standard:
> >
> SM3 is based on 512 bit input blocks, like _SHA-2_.
> The SHA-3 variants use block sizes between 576 and 1152 bits,
> depending on the output (digest) size.
> 
> The -xxx is referring to output (digest) size, not block size by the way.
> And SHA-3 is indeed defined for 512 bit output size, amongst others.
> 
> > https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.ietf.org%2Farchive%2Fid%2Fdraft-sca-cfrg-sm3-
> > 02.txt&amp;data=01%7C01%7Cpvanleeuwen%40verimatrix.com%7C3a51d0c133dd4b00fd9a08d7ae47d6d6%7Cdcb260f9022d44958602
> > eae51035a0d0%7C0&amp;sdata=9pfgM0bG%2Bp0zUavsknwn9vquWqPsqzPENV2okmgCOqE%3D&amp;reserved=0
> >
> > Currently only defines a 256 output (via compression from the final 512
> > bit output).
> >
> Yes. Although that is not the original (Chinese) specification.
> 
> > In theory, like SHA-3, SM3 could support 384 and 512
> > output variants.  However, there's no evidence anyone is working on
> > adding this.
> >
> Hmm ... not without changing the word width (as for SHA-512) and/or
> increasing the number of rounds plus other tweaking, I would say.
> It's not as straightforward as you are suggesting (crypto rarely is).
> I would even go as far as saying that is highly unlikely to happen.

So in terms of this discussion, does this mean you don't see a problem
with renaming "sm3-256" to "sm3" in crypto/hash_info.c?  If that's the
case, please add your Reviewed-by tag to the 1/2.

thanks,

Mimi


^ permalink raw reply

* Re: [RFC PATCH 0/2] ima: uncompressed module appraisal support
From: Mimi Zohar @ 2020-02-10 17:09 UTC (permalink / raw)
  To: Eric Snowberg
  Cc: Nayna, dmitry.kasatkin, jmorris, serge, dhowells, geert, gregkh,
	nayna, tglx, bauerman, mpe, linux-integrity,
	linux-security-module, linux-kernel, Roberto Sassu
In-Reply-To: <0F13CB66-6962-44AC-A20D-CCBD82B43625@oracle.com>

On Mon, 2020-02-10 at 09:34 -0700, Eric Snowberg wrote:
> > On Feb 8, 2020, at 4:43 PM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> > 
> > On Fri, 2020-02-07 at 14:38 -0700, Eric Snowberg wrote:
> >>> On Feb 7, 2020, at 11:54 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> >>> 
> >>> On Fri, 2020-02-07 at 11:45 -0700, Eric Snowberg wrote:
> >>>> 
> >>>>> On Feb 7, 2020, at 11:28 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> >>>>> 
> >>>>> On Fri, 2020-02-07 at 10:49 -0700, Eric Snowberg wrote:
> >>>>>> 
> >>>>>>> On Feb 7, 2020, at 10:40 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> >>>>>>> 
> >>>>>>>> $ insmod ./foo.ko
> >>>>>>>> insmod: ERROR: could not insert module ./foo.ko: Permission denied
> >>>>>>>> 
> >>>>>>>> last entry from audit log:
> >>>>>>>> type=INTEGRITY_DATA msg=audit(1581089373.076:83): pid=2874 uid=0
> >>>>>>>> auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-
> >>>>>>>> s0:c0.c1023 op=appraise_data cause=invalid-signature comm="insmod"
> >>>>>>>> name="/root/keys/modules/foo.ko" dev="dm-0" ino=10918365
> >>>>>>>> res=0^]UID="root" AUID=“root"
> >>>>>>>> 
> >>>>>>>> This is because modsig_verify() will be called from within
> >>>>>>>> ima_appraise_measurement(), 
> >>>>>>>> since try_modsig is true.  Then modsig_verify() will return
> >>>>>>>> INTEGRITY_FAIL.
> >>>>>>> 
> >>>>>>> Why is it an "invalid signature"?  For that you need to look at the
> >>>>>>> kernel messages.  Most likely it can't find the public key on the .ima
> >>>>>>> keyring to verify the signature.
> >>>>>> 
> >>>>>> It is invalid because the module has not been ima signed. 
> >>>>> 
> >>>>> With the IMA policy rule "appraise func=MODULE_CHECK
> >>>>> appraise_type=imasig|modsig", IMA first tries to verify the IMA
> >>>>> signature stored as an xattr and on failure then attempts to verify
> >>>>> the appended signatures.
> >>>>> 
> >>>>> The audit message above indicates that there was a signature, but the
> >>>>> signature validation failed.
> >>>>> 
> >>>> 
> >>>> I do have  CONFIG_IMA_APPRAISE_MODSIG enabled.  I believe the audit message above 
> >>>> is coming from modsig_verify in security/integrity/ima/ima_appraise.c.
> >>> 
> >>> Right, and it's calling:
> >>> 
> >>> 	rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
> >>> 
> >>> It's failing because it is trying to find the public key on the .ima
> >>> keyring.  Make sure that the public needed to validate the kernel
> >>> module is on the IMA keyring (eg. keyctl show %keyring:.ima).
> >>> 
> >> 
> >> I know that will validate the module properly, but that is not what I’m 
> >> trying to solve here. I thought the point of adding “|modsig” to the
> >> ima policy was to tell ima it can either validate against an ima keyring OR 
> >> default back to the kernel keyring.  This is what happens with the compressed
> >> module.  There isn’t anything in the ima keyring to validate the compressed
> >> modules and it loads when I add “|modsig”.
> > 
> > "modsig" has nothing to do with keyrings.  The term "modsig" is
> > juxtaposed to "imasig".  "modsig" refers to kernel module appended
> > signature. 
> 
> Ok, understood, “modsig” refers to strictly kernel module appended signatures
> without regard to the keyring that verifies it.  Since there are inconsistencies
> here, would you consider something like my first patch?  It will verify an 
> uncompressed kernel module containing an appended signature  when the public key
> is contained within the kernel keyring instead of the ima keyring.  Why force a 
> person to add the same keys into the ima keyring for validation?  Especially when
> the kernel keyring is now used to verify appended signatures in the compressed
> modules.

Different use case scenarios have different requirements.  Suppose for
example that the group creating the kernel image is not the same as
using it.  The group using the kernel image could sign all files,
including kernel modules (imasig), with their own private key. Only
files that they signed would be permitted.  Your proposal would break
the current expectations, allowing kernel modules signed by someone
else to be loaded.

Mimi


^ permalink raw reply

* RE: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
From: Van Leeuwen, Pascal @ 2020-02-10 17:01 UTC (permalink / raw)
  To: James Bottomley, Ken Goldman, Eric Biggers, Tianjia Zhang
  Cc: herbert@gondor.apana.org.au, davem@davemloft.net,
	zohar@linux.ibm.com, dmitry.kasatkin@gmail.com, jmorris@namei.org,
	serge@hallyn.com, linux-crypto@vger.kernel.org,
	linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <7a496bb15f264eab920bf081338d67af@MN2PR20MB2973.namprd20.prod.outlook.com>

> -----Original Message-----
> From: linux-crypto-owner@vger.kernel.org <linux-crypto-owner@vger.kernel.org> On Behalf Of James Bottomley
> Sent: Monday, February 10, 2020 5:40 PM
> To: Ken Goldman <kgold@linux.ibm.com>; Eric Biggers <ebiggers@kernel.org>; Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
> Cc: herbert@gondor.apana.org.au; davem@davemloft.net; zohar@linux.ibm.com; dmitry.kasatkin@gmail.com; jmorris@namei.org;
> serge@hallyn.com; linux-crypto@vger.kernel.org; linux-integrity@vger.kernel.org; linux-security-module@vger.kernel.org; linux-
> kernel@vger.kernel.org
> Subject: Re: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
>
> <<< External Email >>>
> CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the
> sender/sender address and know the content is safe.
>
>
> On Mon, 2020-02-10 at 11:30 -0500, Ken Goldman wrote:
> > On 2/9/2020 10:17 PM, Eric Biggers wrote:
> > > According to https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Ftools.ietf.org%2Fid%2Fdraft-oscca-cfrg-sm3-
> 01.html&amp;data=01%7C01%7Cpvanleeuwen%40verimatrix.com%7C3a51d0c133dd4b00fd9a08d7ae47d6d6%7Cdcb260f9022d449586
> 02eae51035a0d0%7C0&amp;sdata=0nQ6tWMdVR5uB0MTCgdMXiOmkvTvGEKDTLcMXdzyZpg%3D&amp;reserved=0
> > > ,
> > > SM3 always produces a 256-bit hash value.  E.g., it says:
> > >
> > >     "SM3 produces an output hash value of 256 bits long"
> > >
> > > and
> > >
> > >     "SM3 is a hash function that generates a 256-bit hash value."
> > >
> > > I don't see any mention of "SM3-256".
> > >
> > > So why not just keep it as "sm3" and change hash_info.c instead?
> > > Since the name there is currently wrong, no one can be using it
> > > yet.
> >
> > Question:  Is 256 bits fundamental to SM3?
>
> No.
>
Well, the current specification surely doesn't define anything else and is
already over a decade old. So what would be the odds that they add a
different blocksize variant _now_ AND still call that SM3-something?

> >   Could there ever be a
> > variant in the future that's e.g., 512 bits?
>
> Yes, SM3 like SHA-3 is based on a 512  bit input blocks.  However,
> what's left of the standard:
>
SM3 is based on 512 bit input blocks, like _SHA-2_.
The SHA-3 variants use block sizes between 576 and 1152 bits,
depending on the output (digest) size.

The -xxx is referring to output (digest) size, not block size by the way.
And SHA-3 is indeed defined for 512 bit output size, amongst others.

> https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.ietf.org%2Farchive%2Fid%2Fdraft-sca-cfrg-sm3-
> 02.txt&amp;data=01%7C01%7Cpvanleeuwen%40verimatrix.com%7C3a51d0c133dd4b00fd9a08d7ae47d6d6%7Cdcb260f9022d44958602
> eae51035a0d0%7C0&amp;sdata=9pfgM0bG%2Bp0zUavsknwn9vquWqPsqzPENV2okmgCOqE%3D&amp;reserved=0
>
> Currently only defines a 256 output (via compression from the final 512
> bit output).
>
Yes. Although that is not the original (Chinese) specification.

> In theory, like SHA-3, SM3 could support 384 and 512
> output variants.  However, there's no evidence anyone is working on
> adding this.
>
Hmm ... not without changing the word width (as for SHA-512) and/or
increasing the number of rounds plus other tweaking, I would say.
It's not as straightforward as you are suggesting (crypto rarely is).
I would even go as far as saying that is highly unlikely to happen.

Regards,
Pascal van Leeuwen
Silicon IP Architect Multi-Protocol Engines, Rambus Security
Rambus ROTW Holding BV
+31-73 6581953

Note: The Inside Secure/Verimatrix Silicon IP team was recently acquired by Rambus.
Please be so kind to update your e-mail address book with my new e-mail address.


** This message and any attachments are for the sole use of the intended recipient(s). It may contain information that is confidential and privileged. If you are not the intended recipient of this message, you are prohibited from printing, copying, forwarding or saving it. Please delete the message and attachments and notify the sender immediately. **

Rambus Inc.<http://www.rambus.com>

^ permalink raw reply

* Re: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
From: James Bottomley @ 2020-02-10 16:39 UTC (permalink / raw)
  To: Ken Goldman, Eric Biggers, Tianjia Zhang
  Cc: herbert, davem, zohar, dmitry.kasatkin, jmorris, serge,
	linux-crypto, linux-integrity, linux-security-module,
	linux-kernel
In-Reply-To: <1a623251-e83a-3b70-9fbd-8e929a23f7d8@linux.ibm.com>

On Mon, 2020-02-10 at 11:30 -0500, Ken Goldman wrote:
> On 2/9/2020 10:17 PM, Eric Biggers wrote:
> > According to https://tools.ietf.org/id/draft-oscca-cfrg-sm3-01.html
> > ,
> > SM3 always produces a 256-bit hash value.  E.g., it says:
> > 
> > 	"SM3 produces an output hash value of 256 bits long"
> > 
> > and
> > 
> > 	"SM3 is a hash function that generates a 256-bit hash value."
> > 
> > I don't see any mention of "SM3-256".
> > 
> > So why not just keep it as "sm3" and change hash_info.c instead?
> > Since the name there is currently wrong, no one can be using it
> > yet.
> 
> Question:  Is 256 bits fundamental to SM3?

No.

>   Could there ever be a 
> variant in the future that's e.g., 512 bits?

Yes, SM3 like SHA-3 is based on a 512  bit input blocks.  However,
what's left of the standard:

https://www.ietf.org/archive/id/draft-sca-cfrg-sm3-02.txt

Currently only defines a 256 output (via compression from the final 512
bit output).  In theory, like SHA-3, SM3 could support 384 and 512
output variants.  However, there's no evidence anyone is working on
adding this.

James


^ permalink raw reply

* Re: [RFC PATCH 0/2] ima: uncompressed module appraisal support
From: Eric Snowberg @ 2020-02-10 16:34 UTC (permalink / raw)
  To: Mimi Zohar
  Cc: Nayna, dmitry.kasatkin, jmorris, serge, dhowells, geert, gregkh,
	nayna, tglx, bauerman, mpe, linux-integrity,
	linux-security-module, linux-kernel, Roberto Sassu
In-Reply-To: <1581205431.5585.645.camel@linux.ibm.com>


> On Feb 8, 2020, at 4:43 PM, Mimi Zohar <zohar@linux.ibm.com> wrote:
> 
> On Fri, 2020-02-07 at 14:38 -0700, Eric Snowberg wrote:
>>> On Feb 7, 2020, at 11:54 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
>>> 
>>> On Fri, 2020-02-07 at 11:45 -0700, Eric Snowberg wrote:
>>>> 
>>>>> On Feb 7, 2020, at 11:28 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
>>>>> 
>>>>> On Fri, 2020-02-07 at 10:49 -0700, Eric Snowberg wrote:
>>>>>> 
>>>>>>> On Feb 7, 2020, at 10:40 AM, Mimi Zohar <zohar@linux.ibm.com> wrote:
>>>>>>> 
>>>>>>>> $ insmod ./foo.ko
>>>>>>>> insmod: ERROR: could not insert module ./foo.ko: Permission denied
>>>>>>>> 
>>>>>>>> last entry from audit log:
>>>>>>>> type=INTEGRITY_DATA msg=audit(1581089373.076:83): pid=2874 uid=0
>>>>>>>> auid=0 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-
>>>>>>>> s0:c0.c1023 op=appraise_data cause=invalid-signature comm="insmod"
>>>>>>>> name="/root/keys/modules/foo.ko" dev="dm-0" ino=10918365
>>>>>>>> res=0^]UID="root" AUID=“root"
>>>>>>>> 
>>>>>>>> This is because modsig_verify() will be called from within
>>>>>>>> ima_appraise_measurement(), 
>>>>>>>> since try_modsig is true.  Then modsig_verify() will return
>>>>>>>> INTEGRITY_FAIL.
>>>>>>> 
>>>>>>> Why is it an "invalid signature"?  For that you need to look at the
>>>>>>> kernel messages.  Most likely it can't find the public key on the .ima
>>>>>>> keyring to verify the signature.
>>>>>> 
>>>>>> It is invalid because the module has not been ima signed. 
>>>>> 
>>>>> With the IMA policy rule "appraise func=MODULE_CHECK
>>>>> appraise_type=imasig|modsig", IMA first tries to verify the IMA
>>>>> signature stored as an xattr and on failure then attempts to verify
>>>>> the appended signatures.
>>>>> 
>>>>> The audit message above indicates that there was a signature, but the
>>>>> signature validation failed.
>>>>> 
>>>> 
>>>> I do have  CONFIG_IMA_APPRAISE_MODSIG enabled.  I believe the audit message above 
>>>> is coming from modsig_verify in security/integrity/ima/ima_appraise.c.
>>> 
>>> Right, and it's calling:
>>> 
>>> 	rc = integrity_modsig_verify(INTEGRITY_KEYRING_IMA, modsig);
>>> 
>>> It's failing because it is trying to find the public key on the .ima
>>> keyring.  Make sure that the public needed to validate the kernel
>>> module is on the IMA keyring (eg. keyctl show %keyring:.ima).
>>> 
>> 
>> I know that will validate the module properly, but that is not what I’m 
>> trying to solve here. I thought the point of adding “|modsig” to the
>> ima policy was to tell ima it can either validate against an ima keyring OR 
>> default back to the kernel keyring.  This is what happens with the compressed
>> module.  There isn’t anything in the ima keyring to validate the compressed
>> modules and it loads when I add “|modsig”.
> 
> "modsig" has nothing to do with keyrings.  The term "modsig" is
> juxtaposed to "imasig".  "modsig" refers to kernel module appended
> signature. 

Ok, understood, “modsig” refers to strictly kernel module appended signatures
without regard to the keyring that verifies it.  Since there are inconsistencies
here, would you consider something like my first patch?  It will verify an 
uncompressed kernel module containing an appended signature  when the public key
is contained within the kernel keyring instead of the ima keyring.  Why force a 
person to add the same keys into the ima keyring for validation?  Especially when
the kernel keyring is now used to verify appended signatures in the compressed
modules.

> 
>> 
>> The use case I’m trying to solve is when someone boots with ima_policy=secure_boot.
> 
> As the secure_boot policy rules are replaced once a custom policy is
> loaded, the "secure_boot" policy should probably be deprecated.  I
> highly recommend using the more recent build time and architecture
> specific run time policy rules, which persist after loading a custom
> policy. 

I found the secure_boot policy useful, until a custom policy got loaded.  But if it
is targeted to be deprecated, I’ll drop my second patch.  I will look at the run
time policy rules instead. Thanks.


^ permalink raw reply

* Re: [PATCH 1/2] crypto: sm3 - add a new alias name sm3-256
From: Ken Goldman @ 2020-02-10 16:30 UTC (permalink / raw)
  To: Eric Biggers, Tianjia Zhang
  Cc: herbert, davem, zohar, dmitry.kasatkin, jmorris, serge,
	linux-crypto, linux-integrity, linux-security-module,
	linux-kernel
In-Reply-To: <20200210031717.GA5198@sol.localdomain>

On 2/9/2020 10:17 PM, Eric Biggers wrote:
> According to https://tools.ietf.org/id/draft-oscca-cfrg-sm3-01.html,
> SM3 always produces a 256-bit hash value.  E.g., it says:
> 
> 	"SM3 produces an output hash value of 256 bits long"
> 
> and
> 
> 	"SM3 is a hash function that generates a 256-bit hash value."
> 
> I don't see any mention of "SM3-256".
> 
> So why not just keep it as "sm3" and change hash_info.c instead?
> Since the name there is currently wrong, no one can be using it yet.

Question:  Is 256 bits fundamental to SM3?  Could there ever be a 
variant in the future that's e.g., 512 bits?


^ permalink raw reply

* Re: [PATCH v8 08/11] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
From: Jordan Glover @ 2020-02-10 16:29 UTC (permalink / raw)
  To: Alexey Gladkov
  Cc: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module, Akinobu Mita, Alexander Viro,
	Alexey Dobriyan, Andrew Morton, Andy Lutomirski, Daniel Micay,
	Djalal Harouni, Dmitry V . Levin, Eric W . Biederman,
	Greg Kroah-Hartman, Ingo Molnar, J . Bruce Fields, Jeff Layton,
	Jonathan Corbet, Kees Cook, Linus Torvalds, Oleg Nesterov,
	Solar Designer
In-Reply-To: <20200210150519.538333-9-gladkov.alexey@gmail.com>

On Monday, February 10, 2020 3:05 PM, Alexey Gladkov <gladkov.alexey@gmail.com> wrote:

> If "hidepid=4" mount option is set then do not instantiate pids that
> we can not ptrace. "hidepid=4" means that procfs should only contain
> pids that the caller can ptrace.
>
> Cc: Kees Cook keescook@chromium.org
> Cc: Andy Lutomirski luto@kernel.org
> Signed-off-by: Djalal Harouni tixxdz@gmail.com
> Signed-off-by: Alexey Gladkov gladkov.alexey@gmail.com
>
> fs/proc/base.c | 15 +++++++++++++++
> fs/proc/root.c | 14 +++++++++++---
> include/linux/proc_fs.h | 1 +
> 3 files changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/fs/proc/base.c b/fs/proc/base.c
> index 24b7c620ded3..49937d54e745 100644
> --- a/fs/proc/base.c
> +++ b/fs/proc/base.c
> @@ -699,6 +699,14 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info,
> struct task_struct *task,
> int hide_pid_min)
> {
>
> -   /*
> -   -   If 'hidpid' mount option is set force a ptrace check,
> -   -   we indicate that we are using a filesystem syscall
> -   -   by passing PTRACE_MODE_READ_FSCREDS
> -   */
> -   if (proc_fs_hide_pid(fs_info) == HIDEPID_NOT_PTRACABLE)
> -         return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
>
>
> -   if (proc_fs_hide_pid(fs_info) < hide_pid_min)
>     return true;
>     if (in_group_p(proc_fs_pid_gid(fs_info)))
>     @@ -3271,7 +3279,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
>     if (!task)
>     goto out;
>
> -   /* Limit procfs to only ptracable tasks */
> -   if (proc_fs_hide_pid(fs_info) == HIDEPID_NOT_PTRACABLE) {
> -         if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS))
>
>
> -         	goto out_put_task;
>
>
> -   }
> -   result = proc_pid_instantiate(dentry, task, NULL);
>     +out_put_task:
>     put_task_struct(task);
>     out:
>     return result;
>     diff --git a/fs/proc/root.c b/fs/proc/root.c
>     index e2bb015da1a8..5e27bb31f125 100644
>     --- a/fs/proc/root.c
>     +++ b/fs/proc/root.c
>     @@ -52,6 +52,15 @@ static const struct fs_parameter_description proc_fs_parameters = {
>     .specs = proc_param_specs,
>     };
>
>     +static inline int
>     +valid_hidepid(unsigned int value)
>     +{
>
> -   return (value == HIDEPID_OFF ||
> -         value == HIDEPID_NO_ACCESS ||
>
>
> -         value == HIDEPID_INVISIBLE ||
>
>
> -         value == HIDEPID_NOT_PTRACABLE);
>
>
>
> +}
> +
> static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
> {
> struct proc_fs_context *ctx = fc->fs_private;
> @@ -68,10 +77,9 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
> break;
>
> case Opt_hidepid:
>
> -         if (!valid_hidepid(result.uint_32))
>
>
> -         	return invalf(fc, "proc: unknown value of hidepid.\\n");
>           ctx->hidepid = result.uint_32;
>
>
>
> -         if (ctx->hidepid < HIDEPID_OFF ||
>
>
> -             ctx->hidepid > HIDEPID_INVISIBLE)
>
>
> -         	return invalf(fc, "proc: hidepid value must be between 0 and 2.\\n");
>           break;
>
>
>
> default:
> diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
> index f307940f8311..6822548405a7 100644
> --- a/include/linux/proc_fs.h
> +++ b/include/linux/proc_fs.h
> @@ -17,6 +17,7 @@ enum {
> HIDEPID_OFF = 0,
> HIDEPID_NO_ACCESS = 1,
> HIDEPID_INVISIBLE = 2,
>
> -   HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */

Is there a reason new option is "4" instead of "3"? The order 1..2..4 may be
confusing for people.

Jordan

^ permalink raw reply

* Re: [PATCH v3 1/8] tpm: Initialize crypto_id of allocated_banks to HASH_ALGO__LAST
From: Jarkko Sakkinen @ 2020-02-10 16:00 UTC (permalink / raw)
  To: Roberto Sassu
  Cc: zohar, James.Bottomley, linux-integrity, linux-security-module,
	linux-kernel, silviu.vlasceanu, stable
In-Reply-To: <20200210100048.21448-2-roberto.sassu@huawei.com>

On Mon, Feb 10, 2020 at 11:00:41AM +0100, Roberto Sassu wrote:
> chip->allocated_banks, an array of tpm_bank_info structures, contains the
> list of TPM algorithm IDs of allocated PCR banks. It also contains the
> corresponding ID of the crypto subsystem, so that users of the TPM driver
> can calculate a digest for a PCR extend operation.
> 
> However, if there is no mapping between TPM algorithm ID and crypto ID, the
> crypto_id field of tpm_bank_info remains set to zero (the array is
> allocated and initialized with kcalloc() in tpm2_get_pcr_allocation()).
> Zero should not be used as value for unknown mappings, as it is a valid
> crypto ID (HASH_ALGO_MD4).
> 
> Thus, initialize crypto_id to HASH_ALGO__LAST.
> 
> Cc: stable@vger.kernel.org # 5.1.x
> Fixes: 879b589210a9 ("tpm: retrieve digest size of unknown algorithms with PCR read")
> Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
> Reviewed-by: Petr Vorel <pvorel@suse.cz>

Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>

/Jarkko

^ permalink raw reply

* Re: [PATCH v2] ima: export the measurement list when needed
From: Mimi Zohar @ 2020-02-10 15:26 UTC (permalink / raw)
  To: Janne Karhunen
  Cc: linux-integrity, linux-security-module, Ken Goldman,
	david.safford, Wiseman, Monty (GE Global Research, US),
	Amir Goldstein, linux-fsdevel
In-Reply-To: <CAE=NcrYhz7zrhxZoVDSvfs+Cd-vNX30gGXU9Xu4K7ft-1ozN2g@mail.gmail.com>

On Mon, 2020-02-10 at 10:04 +0200, Janne Karhunen wrote:
> On Thu, Feb 6, 2020 at 4:14 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> 
> > The implications of exporting and removing records from the IMA-
> > measurement list needs to be considered carefully.  Verifying a TPM
> > quote will become dependent on knowing where the measurements are
> > stored.  The existing measurement list is stored in kernel memory and,
> > barring a kernel memory attack, is protected from modification.
> >  Before upstreaming this or a similar patch, there needs to be a
> > discussion as to how the measurement list will be protected once is it
> > exported to userspace.
> >
> > This patch now attempts to address two very different scenarios.  The
> > first scenario is where userspace is requesting exporting and removing
> > of the measurement list records.  The other scenario is the kernel
> > exporting and removing of the measurement list records.  Conflating
> > these two different use cases might not be the right solution, as we
> > originally thought.
> >
> > The kernel already exports the IMA measurement list to userspace via a
> > securityfs file.  From a userspace perspective, missing is the ability
> > of removing N number of records.  In this scenario, userspace would be
> > responsible for safely storing the measurements (e.g. blockchain).
> >  The kernel would only be responsible for limiting permission, perhaps
> > based on a capability, before removing records from the measurement
> > list.
> 
> This is a good point. I will adapt the patch to this.
> 
> 
> > In the kernel usecase, somehow the kernel would need to safely export
> > the measurement list, or some portion of the measurement list, to a
> > file and then delete that portion.  What protects the exported records
> > stored in a file from modification?
> 
> Are we looking at protecting this file from a root exploit and the
> potential DOS it might cause? In the original patch the file was root
> writable only. As far as further limitations go, the easiest would
> probably be to use the file immutable bit. If the kernel opens the
> file and sets the immutable bit, it is the only entity that can ever
> write to it - not even another root task could directly write to it.
> The kernel could, as long as it keeps the file open.

The problem being addressed is freeing kernel memory instead of
letting the measurement list grow unbounded.  One solution is to
remove measurement list records, as you did, but that changes the
existing userspace expectations of returning the entire measurement
list.  In the userspace scenario, removing measurement list records is
the requirement.  For the kernel scenario, I don't think it is a
requirement.

> 
> > Instead of exporting the measurement records, one option as suggested
> > by Amir Goldstein, would be to use a vfs_tmpfile() to get an anonymous
> > file for backing store.  The existing securityfs measurement lists
> > would then read from this private copy of the anonymous file.
> >
> > I've Cc'ed fsdevel for additional comments/suggestions.
> 
> I didn't quickly see what the actual problem is that the vfs_tmpfile
> solves in this context, will check.

The existing IMA measurement list is by design, as coined by George
Wilson, a "deliberate memory leak".  Fixing the "Deliberate IMA event
log memory leak" should be the problem description.  Amir's suggestion
of using a vfs_tmpfile seems like a reasonable solution.

Mimi


^ permalink raw reply

* [PATCH v8 02/11] proc: add proc_fs_info struct to store proc information
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This is a preparation patch that adds proc_fs_info to be able to store
different procfs options and informations. Right now some mount options
are stored inside the pid namespace which makes it hard to change or
modernize procfs without affecting pid namespaces. Plus we do want to
treat proc as more of a real mount point and filesystem. procfs is part
of Linux API where it offers some features using filesystem syscalls and
in order to support some features where we are able to have multiple
instances of procfs, each one with its mount options inside the same pid
namespace, we have to separate these procfs instances.

This is the same feature that was also added to other Linux interfaces
like devpts in order to support containers, sandboxes, and to have
multiple instances of devpts filesystem [1].

[1] https://elixir.bootlin.com/linux/v3.4/source/Documentation/filesystems/devpts.txt

Cc: Kees Cook <keescook@chromium.org>
Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/locks.c              |  6 +++--
 fs/proc/base.c          |  8 +++++--
 fs/proc/inode.c         |  4 ++--
 fs/proc/root.c          | 49 +++++++++++++++++++++++++++--------------
 include/linux/proc_fs.h | 11 ++++++++-
 5 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/fs/locks.c b/fs/locks.c
index 6970f55daf54..21200e3005e4 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -2795,7 +2795,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
 {
 	struct inode *inode = NULL;
 	unsigned int fl_pid;
-	struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
+	struct proc_fs_info *fs_info = proc_sb_info(file_inode(f->file)->i_sb);
+	struct pid_namespace *proc_pidns = fs_info->pid_ns;
 
 	fl_pid = locks_translate_pid(fl, proc_pidns);
 	/*
@@ -2873,7 +2874,8 @@ static int locks_show(struct seq_file *f, void *v)
 {
 	struct locks_iterator *iter = f->private;
 	struct file_lock *fl, *bfl;
-	struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
+	struct proc_fs_info *fs_info = proc_sb_info(file_inode(f->file)->i_sb);
+	struct pid_namespace *proc_pidns = fs_info->pid_ns;
 
 	fl = hlist_entry(v, struct file_lock, fl_link);
 
diff --git a/fs/proc/base.c b/fs/proc/base.c
index ebea9501afb8..672e71c52dbd 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3243,6 +3243,7 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
 {
 	struct task_struct *task;
 	unsigned tgid;
+	struct proc_fs_info *fs_info;
 	struct pid_namespace *ns;
 	struct dentry *result = ERR_PTR(-ENOENT);
 
@@ -3250,7 +3251,8 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
 	if (tgid == ~0U)
 		goto out;
 
-	ns = dentry->d_sb->s_fs_info;
+	fs_info = proc_sb_info(dentry->d_sb);
+	ns = fs_info->pid_ns;
 	rcu_read_lock();
 	task = find_task_by_pid_ns(tgid, ns);
 	if (task)
@@ -3538,6 +3540,7 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
 	struct task_struct *task;
 	struct task_struct *leader = get_proc_task(dir);
 	unsigned tid;
+	struct proc_fs_info *fs_info;
 	struct pid_namespace *ns;
 	struct dentry *result = ERR_PTR(-ENOENT);
 
@@ -3548,7 +3551,8 @@ static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry
 	if (tid == ~0U)
 		goto out;
 
-	ns = dentry->d_sb->s_fs_info;
+	fs_info = proc_sb_info(dentry->d_sb);
+	ns = fs_info->pid_ns;
 	rcu_read_lock();
 	task = find_task_by_pid_ns(tid, ns);
 	if (task)
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index dbe43a50caf2..b631608dfbcc 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -104,8 +104,8 @@ void __init proc_init_kmemcache(void)
 
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
 {
-	struct super_block *sb = root->d_sb;
-	struct pid_namespace *pid = sb->s_fs_info;
+	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
+	struct pid_namespace *pid = fs_info->pid_ns;
 
 	if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
 		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 0b7c8dffc9ae..d449f095f0f7 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -30,7 +30,7 @@
 #include "internal.h"
 
 struct proc_fs_context {
-	struct pid_namespace	*pid_ns;
+	struct proc_fs_info	*fs_info;
 	unsigned int		mask;
 	int			hidepid;
 	int			gid;
@@ -97,7 +97,8 @@ static void proc_apply_options(struct super_block *s,
 
 static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 {
-	struct pid_namespace *pid_ns = get_pid_ns(s->s_fs_info);
+	struct proc_fs_context *ctx = fc->fs_private;
+	struct pid_namespace *pid_ns = get_pid_ns(ctx->fs_info->pid_ns);
 	struct inode *root_inode;
 	int ret;
 
@@ -145,7 +146,8 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 static int proc_reconfigure(struct fs_context *fc)
 {
 	struct super_block *sb = fc->root->d_sb;
-	struct pid_namespace *pid = sb->s_fs_info;
+	struct proc_fs_info *fs_info = proc_sb_info(sb);
+	struct pid_namespace *pid = fs_info->pid_ns;
 
 	sync_filesystem(sb);
 
@@ -157,14 +159,14 @@ static int proc_get_tree(struct fs_context *fc)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
 
-	return get_tree_keyed(fc, proc_fill_super, ctx->pid_ns);
+	return get_tree_keyed(fc, proc_fill_super, ctx->fs_info);
 }
 
 static void proc_fs_context_free(struct fs_context *fc)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
 
-	put_pid_ns(ctx->pid_ns);
+	put_pid_ns(ctx->fs_info->pid_ns);
 	kfree(ctx);
 }
 
@@ -178,14 +180,27 @@ static const struct fs_context_operations proc_fs_context_ops = {
 static int proc_init_fs_context(struct fs_context *fc)
 {
 	struct proc_fs_context *ctx;
+	struct pid_namespace *pid_ns;
 
 	ctx = kzalloc(sizeof(struct proc_fs_context), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
-	ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
+	pid_ns = get_pid_ns(task_active_pid_ns(current));
+
+	if (!pid_ns->proc_mnt) {
+		ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL);
+		if (!ctx->fs_info) {
+			kfree(ctx);
+			return -ENOMEM;
+		}
+		ctx->fs_info->pid_ns = pid_ns;
+	} else {
+		ctx->fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
+	}
+
 	put_user_ns(fc->user_ns);
-	fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
+	fc->user_ns = get_user_ns(ctx->fs_info->pid_ns->user_ns);
 	fc->fs_private = ctx;
 	fc->ops = &proc_fs_context_ops;
 	return 0;
@@ -193,15 +208,15 @@ static int proc_init_fs_context(struct fs_context *fc)
 
 static void proc_kill_sb(struct super_block *sb)
 {
-	struct pid_namespace *ns;
+	struct proc_fs_info *fs_info = proc_sb_info(sb);
 
-	ns = (struct pid_namespace *)sb->s_fs_info;
-	if (ns->proc_self)
-		dput(ns->proc_self);
-	if (ns->proc_thread_self)
-		dput(ns->proc_thread_self);
+	if (fs_info->pid_ns->proc_self)
+		dput(fs_info->pid_ns->proc_self);
+	if (fs_info->pid_ns->proc_thread_self)
+		dput(fs_info->pid_ns->proc_thread_self);
 	kill_anon_super(sb);
-	put_pid_ns(ns);
+	put_pid_ns(fs_info->pid_ns);
+	kfree(fs_info);
 }
 
 static struct file_system_type proc_fs_type = {
@@ -314,10 +329,10 @@ int pid_ns_prepare_proc(struct pid_namespace *ns)
 	}
 
 	ctx = fc->fs_private;
-	if (ctx->pid_ns != ns) {
-		put_pid_ns(ctx->pid_ns);
+	if (ctx->fs_info->pid_ns != ns) {
+		put_pid_ns(ctx->fs_info->pid_ns);
 		get_pid_ns(ns);
-		ctx->pid_ns = ns;
+		ctx->fs_info->pid_ns = ns;
 	}
 
 	mnt = fc_mount(fc);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index a705aa2d03f9..2d79489e55aa 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -12,6 +12,15 @@ struct proc_dir_entry;
 struct seq_file;
 struct seq_operations;
 
+struct proc_fs_info {
+	struct pid_namespace *pid_ns;
+};
+
+static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
+{
+	return sb->s_fs_info;
+}
+
 #ifdef CONFIG_PROC_FS
 
 typedef int (*proc_write_t)(struct file *, char *, size_t);
@@ -146,7 +155,7 @@ int open_related_ns(struct ns_common *ns,
 /* get the associated pid namespace for a file in procfs */
 static inline struct pid_namespace *proc_pid_ns(const struct inode *inode)
 {
-	return inode->i_sb->s_fs_info;
+	return proc_sb_info(inode->i_sb)->pid_ns;
 }
 
 #endif /* _LINUX_PROC_FS_H */
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 04/11] proc: move hide_pid, pid_gid from pid_namespace to proc_fs_info
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This is a preparation patch that moves hide_pid and pid_gid parameters
to be stored inside procfs fs_info struct instead of making them per pid
namespace. Since we want to support multiple procfs instances we need to
make sure that all proc-specific parameters are also per-superblock.

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c                | 18 +++++++++---------
 fs/proc/inode.c               |  9 ++++-----
 fs/proc/root.c                | 10 ++++++++--
 include/linux/pid_namespace.h |  8 --------
 include/linux/proc_fs.h       |  9 +++++++++
 5 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 1eb366ad8b06..caca1929fee1 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -695,13 +695,13 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr)
  * May current process learn task's sched/cmdline info (for hide_pid_min=1)
  * or euid/egid (for hide_pid_min=2)?
  */
-static bool has_pid_permissions(struct pid_namespace *pid,
+static bool has_pid_permissions(struct proc_fs_info *fs_info,
 				 struct task_struct *task,
 				 int hide_pid_min)
 {
-	if (pid->hide_pid < hide_pid_min)
+	if (fs_info->hide_pid < hide_pid_min)
 		return true;
-	if (in_group_p(pid->pid_gid))
+	if (in_group_p(fs_info->pid_gid))
 		return true;
 	return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
 }
@@ -709,18 +709,18 @@ static bool has_pid_permissions(struct pid_namespace *pid,
 
 static int proc_pid_permission(struct inode *inode, int mask)
 {
-	struct pid_namespace *pid = proc_pid_ns(inode);
+	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
 	struct task_struct *task;
 	bool has_perms;
 
 	task = get_proc_task(inode);
 	if (!task)
 		return -ESRCH;
-	has_perms = has_pid_permissions(pid, task, HIDEPID_NO_ACCESS);
+	has_perms = has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS);
 	put_task_struct(task);
 
 	if (!has_perms) {
-		if (pid->hide_pid == HIDEPID_INVISIBLE) {
+		if (fs_info->hide_pid == HIDEPID_INVISIBLE) {
 			/*
 			 * Let's make getdents(), stat(), and open()
 			 * consistent with each other.  If a process
@@ -1784,7 +1784,7 @@ int pid_getattr(const struct path *path, struct kstat *stat,
 		u32 request_mask, unsigned int query_flags)
 {
 	struct inode *inode = d_inode(path->dentry);
-	struct pid_namespace *pid = proc_pid_ns(inode);
+	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
 	struct task_struct *task;
 
 	generic_fillattr(inode, stat);
@@ -1794,7 +1794,7 @@ int pid_getattr(const struct path *path, struct kstat *stat,
 	rcu_read_lock();
 	task = pid_task(proc_pid(inode), PIDTYPE_PID);
 	if (task) {
-		if (!has_pid_permissions(pid, task, HIDEPID_INVISIBLE)) {
+		if (!has_pid_permissions(fs_info, task, HIDEPID_INVISIBLE)) {
 			rcu_read_unlock();
 			/*
 			 * This doesn't prevent learning whether PID exists,
@@ -3344,7 +3344,7 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 		unsigned int len;
 
 		cond_resched();
-		if (!has_pid_permissions(ns, iter.task, HIDEPID_INVISIBLE))
+		if (!has_pid_permissions(fs_info, iter.task, HIDEPID_INVISIBLE))
 			continue;
 
 		len = snprintf(name, sizeof(name), "%u", iter.tgid);
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b631608dfbcc..b90c233e5968 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -105,12 +105,11 @@ void __init proc_init_kmemcache(void)
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
 {
 	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
-	struct pid_namespace *pid = fs_info->pid_ns;
 
-	if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID))
-		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid));
-	if (pid->hide_pid != HIDEPID_OFF)
-		seq_printf(seq, ",hidepid=%u", pid->hide_pid);
+	if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID))
+		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
+	if (fs_info->hide_pid != HIDEPID_OFF)
+		seq_printf(seq, ",hidepid=%u", fs_info->hide_pid);
 
 	return 0;
 }
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 637e26cc795e..1ca47d446aa4 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -89,10 +89,16 @@ static void proc_apply_options(struct super_block *s,
 {
 	struct proc_fs_context *ctx = fc->fs_private;
 
+	if (pid_ns->proc_mnt) {
+		struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
+		ctx->fs_info->pid_gid = fs_info->pid_gid;
+		ctx->fs_info->hide_pid = fs_info->hide_pid;
+	}
+
 	if (ctx->mask & (1 << Opt_gid))
-		pid_ns->pid_gid = make_kgid(user_ns, ctx->gid);
+		ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
 	if (ctx->mask & (1 << Opt_hidepid))
-		pid_ns->hide_pid = ctx->hidepid;
+		ctx->fs_info->hide_pid = ctx->hidepid;
 }
 
 static int proc_fill_super(struct super_block *s, struct fs_context *fc)
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index f91a8bf6e09e..66f47f1afe0d 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -15,12 +15,6 @@
 
 struct fs_pin;
 
-enum { /* definitions for pid_namespace's hide_pid field */
-	HIDEPID_OFF	  = 0,
-	HIDEPID_NO_ACCESS = 1,
-	HIDEPID_INVISIBLE = 2,
-};
-
 struct pid_namespace {
 	struct kref kref;
 	struct idr idr;
@@ -39,8 +33,6 @@ struct pid_namespace {
 	struct user_namespace *user_ns;
 	struct ucounts *ucounts;
 	struct work_struct proc_work;
-	kgid_t pid_gid;
-	int hide_pid;
 	int reboot;	/* group exit code if this pidns was rebooted */
 	struct ns_common ns;
 } __randomize_layout;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 59162988998e..5f0b1b7e4271 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -12,10 +12,19 @@ struct proc_dir_entry;
 struct seq_file;
 struct seq_operations;
 
+/* definitions for hide_pid field */
+enum {
+	HIDEPID_OFF	  = 0,
+	HIDEPID_NO_ACCESS = 1,
+	HIDEPID_INVISIBLE = 2,
+};
+
 struct proc_fs_info {
 	struct pid_namespace *pid_ns;
 	struct dentry *proc_self;        /* For /proc/self */
 	struct dentry *proc_thread_self; /* For /proc/thread-self */
+	kgid_t pid_gid;
+	int hide_pid;
 };
 
 static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 06/11] proc: support mounting procfs instances inside same pid namespace
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This patch allows to have multiple procfs instances inside the
same pid namespace. The aim here is lightweight sandboxes, and to allow
that we have to modernize procfs internals.

1) The main aim of this work is to have on embedded systems one
supervisor for apps. Right now we have some lightweight sandbox support,
however if we create pid namespacess we have to manages all the
processes inside too, where our goal is to be able to run a bunch of
apps each one inside its own mount namespace without being able to
notice each other. We only want to use mount namespaces, and we want
procfs to behave more like a real mount point.

2) Linux Security Modules have multiple ptrace paths inside some
subsystems, however inside procfs, the implementation does not guarantee
that the ptrace() check which triggers the security_ptrace_check() hook
will always run. We have the 'hidepid' mount option that can be used to
force the ptrace_may_access() check inside has_pid_permissions() to run.
The problem is that 'hidepid' is per pid namespace and not attached to
the mount point, any remount or modification of 'hidepid' will propagate
to all other procfs mounts.

This also does not allow to support Yama LSM easily in desktop and user
sessions. Yama ptrace scope which restricts ptrace and some other
syscalls to be allowed only on inferiors, can be updated to have a
per-task context, where the context will be inherited during fork(),
clone() and preserved across execve(). If we support multiple private
procfs instances, then we may force the ptrace_may_access() on
/proc/<pids>/ to always run inside that new procfs instances. This will
allow to specifiy on user sessions if we should populate procfs with
pids that the user can ptrace or not.

By using Yama ptrace scope, some restricted users will only be able to see
inferiors inside /proc, they won't even be able to see their other
processes. Some software like Chromium, Firefox's crash handler, Wine
and others are already using Yama to restrict which processes can be
ptracable. With this change this will give the possibility to restrict
/proc/<pids>/ but more importantly this will give desktop users a
generic and usuable way to specifiy which users should see all processes
and which users can not.

Side notes:
* This covers the lack of seccomp where it is not able to parse
arguments, it is easy to install a seccomp filter on direct syscalls
that operate on pids, however /proc/<pid>/ is a Linux ABI using
filesystem syscalls. With this change LSMs should be able to analyze
open/read/write/close...

In the new patchset version I removed the 'newinstance' option
as Eric W. Biederman suggested.

Cc: Kees Cook <keescook@chromium.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/root.c | 41 ++++++++++++++++++-----------------------
 1 file changed, 18 insertions(+), 23 deletions(-)

diff --git a/fs/proc/root.c b/fs/proc/root.c
index efd76c004e86..5d5cba4c899b 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -82,7 +82,7 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 	return 0;
 }
 
-static void proc_apply_options(struct super_block *s,
+static void proc_apply_options(struct proc_fs_info *fs_info,
 			       struct fs_context *fc,
 			       struct pid_namespace *pid_ns,
 			       struct user_namespace *user_ns)
@@ -90,15 +90,17 @@ static void proc_apply_options(struct super_block *s,
 	struct proc_fs_context *ctx = fc->fs_private;
 
 	if (pid_ns->proc_mnt) {
-		struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
-		proc_fs_set_pid_gid(ctx->fs_info, proc_fs_pid_gid(fs_info));
-		proc_fs_set_hide_pid(ctx->fs_info, proc_fs_hide_pid(fs_info));
+		struct proc_fs_info *pidns_fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
+
+		proc_fs_set_pid_gid(fs_info, proc_fs_pid_gid(pidns_fs_info));
+		proc_fs_set_hide_pid(fs_info, proc_fs_hide_pid(pidns_fs_info));
 	}
 
 	if (ctx->mask & (1 << Opt_gid))
-		proc_fs_set_pid_gid(ctx->fs_info, make_kgid(user_ns, ctx->gid));
+		proc_fs_set_pid_gid(fs_info, make_kgid(user_ns, ctx->gid));
+
 	if (ctx->mask & (1 << Opt_hidepid))
-		proc_fs_set_hide_pid(ctx->fs_info, ctx->hidepid);
+		proc_fs_set_hide_pid(fs_info, ctx->hidepid);
 }
 
 static int proc_fill_super(struct super_block *s, struct fs_context *fc)
@@ -108,7 +110,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 	struct inode *root_inode;
 	int ret;
 
-	proc_apply_options(s, fc, pid_ns, current_user_ns());
+	proc_apply_options(ctx->fs_info, fc, pid_ns, current_user_ns());
 
 	/* User space would break if executables or devices appear on proc */
 	s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV;
@@ -118,6 +120,7 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 	s->s_magic = PROC_SUPER_MAGIC;
 	s->s_op = &proc_sops;
 	s->s_time_gran = 1;
+	s->s_fs_info = ctx->fs_info;
 
 	/*
 	 * procfs isn't actually a stacking filesystem; however, there is
@@ -157,15 +160,13 @@ static int proc_reconfigure(struct fs_context *fc)
 
 	sync_filesystem(sb);
 
-	proc_apply_options(sb, fc, pid, current_user_ns());
+	proc_apply_options(fs_info, fc, pid, current_user_ns());
 	return 0;
 }
 
 static int proc_get_tree(struct fs_context *fc)
 {
-	struct proc_fs_context *ctx = fc->fs_private;
-
-	return get_tree_keyed(fc, proc_fill_super, ctx->fs_info);
+	return get_tree_nodev(fc, proc_fill_super);
 }
 
 static void proc_fs_context_free(struct fs_context *fc)
@@ -186,25 +187,19 @@ static const struct fs_context_operations proc_fs_context_ops = {
 static int proc_init_fs_context(struct fs_context *fc)
 {
 	struct proc_fs_context *ctx;
-	struct pid_namespace *pid_ns;
 
 	ctx = kzalloc(sizeof(struct proc_fs_context), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
-	pid_ns = get_pid_ns(task_active_pid_ns(current));
-
-	if (!pid_ns->proc_mnt) {
-		ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL);
-		if (!ctx->fs_info) {
-			kfree(ctx);
-			return -ENOMEM;
-		}
-		ctx->fs_info->pid_ns = pid_ns;
-	} else {
-		ctx->fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
+	ctx->fs_info = kzalloc(sizeof(struct proc_fs_info), GFP_KERNEL);
+	if (!ctx->fs_info) {
+		kfree(ctx);
+		return -ENOMEM;
 	}
 
+	ctx->fs_info->pid_ns = get_pid_ns(task_active_pid_ns(current));
+
 	put_user_ns(fc->user_ns);
 	fc->user_ns = get_user_ns(ctx->fs_info->pid_ns->user_ns);
 	fc->fs_private = ctx;
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 05/11] proc: add helpers to set and get proc hidepid and gid mount options
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This is a cleaning patch to add helpers to set and get proc mount
options instead of directly using them. This make it easy to track
what's happening and easy to update in future.

Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c     |  6 +++---
 fs/proc/inode.c    | 11 +++++++----
 fs/proc/internal.h | 20 ++++++++++++++++++++
 fs/proc/root.c     |  8 ++++----
 4 files changed, 34 insertions(+), 11 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index caca1929fee1..4ccb280a3e79 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -699,9 +699,9 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info,
 				 struct task_struct *task,
 				 int hide_pid_min)
 {
-	if (fs_info->hide_pid < hide_pid_min)
+	if (proc_fs_hide_pid(fs_info) < hide_pid_min)
 		return true;
-	if (in_group_p(fs_info->pid_gid))
+	if (in_group_p(proc_fs_pid_gid(fs_info)))
 		return true;
 	return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
 }
@@ -720,7 +720,7 @@ static int proc_pid_permission(struct inode *inode, int mask)
 	put_task_struct(task);
 
 	if (!has_perms) {
-		if (fs_info->hide_pid == HIDEPID_INVISIBLE) {
+		if (proc_fs_hide_pid(fs_info) == HIDEPID_INVISIBLE) {
 			/*
 			 * Let's make getdents(), stat(), and open()
 			 * consistent with each other.  If a process
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index b90c233e5968..70b722fb8811 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -105,11 +105,14 @@ void __init proc_init_kmemcache(void)
 static int proc_show_options(struct seq_file *seq, struct dentry *root)
 {
 	struct proc_fs_info *fs_info = proc_sb_info(root->d_sb);
+	int hidepid = proc_fs_hide_pid(fs_info);
+	kgid_t gid = proc_fs_pid_gid(fs_info);
 
-	if (!gid_eq(fs_info->pid_gid, GLOBAL_ROOT_GID))
-		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, fs_info->pid_gid));
-	if (fs_info->hide_pid != HIDEPID_OFF)
-		seq_printf(seq, ",hidepid=%u", fs_info->hide_pid);
+	if (!gid_eq(gid, GLOBAL_ROOT_GID))
+		seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, gid));
+
+	if (hidepid != HIDEPID_OFF)
+		seq_printf(seq, ",hidepid=%u", hidepid);
 
 	return 0;
 }
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index cd0c8d5ce9a1..ff2f274b2e0d 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -121,6 +121,26 @@ static inline struct task_struct *get_proc_task(const struct inode *inode)
 	return get_pid_task(proc_pid(inode), PIDTYPE_PID);
 }
 
+static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_pid)
+{
+	fs_info->hide_pid = hide_pid;
+}
+
+static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid)
+{
+	fs_info->pid_gid = gid;
+}
+
+static inline int proc_fs_hide_pid(struct proc_fs_info *fs_info)
+{
+	return fs_info->hide_pid;
+}
+
+static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info)
+{
+	return fs_info->pid_gid;
+}
+
 void task_dump_owner(struct task_struct *task, umode_t mode,
 		     kuid_t *ruid, kgid_t *rgid);
 
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 1ca47d446aa4..efd76c004e86 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -91,14 +91,14 @@ static void proc_apply_options(struct super_block *s,
 
 	if (pid_ns->proc_mnt) {
 		struct proc_fs_info *fs_info = proc_sb_info(pid_ns->proc_mnt->mnt_sb);
-		ctx->fs_info->pid_gid = fs_info->pid_gid;
-		ctx->fs_info->hide_pid = fs_info->hide_pid;
+		proc_fs_set_pid_gid(ctx->fs_info, proc_fs_pid_gid(fs_info));
+		proc_fs_set_hide_pid(ctx->fs_info, proc_fs_hide_pid(fs_info));
 	}
 
 	if (ctx->mask & (1 << Opt_gid))
-		ctx->fs_info->pid_gid = make_kgid(user_ns, ctx->gid);
+		proc_fs_set_pid_gid(ctx->fs_info, make_kgid(user_ns, ctx->gid));
 	if (ctx->mask & (1 << Opt_hidepid))
-		ctx->fs_info->hide_pid = ctx->hidepid;
+		proc_fs_set_hide_pid(ctx->fs_info, ctx->hidepid);
 }
 
 static int proc_fill_super(struct super_block *s, struct fs_context *fc)
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 07/11] proc: flush task dcache entries from all procfs instances
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This allows to flush dcache entries of a task on multiple procfs mounts
per pid namespace.

The RCU lock is used because the number of reads at the task exit time
is much larger than the number of procfs mounts.

Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c                | 20 +++++++++++++++-----
 fs/proc/root.c                | 27 ++++++++++++++++++++++++++-
 include/linux/pid_namespace.h |  2 ++
 include/linux/proc_fs.h       |  2 ++
 4 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 4ccb280a3e79..24b7c620ded3 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3133,7 +3133,7 @@ static const struct inode_operations proc_tgid_base_inode_operations = {
 	.permission	= proc_pid_permission,
 };
 
-static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
+static void proc_flush_task_mnt_root(struct dentry *mnt_root, pid_t pid, pid_t tgid)
 {
 	struct dentry *dentry, *leader, *dir;
 	char buf[10 + 1];
@@ -3142,7 +3142,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
 	name.name = buf;
 	name.len = snprintf(buf, sizeof(buf), "%u", pid);
 	/* no ->d_hash() rejects on procfs */
-	dentry = d_hash_and_lookup(mnt->mnt_root, &name);
+	dentry = d_hash_and_lookup(mnt_root, &name);
 	if (dentry) {
 		d_invalidate(dentry);
 		dput(dentry);
@@ -3153,7 +3153,7 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
 
 	name.name = buf;
 	name.len = snprintf(buf, sizeof(buf), "%u", tgid);
-	leader = d_hash_and_lookup(mnt->mnt_root, &name);
+	leader = d_hash_and_lookup(mnt_root, &name);
 	if (!leader)
 		goto out;
 
@@ -3208,14 +3208,24 @@ void proc_flush_task(struct task_struct *task)
 	int i;
 	struct pid *pid, *tgid;
 	struct upid *upid;
+	struct dentry *mnt_root;
+	struct proc_fs_info *fs_info;
 
 	pid = task_pid(task);
 	tgid = task_tgid(task);
 
 	for (i = 0; i <= pid->level; i++) {
 		upid = &pid->numbers[i];
-		proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr,
-					tgid->numbers[i].nr);
+
+		rcu_read_lock();
+		list_for_each_entry_rcu(fs_info, &upid->ns->proc_mounts, pidns_entry) {
+			mnt_root = fs_info->m_super->s_root;
+			proc_flush_task_mnt_root(mnt_root, upid->nr, tgid->numbers[i].nr);
+		}
+		rcu_read_unlock();
+
+		mnt_root = upid->ns->proc_mnt->mnt_root;
+		proc_flush_task_mnt_root(mnt_root, upid->nr, tgid->numbers[i].nr);
 	}
 }
 
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 5d5cba4c899b..e2bb015da1a8 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -149,7 +149,22 @@ static int proc_fill_super(struct super_block *s, struct fs_context *fc)
 	if (ret) {
 		return ret;
 	}
-	return proc_setup_thread_self(s);
+
+	ret = proc_setup_thread_self(s);
+	if (ret) {
+		return ret;
+	}
+
+	/*
+	 * back reference to flush dcache entries at process exit time.
+	 */
+	ctx->fs_info->m_super = s;
+
+	spin_lock(&pid_ns->proc_mounts_lock);
+	list_add_tail_rcu(&ctx->fs_info->pidns_entry, &pid_ns->proc_mounts);
+	spin_unlock(&pid_ns->proc_mounts_lock);
+
+	return 0;
 }
 
 static int proc_reconfigure(struct fs_context *fc)
@@ -211,10 +226,17 @@ static void proc_kill_sb(struct super_block *sb)
 {
 	struct proc_fs_info *fs_info = proc_sb_info(sb);
 
+	spin_lock(&fs_info->pid_ns->proc_mounts_lock);
+	list_del_rcu(&fs_info->pidns_entry);
+	spin_unlock(&fs_info->pid_ns->proc_mounts_lock);
+
+	synchronize_rcu();
+
 	if (fs_info->proc_self)
 		dput(fs_info->proc_self);
 	if (fs_info->proc_thread_self)
 		dput(fs_info->proc_thread_self);
+
 	kill_anon_super(sb);
 	put_pid_ns(fs_info->pid_ns);
 	kfree(fs_info);
@@ -336,6 +358,9 @@ int pid_ns_prepare_proc(struct pid_namespace *ns)
 		ctx->fs_info->pid_ns = ns;
 	}
 
+	spin_lock_init(&ns->proc_mounts_lock);
+	INIT_LIST_HEAD_RCU(&ns->proc_mounts);
+
 	mnt = fc_mount(fc);
 	put_fs_context(fc);
 	if (IS_ERR(mnt))
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 66f47f1afe0d..c36af1dfd862 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -26,6 +26,8 @@ struct pid_namespace {
 	struct pid_namespace *parent;
 #ifdef CONFIG_PROC_FS
 	struct vfsmount *proc_mnt; /* Internal proc mounted during each new pidns */
+	spinlock_t proc_mounts_lock;
+	struct list_head proc_mounts; /* list of separated procfs mounts */
 #endif
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	struct fs_pin *bacct;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 5f0b1b7e4271..f307940f8311 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -20,6 +20,8 @@ enum {
 };
 
 struct proc_fs_info {
+	struct list_head pidns_entry;    /* Node in procfs_mounts of a pidns */
+	struct super_block *m_super;
 	struct pid_namespace *pid_ns;
 	struct dentry *proc_self;        /* For /proc/self */
 	struct dentry *proc_thread_self; /* For /proc/thread-self */
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 08/11] proc: instantiate only pids that we can ptrace on 'hidepid=4' mount option
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

If "hidepid=4" mount option is set then do not instantiate pids that
we can not ptrace. "hidepid=4" means that procfs should only contain
pids that the caller can ptrace.

Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c          | 15 +++++++++++++++
 fs/proc/root.c          | 14 +++++++++++---
 include/linux/proc_fs.h |  1 +
 3 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 24b7c620ded3..49937d54e745 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -699,6 +699,14 @@ static bool has_pid_permissions(struct proc_fs_info *fs_info,
 				 struct task_struct *task,
 				 int hide_pid_min)
 {
+	/*
+	 * If 'hidpid' mount option is set force a ptrace check,
+	 * we indicate that we are using a filesystem syscall
+	 * by passing PTRACE_MODE_READ_FSCREDS
+	 */
+	if (proc_fs_hide_pid(fs_info) == HIDEPID_NOT_PTRACABLE)
+		return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
+
 	if (proc_fs_hide_pid(fs_info) < hide_pid_min)
 		return true;
 	if (in_group_p(proc_fs_pid_gid(fs_info)))
@@ -3271,7 +3279,14 @@ struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
 	if (!task)
 		goto out;
 
+	/* Limit procfs to only ptracable tasks */
+	if (proc_fs_hide_pid(fs_info) == HIDEPID_NOT_PTRACABLE) {
+		if (!has_pid_permissions(fs_info, task, HIDEPID_NO_ACCESS))
+			goto out_put_task;
+	}
+
 	result = proc_pid_instantiate(dentry, task, NULL);
+out_put_task:
 	put_task_struct(task);
 out:
 	return result;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index e2bb015da1a8..5e27bb31f125 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -52,6 +52,15 @@ static const struct fs_parameter_description proc_fs_parameters = {
 	.specs		= proc_param_specs,
 };
 
+static inline int
+valid_hidepid(unsigned int value)
+{
+	return (value == HIDEPID_OFF ||
+		value == HIDEPID_NO_ACCESS ||
+		value == HIDEPID_INVISIBLE ||
+		value == HIDEPID_NOT_PTRACABLE);
+}
+
 static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
@@ -68,10 +77,9 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		break;
 
 	case Opt_hidepid:
+		if (!valid_hidepid(result.uint_32))
+			return invalf(fc, "proc: unknown value of hidepid.\n");
 		ctx->hidepid = result.uint_32;
-		if (ctx->hidepid < HIDEPID_OFF ||
-		    ctx->hidepid > HIDEPID_INVISIBLE)
-			return invalf(fc, "proc: hidepid value must be between 0 and 2.\n");
 		break;
 
 	default:
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index f307940f8311..6822548405a7 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -17,6 +17,7 @@ enum {
 	HIDEPID_OFF	  = 0,
 	HIDEPID_NO_ACCESS = 1,
 	HIDEPID_INVISIBLE = 2,
+	HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */
 };
 
 struct proc_fs_info {
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 09/11] proc: add option to mount only a pids subset
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This allows to hide all files and directories in the procfs that are not
related to tasks.

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/generic.c       |  9 +++++++++
 fs/proc/inode.c         |  7 +++++++
 fs/proc/internal.h      | 10 ++++++++++
 fs/proc/root.c          | 36 ++++++++++++++++++++++++++++++++++++
 include/linux/proc_fs.h |  7 +++++++
 5 files changed, 69 insertions(+)

diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 64e9ee1b129e..6f6517d63053 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -267,6 +267,11 @@ struct dentry *proc_lookup_de(struct inode *dir, struct dentry *dentry,
 struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry,
 		unsigned int flags)
 {
+	struct proc_fs_info *fs_info = proc_sb_info(dir->i_sb);
+
+	if (proc_fs_pidonly(fs_info) == PROC_PIDONLY_ON)
+		return ERR_PTR(-ENOENT);
+
 	return proc_lookup_de(dir, dentry, PDE(dir));
 }
 
@@ -323,6 +328,10 @@ int proc_readdir_de(struct file *file, struct dir_context *ctx,
 int proc_readdir(struct file *file, struct dir_context *ctx)
 {
 	struct inode *inode = file_inode(file);
+	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
+
+	if (proc_fs_pidonly(fs_info) == PROC_PIDONLY_ON)
+		return 1;
 
 	return proc_readdir_de(file, ctx, PDE(inode));
 }
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 70b722fb8811..f35eef117775 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -114,6 +114,9 @@ static int proc_show_options(struct seq_file *seq, struct dentry *root)
 	if (hidepid != HIDEPID_OFF)
 		seq_printf(seq, ",hidepid=%u", hidepid);
 
+	if (proc_fs_pidonly(fs_info) != PROC_PIDONLY_OFF)
+		seq_printf(seq, ",subset=pidfs");
+
 	return 0;
 }
 
@@ -333,12 +336,16 @@ proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr,
 
 static int proc_reg_open(struct inode *inode, struct file *file)
 {
+	struct proc_fs_info *fs_info = proc_sb_info(inode->i_sb);
 	struct proc_dir_entry *pde = PDE(inode);
 	int rv = 0;
 	typeof_member(struct file_operations, open) open;
 	typeof_member(struct file_operations, release) release;
 	struct pde_opener *pdeo;
 
+	if (proc_fs_pidonly(fs_info) == PROC_PIDONLY_ON)
+		return -ENOENT;
+
 	/*
 	 * Ensure that
 	 * 1) PDE's ->release hook will be called no matter what
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index ff2f274b2e0d..e2c729267317 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -126,6 +126,11 @@ static inline void proc_fs_set_hide_pid(struct proc_fs_info *fs_info, int hide_p
 	fs_info->hide_pid = hide_pid;
 }
 
+static inline void proc_fs_set_pidonly(struct proc_fs_info *fs_info, int value)
+{
+	fs_info->pidonly = value;
+}
+
 static inline void proc_fs_set_pid_gid(struct proc_fs_info *fs_info, kgid_t gid)
 {
 	fs_info->pid_gid = gid;
@@ -141,6 +146,11 @@ static inline kgid_t proc_fs_pid_gid(struct proc_fs_info *fs_info)
 	return fs_info->pid_gid;
 }
 
+static inline int proc_fs_pidonly(struct proc_fs_info *fs_info)
+{
+	return fs_info->pidonly;
+}
+
 void task_dump_owner(struct task_struct *task, umode_t mode,
 		     kuid_t *ruid, kgid_t *rgid);
 
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 5e27bb31f125..4dce77639c2b 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -34,16 +34,19 @@ struct proc_fs_context {
 	unsigned int		mask;
 	int			hidepid;
 	int			gid;
+	int			pidonly;
 };
 
 enum proc_param {
 	Opt_gid,
 	Opt_hidepid,
+	Opt_subset,
 };
 
 static const struct fs_parameter_spec proc_param_specs[] = {
 	fsparam_u32("gid",	Opt_gid),
 	fsparam_u32("hidepid",	Opt_hidepid),
+	fsparam_string("subset",	Opt_subset),
 	{}
 };
 
@@ -61,6 +64,30 @@ valid_hidepid(unsigned int value)
 		value == HIDEPID_NOT_PTRACABLE);
 }
 
+static inline int
+proc_parse_subset_param(struct fs_context *fc, char *value)
+{
+	struct proc_fs_context *ctx = fc->fs_private;
+
+	while (value) {
+		char *ptr = strchr(value, ',');
+
+		if (ptr != NULL)
+			*ptr++ = '\0';
+
+		if (*value != '\0') {
+			if (!strcmp(value, "pidfs")) {
+				ctx->pidonly = PROC_PIDONLY_ON;
+			} else {
+				return invalf(fc, "proc: unsupported subset option - %s\n", value);
+			}
+		}
+		value = ptr;
+	}
+
+	return 0;
+}
+
 static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 {
 	struct proc_fs_context *ctx = fc->fs_private;
@@ -82,6 +109,11 @@ static int proc_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		ctx->hidepid = result.uint_32;
 		break;
 
+	case Opt_subset:
+		if (proc_parse_subset_param(fc, param->string) < 0)
+			return -EINVAL;
+		break;
+
 	default:
 		return -EINVAL;
 	}
@@ -102,6 +134,7 @@ static void proc_apply_options(struct proc_fs_info *fs_info,
 
 		proc_fs_set_pid_gid(fs_info, proc_fs_pid_gid(pidns_fs_info));
 		proc_fs_set_hide_pid(fs_info, proc_fs_hide_pid(pidns_fs_info));
+		proc_fs_set_pidonly(fs_info, proc_fs_pidonly(pidns_fs_info));
 	}
 
 	if (ctx->mask & (1 << Opt_gid))
@@ -109,6 +142,9 @@ static void proc_apply_options(struct proc_fs_info *fs_info,
 
 	if (ctx->mask & (1 << Opt_hidepid))
 		proc_fs_set_hide_pid(fs_info, ctx->hidepid);
+
+	if (ctx->mask & (1 << Opt_subset))
+		proc_fs_set_pidonly(fs_info, ctx->pidonly);
 }
 
 static int proc_fill_super(struct super_block *s, struct fs_context *fc)
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 6822548405a7..3ad0a47c3556 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -20,6 +20,12 @@ enum {
 	HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */
 };
 
+/* definitions for proc mount option pidonly */
+enum {
+	PROC_PIDONLY_OFF = 0,
+	PROC_PIDONLY_ON  = 1,
+};
+
 struct proc_fs_info {
 	struct list_head pidns_entry;    /* Node in procfs_mounts of a pidns */
 	struct super_block *m_super;
@@ -28,6 +34,7 @@ struct proc_fs_info {
 	struct dentry *proc_thread_self; /* For /proc/thread-self */
 	kgid_t pid_gid;
 	int hide_pid;
+	int pidonly;
 };
 
 static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 11/11] proc: Move hidepid values to uapi as they are user interface to mount
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

Suggested-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 include/linux/proc_fs.h      |  9 +--------
 include/uapi/linux/proc_fs.h | 13 +++++++++++++
 2 files changed, 14 insertions(+), 8 deletions(-)
 create mode 100644 include/uapi/linux/proc_fs.h

diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 3ad0a47c3556..f2b4a411d371 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -7,19 +7,12 @@
 
 #include <linux/types.h>
 #include <linux/fs.h>
+#include <uapi/linux/proc_fs.h>
 
 struct proc_dir_entry;
 struct seq_file;
 struct seq_operations;
 
-/* definitions for hide_pid field */
-enum {
-	HIDEPID_OFF	  = 0,
-	HIDEPID_NO_ACCESS = 1,
-	HIDEPID_INVISIBLE = 2,
-	HIDEPID_NOT_PTRACABLE = 4, /* Limit pids to only ptracable pids */
-};
-
 /* definitions for proc mount option pidonly */
 enum {
 	PROC_PIDONLY_OFF = 0,
diff --git a/include/uapi/linux/proc_fs.h b/include/uapi/linux/proc_fs.h
new file mode 100644
index 000000000000..1e3374efffe2
--- /dev/null
+++ b/include/uapi/linux/proc_fs.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_PROC_FS_H
+#define _UAPI_PROC_FS_H
+
+/* definitions for hide_pid field */
+enum {
+	HIDEPID_OFF           = 0,
+	HIDEPID_NO_ACCESS     = 1,
+	HIDEPID_INVISIBLE     = 2,
+	HIDEPID_NOT_PTRACABLE = 4,
+};
+
+#endif
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 10/11] docs: proc: add documentation for "hidepid=4" and "subset=pidfs" options and new mount behavior
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 Documentation/filesystems/proc.txt | 53 ++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 99ca040e3f90..4741fd092f36 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -50,6 +50,8 @@ Table of Contents
   4	Configuring procfs
   4.1	Mount options
 
+  5	Filesystem behavior
+
 ------------------------------------------------------------------------------
 Preface
 ------------------------------------------------------------------------------
@@ -2021,6 +2023,7 @@ The following mount options are supported:
 
 	hidepid=	Set /proc/<pid>/ access mode.
 	gid=		Set the group authorized to learn processes information.
+	subset=		Show only the specified subset of procfs.
 
 hidepid=0 means classic mode - everybody may access all /proc/<pid>/ directories
 (default).
@@ -2042,6 +2045,56 @@ information about running processes, whether some daemon runs with elevated
 privileges, whether other user runs some sensitive program, whether other users
 run any program at all, etc.
 
+hidepid=4 means that procfs should only contain /proc/<pid>/ directories
+that the caller can ptrace.
+
 gid= defines a group authorized to learn processes information otherwise
 prohibited by hidepid=.  If you use some daemon like identd which needs to learn
 information about processes information, just add identd to this group.
+
+subset=pidfs hides all top level files and directories in the procfs that
+are not related to tasks.
+
+------------------------------------------------------------------------------
+5 Filesystem behavior
+------------------------------------------------------------------------------
+
+Originally, before the advent of pid namepsace, procfs was a global file
+system. It means that there was only one procfs instance in the system.
+
+When pid namespace was added, a separate procfs instance was mounted in
+each pid namespace. So, procfs mount options are global among all
+mountpoints within the same namespace.
+
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=2 0 0
+
+# strace -e mount mount -o hidepid=1 -t proc proc /tmp/proc
+mount("proc", "/tmp/proc", "proc", 0, "hidepid=1") = 0
++++ exited with 0 +++
+
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=2 0 0
+proc /tmp/proc proc rw,relatime,hidepid=2 0 0
+
+and only after remounting procfs mount options will change at all
+mountpoints.
+
+# mount -o remount,hidepid=1 -t proc proc /tmp/proc
+
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=1 0 0
+proc /tmp/proc proc rw,relatime,hidepid=1 0 0
+
+This behavior is different from the behavior of other filesystems.
+
+The new procfs behavior is more like other filesystems. Each procfs mount
+creates a new procfs instance. Mount options affect own procfs instance.
+It means that it became possible to have several procfs instances
+displaying tasks with different filtering options in one pid namespace.
+
+# mount -o hidepid=2 -t proc proc /proc
+# mount -o hidepid=1 -t proc proc /tmp/proc
+# grep ^proc /proc/mounts
+proc /proc proc rw,relatime,hidepid=2 0 0
+proc /tmp/proc proc rw,relatime,hidepid=1 0 0
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 03/11] proc: move /proc/{self|thread-self} dentries to proc_fs_info
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

This is a preparation patch that moves /proc/{self|thread-self} dentries
to be stored inside procfs fs_info struct instead of making them per pid
namespace. Since we want to support multiple procfs instances we need to
make sure that these dentries are also per-superblock instead of
per-pidns, unmounting a private procfs won't clash with other procfs
mounts.

Cc: Kees Cook <keescook@chromium.org>
Cc: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Djalal Harouni <tixxdz@gmail.com>
Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc/base.c                | 5 +++--
 fs/proc/root.c                | 8 ++++----
 fs/proc/self.c                | 4 ++--
 fs/proc/thread_self.c         | 6 +++---
 include/linux/pid_namespace.h | 4 +---
 include/linux/proc_fs.h       | 2 ++
 6 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 672e71c52dbd..1eb366ad8b06 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -3316,6 +3316,7 @@ static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter ite
 int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 {
 	struct tgid_iter iter;
+	struct proc_fs_info *fs_info = proc_sb_info(file_inode(file)->i_sb);
 	struct pid_namespace *ns = proc_pid_ns(file_inode(file));
 	loff_t pos = ctx->pos;
 
@@ -3323,13 +3324,13 @@ int proc_pid_readdir(struct file *file, struct dir_context *ctx)
 		return 0;
 
 	if (pos == TGID_OFFSET - 2) {
-		struct inode *inode = d_inode(ns->proc_self);
+		struct inode *inode = d_inode(fs_info->proc_self);
 		if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
 			return 0;
 		ctx->pos = pos = pos + 1;
 	}
 	if (pos == TGID_OFFSET - 1) {
-		struct inode *inode = d_inode(ns->proc_thread_self);
+		struct inode *inode = d_inode(fs_info->proc_thread_self);
 		if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
 			return 0;
 		ctx->pos = pos = pos + 1;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index d449f095f0f7..637e26cc795e 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -210,10 +210,10 @@ static void proc_kill_sb(struct super_block *sb)
 {
 	struct proc_fs_info *fs_info = proc_sb_info(sb);
 
-	if (fs_info->pid_ns->proc_self)
-		dput(fs_info->pid_ns->proc_self);
-	if (fs_info->pid_ns->proc_thread_self)
-		dput(fs_info->pid_ns->proc_thread_self);
+	if (fs_info->proc_self)
+		dput(fs_info->proc_self);
+	if (fs_info->proc_thread_self)
+		dput(fs_info->proc_thread_self);
 	kill_anon_super(sb);
 	put_pid_ns(fs_info->pid_ns);
 	kfree(fs_info);
diff --git a/fs/proc/self.c b/fs/proc/self.c
index 57c0a1047250..846fc2b7c8a8 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -36,7 +36,7 @@ static unsigned self_inum __ro_after_init;
 int proc_setup_self(struct super_block *s)
 {
 	struct inode *root_inode = d_inode(s->s_root);
-	struct pid_namespace *ns = proc_pid_ns(root_inode);
+	struct proc_fs_info *fs_info = proc_sb_info(s);
 	struct dentry *self;
 	int ret = -ENOMEM;
 	
@@ -62,7 +62,7 @@ int proc_setup_self(struct super_block *s)
 	if (ret)
 		pr_err("proc_fill_super: can't allocate /proc/self\n");
 	else
-		ns->proc_self = self;
+		fs_info->proc_self = self;
 
 	return ret;
 }
diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
index f61ae53533f5..2493cbbdfa6f 100644
--- a/fs/proc/thread_self.c
+++ b/fs/proc/thread_self.c
@@ -36,7 +36,7 @@ static unsigned thread_self_inum __ro_after_init;
 int proc_setup_thread_self(struct super_block *s)
 {
 	struct inode *root_inode = d_inode(s->s_root);
-	struct pid_namespace *ns = proc_pid_ns(root_inode);
+	struct proc_fs_info *fs_info = proc_sb_info(s);
 	struct dentry *thread_self;
 	int ret = -ENOMEM;
 
@@ -60,9 +60,9 @@ int proc_setup_thread_self(struct super_block *s)
 	inode_unlock(root_inode);
 
 	if (ret)
-		pr_err("proc_fill_super: can't allocate /proc/thread_self\n");
+		pr_err("proc_fill_super: can't allocate /proc/thread-self\n");
 	else
-		ns->proc_thread_self = thread_self;
+		fs_info->proc_thread_self = thread_self;
 
 	return ret;
 }
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 49538b172483..f91a8bf6e09e 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -31,9 +31,7 @@ struct pid_namespace {
 	unsigned int level;
 	struct pid_namespace *parent;
 #ifdef CONFIG_PROC_FS
-	struct vfsmount *proc_mnt;
-	struct dentry *proc_self;
-	struct dentry *proc_thread_self;
+	struct vfsmount *proc_mnt; /* Internal proc mounted during each new pidns */
 #endif
 #ifdef CONFIG_BSD_PROCESS_ACCT
 	struct fs_pin *bacct;
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 2d79489e55aa..59162988998e 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -14,6 +14,8 @@ struct seq_operations;
 
 struct proc_fs_info {
 	struct pid_namespace *pid_ns;
+	struct dentry *proc_self;        /* For /proc/self */
+	struct dentry *proc_thread_self; /* For /proc/thread-self */
 };
 
 static inline struct proc_fs_info *proc_sb_info(struct super_block *sb)
-- 
2.24.1


^ permalink raw reply related

* [PATCH v8 01/11] proc: Rename struct proc_fs_info to proc_fs_opts
From: Alexey Gladkov @ 2020-02-10 15:05 UTC (permalink / raw)
  To: LKML, Kernel Hardening, Linux API, Linux FS Devel,
	Linux Security Module
  Cc: Akinobu Mita, Alexander Viro, Alexey Dobriyan, Alexey Gladkov,
	Andrew Morton, Andy Lutomirski, Daniel Micay, Djalal Harouni,
	Dmitry V . Levin, Eric W . Biederman, Greg Kroah-Hartman,
	Ingo Molnar, J . Bruce Fields, Jeff Layton, Jonathan Corbet,
	Kees Cook, Linus Torvalds, Oleg Nesterov, Solar Designer
In-Reply-To: <20200210150519.538333-1-gladkov.alexey@gmail.com>

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 fs/proc_namespace.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
index 273ee82d8aa9..9a8b624bc3db 100644
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -37,23 +37,23 @@ static __poll_t mounts_poll(struct file *file, poll_table *wait)
 	return res;
 }
 
-struct proc_fs_info {
+struct proc_fs_opts {
 	int flag;
 	const char *str;
 };
 
 static int show_sb_opts(struct seq_file *m, struct super_block *sb)
 {
-	static const struct proc_fs_info fs_info[] = {
+	static const struct proc_fs_opts fs_opts[] = {
 		{ SB_SYNCHRONOUS, ",sync" },
 		{ SB_DIRSYNC, ",dirsync" },
 		{ SB_MANDLOCK, ",mand" },
 		{ SB_LAZYTIME, ",lazytime" },
 		{ 0, NULL }
 	};
-	const struct proc_fs_info *fs_infop;
+	const struct proc_fs_opts *fs_infop;
 
-	for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
+	for (fs_infop = fs_opts; fs_infop->flag; fs_infop++) {
 		if (sb->s_flags & fs_infop->flag)
 			seq_puts(m, fs_infop->str);
 	}
@@ -63,7 +63,7 @@ static int show_sb_opts(struct seq_file *m, struct super_block *sb)
 
 static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
 {
-	static const struct proc_fs_info mnt_info[] = {
+	static const struct proc_fs_opts mnt_opts[] = {
 		{ MNT_NOSUID, ",nosuid" },
 		{ MNT_NODEV, ",nodev" },
 		{ MNT_NOEXEC, ",noexec" },
@@ -72,9 +72,9 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
 		{ MNT_RELATIME, ",relatime" },
 		{ 0, NULL }
 	};
-	const struct proc_fs_info *fs_infop;
+	const struct proc_fs_opts *fs_infop;
 
-	for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
+	for (fs_infop = mnt_opts; fs_infop->flag; fs_infop++) {
 		if (mnt->mnt_flags & fs_infop->flag)
 			seq_puts(m, fs_infop->str);
 	}
-- 
2.24.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox