Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
e4236f97
Commit
e4236f97
authored
Oct 26, 2022
by
Christian Brauner
Committed by
Christian Brauner (Microsoft)
Oct 26, 2022
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'fs.vfsuid.conversion' into for-next
parents
03fd1402
eb7718cd
Changes
16
Show whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
150 additions
and
198 deletions
+150
-198
fs/coredump.c
fs/coredump.c
+2
-2
fs/exec.c
fs/exec.c
+8
-8
fs/fuse/acl.c
fs/fuse/acl.c
+1
-1
fs/inode.c
fs/inode.c
+4
-4
fs/namei.c
fs/namei.c
+20
-20
fs/overlayfs/util.c
fs/overlayfs/util.c
+7
-2
fs/remap_range.c
fs/remap_range.c
+1
-1
fs/stat.c
fs/stat.c
+5
-2
include/linux/fs.h
include/linux/fs.h
+0
-34
include/linux/mnt_idmapping.h
include/linux/mnt_idmapping.h
+32
-68
kernel/capability.c
kernel/capability.c
+2
-2
security/apparmor/domain.c
security/apparmor/domain.c
+4
-4
security/apparmor/file.c
security/apparmor/file.c
+3
-1
security/apparmor/lsm.c
security/apparmor/lsm.c
+17
-8
security/commoncap.c
security/commoncap.c
+26
-25
security/integrity/ima/ima_policy.c
security/integrity/ima/ima_policy.c
+18
-16
No files found.
fs/coredump.c
View file @
e4236f97
...
...
@@ -716,7 +716,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
* filesystem.
*/
mnt_userns
=
file_mnt_user_ns
(
cprm
.
file
);
if
(
!
uid_eq
(
i_uid_into_mnt
(
mnt_userns
,
inode
),
if
(
!
vfsuid_eq_kuid
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
),
current_fsuid
()))
{
pr_info_ratelimited
(
"Core dump to %s aborted: cannot preserve file owner
\n
"
,
cn
.
corename
);
...
...
fs/exec.c
View file @
e4236f97
...
...
@@ -1591,8 +1591,8 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
struct
user_namespace
*
mnt_userns
;
struct
inode
*
inode
=
file_inode
(
file
);
unsigned
int
mode
;
kuid_t
uid
;
kgid_t
gid
;
vfsuid_t
vfs
uid
;
vfsgid_t
vfs
gid
;
if
(
!
mnt_may_suid
(
file
->
f_path
.
mnt
))
return
;
...
...
@@ -1611,23 +1611,23 @@ static void bprm_fill_uid(struct linux_binprm *bprm, struct file *file)
/* reload atomically mode/uid/gid now that lock held */
mode
=
inode
->
i_mode
;
uid
=
i_uid_into_mnt
(
mnt_userns
,
inode
);
gid
=
i_gid_into_mnt
(
mnt_userns
,
inode
);
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
vfsgid
=
i_gid_into_vfsgid
(
mnt_userns
,
inode
);
inode_unlock
(
inode
);
/* We ignore suid/sgid if there are no mappings for them in the ns */
if
(
!
kuid_has_mapping
(
bprm
->
cred
->
user_ns
,
uid
)
||
!
kgid_has_mapping
(
bprm
->
cred
->
user_ns
,
gid
))
if
(
!
vfsuid_has_mapping
(
bprm
->
cred
->
user_ns
,
vfs
uid
)
||
!
vfsgid_has_mapping
(
bprm
->
cred
->
user_ns
,
vfs
gid
))
return
;
if
(
mode
&
S_ISUID
)
{
bprm
->
per_clear
|=
PER_CLEAR_ON_SETID
;
bprm
->
cred
->
euid
=
uid
;
bprm
->
cred
->
euid
=
vfsuid_into_kuid
(
vfsuid
)
;
}
if
((
mode
&
(
S_ISGID
|
S_IXGRP
))
==
(
S_ISGID
|
S_IXGRP
))
{
bprm
->
per_clear
|=
PER_CLEAR_ON_SETID
;
bprm
->
cred
->
egid
=
gid
;
bprm
->
cred
->
egid
=
vfsgid_into_kgid
(
vfsgid
)
;
}
}
...
...
fs/fuse/acl.c
View file @
e4236f97
...
...
@@ -99,7 +99,7 @@ int fuse_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
return
ret
;
}
if
(
!
in_group_p
(
i_gid_into_mnt
(
&
init_user_ns
,
inode
))
&&
if
(
!
vfsgid_in_group_p
(
i_gid_into_vfsgid
(
&
init_user_ns
,
inode
))
&&
!
capable_wrt_inode_uidgid
(
&
init_user_ns
,
inode
,
CAP_FSETID
))
extra_flags
|=
FUSE_SETXATTR_ACL_KILL_SGID
;
...
...
fs/inode.c
View file @
e4236f97
...
...
@@ -2326,15 +2326,15 @@ EXPORT_SYMBOL(inode_init_owner);
bool
inode_owner_or_capable
(
struct
user_namespace
*
mnt_userns
,
const
struct
inode
*
inode
)
{
kuid_t
i_
uid
;
vfsuid_t
vfs
uid
;
struct
user_namespace
*
ns
;
i_uid
=
i_uid_into_mnt
(
mnt_userns
,
inode
);
if
(
uid_eq
(
current_fsuid
(),
i_uid
))
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
if
(
vfsuid_eq_kuid
(
vfsuid
,
current_fsuid
()
))
return
true
;
ns
=
current_user_ns
();
if
(
kuid_has_mapping
(
ns
,
i_
uid
)
&&
ns_capable
(
ns
,
CAP_FOWNER
))
if
(
vfsuid_has_mapping
(
ns
,
vfs
uid
)
&&
ns_capable
(
ns
,
CAP_FOWNER
))
return
true
;
return
false
;
}
...
...
fs/namei.c
View file @
e4236f97
...
...
@@ -336,11 +336,11 @@ static int acl_permission_check(struct user_namespace *mnt_userns,
struct
inode
*
inode
,
int
mask
)
{
unsigned
int
mode
=
inode
->
i_mode
;
kuid_t
i_
uid
;
vfsuid_t
vfs
uid
;
/* Are we the owner? If so, ACL's don't matter */
i_uid
=
i_uid_into_mnt
(
mnt_userns
,
inode
);
if
(
likely
(
uid_eq
(
current_fsuid
(),
i_uid
)))
{
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
if
(
likely
(
vfsuid_eq_kuid
(
vfsuid
,
current_fsuid
()
)))
{
mask
&=
7
;
mode
>>=
6
;
return
(
mask
&
~
mode
)
?
-
EACCES
:
0
;
...
...
@@ -362,8 +362,8 @@ static int acl_permission_check(struct user_namespace *mnt_userns,
* about? Need to check group ownership if so.
*/
if
(
mask
&
(
mode
^
(
mode
>>
3
)))
{
kgid_t
kgid
=
i_gid_into_mnt
(
mnt_userns
,
inode
);
if
(
in_group_p
(
k
gid
))
vfsgid_t
vfsgid
=
i_gid_into_vfsgid
(
mnt_userns
,
inode
);
if
(
vfsgid_in_group_p
(
vfs
gid
))
mode
>>=
3
;
}
...
...
@@ -581,7 +581,7 @@ struct nameidata {
struct
nameidata
*
saved
;
unsigned
root_seq
;
int
dfd
;
kuid_t
dir_
uid
;
vfsuid_t
dir_vfs
uid
;
umode_t
dir_mode
;
}
__randomize_layout
;
...
...
@@ -1095,15 +1095,15 @@ fs_initcall(init_fs_namei_sysctls);
static
inline
int
may_follow_link
(
struct
nameidata
*
nd
,
const
struct
inode
*
inode
)
{
struct
user_namespace
*
mnt_userns
;
kuid_t
i_
uid
;
vfsuid_t
vfs
uid
;
if
(
!
sysctl_protected_symlinks
)
return
0
;
mnt_userns
=
mnt_user_ns
(
nd
->
path
.
mnt
);
i_uid
=
i_uid_into_mnt
(
mnt_userns
,
inode
);
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
/* Allowed if owner and follower match. */
if
(
uid_eq
(
current_cred
()
->
fsuid
,
i_uid
))
if
(
vfsuid_eq_kuid
(
vfsuid
,
current_fsuid
()
))
return
0
;
/* Allowed if parent directory not sticky and world-writable. */
...
...
@@ -1111,7 +1111,7 @@ static inline int may_follow_link(struct nameidata *nd, const struct inode *inod
return
0
;
/* Allowed if parent directory and link owner match. */
if
(
uid_valid
(
nd
->
dir_uid
)
&&
uid_eq
(
nd
->
dir_uid
,
i_
uid
))
if
(
vfsuid_valid
(
nd
->
dir_vfsuid
)
&&
vfsuid_eq
(
nd
->
dir_vfsuid
,
vfs
uid
))
return
0
;
if
(
nd
->
flags
&
LOOKUP_RCU
)
...
...
@@ -1183,8 +1183,8 @@ int may_linkat(struct user_namespace *mnt_userns, const struct path *link)
struct
inode
*
inode
=
link
->
dentry
->
d_inode
;
/* Inode writeback is not safe when the uid or gid are invalid. */
if
(
!
uid_valid
(
i_uid_into_mnt
(
mnt_userns
,
inode
))
||
!
gid_valid
(
i_gid_into_mnt
(
mnt_userns
,
inode
)))
if
(
!
vfsuid_valid
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
))
||
!
vfsgid_valid
(
i_gid_into_vfsgid
(
mnt_userns
,
inode
)))
return
-
EOVERFLOW
;
if
(
!
sysctl_protected_hardlinks
)
...
...
@@ -1232,13 +1232,13 @@ static int may_create_in_sticky(struct user_namespace *mnt_userns,
struct
nameidata
*
nd
,
struct
inode
*
const
inode
)
{
umode_t
dir_mode
=
nd
->
dir_mode
;
kuid_t
dir_uid
=
nd
->
dir_
uid
;
vfsuid_t
dir_vfsuid
=
nd
->
dir_vfs
uid
;
if
((
!
sysctl_protected_fifos
&&
S_ISFIFO
(
inode
->
i_mode
))
||
(
!
sysctl_protected_regular
&&
S_ISREG
(
inode
->
i_mode
))
||
likely
(
!
(
dir_mode
&
S_ISVTX
))
||
uid_eq
(
i_uid_into_mnt
(
mnt_userns
,
inode
),
dir_
uid
)
||
uid_eq
(
current_fsuid
(),
i_uid_into_mnt
(
mnt_userns
,
inode
)))
vfsuid_eq
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
),
dir_vfs
uid
)
||
vfsuid_eq_kuid
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
),
current_fsuid
(
)))
return
0
;
if
(
likely
(
dir_mode
&
0002
)
||
...
...
@@ -2307,7 +2307,7 @@ static int link_path_walk(const char *name, struct nameidata *nd)
OK:
/* pathname or trailing symlink, done */
if
(
!
depth
)
{
nd
->
dir_
uid
=
i_uid_into_mnt
(
mnt_userns
,
nd
->
inode
);
nd
->
dir_
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
nd
->
inode
);
nd
->
dir_mode
=
nd
->
inode
->
i_mode
;
nd
->
flags
&=
~
LOOKUP_PARENT
;
return
0
;
...
...
@@ -2885,9 +2885,9 @@ int __check_sticky(struct user_namespace *mnt_userns, struct inode *dir,
{
kuid_t
fsuid
=
current_fsuid
();
if
(
uid_eq
(
i_uid_into_mnt
(
mnt_userns
,
inode
),
fsuid
))
if
(
vfsuid_eq_kuid
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
),
fsuid
))
return
0
;
if
(
uid_eq
(
i_uid_into_mnt
(
mnt_userns
,
dir
),
fsuid
))
if
(
vfsuid_eq_kuid
(
i_uid_into_vfsuid
(
mnt_userns
,
dir
),
fsuid
))
return
0
;
return
!
capable_wrt_inode_uidgid
(
mnt_userns
,
inode
,
CAP_FOWNER
);
}
...
...
@@ -2926,8 +2926,8 @@ static int may_delete(struct user_namespace *mnt_userns, struct inode *dir,
BUG_ON
(
victim
->
d_parent
->
d_inode
!=
dir
);
/* Inode writeback is not safe when the uid or gid are invalid. */
if
(
!
uid_valid
(
i_uid_into_mnt
(
mnt_userns
,
inode
))
||
!
gid_valid
(
i_gid_into_mnt
(
mnt_userns
,
inode
)))
if
(
!
vfsuid_valid
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
))
||
!
vfsgid_valid
(
i_gid_into_vfsgid
(
mnt_userns
,
inode
)))
return
-
EOVERFLOW
;
audit_inode_child
(
dir
,
victim
,
AUDIT_TYPE_CHILD_DELETE
);
...
...
fs/overlayfs/util.c
View file @
e4236f97
...
...
@@ -1104,13 +1104,18 @@ void ovl_copyattr(struct inode *inode)
struct
path
realpath
;
struct
inode
*
realinode
;
struct
user_namespace
*
real_mnt_userns
;
vfsuid_t
vfsuid
;
vfsgid_t
vfsgid
;
ovl_i_path_real
(
inode
,
&
realpath
);
realinode
=
d_inode
(
realpath
.
dentry
);
real_mnt_userns
=
mnt_user_ns
(
realpath
.
mnt
);
inode
->
i_uid
=
i_uid_into_mnt
(
real_mnt_userns
,
realinode
);
inode
->
i_gid
=
i_gid_into_mnt
(
real_mnt_userns
,
realinode
);
vfsuid
=
i_uid_into_vfsuid
(
real_mnt_userns
,
realinode
);
vfsgid
=
i_gid_into_vfsgid
(
real_mnt_userns
,
realinode
);
inode
->
i_uid
=
vfsuid_into_kuid
(
vfsuid
);
inode
->
i_gid
=
vfsgid_into_kgid
(
vfsgid
);
inode
->
i_mode
=
realinode
->
i_mode
;
inode
->
i_atime
=
realinode
->
i_atime
;
inode
->
i_mtime
=
realinode
->
i_mtime
;
...
...
fs/remap_range.c
View file @
e4236f97
...
...
@@ -429,7 +429,7 @@ static bool allow_file_dedupe(struct file *file)
return
true
;
if
(
file
->
f_mode
&
FMODE_WRITE
)
return
true
;
if
(
uid_eq
(
current_fsuid
(),
i_uid_into_mnt
(
mnt_userns
,
inode
)))
if
(
vfsuid_eq_kuid
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
),
current_fsuid
(
)))
return
true
;
if
(
!
inode_permission
(
mnt_userns
,
inode
,
MAY_WRITE
))
return
true
;
...
...
fs/stat.c
View file @
e4236f97
...
...
@@ -44,12 +44,15 @@
void
generic_fillattr
(
struct
user_namespace
*
mnt_userns
,
struct
inode
*
inode
,
struct
kstat
*
stat
)
{
vfsuid_t
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
vfsgid_t
vfsgid
=
i_gid_into_vfsgid
(
mnt_userns
,
inode
);
stat
->
dev
=
inode
->
i_sb
->
s_dev
;
stat
->
ino
=
inode
->
i_ino
;
stat
->
mode
=
inode
->
i_mode
;
stat
->
nlink
=
inode
->
i_nlink
;
stat
->
uid
=
i_uid_into_mnt
(
mnt_userns
,
inode
);
stat
->
gid
=
i_gid_into_mnt
(
mnt_userns
,
inode
);
stat
->
uid
=
vfsuid_into_kuid
(
vfsuid
);
stat
->
gid
=
vfsgid_into_kgid
(
vfsgid
);
stat
->
rdev
=
inode
->
i_rdev
;
stat
->
size
=
i_size_read
(
inode
);
stat
->
atime
=
inode
->
i_atime
;
...
...
include/linux/fs.h
View file @
e4236f97
...
...
@@ -1612,23 +1612,6 @@ static inline void i_gid_write(struct inode *inode, gid_t gid)
inode
->
i_gid
=
make_kgid
(
i_user_ns
(
inode
),
gid
);
}
/**
* i_uid_into_mnt - map an inode's i_uid down into a mnt_userns
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: inode to map
*
* Note, this will eventually be removed completely in favor of the type-safe
* i_uid_into_vfsuid().
*
* Return: the inode's i_uid mapped down according to @mnt_userns.
* If the inode's i_uid has no mapping INVALID_UID is returned.
*/
static
inline
kuid_t
i_uid_into_mnt
(
struct
user_namespace
*
mnt_userns
,
const
struct
inode
*
inode
)
{
return
AS_KUIDT
(
make_vfsuid
(
mnt_userns
,
i_user_ns
(
inode
),
inode
->
i_uid
));
}
/**
* i_uid_into_vfsuid - map an inode's i_uid down into a mnt_userns
* @mnt_userns: user namespace of the mount the inode was found from
...
...
@@ -1681,23 +1664,6 @@ static inline void i_uid_update(struct user_namespace *mnt_userns,
attr
->
ia_vfsuid
);
}
/**
* i_gid_into_mnt - map an inode's i_gid down into a mnt_userns
* @mnt_userns: user namespace of the mount the inode was found from
* @inode: inode to map
*
* Note, this will eventually be removed completely in favor of the type-safe
* i_gid_into_vfsgid().
*
* Return: the inode's i_gid mapped down according to @mnt_userns.
* If the inode's i_gid has no mapping INVALID_GID is returned.
*/
static
inline
kgid_t
i_gid_into_mnt
(
struct
user_namespace
*
mnt_userns
,
const
struct
inode
*
inode
)
{
return
AS_KGIDT
(
make_vfsgid
(
mnt_userns
,
i_user_ns
(
inode
),
inode
->
i_gid
));
}
/**
* i_gid_into_vfsgid - map an inode's i_gid down into a mnt_userns
* @mnt_userns: user namespace of the mount the inode was found from
...
...
include/linux/mnt_idmapping.h
View file @
e4236f97
...
...
@@ -98,6 +98,26 @@ static inline bool vfsgid_eq_kgid(vfsgid_t vfsgid, kgid_t kgid)
return
vfsgid_valid
(
vfsgid
)
&&
__vfsgid_val
(
vfsgid
)
==
__kgid_val
(
kgid
);
}
static
inline
bool
vfsuid_gt_kuid
(
vfsuid_t
vfsuid
,
kuid_t
kuid
)
{
return
__vfsuid_val
(
vfsuid
)
>
__kuid_val
(
kuid
);
}
static
inline
bool
vfsgid_gt_kgid
(
vfsgid_t
vfsgid
,
kgid_t
kgid
)
{
return
__vfsgid_val
(
vfsgid
)
>
__kgid_val
(
kgid
);
}
static
inline
bool
vfsuid_lt_kuid
(
vfsuid_t
vfsuid
,
kuid_t
kuid
)
{
return
__vfsuid_val
(
vfsuid
)
<
__kuid_val
(
kuid
);
}
static
inline
bool
vfsgid_lt_kgid
(
vfsgid_t
vfsgid
,
kgid_t
kgid
)
{
return
__vfsgid_val
(
vfsgid
)
<
__kgid_val
(
kgid
);
}
/*
* vfs{g,u}ids are created from k{g,u}ids.
* We don't allow them to be created from regular {u,g}id.
...
...
@@ -208,13 +228,6 @@ static inline vfsuid_t make_vfsuid(struct user_namespace *mnt_userns,
return
VFSUIDT_INIT
(
make_kuid
(
mnt_userns
,
uid
));
}
static
inline
kuid_t
mapped_kuid_fs
(
struct
user_namespace
*
mnt_userns
,
struct
user_namespace
*
fs_userns
,
kuid_t
kuid
)
{
return
AS_KUIDT
(
make_vfsuid
(
mnt_userns
,
fs_userns
,
kuid
));
}
/**
* make_vfsgid - map a filesystem kgid into a mnt_userns
* @mnt_userns: the mount's idmapping
...
...
@@ -253,13 +266,6 @@ static inline vfsgid_t make_vfsgid(struct user_namespace *mnt_userns,
return
VFSGIDT_INIT
(
make_kgid
(
mnt_userns
,
gid
));
}
static
inline
kgid_t
mapped_kgid_fs
(
struct
user_namespace
*
mnt_userns
,
struct
user_namespace
*
fs_userns
,
kgid_t
kgid
)
{
return
AS_KGIDT
(
make_vfsgid
(
mnt_userns
,
fs_userns
,
kgid
));
}
/**
* from_vfsuid - map a vfsuid into the filesystem idmapping
* @mnt_userns: the mount's idmapping
...
...
@@ -287,33 +293,6 @@ static inline kuid_t from_vfsuid(struct user_namespace *mnt_userns,
return
make_kuid
(
fs_userns
,
uid
);
}
/**
* mapped_kuid_user - map a user kuid into a mnt_userns
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
* @kuid : kuid to be mapped
*
* Use the idmapping of @mnt_userns to remap a @kuid into @fs_userns. Use this
* function when preparing a @kuid to be written to disk or inode.
*
* If no_idmapping() determines that this is not an idmapped mount we can
* simply return @kuid unchanged.
* If initial_idmapping() tells us that the filesystem is not mounted with an
* idmapping we know the value of @kuid won't change when calling
* make_kuid() so we can simply retrieve the value via KUIDT_INIT()
* directly.
*
* Return: @kuid mapped according to @mnt_userns.
* If @kuid has no mapping in either @mnt_userns or @fs_userns INVALID_UID is
* returned.
*/
static
inline
kuid_t
mapped_kuid_user
(
struct
user_namespace
*
mnt_userns
,
struct
user_namespace
*
fs_userns
,
kuid_t
kuid
)
{
return
from_vfsuid
(
mnt_userns
,
fs_userns
,
VFSUIDT_INIT
(
kuid
));
}
/**
* vfsuid_has_fsmapping - check whether a vfsuid maps into the filesystem
* @mnt_userns: the mount's idmapping
...
...
@@ -333,6 +312,12 @@ static inline bool vfsuid_has_fsmapping(struct user_namespace *mnt_userns,
return
uid_valid
(
from_vfsuid
(
mnt_userns
,
fs_userns
,
vfsuid
));
}
static
inline
bool
vfsuid_has_mapping
(
struct
user_namespace
*
userns
,
vfsuid_t
vfsuid
)
{
return
from_kuid
(
userns
,
AS_KUIDT
(
vfsuid
))
!=
(
uid_t
)
-
1
;
}
/**
* vfsuid_into_kuid - convert vfsuid into kuid
* @vfsuid: the vfsuid to convert
...
...
@@ -373,33 +358,6 @@ static inline kgid_t from_vfsgid(struct user_namespace *mnt_userns,
return
make_kgid
(
fs_userns
,
gid
);
}
/**
* mapped_kgid_user - map a user kgid into a mnt_userns
* @mnt_userns: the mount's idmapping
* @fs_userns: the filesystem's idmapping
* @kgid : kgid to be mapped
*
* Use the idmapping of @mnt_userns to remap a @kgid into @fs_userns. Use this
* function when preparing a @kgid to be written to disk or inode.
*
* If no_idmapping() determines that this is not an idmapped mount we can
* simply return @kgid unchanged.
* If initial_idmapping() tells us that the filesystem is not mounted with an
* idmapping we know the value of @kgid won't change when calling
* make_kgid() so we can simply retrieve the value via KGIDT_INIT()
* directly.
*
* Return: @kgid mapped according to @mnt_userns.
* If @kgid has no mapping in either @mnt_userns or @fs_userns INVALID_GID is
* returned.
*/
static
inline
kgid_t
mapped_kgid_user
(
struct
user_namespace
*
mnt_userns
,
struct
user_namespace
*
fs_userns
,
kgid_t
kgid
)
{
return
from_vfsgid
(
mnt_userns
,
fs_userns
,
VFSGIDT_INIT
(
kgid
));
}
/**
* vfsgid_has_fsmapping - check whether a vfsgid maps into the filesystem
* @mnt_userns: the mount's idmapping
...
...
@@ -419,6 +377,12 @@ static inline bool vfsgid_has_fsmapping(struct user_namespace *mnt_userns,
return
gid_valid
(
from_vfsgid
(
mnt_userns
,
fs_userns
,
vfsgid
));
}
static
inline
bool
vfsgid_has_mapping
(
struct
user_namespace
*
userns
,
vfsgid_t
vfsgid
)
{
return
from_kgid
(
userns
,
AS_KGIDT
(
vfsgid
))
!=
(
gid_t
)
-
1
;
}
/**
* vfsgid_into_kgid - convert vfsgid into kgid
* @vfsgid: the vfsgid to convert
...
...
kernel/capability.c
View file @
e4236f97
...
...
@@ -489,8 +489,8 @@ bool privileged_wrt_inode_uidgid(struct user_namespace *ns,
struct
user_namespace
*
mnt_userns
,
const
struct
inode
*
inode
)
{
return
kuid_has_mapping
(
ns
,
i_uid_into_mnt
(
mnt_userns
,
inode
))
&&
kgid_has_mapping
(
ns
,
i_gid_into_mnt
(
mnt_userns
,
inode
));
return
vfsuid_has_mapping
(
ns
,
i_uid_into_vfsuid
(
mnt_userns
,
inode
))
&&
vfsgid_has_mapping
(
ns
,
i_gid_into_vfsgid
(
mnt_userns
,
inode
));
}
/**
...
...
security/apparmor/domain.c
View file @
e4236f97
...
...
@@ -859,10 +859,10 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
const
char
*
info
=
NULL
;
int
error
=
0
;
bool
unsafe
=
false
;
kuid_t
i_uid
=
i_uid_into_mnt
(
file_mnt_user_ns
(
bprm
->
file
),
vfsuid_t
vfsuid
=
i_uid_into_vfsuid
(
file_mnt_user_ns
(
bprm
->
file
),
file_inode
(
bprm
->
file
));
struct
path_cond
cond
=
{
i_uid
,
vfsuid_into_kuid
(
vfsuid
)
,
file_inode
(
bprm
->
file
)
->
i_mode
};
...
...
@@ -970,7 +970,7 @@ int apparmor_bprm_creds_for_exec(struct linux_binprm *bprm)
error
=
fn_for_each
(
label
,
profile
,
aa_audit_file
(
profile
,
&
nullperms
,
OP_EXEC
,
MAY_EXEC
,
bprm
->
filename
,
NULL
,
new
,
i_uid
,
info
,
error
));
vfsuid_into_kuid
(
vfsuid
)
,
info
,
error
));
aa_put_label
(
new
);
goto
done
;
}
...
...
security/apparmor/file.c
View file @
e4236f97
...
...
@@ -510,8 +510,10 @@ static int __file_path_perm(const char *op, struct aa_label *label,
{
struct
aa_profile
*
profile
;
struct
aa_perms
perms
=
{};
vfsuid_t
vfsuid
=
i_uid_into_vfsuid
(
file_mnt_user_ns
(
file
),
file_inode
(
file
));
struct
path_cond
cond
=
{
.
uid
=
i_uid_into_mnt
(
file_mnt_user_ns
(
file
),
file_inode
(
file
)
),
.
uid
=
vfsuid_into_kuid
(
vfsuid
),
.
mode
=
file_inode
(
file
)
->
i_mode
};
char
*
buffer
;
...
...
security/apparmor/lsm.c
View file @
e4236f97
...
...
@@ -225,8 +225,10 @@ static int common_perm(const char *op, const struct path *path, u32 mask,
static
int
common_perm_cond
(
const
char
*
op
,
const
struct
path
*
path
,
u32
mask
)
{
struct
user_namespace
*
mnt_userns
=
mnt_user_ns
(
path
->
mnt
);
vfsuid_t
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
d_backing_inode
(
path
->
dentry
));
struct
path_cond
cond
=
{
i_uid_into_mnt
(
mnt_userns
,
d_backing_inode
(
path
->
dentry
)
),
vfsuid_into_kuid
(
vfsuid
),
d_backing_inode
(
path
->
dentry
)
->
i_mode
};
...
...
@@ -270,11 +272,13 @@ static int common_perm_rm(const char *op, const struct path *dir,
struct
inode
*
inode
=
d_backing_inode
(
dentry
);
struct
user_namespace
*
mnt_userns
=
mnt_user_ns
(
dir
->
mnt
);
struct
path_cond
cond
=
{
};
vfsuid_t
vfsuid
;
if
(
!
inode
||
!
path_mediated_fs
(
dentry
))
return
0
;
cond
.
uid
=
i_uid_into_mnt
(
mnt_userns
,
inode
);
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
cond
.
uid
=
vfsuid_into_kuid
(
vfsuid
);
cond
.
mode
=
inode
->
i_mode
;
return
common_perm_dir_dentry
(
op
,
dir
,
dentry
,
mask
,
&
cond
);
...
...
@@ -368,20 +372,23 @@ static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_d
label
=
begin_current_label_crit_section
();
if
(
!
unconfined
(
label
))
{
struct
user_namespace
*
mnt_userns
=
mnt_user_ns
(
old_dir
->
mnt
);
vfsuid_t
vfsuid
;
struct
path
old_path
=
{
.
mnt
=
old_dir
->
mnt
,
.
dentry
=
old_dentry
};
struct
path
new_path
=
{
.
mnt
=
new_dir
->
mnt
,
.
dentry
=
new_dentry
};
struct
path_cond
cond
=
{
i_uid_into_mnt
(
mnt_userns
,
d_backing_inode
(
old_dentry
)),
d_backing_inode
(
old_dentry
)
->
i_mode
.
mode
=
d_backing_inode
(
old_dentry
)
->
i_mode
};
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
d_backing_inode
(
old_dentry
));
cond
.
uid
=
vfsuid_into_kuid
(
vfsuid
);
if
(
flags
&
RENAME_EXCHANGE
)
{
struct
path_cond
cond_exchange
=
{
i_uid_into_mnt
(
mnt_userns
,
d_backing_inode
(
new_dentry
)),
d_backing_inode
(
new_dentry
)
->
i_mode
.
mode
=
d_backing_inode
(
new_dentry
)
->
i_mode
,
};
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
d_backing_inode
(
old_dentry
));
cond_exchange
.
uid
=
vfsuid_into_kuid
(
vfsuid
);
error
=
aa_path_perm
(
OP_RENAME_SRC
,
label
,
&
new_path
,
0
,
MAY_READ
|
AA_MAY_GETATTR
|
MAY_WRITE
|
...
...
@@ -447,10 +454,12 @@ static int apparmor_file_open(struct file *file)
if
(
!
unconfined
(
label
))
{
struct
user_namespace
*
mnt_userns
=
file_mnt_user_ns
(
file
);
struct
inode
*
inode
=
file_inode
(
file
);
vfsuid_t
vfsuid
;
struct
path_cond
cond
=
{
i_uid_into_mnt
(
mnt_userns
,
inode
),
inode
->
i_mode
.
mode
=
inode
->
i_mode
,
};
vfsuid
=
i_uid_into_vfsuid
(
mnt_userns
,
inode
);
cond
.
uid
=
vfsuid_into_kuid
(
vfsuid
);
error
=
aa_path_perm
(
OP_OPEN
,
label
,
&
file
->
f_path
,
0
,
aa_map_file_to_perms
(
file
),
&
cond
);
...
...
security/commoncap.c
View file @
e4236f97
...
...
@@ -328,14 +328,16 @@ int cap_inode_killpriv(struct user_namespace *mnt_userns, struct dentry *dentry)
return
error
;
}
static
bool
rootid_owns_currentns
(
kuid_t
kroot
)
static
bool
rootid_owns_currentns
(
vfsuid_t
rootvfsuid
)
{
struct
user_namespace
*
ns
;
kuid_t
kroot
;
if
(
!
uid_valid
(
kroot
))
if
(
!
vfsuid_valid
(
rootvfsuid
))
return
false
;
for
(
ns
=
current_user_ns
();
;
ns
=
ns
->
parent
)
{
kroot
=
vfsuid_into_kuid
(
rootvfsuid
);
for
(
ns
=
current_user_ns
();;
ns
=
ns
->
parent
)
{
if
(
from_kuid
(
ns
,
kroot
)
==
0
)
return
true
;
if
(
ns
==
&
init_user_ns
)
...
...
@@ -381,6 +383,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
{
int
size
,
ret
;
kuid_t
kroot
;
vfsuid_t
vfsroot
;
u32
nsmagic
,
magic
;
uid_t
root
,
mappedroot
;
char
*
tmpbuf
=
NULL
;
...
...
@@ -419,11 +422,11 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
kroot
=
make_kuid
(
fs_ns
,
root
);
/* If this is an idmapped mount shift the kuid. */
kroot
=
mapped_kuid_fs
(
mnt_userns
,
fs_ns
,
kroot
);
vfsroot
=
make_vfsuid
(
mnt_userns
,
fs_ns
,
kroot
);
/* If the root kuid maps to a valid uid in current ns, then return
* this as a nscap. */
mappedroot
=
from_kuid
(
current_user_ns
(),
kroot
);
mappedroot
=
from_kuid
(
current_user_ns
(),
vfsuid_into_kuid
(
vfsroot
)
);
if
(
mappedroot
!=
(
uid_t
)
-
1
&&
mappedroot
!=
(
uid_t
)
0
)
{
size
=
sizeof
(
struct
vfs_ns_cap_data
);
if
(
alloc
)
{
...
...
@@ -450,7 +453,7 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
goto
out_free
;
}
if
(
!
rootid_owns_currentns
(
k
root
))
{
if
(
!
rootid_owns_currentns
(
vfs
root
))
{
size
=
-
EOVERFLOW
;
goto
out_free
;
}
...
...
@@ -488,29 +491,17 @@ int cap_inode_getsecurity(struct user_namespace *mnt_userns,
* @value: vfs caps value which may be modified by this function
* @size: size of @ivalue
* @task_ns: user namespace of the caller
* @mnt_userns: user namespace of the mount the inode was found from
* @fs_userns: user namespace of the filesystem
*
* If the inode has been found through an idmapped mount the user namespace of
* the vfsmount must be passed through @mnt_userns. This function will then
* take care to map the inode according to @mnt_userns before checking
* permissions. On non-idmapped mounts or if permission checking is to be
* performed on the raw inode simply passs init_user_ns.
*/
static
kuid_t
rootid_from_xattr
(
const
void
*
value
,
size_t
size
,
struct
user_namespace
*
task_ns
,
struct
user_namespace
*
mnt_userns
,
struct
user_namespace
*
fs_userns
)
static
vfsuid_t
rootid_from_xattr
(
const
void
*
value
,
size_t
size
,
struct
user_namespace
*
task_ns
)
{
const
struct
vfs_ns_cap_data
*
nscap
=
value
;
kuid_t
rootkid
;
uid_t
rootid
=
0
;
if
(
size
==
XATTR_CAPS_SZ_3
)
rootid
=
le32_to_cpu
(
nscap
->
rootid
);
rootkid
=
make_kuid
(
task_ns
,
rootid
);
return
mapped_kuid_user
(
mnt_userns
,
fs_userns
,
rootkid
);
return
VFSUIDT_INIT
(
make_kuid
(
task_ns
,
rootid
));
}
static
bool
validheader
(
size_t
size
,
const
struct
vfs_cap_data
*
cap
)
...
...
@@ -548,6 +539,7 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
struct
user_namespace
*
task_ns
=
current_user_ns
(),
*
fs_ns
=
inode
->
i_sb
->
s_user_ns
;
kuid_t
rootid
;
vfsuid_t
vfsrootid
;
size_t
newsize
;
if
(
!*
ivalue
)
...
...
@@ -561,7 +553,11 @@ int cap_convert_nscap(struct user_namespace *mnt_userns, struct dentry *dentry,
/* user is privileged, just write the v2 */
return
size
;
rootid
=
rootid_from_xattr
(
*
ivalue
,
size
,
task_ns
,
mnt_userns
,
fs_ns
);
vfsrootid
=
rootid_from_xattr
(
*
ivalue
,
size
,
task_ns
);
if
(
!
vfsuid_valid
(
vfsrootid
))
return
-
EINVAL
;
rootid
=
from_vfsuid
(
mnt_userns
,
fs_ns
,
vfsrootid
);
if
(
!
uid_valid
(
rootid
))
return
-
EINVAL
;
...
...
@@ -655,6 +651,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
struct
vfs_ns_cap_data
data
,
*
nscaps
=
&
data
;
struct
vfs_cap_data
*
caps
=
(
struct
vfs_cap_data
*
)
&
data
;
kuid_t
rootkuid
;
vfsuid_t
rootvfsuid
;
struct
user_namespace
*
fs_ns
;
memset
(
cpu_caps
,
0
,
sizeof
(
struct
cpu_vfs_cap_data
));
...
...
@@ -699,11 +696,15 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
default:
return
-
EINVAL
;
}
rootvfsuid
=
make_vfsuid
(
mnt_userns
,
fs_ns
,
rootkuid
);
if
(
!
vfsuid_valid
(
rootvfsuid
))
return
-
ENODATA
;
/* Limit the caps to the mounter of the filesystem
* or the more limited uid specified in the xattr.
*/
rootkuid
=
mapped_kuid_fs
(
mnt_userns
,
fs_ns
,
rootkuid
);
if
(
!
rootid_owns_currentns
(
rootkuid
))
if
(
!
rootid_owns_currentns
(
rootvfsuid
))
return
-
ENODATA
;
CAP_FOR_EACH_U32
(
i
)
{
...
...
@@ -716,7 +717,7 @@ int get_vfs_caps_from_disk(struct user_namespace *mnt_userns,
cpu_caps
->
permitted
.
cap
[
CAP_LAST_U32
]
&=
CAP_LAST_U32_VALID_MASK
;
cpu_caps
->
inheritable
.
cap
[
CAP_LAST_U32
]
&=
CAP_LAST_U32_VALID_MASK
;
cpu_caps
->
rootid
=
rootkuid
;
cpu_caps
->
rootid
=
vfsuid_into_kuid
(
rootvfsuid
)
;
return
0
;
}
...
...
security/integrity/ima/ima_policy.c
View file @
e4236f97
...
...
@@ -85,8 +85,8 @@ struct ima_rule_entry {
kgid_t
fgroup
;
bool
(
*
uid_op
)(
kuid_t
cred_uid
,
kuid_t
rule_uid
);
/* Handlers for operators */
bool
(
*
gid_op
)(
kgid_t
cred_gid
,
kgid_t
rule_gid
);
bool
(
*
fowner_op
)(
kuid_t
cred_uid
,
kuid_t
rule_uid
);
/* uid_eq(), uid_gt(), uid_lt
() */
bool
(
*
fgroup_op
)(
kgid_t
cred_gid
,
kgid_t
rule_gid
);
/* gid_eq(), gid_gt(), gid_lt
() */
bool
(
*
fowner_op
)(
vfsuid_t
vfsuid
,
kuid_t
rule_uid
);
/* vfsuid_eq_kuid(), vfsuid_gt_kuid(), vfsuid_lt_kuid
() */
bool
(
*
fgroup_op
)(
vfsgid_t
vfsgid
,
kgid_t
rule_gid
);
/* vfsgid_eq_kgid(), vfsgid_gt_kgid(), vfsgid_lt_kgid
() */
int
pcr
;
unsigned
int
allowed_algos
;
/* bitfield of allowed hash algorithms */
struct
{
...
...
@@ -186,11 +186,11 @@ static struct ima_rule_entry default_appraise_rules[] __ro_after_init = {
.
flags
=
IMA_FUNC
|
IMA_DIGSIG_REQUIRED
},
#endif
#ifndef CONFIG_IMA_APPRAISE_SIGNED_INIT
{.
action
=
APPRAISE
,
.
fowner
=
GLOBAL_ROOT_UID
,
.
fowner_op
=
&
uid_eq
,
{.
action
=
APPRAISE
,
.
fowner
=
GLOBAL_ROOT_UID
,
.
fowner_op
=
&
vfsuid_eq_kuid
,
.
flags
=
IMA_FOWNER
},
#else
/* force signature */
{.
action
=
APPRAISE
,
.
fowner
=
GLOBAL_ROOT_UID
,
.
fowner_op
=
&
uid_eq
,
{.
action
=
APPRAISE
,
.
fowner
=
GLOBAL_ROOT_UID
,
.
fowner_op
=
&
vfsuid_eq_kuid
,
.
flags
=
IMA_FOWNER
|
IMA_DIGSIG_REQUIRED
},
#endif
};
...
...
@@ -601,10 +601,12 @@ static bool ima_match_rules(struct ima_rule_entry *rule,
return
false
;
}
if
((
rule
->
flags
&
IMA_FOWNER
)
&&
!
rule
->
fowner_op
(
i_uid_into_mnt
(
mnt_userns
,
inode
),
rule
->
fowner
))
!
rule
->
fowner_op
(
i_uid_into_vfsuid
(
mnt_userns
,
inode
),
rule
->
fowner
))
return
false
;
if
((
rule
->
flags
&
IMA_FGROUP
)
&&
!
rule
->
fgroup_op
(
i_gid_into_mnt
(
mnt_userns
,
inode
),
rule
->
fgroup
))
!
rule
->
fgroup_op
(
i_gid_into_vfsgid
(
mnt_userns
,
inode
),
rule
->
fgroup
))
return
false
;
for
(
i
=
0
;
i
<
MAX_LSM_RULES
;
i
++
)
{
int
rc
=
0
;
...
...
@@ -1371,8 +1373,8 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
entry
->
fgroup
=
INVALID_GID
;
entry
->
uid_op
=
&
uid_eq
;
entry
->
gid_op
=
&
gid_eq
;
entry
->
fowner_op
=
&
uid_eq
;
entry
->
fgroup_op
=
&
gid_eq
;
entry
->
fowner_op
=
&
vfsuid_eq_kuid
;
entry
->
fgroup_op
=
&
vfsgid_eq_kgid
;
entry
->
action
=
UNKNOWN
;
while
((
p
=
strsep
(
&
rule
,
"
\t
"
))
!=
NULL
)
{
substring_t
args
[
MAX_OPT_ARGS
];
...
...
@@ -1650,11 +1652,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
break
;
case
Opt_fowner_gt
:
entry
->
fowner_op
=
&
uid_gt
;
entry
->
fowner_op
=
&
vfsuid_gt_kuid
;
fallthrough
;
case
Opt_fowner_lt
:
if
(
token
==
Opt_fowner_lt
)
entry
->
fowner_op
=
&
uid_lt
;
entry
->
fowner_op
=
&
vfsuid_lt_kuid
;
fallthrough
;
case
Opt_fowner_eq
:
ima_log_string_op
(
ab
,
"fowner"
,
args
[
0
].
from
,
token
);
...
...
@@ -1676,11 +1678,11 @@ static int ima_parse_rule(char *rule, struct ima_rule_entry *entry)
}
break
;
case
Opt_fgroup_gt
:
entry
->
fgroup_op
=
&
gid_gt
;
entry
->
fgroup_op
=
&
vfsgid_gt_kgid
;
fallthrough
;
case
Opt_fgroup_lt
:
if
(
token
==
Opt_fgroup_lt
)
entry
->
fgroup_op
=
&
gid_lt
;
entry
->
fgroup_op
=
&
vfsgid_lt_kgid
;
fallthrough
;
case
Opt_fgroup_eq
:
ima_log_string_op
(
ab
,
"fgroup"
,
args
[
0
].
from
,
token
);
...
...
@@ -2151,9 +2153,9 @@ int ima_policy_show(struct seq_file *m, void *v)
if
(
entry
->
flags
&
IMA_FOWNER
)
{
snprintf
(
tbuf
,
sizeof
(
tbuf
),
"%d"
,
__kuid_val
(
entry
->
fowner
));
if
(
entry
->
fowner_op
==
&
uid_gt
)
if
(
entry
->
fowner_op
==
&
vfsuid_gt_kuid
)
seq_printf
(
m
,
pt
(
Opt_fowner_gt
),
tbuf
);
else
if
(
entry
->
fowner_op
==
&
uid_lt
)
else
if
(
entry
->
fowner_op
==
&
vfsuid_lt_kuid
)
seq_printf
(
m
,
pt
(
Opt_fowner_lt
),
tbuf
);
else
seq_printf
(
m
,
pt
(
Opt_fowner_eq
),
tbuf
);
...
...
@@ -2162,9 +2164,9 @@ int ima_policy_show(struct seq_file *m, void *v)
if
(
entry
->
flags
&
IMA_FGROUP
)
{
snprintf
(
tbuf
,
sizeof
(
tbuf
),
"%d"
,
__kgid_val
(
entry
->
fgroup
));
if
(
entry
->
fgroup_op
==
&
gid_gt
)
if
(
entry
->
fgroup_op
==
&
vfsgid_gt_kgid
)
seq_printf
(
m
,
pt
(
Opt_fgroup_gt
),
tbuf
);
else
if
(
entry
->
fgroup_op
==
&
gid_lt
)
else
if
(
entry
->
fgroup_op
==
&
vfsgid_lt_kgid
)
seq_printf
(
m
,
pt
(
Opt_fgroup_lt
),
tbuf
);
else
seq_printf
(
m
,
pt
(
Opt_fgroup_eq
),
tbuf
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment