capabilities: do not grant full privs for setuid w/ file caps + no effective caps
A task (when !SECURE_NOROOT) which executes a setuid-root binary will obtain root privileges while executing that binary. If the binary also has effective capabilities set, then only those capabilities will be granted. The rationale is that the same binary can carry both setuid-root and the minimal file capability set, so that on a filesystem not supporting file caps the binary can still be executed with privilege, while on a filesystem supporting file caps it will run with minimal privilege. This special case currently does NOT happen if there are file capabilities but no effective capabilities. Since capability-aware programs can very well start with empty pE but populated pP and move those caps to pE when needed. In other words, if the file has file capabilities but NOT effective capabilities, then we should do the same thing as if there were file capabilities, and not grant full root privileges. This patchset does that. (Changelog by Serge Hallyn). Signed-off-by: Zhi Li <lizhi1215@gmail.com> Acked-by: Serge Hallyn <serge.hallyn@canonical.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
Родитель
f995e74087
Коммит
4d49f6710b
|
@ -332,7 +332,8 @@ int cap_inode_killpriv(struct dentry *dentry)
|
||||||
*/
|
*/
|
||||||
static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
||||||
struct linux_binprm *bprm,
|
struct linux_binprm *bprm,
|
||||||
bool *effective)
|
bool *effective,
|
||||||
|
bool *has_cap)
|
||||||
{
|
{
|
||||||
struct cred *new = bprm->cred;
|
struct cred *new = bprm->cred;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -341,6 +342,9 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps,
|
||||||
if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
|
if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE)
|
||||||
*effective = true;
|
*effective = true;
|
||||||
|
|
||||||
|
if (caps->magic_etc & VFS_CAP_REVISION_MASK)
|
||||||
|
*has_cap = true;
|
||||||
|
|
||||||
CAP_FOR_EACH_U32(i) {
|
CAP_FOR_EACH_U32(i) {
|
||||||
__u32 permitted = caps->permitted.cap[i];
|
__u32 permitted = caps->permitted.cap[i];
|
||||||
__u32 inheritable = caps->inheritable.cap[i];
|
__u32 inheritable = caps->inheritable.cap[i];
|
||||||
|
@ -424,7 +428,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
|
||||||
* its xattrs and, if present, apply them to the proposed credentials being
|
* its xattrs and, if present, apply them to the proposed credentials being
|
||||||
* constructed by execve().
|
* constructed by execve().
|
||||||
*/
|
*/
|
||||||
static int get_file_caps(struct linux_binprm *bprm, bool *effective)
|
static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
@ -450,7 +454,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective);
|
rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap);
|
||||||
if (rc == -EINVAL)
|
if (rc == -EINVAL)
|
||||||
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
|
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
|
||||||
__func__, rc, bprm->filename);
|
__func__, rc, bprm->filename);
|
||||||
|
@ -475,11 +479,11 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
{
|
{
|
||||||
const struct cred *old = current_cred();
|
const struct cred *old = current_cred();
|
||||||
struct cred *new = bprm->cred;
|
struct cred *new = bprm->cred;
|
||||||
bool effective;
|
bool effective, has_cap;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
effective = false;
|
effective = false;
|
||||||
ret = get_file_caps(bprm, &effective);
|
ret = get_file_caps(bprm, &effective, &has_cap);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -489,7 +493,7 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
|
||||||
* for a setuid root binary run by a non-root user. Do set it
|
* for a setuid root binary run by a non-root user. Do set it
|
||||||
* for a root user just to cause least surprise to an admin.
|
* for a root user just to cause least surprise to an admin.
|
||||||
*/
|
*/
|
||||||
if (effective && new->uid != 0 && new->euid == 0) {
|
if (has_cap && new->uid != 0 && new->euid == 0) {
|
||||||
warn_setuid_and_fcaps_mixed(bprm->filename);
|
warn_setuid_and_fcaps_mixed(bprm->filename);
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче