@@ -69,7 +69,7 @@ int ioprio_check_cap(int ioprio)
switch (class) {
case IOPRIO_CLASS_RT:
- if (!capable(CAP_SYS_NICE) && !capable(CAP_SYS_ADMIN))
+ if (!capable_or(CAP_SYS_NICE, CAP_SYS_ADMIN))
return -EPERM;
fallthrough;
/* rt has prio field too */
@@ -207,6 +207,8 @@ extern bool has_ns_capability(struct task_struct *t,
extern bool has_capability_noaudit(struct task_struct *t, int cap);
extern bool has_ns_capability_noaudit(struct task_struct *t,
struct user_namespace *ns, int cap);
+#define capable_or(...) _capable_or((sizeof((int[]){__VA_ARGS__}) / sizeof(int)), __VA_ARGS__)
+extern bool _capable_or(int count, ...);
extern bool capable(int cap);
extern bool ns_capable(struct user_namespace *ns, int cap);
extern bool ns_capable_noaudit(struct user_namespace *ns, int cap);
@@ -230,6 +232,10 @@ static inline bool has_ns_capability_noaudit(struct task_struct *t,
{
return true;
}
+static inline bool capable_or(int first_cap, ...)
+{
+ return true;
+}
static inline bool capable(int cap)
{
return true;
@@ -434,6 +434,52 @@ bool ns_capable_setid(struct user_namespace *ns, int cap)
}
EXPORT_SYMBOL(ns_capable_setid);
+/**
+ * _capable_or - Determine if the current task has one of multiple superior capabilities in effect
+ * @cap: The capabilities to be tested for
+ *
+ * Return true if the current task has at least one of the given superior capabilities currently
+ * available for use, false if not.
+ *
+ * In contrast to or'ing capable() this call will create exactly one audit message, either for the
+ * left most capability in effect or (if the task has none of the tested capabilities) the first
+ * capabilit in the test list.
+ *
+ * This sets PF_SUPERPRIV on the task if the capability is available on the
+ * assumption that it's about to be used.
+ */
+bool _capable_or(int count, ...)
+{
+ va_list args;
+ int cap, first_cap, i;
+
+ BUG_ON(count < 1);
+ BUG_ON(count > CAP_LAST_CAP);
+
+ va_start(args, count);
+
+ for (i = 0; i < count; i++) {
+ int ret;
+
+ cap = va_arg(args, int);
+ if (i == 0)
+ first_cap = cap;
+
+ rcu_read_lock();
+ ret = security_capable(current_cred(), &init_user_ns, cap, CAP_OPT_NOAUDIT);
+ rcu_read_unlock();
+
+ if (ret == 0)
+ goto out;
+ }
+
+ cap = first_cap;
+
+out:
+ va_end(args);
+ return ns_capable(&init_user_ns, cap);
+}
+
/**
* capable - Determine if the current task has a superior capability in effect
* @cap: The capability to be tested for