|
@@ -24,11 +24,8 @@
|
|
|
#include <linux/hugetlb.h>
|
|
|
#include <linux/mount.h>
|
|
|
#include <linux/sched.h>
|
|
|
-
|
|
|
-/* Global security state */
|
|
|
-
|
|
|
-unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
|
|
|
-EXPORT_SYMBOL(securebits);
|
|
|
+#include <linux/prctl.h>
|
|
|
+#include <linux/securebits.h>
|
|
|
|
|
|
int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
|
|
|
{
|
|
@@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
|
|
|
|
|
|
/* AUD: Audit candidate if current->cap_effective is set */
|
|
|
|
|
|
- current->keep_capabilities = 0;
|
|
|
+ current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
|
|
|
}
|
|
|
|
|
|
int cap_bprm_secureexec (struct linux_binprm *bprm)
|
|
@@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
|
|
|
{
|
|
|
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
|
|
|
(current->uid != 0 && current->euid != 0 && current->suid != 0) &&
|
|
|
- !current->keep_capabilities) {
|
|
|
+ !issecure(SECURE_KEEP_CAPS)) {
|
|
|
cap_clear (current->cap_permitted);
|
|
|
cap_clear (current->cap_effective);
|
|
|
}
|
|
@@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice)
|
|
|
* this task could get inconsistent info. There can be no
|
|
|
* racing writer bc a task can only change its own caps.
|
|
|
*/
|
|
|
-long cap_prctl_drop(unsigned long cap)
|
|
|
+static long cap_prctl_drop(unsigned long cap)
|
|
|
{
|
|
|
if (!capable(CAP_SETPCAP))
|
|
|
return -EPERM;
|
|
@@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap)
|
|
|
cap_lower(current->cap_bset, cap);
|
|
|
return 0;
|
|
|
}
|
|
|
+
|
|
|
#else
|
|
|
int cap_task_setscheduler (struct task_struct *p, int policy,
|
|
|
struct sched_param *lp)
|
|
@@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
|
|
|
+ unsigned long arg4, unsigned long arg5, long *rc_p)
|
|
|
+{
|
|
|
+ long error = 0;
|
|
|
+
|
|
|
+ switch (option) {
|
|
|
+ case PR_CAPBSET_READ:
|
|
|
+ if (!cap_valid(arg2))
|
|
|
+ error = -EINVAL;
|
|
|
+ else
|
|
|
+ error = !!cap_raised(current->cap_bset, arg2);
|
|
|
+ break;
|
|
|
+#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
|
|
|
+ case PR_CAPBSET_DROP:
|
|
|
+ error = cap_prctl_drop(arg2);
|
|
|
+ break;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The next four prctl's remain to assist with transitioning a
|
|
|
+ * system from legacy UID=0 based privilege (when filesystem
|
|
|
+ * capabilities are not in use) to a system using filesystem
|
|
|
+ * capabilities only - as the POSIX.1e draft intended.
|
|
|
+ *
|
|
|
+ * Note:
|
|
|
+ *
|
|
|
+ * PR_SET_SECUREBITS =
|
|
|
+ * issecure_mask(SECURE_KEEP_CAPS_LOCKED)
|
|
|
+ * | issecure_mask(SECURE_NOROOT)
|
|
|
+ * | issecure_mask(SECURE_NOROOT_LOCKED)
|
|
|
+ * | issecure_mask(SECURE_NO_SETUID_FIXUP)
|
|
|
+ * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)
|
|
|
+ *
|
|
|
+ * will ensure that the current process and all of its
|
|
|
+ * children will be locked into a pure
|
|
|
+ * capability-based-privilege environment.
|
|
|
+ */
|
|
|
+ case PR_SET_SECUREBITS:
|
|
|
+ if ((((current->securebits & SECURE_ALL_LOCKS) >> 1)
|
|
|
+ & (current->securebits ^ arg2)) /*[1]*/
|
|
|
+ || ((current->securebits & SECURE_ALL_LOCKS
|
|
|
+ & ~arg2)) /*[2]*/
|
|
|
+ || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|
|
|
+ || (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/
|
|
|
+ /*
|
|
|
+ * [1] no changing of bits that are locked
|
|
|
+ * [2] no unlocking of locks
|
|
|
+ * [3] no setting of unsupported bits
|
|
|
+ * [4] doing anything requires privilege (go read about
|
|
|
+ * the "sendmail capabilities bug")
|
|
|
+ */
|
|
|
+ error = -EPERM; /* cannot change a locked bit */
|
|
|
+ } else {
|
|
|
+ current->securebits = arg2;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case PR_GET_SECUREBITS:
|
|
|
+ error = current->securebits;
|
|
|
+ break;
|
|
|
+
|
|
|
+#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */
|
|
|
+
|
|
|
+ case PR_GET_KEEPCAPS:
|
|
|
+ if (issecure(SECURE_KEEP_CAPS))
|
|
|
+ error = 1;
|
|
|
+ break;
|
|
|
+ case PR_SET_KEEPCAPS:
|
|
|
+ if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
|
|
|
+ error = -EINVAL;
|
|
|
+ else if (issecure(SECURE_KEEP_CAPS_LOCKED))
|
|
|
+ error = -EPERM;
|
|
|
+ else if (arg2)
|
|
|
+ current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
|
|
|
+ else
|
|
|
+ current->securebits &=
|
|
|
+ ~issecure_mask(SECURE_KEEP_CAPS);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ /* No functionality available - continue with default */
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Functionality provided */
|
|
|
+ *rc_p = error;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
void cap_task_reparent_to_init (struct task_struct *p)
|
|
|
{
|
|
|
cap_set_init_eff(p->cap_effective);
|
|
|
cap_clear(p->cap_inheritable);
|
|
|
cap_set_full(p->cap_permitted);
|
|
|
- p->keep_capabilities = 0;
|
|
|
+ p->securebits = SECUREBITS_DEFAULT;
|
|
|
return;
|
|
|
}
|
|
|
|