Re: [PATCH v2] Add flags option to get xattr method paired to __vfs_getxattr

2019-08-15 Thread Jan Kara
On Wed 14-08-19 07:54:16, Mark Salyzyn wrote:
> On 8/14/19 4:00 AM, Jan Kara wrote:
> > On Tue 13-08-19 07:55:06, Mark Salyzyn wrote:
> > ...
> > > diff --git a/fs/xattr.c b/fs/xattr.c
> > > index 90dd78f0eb27..71f887518d6f 100644
> > > --- a/fs/xattr.c
> > > +++ b/fs/xattr.c
> > ...
> > >   ssize_t
> > >   __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char 
> > > *name,
> > > -void *value, size_t size)
> > > +void *value, size_t size, int flags)
> > >   {
> > >   const struct xattr_handler *handler;
> > > -
> > > - handler = xattr_resolve_name(inode, );
> > > - if (IS_ERR(handler))
> > > - return PTR_ERR(handler);
> > > - if (!handler->get)
> > > - return -EOPNOTSUPP;
> > > - return handler->get(handler, dentry, inode, name, value, size);
> > > -}
> > > -EXPORT_SYMBOL(__vfs_getxattr);
> > > -
> > > -ssize_t
> > > -vfs_getxattr(struct dentry *dentry, const char *name, void *value, 
> > > size_t size)
> > > -{
> > > - struct inode *inode = dentry->d_inode;
> > >   int error;
> > > + if (flags & XATTR_NOSECURITY)
> > > + goto nolsm;
> > Hum, is it OK for XATTR_NOSECURITY to skip even the xattr_permission()
> > check? I understand that for reads of security xattrs it actually does not
> > matter in practice but conceptually that seems wrong to me as
> > XATTR_NOSECURITY is supposed to skip just security-module checks to avoid
> > recursion AFAIU.
> 
> Good catch I think.
> 
> I was attempting to make this change purely inert, no change in
> functionality, only a change in API. Adding a call to xattr_permission would
> incur a change in overall functionality, as it would introduce into the
> current and original __vfs_getxattr a call to xattr_permission that was not
> there before.
> 
> (I will have to defer the real answer and requirements to the security
> folks)
> 
> AFAIK you are correct, and to make the call would reduce the attack surface,
> trading a very small amount of CPU utilization, for a much larger amount of
> trust.
> 
> Given the long history of this patch set (for overlayfs) and the large
> amount of stakeholders, I would _prefer_ to submit a followup independent
> functionality/security change to _vfs_get_xattr _after_ this makes it in.

You're right. The problem was there before. So ack to changing this later.

> > > diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
> > > index c1395b5bd432..1216d777d210 100644
> > > --- a/include/uapi/linux/xattr.h
> > > +++ b/include/uapi/linux/xattr.h
> > > @@ -17,8 +17,9 @@
> > >   #if __UAPI_DEF_XATTR
> > >   #define __USE_KERNEL_XATTR_DEFS
> > > -#define XATTR_CREATE 0x1 /* set value, fail if attr already 
> > > exists */
> > > -#define XATTR_REPLACE0x2 /* set value, fail if attr does not 
> > > exist */
> > > +#define XATTR_CREATE  0x1/* set value, fail if attr already 
> > > exists */
> > > +#define XATTR_REPLACE 0x2/* set value, fail if attr does not 
> > > exist */
> > > +#define XATTR_NOSECURITY 0x4 /* get value, do not involve security 
> > > check */
> > >   #endif
> > It seems confusing to export XATTR_NOSECURITY definition to userspace when
> > that is kernel-internal flag. I'd just define it in include/linux/xattr.h
> > somewhere from the top of flags space (like 0x4000).
> > 
> > Otherwise the patch looks OK to me (cannot really comment on the security
> > module aspect of this whole thing though).
> 
> Good point. However, we do need to keep these flags together to reduce
> maintenance risk, I personally abhor two locations for flags bits even if
> one comes from the opposite bit-side; collisions are undetectable at build
> time. Although I have not gone through the entire thought experiment, I am
> expecting that fuse could possibly benefit from this flag (if exposed) since
> it also has a security recursion. That said, fuse is probably the example of
> a gaping wide attack surface if user space had access to it ... your
> xattr_permissions call addition requested above would be realistically, not
> just pedantically, required!

Yeah, flags bits in two places are bad as well. So maybe at least
#ifdef __KERNEL__ bit around the definitiona and a comment that it is
kernel internal flag?

Honza
-- 
Jan Kara 
SUSE Labs, CR


Re: [PATCH v2] Add flags option to get xattr method paired to __vfs_getxattr

2019-08-14 Thread kbuild test robot
Hi Mark,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[cannot apply to v5.3-rc4 next-20190813]
[if your patch is applied to the wrong git tree, please drop us a note to help 
improve the system]

url:
https://github.com/0day-ci/linux/commits/Mark-Salyzyn/Add-flags-option-to-get-xattr-method-paired-to-__vfs_getxattr/20190814-124805
config: nds32-allmodconfig (attached as .config)
compiler: nds32le-linux-gcc (GCC) 8.1.0
reproduce:
wget 
https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O 
~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
GCC_VERSION=8.1.0 make.cross ARCH=nds32 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot 

All errors (new ones prefixed by >>):

   fs/ubifs/xattr.c:326:9: error: conflicting types for 'ubifs_xattr_get'
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
^~~
   In file included from fs/ubifs/xattr.c:46:
   fs/ubifs/ubifs.h:2006:9: note: previous declaration of 'ubifs_xattr_get' was 
here
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
^~~
   fs/ubifs/xattr.c: In function 'xattr_get':
   fs/ubifs/xattr.c:678:9: error: too few arguments to function 
'ubifs_xattr_get'
 return ubifs_xattr_get(inode, name, buffer, size);
^~~
   fs/ubifs/xattr.c:326:9: note: declared here
ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
^~~
   fs/ubifs/xattr.c: At top level:
>> fs/ubifs/xattr.c:699:9: error: initialization of 'int (*)(const struct 
>> xattr_handler *, struct dentry *, struct inode *, const char *, void *, 
>> size_t,  int)' {aka 'int (*)(const struct xattr_handler *, struct dentry *, 
>> struct inode *, const char *, void *, unsigned int,  int)'} from 
>> incompatible pointer type 'int (*)(const struct xattr_handler *, struct 
>> dentry *, struct inode *, const char *, void *, size_t)' {aka 'int (*)(const 
>> struct xattr_handler *, struct dentry *, struct inode *, const char *, void 
>> *, unsigned int)'} [-Werror=incompatible-pointer-types]
 .get = xattr_get,
^
   fs/ubifs/xattr.c:699:9: note: (near initialization for 
'ubifs_user_xattr_handler.get')
   fs/ubifs/xattr.c:705:9: error: initialization of 'int (*)(const struct 
xattr_handler *, struct dentry *, struct inode *, const char *, void *, size_t, 
 int)' {aka 'int (*)(const struct xattr_handler *, struct dentry *, struct 
inode *, const char *, void *, unsigned int,  int)'} from incompatible pointer 
type 'int (*)(const struct xattr_handler *, struct dentry *, struct inode *, 
const char *, void *, size_t)' {aka 'int (*)(const struct xattr_handler *, 
struct dentry *, struct inode *, const char *, void *, unsigned int)'} 
[-Werror=incompatible-pointer-types]
 .get = xattr_get,
^
   fs/ubifs/xattr.c:705:9: note: (near initialization for 
'ubifs_trusted_xattr_handler.get')
   fs/ubifs/xattr.c:712:9: error: initialization of 'int (*)(const struct 
xattr_handler *, struct dentry *, struct inode *, const char *, void *, size_t, 
 int)' {aka 'int (*)(const struct xattr_handler *, struct dentry *, struct 
inode *, const char *, void *, unsigned int,  int)'} from incompatible pointer 
type 'int (*)(const struct xattr_handler *, struct dentry *, struct inode *, 
const char *, void *, size_t)' {aka 'int (*)(const struct xattr_handler *, 
struct dentry *, struct inode *, const char *, void *, unsigned int)'} 
[-Werror=incompatible-pointer-types]
 .get = xattr_get,
^
   fs/ubifs/xattr.c:712:9: note: (near initialization for 
'ubifs_security_xattr_handler.get')
   fs/ubifs/xattr.c: In function 'xattr_get':
   fs/ubifs/xattr.c:679:1: warning: control reaches end of non-void function 
[-Wreturn-type]
}
^
   cc1: some warnings being treated as errors

vim +699 fs/ubifs/xattr.c

