Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openeuler
Kernel
提交
89dbf196
K
Kernel
项目概览
openeuler
/
Kernel
大约 1 年 前同步成功
通知
5
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
K
Kernel
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
89dbf196
编写于
6月 09, 2017
作者:
J
John Johansen
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
apparmor: move change_hat mediation to using labels
Signed-off-by:
N
John Johansen
<
john.johansen@canonical.com
>
上级
93c98a48
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
201 addition
and
102 deletion
+201
-102
security/apparmor/domain.c
security/apparmor/domain.c
+201
-102
未找到文件。
security/apparmor/domain.c
浏览文件 @
89dbf196
...
...
@@ -884,19 +884,153 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm)
* Functions for self directed profile change
*/
/**
* new_compound_name - create an hname with @n2 appended to @n1
* @n1: base of hname (NOT NULL)
* @n2: name to append (NOT NULL)
/* helper fn for change_hat
*
* Returns:
new name or NULL on error
* Returns:
label for hat transition OR ERR_PTR. Does NOT return NULL
*/
static
char
*
new_compound_name
(
const
char
*
n1
,
const
char
*
n2
)
static
struct
aa_label
*
build_change_hat
(
struct
aa_profile
*
profile
,
const
char
*
name
,
bool
sibling
)
{
char
*
name
=
kmalloc
(
strlen
(
n1
)
+
strlen
(
n2
)
+
3
,
GFP_KERNEL
);
if
(
name
)
sprintf
(
name
,
"%s//%s"
,
n1
,
n2
);
return
name
;
struct
aa_profile
*
root
,
*
hat
=
NULL
;
const
char
*
info
=
NULL
;
int
error
=
0
;
if
(
sibling
&&
PROFILE_IS_HAT
(
profile
))
{
root
=
aa_get_profile_rcu
(
&
profile
->
parent
);
}
else
if
(
!
sibling
&&
!
PROFILE_IS_HAT
(
profile
))
{
root
=
aa_get_profile
(
profile
);
}
else
{
info
=
"conflicting target types"
;
error
=
-
EPERM
;
goto
audit
;
}
hat
=
aa_find_child
(
root
,
name
);
if
(
!
hat
)
{
error
=
-
ENOENT
;
if
(
COMPLAIN_MODE
(
profile
))
{
hat
=
aa_new_null_profile
(
profile
,
true
,
name
,
GFP_KERNEL
);
if
(
!
hat
)
{
info
=
"failed null profile create"
;
error
=
-
ENOMEM
;
}
}
}
aa_put_profile
(
root
);
audit:
aa_audit_file
(
profile
,
&
nullperms
,
OP_CHANGE_HAT
,
AA_MAY_CHANGEHAT
,
name
,
hat
?
hat
->
base
.
hname
:
NULL
,
hat
?
&
hat
->
label
:
NULL
,
GLOBAL_ROOT_UID
,
NULL
,
error
);
if
(
!
hat
||
(
error
&&
error
!=
-
ENOENT
))
return
ERR_PTR
(
error
);
/* if hat && error - complain mode, already audited and we adjust for
* complain mode allow by returning hat->label
*/
return
&
hat
->
label
;
}
/* helper fn for changing into a hat
*
* Returns: label for hat transition or ERR_PTR. Does not return NULL
*/
static
struct
aa_label
*
change_hat
(
struct
aa_label
*
label
,
const
char
*
hats
[],
int
count
,
int
flags
)
{
struct
aa_profile
*
profile
,
*
root
,
*
hat
=
NULL
;
struct
aa_label
*
new
;
struct
label_it
it
;
bool
sibling
=
false
;
const
char
*
name
,
*
info
=
NULL
;
int
i
,
error
;
AA_BUG
(
!
label
);
AA_BUG
(
!
hats
);
AA_BUG
(
count
<
1
);
if
(
PROFILE_IS_HAT
(
labels_profile
(
label
)))
sibling
=
true
;
/*find first matching hat */
for
(
i
=
0
;
i
<
count
&&
!
hat
;
i
++
)
{
name
=
hats
[
i
];
label_for_each_in_ns
(
it
,
labels_ns
(
label
),
label
,
profile
)
{
if
(
sibling
&&
PROFILE_IS_HAT
(
profile
))
{
root
=
aa_get_profile_rcu
(
&
profile
->
parent
);
}
else
if
(
!
sibling
&&
!
PROFILE_IS_HAT
(
profile
))
{
root
=
aa_get_profile
(
profile
);
}
else
{
/* conflicting change type */
info
=
"conflicting targets types"
;
error
=
-
EPERM
;
goto
fail
;
}
hat
=
aa_find_child
(
root
,
name
);
aa_put_profile
(
root
);
if
(
!
hat
)
{
if
(
!
COMPLAIN_MODE
(
profile
))
goto
outer_continue
;
/* complain mode succeed as if hat */
}
else
if
(
!
PROFILE_IS_HAT
(
hat
))
{
info
=
"target not hat"
;
error
=
-
EPERM
;
aa_put_profile
(
hat
);
goto
fail
;
}
aa_put_profile
(
hat
);
}
/* found a hat for all profiles in ns */
goto
build
;
outer_continue:
;
}
/* no hats that match, find appropriate error
*
* In complain mode audit of the failure is based off of the first
* hat supplied. This is done due how userspace interacts with
* change_hat.
*/
name
=
NULL
;
label_for_each_in_ns
(
it
,
labels_ns
(
label
),
label
,
profile
)
{
if
(
!
list_empty
(
&
profile
->
base
.
profiles
))
{
info
=
"hat not found"
;
error
=
-
ENOENT
;
goto
fail
;
}
}
info
=
"no hats defined"
;
error
=
-
ECHILD
;
fail:
label_for_each_in_ns
(
it
,
labels_ns
(
label
),
label
,
profile
)
{
/*
* no target as it has failed to be found or built
*
* change_hat uses probing and should not log failures
* related to missing hats
*/
/* TODO: get rid of GLOBAL_ROOT_UID */
if
(
count
>
1
||
COMPLAIN_MODE
(
profile
))
{
aa_audit_file
(
profile
,
&
nullperms
,
OP_CHANGE_HAT
,
AA_MAY_CHANGEHAT
,
name
,
NULL
,
NULL
,
GLOBAL_ROOT_UID
,
info
,
error
);
}
}
return
ERR_PTR
(
error
);
build:
new
=
fn_label_build_in_ns
(
label
,
profile
,
GFP_KERNEL
,
build_change_hat
(
profile
,
name
,
sibling
),
aa_get_label
(
&
profile
->
label
));
if
(
!
new
)
{
info
=
"label build failed"
;
error
=
-
ENOMEM
;
goto
fail
;
}
/* else if (IS_ERR) build_change_hat has logged error so return new */
return
new
;
}
/**
...
...
@@ -906,23 +1040,24 @@ static char *new_compound_name(const char *n1, const char *n2)
* @token: magic value to validate the hat change
* @flags: flags affecting behavior of the change
*
* Returns %0 on success, error otherwise.
*
* Change to the first profile specified in @hats that exists, and store
* the @hat_magic in the current task context. If the count == 0 and the
* @token matches that stored in the current task context, return to the
* top level profile.
*
* Returns %0 on success, error otherwise.
* change_hat only applies to profiles in the current ns, and each profile
* in the ns must make the same transition otherwise change_hat will fail.
*/
int
aa_change_hat
(
const
char
*
hats
[],
int
count
,
u64
token
,
int
flags
)
{
const
struct
cred
*
cred
;
struct
aa_task_ctx
*
ctx
;
struct
aa_label
*
label
,
*
previous_label
;
struct
aa_profile
*
profile
,
*
hat
=
NULL
;
char
*
name
=
NULL
;
int
i
;
struct
aa_label
*
label
,
*
previous
,
*
new
=
NULL
,
*
target
=
NULL
;
struct
aa_profile
*
profile
;
struct
aa_perms
perms
=
{};
const
char
*
target
=
NULL
,
*
info
=
NULL
;
const
char
*
info
=
NULL
;
int
error
=
0
;
/*
...
...
@@ -930,118 +1065,82 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags)
* There is no exception for unconfined as change_hat is not
* available.
*/
if
(
task_no_new_privs
(
current
))
if
(
task_no_new_privs
(
current
))
{
/* not an apparmor denial per se, so don't log it */
AA_DEBUG
(
"no_new_privs - change_hat denied"
);
return
-
EPERM
;
}
/* released below */
cred
=
get_current_cred
();
ctx
=
cred_ctx
(
cred
);
label
=
aa_get_newest_cred_label
(
cred
);
previous_label
=
aa_get_newest_label
(
ctx
->
previous
);
profile
=
labels_profile
(
label
);
previous
=
aa_get_newest_label
(
ctx
->
previous
);
if
(
unconfined
(
label
))
{
info
=
"unconfined"
;
info
=
"unconfined
can not change_hat
"
;
error
=
-
EPERM
;
goto
audit
;
goto
fail
;
}
if
(
count
)
{
/* attempting to change into a new hat or switch to a sibling */
struct
aa_profile
*
root
;
if
(
PROFILE_IS_HAT
(
profile
))
root
=
aa_get_profile_rcu
(
&
profile
->
parent
);
else
root
=
aa_get_profile
(
profile
);
/* find first matching hat */
for
(
i
=
0
;
i
<
count
&&
!
hat
;
i
++
)
/* released below */
hat
=
aa_find_child
(
root
,
hats
[
i
]);
if
(
!
hat
)
{
if
(
!
COMPLAIN_MODE
(
root
)
||
(
flags
&
AA_CHANGE_TEST
))
{
if
(
list_empty
(
&
root
->
base
.
profiles
))
error
=
-
ECHILD
;
else
error
=
-
ENOENT
;
aa_put_profile
(
root
);
goto
out
;
}
/*
* In complain mode and failed to match any hats.
* Audit the failure is based off of the first hat
* supplied. This is done due how userspace
* interacts with change_hat.
*
* TODO: Add logging of all failed hats
*/
/* freed below */
name
=
new_compound_name
(
root
->
base
.
hname
,
hats
[
0
]);
aa_put_profile
(
root
);
target
=
name
;
/* released below */
hat
=
aa_new_null_profile
(
profile
,
true
,
hats
[
0
],
GFP_KERNEL
);
if
(
!
hat
)
{
info
=
"failed null profile create"
;
error
=
-
ENOMEM
;
goto
audit
;
}
}
else
{
aa_put_profile
(
root
);
target
=
hat
->
base
.
hname
;
if
(
!
PROFILE_IS_HAT
(
hat
))
{
info
=
"target not hat"
;
error
=
-
EPERM
;
goto
audit
;
}
new
=
change_hat
(
label
,
hats
,
count
,
flags
);
AA_BUG
(
!
new
);
if
(
IS_ERR
(
new
))
{
error
=
PTR_ERR
(
new
);
new
=
NULL
;
/* already audited */
goto
out
;
}
error
=
may_change_ptraced_domain
(
&
hat
->
label
,
&
info
);
if
(
error
)
{
info
=
"ptraced"
;
error
=
-
EPERM
;
goto
audit
;
}
error
=
may_change_ptraced_domain
(
new
,
&
info
);
if
(
error
)
goto
fail
;
if
(
!
(
flags
&
AA_CHANGE_TEST
))
{
error
=
aa_set_current_hat
(
&
hat
->
label
,
token
);
if
(
error
==
-
EACCES
)
/* kill task in case of brute force attacks */
perms
.
kill
=
AA_MAY_CHANGEHAT
;
else
if
(
name
&&
!
error
)
/* reset error for learning of new hats */
error
=
-
ENOENT
;
}
}
else
if
(
previous_label
)
{
/* Return to saved profile. Kill task if restore fails
if
(
flags
&
AA_CHANGE_TEST
)
goto
out
;
target
=
new
;
error
=
aa_set_current_hat
(
new
,
token
);
if
(
error
==
-
EACCES
)
/* kill task in case of brute force attacks */
goto
kill
;
}
else
if
(
previous
&&
!
(
flags
&
AA_CHANGE_TEST
))
{
/* Return to saved label. Kill task if restore fails
* to avoid brute force attacks
*/
target
=
previous
_label
->
hname
;
target
=
previous
;
error
=
aa_restore_previous_label
(
token
);
perms
.
kill
=
AA_MAY_CHANGEHAT
;
}
else
/* ignore restores when there is no saved profile */
goto
out
;
audit:
if
(
!
(
flags
&
AA_CHANGE_TEST
))
error
=
aa_audit_file
(
profile
,
&
perms
,
OP_CHANGE_HAT
,
AA_MAY_CHANGEHAT
,
NULL
,
target
,
NULL
,
GLOBAL_ROOT_UID
,
info
,
error
);
if
(
error
)
{
if
(
error
==
-
EACCES
)
goto
kill
;
goto
fail
;
}
}
/* else ignore @flags && restores when there is no saved profile */
out:
aa_put_
profile
(
hat
);
kfree
(
name
);
aa_put_
label
(
new
);
aa_put_label
(
previous
);
aa_put_label
(
label
);
aa_put_label
(
previous_label
);
put_cred
(
cred
);
return
error
;
kill:
info
=
"failed token match"
;
perms
.
kill
=
AA_MAY_CHANGEHAT
;
fail:
fn_for_each_in_ns
(
label
,
profile
,
aa_audit_file
(
profile
,
&
perms
,
OP_CHANGE_HAT
,
AA_MAY_CHANGEHAT
,
NULL
,
NULL
,
target
,
GLOBAL_ROOT_UID
,
info
,
error
));
goto
out
;
}
/**
* aa_change_profile - perform a one-way profile transition
* @fqname: name of profile may include namespace (NOT NULL)
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录