static inline void bprm_clear_caps(struct linux_binprm *bprm)
{
- cap_clear(bprm->cap_inheritable);
- cap_clear(bprm->cap_permitted);
+ cap_clear(bprm->cap_post_exec_permitted);
bprm->cap_effective = false;
}
{
__u32 magic_etc;
unsigned tocopy, i;
+ int ret;
if (size < sizeof(magic_etc))
return -EINVAL;
bprm->cap_effective = false;
}
- for (i = 0; i < tocopy; ++i) {
- bprm->cap_permitted.cap[i] =
- le32_to_cpu(caps->data[i].permitted);
- bprm->cap_inheritable.cap[i] =
- le32_to_cpu(caps->data[i].inheritable);
- }
- while (i < VFS_CAP_U32) {
- bprm->cap_permitted.cap[i] = 0;
- bprm->cap_inheritable.cap[i] = 0;
- i++;
+ ret = 0;
+
+ CAP_FOR_EACH_U32(i) {
+ __u32 value_cpu;
+
+ if (i >= tocopy) {
+ /*
+ * Legacy capability sets have no upper bits
+ */
+ bprm->cap_post_exec_permitted.cap[i] = 0;
+ continue;
+ }
+ /*
+ * pP' = (X & fP) | (pI & fI)
+ */
+ value_cpu = le32_to_cpu(caps->data[i].permitted);
+ bprm->cap_post_exec_permitted.cap[i] =
+ (current->cap_bset.cap[i] & value_cpu) |
+ (current->cap_inheritable.cap[i] &
+ le32_to_cpu(caps->data[i].inheritable));
+ if (value_cpu & ~bprm->cap_post_exec_permitted.cap[i]) {
+ /*
+ * insufficient to execute correctly
+ */
+ ret = -EPERM;
+ }
}
- return 0;
+ /*
+ * For legacy apps, with no internal support for recognizing they
+ * do not have enough capabilities, we return an error if they are
+ * missing some "forced" (aka file-permitted) capabilities.
+ */
+ return bprm->cap_effective ? ret : 0;
}
/* Locate any VFS capabilities: */
goto out;
rc = cap_from_disk(&vcaps, bprm, rc);
- if (rc)
+ if (rc == -EINVAL)
printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n",
- __func__, rc, bprm->filename);
+ __func__, rc, bprm->filename);
out:
dput(dentry);
int ret;
ret = get_file_caps(bprm);
- if (ret)
- printk(KERN_NOTICE "%s: get_file_caps returned %d for %s\n",
- __func__, ret, bprm->filename);
-
- /* To support inheritance of root-permissions and suid-root
- * executables under compatibility mode, we raise all three
- * capability sets for the file.
- *
- * If only the real uid is 0, we only raise the inheritable
- * and permitted sets of the executable file.
- */
- if (!issecure (SECURE_NOROOT)) {
+ if (!issecure(SECURE_NOROOT)) {
+ /*
+ * To support inheritance of root-permissions and suid-root
+ * executables under compatibility mode, we override the
+ * capability sets for the file.
+ *
+ * If only the real uid is 0, we do not set the effective
+ * bit.
+ */
if (bprm->e_uid == 0 || current->uid == 0) {
- cap_set_full (bprm->cap_inheritable);
- cap_set_full (bprm->cap_permitted);
+ /* pP' = (cap_bset & ~0) | (pI & ~0) */
+ bprm->cap_post_exec_permitted = cap_combine(
+ current->cap_bset, current->cap_inheritable
+ );
+ bprm->cap_effective = (bprm->e_uid == 0);
+ ret = 0;
}
- if (bprm->e_uid == 0)
- bprm->cap_effective = true;
}
return ret;
void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
{
- /* Derived from fs/exec.c:compute_creds. */
- kernel_cap_t new_permitted, working;
-
- new_permitted = cap_intersect(bprm->cap_permitted,
- current->cap_bset);
- working = cap_intersect(bprm->cap_inheritable,
- current->cap_inheritable);
- new_permitted = cap_combine(new_permitted, working);
-
if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
- !cap_issubset (new_permitted, current->cap_permitted)) {
+ !cap_issubset(bprm->cap_post_exec_permitted,
+ current->cap_permitted)) {
set_dumpable(current->mm, suid_dumpable);
current->pdeath_signal = 0;
bprm->e_gid = current->gid;
}
if (cap_limit_ptraced_target()) {
- new_permitted =
- cap_intersect(new_permitted,
- current->cap_permitted);
+ bprm->cap_post_exec_permitted = cap_intersect(
+ bprm->cap_post_exec_permitted,
+ current->cap_permitted);
}
}
}
* in the init_task struct. Thus we skip the usual
* capability rules */
if (!is_global_init(current)) {
- current->cap_permitted = new_permitted;
+ current->cap_permitted = bprm->cap_post_exec_permitted;
if (bprm->cap_effective)
- current->cap_effective = new_permitted;
+ current->cap_effective = bprm->cap_post_exec_permitted;
else
cap_clear(current->cap_effective);
}
if (current->uid != 0) {
if (bprm->cap_effective)
return 1;
- if (!cap_isclear(bprm->cap_permitted))
- return 1;
- if (!cap_isclear(bprm->cap_inheritable))
+ if (!cap_isclear(bprm->cap_post_exec_permitted))
return 1;
}