2b88fc21cae91e Andreas Gruenbacher 2016-04-22  669  
ade46c3a6029de Richard Weinberger  2016-09-19  670  static int xattr_get(const 
struct xattr_handler *handler,
2b88fc21cae91e Andreas Gruenbacher 2016-04-22  671 
struct dentry *dentry, struct inode *inode,
2b88fc21cae91e Andreas Gruenbacher 2016-04-22  672 
const char *name, void *buffer, size_t size)
2b88fc21cae91e Andreas Gruenbacher 2016-04-22  673  {
2b88fc21cae91e Andreas Gruenbacher 2016-04-22  674  dbg_gen("xattr '%s', 
ino %lu ('%pd'), buf size %zd", name,
2b88fc21cae91e Andreas Gruenbacher 2016-04-22  675  inode->i_ino, 
dentry, size);
2b88fc21cae91e Andreas Gruenbacher 2016-04-22  676  
17ce1eb0b64eb2 Richard Weinberger  2016-07-31  677  name = 
xattr_full_name(handler, name);
ade46c3a6029de Richard Weinberger  2016-09-19 @678  return 
ubifs_xattr_get(inode, name, buffer, size);
2b88fc21cae91e 

Re: [PATCH v2] Add flags option to get xattr method paired to __vfs_getxattr

2019-08-14 Thread Jan Kara
On Tue 13-08-19 07:55:06, Mark Salyzyn wrote:
...
> diff --git a/fs/xattr.c b/fs/xattr.c
> index 90dd78f0eb27..71f887518d6f 100644
> --- a/fs/xattr.c
> +++ b/fs/xattr.c
...
>  ssize_t
>  __vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
> -void *value, size_t size)
> +void *value, size_t size, int flags)
>  {
>   const struct xattr_handler *handler;
> -
> - handler = xattr_resolve_name(inode, );
> - if (IS_ERR(handler))
> - return PTR_ERR(handler);
> - if (!handler->get)
> - return -EOPNOTSUPP;
> - return handler->get(handler, dentry, inode, name, value, size);
> -}
> -EXPORT_SYMBOL(__vfs_getxattr);
> -
> -ssize_t
> -vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t 
> size)
> -{
> - struct inode *inode = dentry->d_inode;
>   int error;
>  
> + if (flags & XATTR_NOSECURITY)
> + goto nolsm;

Hum, is it OK for XATTR_NOSECURITY to skip even the xattr_permission()
check? I understand that for reads of security xattrs it actually does not
matter in practice but conceptually that seems wrong to me as
XATTR_NOSECURITY is supposed to skip just security-module checks to avoid
recursion AFAIU.

> diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h
> index c1395b5bd432..1216d777d210 100644
> --- a/include/uapi/linux/xattr.h
> +++ b/include/uapi/linux/xattr.h
> @@ -17,8 +17,9 @@
>  #if __UAPI_DEF_XATTR
>  #define __USE_KERNEL_XATTR_DEFS
>  
> -#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
> -#define XATTR_REPLACE0x2 /* set value, fail if attr does not 
> exist */
> +#define XATTR_CREATE  0x1/* set value, fail if attr already exists */
> +#define XATTR_REPLACE 0x2/* set value, fail if attr does not 
> exist */
> +#define XATTR_NOSECURITY 0x4 /* get value, do not involve security check */
>  #endif

It seems confusing to export XATTR_NOSECURITY definition to userspace when
that is kernel-internal flag. I'd just define it in include/linux/xattr.h
somewhere from the top of flags space (like 0x4000).

Otherwise the patch looks OK to me (cannot really comment on the security
module aspect of this whole thing though).

Honza
-- 
Jan Kara 
SUSE Labs, CR


[PATCH v2] Add flags option to get xattr method paired to __vfs_getxattr

2019-08-13 Thread Mark Salyzyn via Linux-erofs
Add a flag option to get xattr method that could have a bit flag of
XATTR_NOSECURITY passed to it.  XATTR_NOSECURITY is generally then
set in the __vfs_getxattr path.

This handles the case of a union filesystem driver that is being
requested by the security layer to report back the xattr data from a
lower layer.

For the use case where access is to be blocked by the security layer.

The path then could be security(dentry) ->
__vfs_getxattr(dentry...XATTR_NOSECUIRTY) ->
handler->get(dentry...XATTR_NOSECURITY) ->
__vfs_getxattr(lower_dentry...XATTR_NOSECUIRTY) ->
lower_handler->get(lower_dentry...XATTR_NOSECUIRTY)
which would report back through the chain data and success as
expected, the logging security layer at the top would have the
data to determine the access permissions and report back the target
context that was blocked.

Without the get handler flag, the path on a union filesystem would be
the errant security(dentry) -> __vfs_getxattr(dentry) ->
handler->get(dentry) -> vfs_getxattr(lower_dentry) -> nested ->
security(lower_dentry, log off) -> lower_handler->get(lower_dentry)
which would report back through the chain no data, and -EACCES.

For selinux for both cases, this would translate to a correctly
determined blocked access. In the first case with this change a correct avc
log would be reported, in the second legacy case an incorrect avc log
would be reported against an uninitialized u:object_r:unlabeled:s0
context making the logs cosmetically useless for audit2allow.

This patch series is inert and is the wide-spread addition of the
flags option for xattr functions, and a replacement of _vfs_getxattr
with __vfs_getxattr(...XATTR_NOSECURITY).

Signed-off-by: Mark Salyzyn 
Cc: Stephen Smalley 
Cc: linux-ker...@vger.kernel.org
Cc: kernel-t...@android.com
Cc: linux-security-mod...@vger.kernel.org
Cc: sta...@vger.kernel.org # 4.4, 4.9, 4.14 & 4.19
---
v2:
Missed a spot: ubifs, erofs and afs.

v1:
Removed from an overlayfs patch set, and made independent.
Expect this to be the basis of some security improvements.
---
 drivers/staging/erofs/xattr.c |  3 ++-
 fs/9p/acl.c   |  3 ++-
 fs/9p/xattr.c |  3 ++-
 fs/afs/xattr.c|  8 +++
 fs/btrfs/xattr.c  |  3 ++-
 fs/ceph/xattr.c   |  3 ++-
 fs/cifs/xattr.c   |  2 +-
 fs/ecryptfs/inode.c   |  6 --
 fs/ecryptfs/mmap.c|  2 +-
 fs/ext2/xattr_trusted.c   |  2 +-
 fs/ext2/xattr_user.c  |  2 +-
 fs/ext4/xattr_security.c  |  2 +-
 fs/ext4/xattr_trusted.c   |  2 +-
 fs/ext4/xattr_user.c  |  2 +-
 fs/f2fs/xattr.c   |  4 ++--
 fs/fuse/xattr.c   |  4 ++--
 fs/gfs2/xattr.c   |  3 ++-
 fs/hfs/attr.c |  2 +-
 fs/hfsplus/xattr.c|  3 ++-
 fs/hfsplus/xattr_trusted.c|  3 ++-
 fs/hfsplus/xattr_user.c   |  3 ++-
 fs/jffs2/security.c   |  3 ++-
 fs/jffs2/xattr_trusted.c  |  3 ++-
 fs/jffs2/xattr_user.c |  3 ++-
 fs/jfs/xattr.c|  5 +++--
 fs/kernfs/inode.c |  3 ++-
 fs/nfs/nfs4proc.c |  6 --
 fs/ocfs2/xattr.c  |  9 +---
 fs/orangefs/xattr.c   |  3 ++-
 fs/overlayfs/super.c  |  8 ---
 fs/posix_acl.c|  2 +-
 fs/reiserfs/xattr_security.c  |  3 ++-
 fs/reiserfs/xattr_trusted.c   |  3 ++-
 fs/reiserfs/xattr_user.c  |  3 ++-
 fs/squashfs/xattr.c   |  2 +-
 fs/ubifs/xattr.c  |  2 +-
 fs/xattr.c| 36 +++
 fs/xfs/xfs_xattr.c|  3 ++-
 include/linux/xattr.h |  9 
 include/uapi/linux/xattr.h|  5 +++--
 mm/shmem.c|  3 ++-
 net/socket.c  |  3 ++-
 security/commoncap.c  |  6 --
 security/integrity/evm/evm_main.c |  3 ++-
 security/selinux/hooks.c  | 11 ++
 security/smack/smack_lsm.c|  5 +++--
 46 files changed, 123 insertions(+), 84 deletions(-)

diff --git a/drivers/staging/erofs/xattr.c b/drivers/staging/erofs/xattr.c
index df40654b9fbb..69440065432c 100644
--- a/drivers/staging/erofs/xattr.c
+++ b/drivers/staging/erofs/xattr.c
@@ -463,7 +463,8 @@ int erofs_getxattr(struct inode *inode, int index,
 
 static int erofs_xattr_generic_get(const struct xattr_handler *handler,
   struct dentry *unused, struct inode *inode,
-  const char *name, void *buffer, size_t size)
+  const char *name, void *buffer, size_t size,
+  int flags)
 {
struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
 
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 6261719f6f2a..cb14e8b312bc 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@