Jan Engelhardt
2006-05-01T13:49:12Z

[PATCH 1/4] security_cap_extra() and more

- Renames capable() to capable_light().
This function is used if only a capability is to be checked.

- Implement a new capable that calls security_cap_extra().
Since a subadmin has almost the same capabilities as a
superadmin, an extra helper is needed to decide whether an
action is allowed, based on the philosophy of the LSM.

- implement the .cap_extra LSM hook

Signed-off-by: Jan Engelhardt <jengelh@gmx.de>

diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/include/linux/capability.h linux-2.6.17-rc3+/include/linux/capability.h
--- linux-2.6.17-rc3~/include/linux/capability.h 2006-04-27 04:19:25.000000000 +0200
+++ linux-2.6.17-rc3+/include/linux/capability.h 2006-04-30 23:25:25.233048000 +0200
@@ -357,6 +357,8 @@ static inline kernel_cap_t cap_invert(ke

#define cap_is_fs_cap(c) (CAP_TO_MASK(c) & CAP_FS_MASK)

+int capable_light(int);
+int __capable_light(struct task_struct *, int);
int capable(int cap);
int __capable(struct task_struct *t, int cap);

diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/include/linux/security.h linux-2.6.17-rc3+/include/linux/security.h
--- linux-2.6.17-rc3~/include/linux/security.h 2006-04-27 04:19:25.000000000 +0200
+++ linux-2.6.17-rc3+/include/linux/security.h 2006-04-30 23:25:35.893048000 +0200
@@ -1319,6 +1319,7 @@ struct security_operations {

#endif /* CONFIG_KEYS */

+ int (*cap_extra)(int);
};

/* global variables */
@@ -2018,6 +2019,11 @@ static inline int security_netlink_recv(
return security_ops->netlink_recv(skb);
}

+static inline int security_cap_extra(int cap)
+{
+ return security_ops->cap_extra(cap);
+}
+
/* prototypes */
extern int security_init (void);
extern int register_security (struct security_operations *ops);
@@ -2651,6 +2657,12 @@ static inline int security_netlink_recv
return cap_netlink_recv (skb);
}

+static inline int security_cap_extra(int cap);
+{
+ /* Capability test already passed. No more checks. => Allow. */
+ return 1;
+}
+
static inline struct dentry *securityfs_create_dir(const char *name,
struct dentry *parent)
{
diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/kernel/capability.c linux-2.6.17-rc3+/kernel/capability.c
--- linux-2.6.17-rc3~/kernel/capability.c 2006-04-27 04:19:25.000000000 +0200
+++ linux-2.6.17-rc3+/kernel/capability.c 2006-04-30 23:30:06.143048000 +0200
@@ -238,7 +238,7 @@ int __capable(struct task_struct *t, int
{
if (security_capable(t, cap) == 0) {
t->flags |= PF_SUPERPRIV;
- return 1;
+ return security_cap_extra(cap);
}
return 0;
}
@@ -249,3 +249,20 @@ int capable(int cap)
return __capable(current, cap);
}
EXPORT_SYMBOL(capable);
+
+int __capable_light(struct task_struct *t, int cap)
+{
+ if (security_capable(t, cap) == 0) {
+ t->flags |= PF_SUPERPRIV;
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(__capable_light);
+
+int capable_light(int cap)
+{
+ return __capable_light(current, cap);
+}
+EXPORT_SYMBOL(capable_light);
+
diff --fast -Ndpru -X dontdiff linux-2.6.17-rc3~/security/dummy.c linux-2.6.17-rc3+/security/dummy.c
--- linux-2.6.17-rc3~/security/dummy.c 2006-04-27 04:19:25.000000000 +0200
+++ linux-2.6.17-rc3+/security/dummy.c 2006-04-30 23:30:24.763048000 +0200
@@ -677,6 +677,11 @@ static int dummy_netlink_recv (struct sk
return 0;
}

+static int dummy_cap_extra(int cap)
+{
+ return 1; /* allow */
+}
+
#ifdef CONFIG_SECURITY_NETWORK
static int dummy_unix_stream_connect (struct socket *sock,
struct socket *other,
@@ -1040,5 +1045,6 @@ void security_fixup_ops (struct security
set_to_dummy_if_null(ops, key_permission);
#endif /* CONFIG_KEYS */

+ set_to_dummy_if_null(ops, cap_extra);
}

#<<eof>>

Jan Engelhardt
--