* [PATCH 1/6] Keys: Sort out key quota system [try #3]
2006-06-20 17:37 [PATCH 0/6] Keys: Key management updates [try #3] David Howells
@ 2006-06-20 17:37 ` David Howells
2006-06-20 17:37 ` [PATCH 2/6] Keys: Discard the contents of a key on revocation " David Howells
` (5 subsequent siblings)
6 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2006-06-20 17:37 UTC (permalink / raw)
To: torvalds, akpm; +Cc: linux-kernel, keyrings
From: David Howells <dhowells@redhat.com>
The attached patch adds the ability for key creation to overrun the user's
quota in some circumstances - notably when a session keyring is created and
assigned to a process that didn't previously have one.
This means it's still possible to log in, should PAM require the creation of a
new session keyring, and fix an overburdened key quota.
Signed-Off-By: David Howells <dhowells@redhat.com>
---
include/linux/key.h | 13 ++++++++++---
include/linux/security.h | 11 +++++++----
security/dummy.c | 3 ++-
security/keys/internal.h | 3 ++-
security/keys/key.c | 26 ++++++++++++++------------
security/keys/keyctl.c | 5 +++--
security/keys/keyring.c | 4 ++--
security/keys/process_keys.c | 24 +++++++++++++++++-------
security/keys/request_key.c | 36 +++++++++++++++++++++---------------
security/keys/request_key_auth.c | 2 +-
security/selinux/hooks.c | 9 ++++++---
11 files changed, 85 insertions(+), 51 deletions(-)
diff --git a/include/linux/key.h b/include/linux/key.h
index e81ebf9..e693e72 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -248,7 +248,14 @@ extern struct key *key_alloc(struct key_
const char *desc,
uid_t uid, gid_t gid,
struct task_struct *ctx,
- key_perm_t perm, int not_in_quota);
+ key_perm_t perm,
+ unsigned long flags);
+
+
+#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
+#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
+#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
+
extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key,
const void *data,
@@ -285,7 +292,7 @@ extern key_ref_t key_create_or_update(ke
const char *description,
const void *payload,
size_t plen,
- int not_in_quota);
+ unsigned long flags);
extern int key_update(key_ref_t key,
const void *payload,
@@ -299,7 +306,7 @@ extern int key_unlink(struct key *keyrin
extern struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
struct task_struct *ctx,
- int not_in_quota,
+ unsigned long flags,
struct key *dest);
extern int keyring_clear(struct key *keyring);
diff --git a/include/linux/security.h b/include/linux/security.h
index 383c320..d4aa1bf 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -853,6 +853,7 @@ #ifdef CONFIG_SECURITY
* Permit allocation of a key and assign security data. Note that key does
* not have a serial number assigned at this point.
* @key points to the key.
+ * @flags is the allocation flags
* Return 0 if permission is granted, -ve error otherwise.
* @key_free:
* Notification of destruction; free security data.
@@ -1313,7 +1314,7 @@ #endif /* CONFIG_SECURITY_NETWORK_XFRM *
/* key management security hooks */
#ifdef CONFIG_KEYS
- int (*key_alloc)(struct key *key, struct task_struct *tsk);
+ int (*key_alloc)(struct key *key, struct task_struct *tsk, unsigned long flags);
void (*key_free)(struct key *key);
int (*key_permission)(key_ref_t key_ref,
struct task_struct *context,
@@ -3009,9 +3010,10 @@ #endif /* CONFIG_SECURITY_NETWORK_XFRM *
#ifdef CONFIG_KEYS
#ifdef CONFIG_SECURITY
static inline int security_key_alloc(struct key *key,
- struct task_struct *tsk)
+ struct task_struct *tsk,
+ unsigned long flags)
{
- return security_ops->key_alloc(key, tsk);
+ return security_ops->key_alloc(key, tsk, flags);
}
static inline void security_key_free(struct key *key)
@@ -3029,7 +3031,8 @@ static inline int security_key_permissio
#else
static inline int security_key_alloc(struct key *key,
- struct task_struct *tsk)
+ struct task_struct *tsk,
+ unsigned long flags)
{
return 0;
}
diff --git a/security/dummy.c b/security/dummy.c
index c98d553..93a9180 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -860,7 +860,8 @@ static int dummy_setprocattr(struct task
}
#ifdef CONFIG_KEYS
-static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx)
+static inline int dummy_key_alloc(struct key *key, struct task_struct *ctx,
+ unsigned long flags)
{
return 0;
}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index e066e60..3c2877f 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -99,7 +99,8 @@ extern int install_process_keyring(struc
extern struct key *request_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
- struct key *dest_keyring);
+ struct key *dest_keyring,
+ unsigned long flags);
/*
* request_key authorisation
diff --git a/security/keys/key.c b/security/keys/key.c
index 9ef9e5b..a9b6ca7 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -248,7 +248,7 @@ static inline void key_alloc_serial(stru
*/
struct key *key_alloc(struct key_type *type, const char *desc,
uid_t uid, gid_t gid, struct task_struct *ctx,
- key_perm_t perm, int not_in_quota)
+ key_perm_t perm, unsigned long flags)
{
struct key_user *user = NULL;
struct key *key;
@@ -269,12 +269,14 @@ struct key *key_alloc(struct key_type *t
/* check that the user's quota permits allocation of another key and
* its description */
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
- if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
- user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
- )
- goto no_quota;
+ if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
+ if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
+ user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
+ )
+ goto no_quota;
+ }
user->qnkeys++;
user->qnbytes += quotalen;
@@ -308,7 +310,7 @@ struct key *key_alloc(struct key_type *t
key->payload.data = NULL;
key->security = NULL;
- if (!not_in_quota)
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
memset(&key->type_data, 0, sizeof(key->type_data));
@@ -318,7 +320,7 @@ #ifdef KEY_DEBUGGING
#endif
/* let the security module know about the key */
- ret = security_key_alloc(key, ctx);
+ ret = security_key_alloc(key, ctx, flags);
if (ret < 0)
goto security_error;
@@ -332,7 +334,7 @@ error:
security_error:
kfree(key->description);
kmem_cache_free(key_jar, key);
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
user->qnkeys--;
user->qnbytes -= quotalen;
@@ -345,7 +347,7 @@ security_error:
no_memory_3:
kmem_cache_free(key_jar, key);
no_memory_2:
- if (!not_in_quota) {
+ if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
spin_lock(&user->lock);
user->qnkeys--;
user->qnbytes -= quotalen;
@@ -761,7 +763,7 @@ key_ref_t key_create_or_update(key_ref_t
const char *description,
const void *payload,
size_t plen,
- int not_in_quota)
+ unsigned long flags)
{
struct key_type *ktype;
struct key *keyring, *key = NULL;
@@ -822,7 +824,7 @@ key_ref_t key_create_or_update(key_ref_t
/* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
- current, perm, not_in_quota);
+ current, perm, flags);
if (IS_ERR(key)) {
key_ref = ERR_PTR(PTR_ERR(key));
goto error_3;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index ed71d86..d744585 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -102,7 +102,7 @@ asmlinkage long sys_add_key(const char _
/* create or update the requested key and add it to the target
* keyring */
key_ref = key_create_or_update(keyring_ref, type, description,
- payload, plen, 0);
+ payload, plen, KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
@@ -184,7 +184,8 @@ asmlinkage long sys_request_key(const ch
/* do the search */
key = request_key_and_link(ktype, description, callout_info,
- key_ref_to_ptr(dest_ref));
+ key_ref_to_ptr(dest_ref),
+ KEY_ALLOC_IN_QUOTA);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 1357207..6c282bd 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -240,7 +240,7 @@ static long keyring_read(const struct ke
* allocate a keyring and link into the destination keyring
*/
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
- struct task_struct *ctx, int not_in_quota,
+ struct task_struct *ctx, unsigned long flags,
struct key *dest)
{
struct key *keyring;
@@ -249,7 +249,7 @@ struct key *keyring_alloc(const char *de
keyring = key_alloc(&key_type_keyring, description,
uid, gid, ctx,
(KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
- not_in_quota);
+ flags);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index e4eddbb..f5fbc37 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -77,7 +77,8 @@ int alloc_uid_keyring(struct user_struct
/* concoct a default session keyring */
sprintf(buf, "_uid_ses.%u", user->uid);
- session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0, NULL);
+ session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+ KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error;
@@ -87,8 +88,8 @@ int alloc_uid_keyring(struct user_struct
* keyring */
sprintf(buf, "_uid.%u", user->uid);
- uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx, 0,
- session_keyring);
+ uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
+ KEY_ALLOC_IN_QUOTA, session_keyring);
if (IS_ERR(uid_keyring)) {
key_put(session_keyring);
ret = PTR_ERR(uid_keyring);
@@ -144,7 +145,8 @@ int install_thread_keyring(struct task_s
sprintf(buf, "_tid.%u", tsk->pid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -178,7 +180,8 @@ int install_process_keyring(struct task_
if (!tsk->signal->process_keyring) {
sprintf(buf, "_pid.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -209,6 +212,7 @@ error:
static int install_session_keyring(struct task_struct *tsk,
struct key *keyring)
{
+ unsigned long flags;
struct key *old;
char buf[20];
@@ -218,7 +222,12 @@ static int install_session_keyring(struc
if (!keyring) {
sprintf(buf, "_ses.%u", tsk->tgid);
- keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk, 1, NULL);
+ flags = KEY_ALLOC_QUOTA_OVERRUN;
+ if (tsk->signal->session_keyring)
+ flags = KEY_ALLOC_IN_QUOTA;
+
+ keyring = keyring_alloc(buf, tsk->uid, tsk->gid, tsk,
+ flags, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
}
@@ -729,7 +738,8 @@ long join_session_keyring(const char *na
keyring = find_keyring_by_name(name, 0);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
- keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk, 0, NULL);
+ keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
+ KEY_ALLOC_IN_QUOTA, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index eab66a0..58d1efd 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -48,8 +48,8 @@ static int call_sbin_request_key(struct
/* allocate a new session keyring */
sprintf(desc, "_req.%u", key->serial);
- keyring = keyring_alloc(desc, current->fsuid, current->fsgid,
- current, 1, NULL);
+ keyring = keyring_alloc(desc, current->fsuid, current->fsgid, current,
+ KEY_ALLOC_QUOTA_OVERRUN, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error_alloc;
@@ -126,7 +126,8 @@ error_alloc:
*/
static struct key *__request_key_construction(struct key_type *type,
const char *description,
- const char *callout_info)
+ const char *callout_info,
+ unsigned long flags)
{
request_key_actor_t actor;
struct key_construction cons;
@@ -134,12 +135,12 @@ static struct key *__request_key_constru
struct key *key, *authkey;
int ret, negated;
- kenter("%s,%s,%s", type->name, description, callout_info);
+ kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags);
/* create a key and add it to the queue */
key = key_alloc(type, description,
- current->fsuid, current->fsgid,
- current, KEY_POS_ALL, 0);
+ current->fsuid, current->fsgid, current, KEY_POS_ALL,
+ flags);
if (IS_ERR(key))
goto alloc_failed;
@@ -258,15 +259,16 @@ alloc_failed:
static struct key *request_key_construction(struct key_type *type,
const char *description,
struct key_user *user,
- const char *callout_info)
+ const char *callout_info,
+ unsigned long flags)
{
struct key_construction *pcons;
struct key *key, *ckey;
DECLARE_WAITQUEUE(myself, current);
- kenter("%s,%s,{%d},%s",
- type->name, description, user->uid, callout_info);
+ kenter("%s,%s,{%d},%s,%lx",
+ type->name, description, user->uid, callout_info, flags);
/* see if there's such a key under construction already */
down_write(&key_construction_sem);
@@ -282,7 +284,8 @@ static struct key *request_key_construct
}
/* see about getting userspace to construct the key */
- key = __request_key_construction(type, description, callout_info);
+ key = __request_key_construction(type, description, callout_info,
+ flags);
error:
kleave(" = %p", key);
return key;
@@ -389,14 +392,15 @@ static void request_key_link(struct key
struct key *request_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
- struct key *dest_keyring)
+ struct key *dest_keyring,
+ unsigned long flags)
{
struct key_user *user;
struct key *key;
key_ref_t key_ref;
- kenter("%s,%s,%s,%p",
- type->name, description, callout_info, dest_keyring);
+ kenter("%s,%s,%s,%p,%lx",
+ type->name, description, callout_info, dest_keyring, flags);
/* search all the process keyrings for a key */
key_ref = search_process_keyrings(type, description, type->match,
@@ -429,7 +433,8 @@ struct key *request_key_and_link(struct
/* ask userspace (returns NULL if it waited on a key
* being constructed) */
key = request_key_construction(type, description,
- user, callout_info);
+ user, callout_info,
+ flags);
if (key)
break;
@@ -485,7 +490,8 @@ struct key *request_key(struct key_type
const char *description,
const char *callout_info)
{
- return request_key_and_link(type, description, callout_info, NULL);
+ return request_key_and_link(type, description, callout_info, NULL,
+ KEY_ALLOC_IN_QUOTA);
} /* end request_key() */
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index cb9817c..cbf58a9 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -187,7 +187,7 @@ struct key *request_key_auth_new(struct
authkey = key_alloc(&key_type_request_key_auth, desc,
current->fsuid, current->fsgid, current,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
- KEY_USR_VIEW, 1);
+ KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey);
goto error_alloc;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 093efba..f80c74d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4254,7 +4254,8 @@ static int selinux_setprocattr(struct ta
#ifdef CONFIG_KEYS
-static int selinux_key_alloc(struct key *k, struct task_struct *tsk)
+static int selinux_key_alloc(struct key *k, struct task_struct *tsk,
+ unsigned long flags)
{
struct task_security_struct *tsec = tsk->security;
struct key_security_struct *ksec;
@@ -4501,8 +4502,10 @@ static __init int selinux_init(void)
#ifdef CONFIG_KEYS
/* Add security information to initial keyrings */
- security_key_alloc(&root_user_keyring, current);
- security_key_alloc(&root_session_keyring, current);
+ security_key_alloc(&root_user_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ security_key_alloc(&root_session_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
#endif
return 0;
^ permalink raw reply [flat|nested] 9+ messages in thread* [PATCH 6/6] Keys: Add a way to store the appropriate context for newly-created keys [try #3]
2006-06-20 17:37 [PATCH 0/6] Keys: Key management updates [try #3] David Howells
` (4 preceding siblings ...)
2006-06-20 17:37 ` [PATCH 5/6] Keys: Restrict contents of /proc/keys to Viewable keys " David Howells
@ 2006-06-20 17:37 ` David Howells
2006-06-20 20:44 ` [Keyrings] [PATCH 0/6] Keys: Key management updates " James Morris
6 siblings, 0 replies; 9+ messages in thread
From: David Howells @ 2006-06-20 17:37 UTC (permalink / raw)
To: torvalds, akpm; +Cc: linux-kernel, keyrings
From: Michael LeMay <mdlemay@epoch.ncsc.mil>
Add a /proc/<pid>/attr/keycreate entry that stores the appropriate
context for newly-created keys. Modify the selinux_key_alloc
hook to make use of the new entry. Update the flask headers to
include a new "setkeycreate" permission for processes. Update the
flask headers to include a new "create" permission for keys. Use
the create permission to restrict which SIDs each task can assign
to newly-created keys. Add a new parameter to the security hook
"security_key_alloc" to indicate whether it is being invoked by
the kernel, or from userspace. If it is being invoked by the
kernel, the security hook should never fail. Update the
documentation to reflect these changes.
Signed-off-by: Michael LeMay <mdlemay@epoch.ncsc.mil>
Signed-off-by: James Morris <jmorris@namei.org>
Signed-Off-By: David Howells <dhowells@redhat.com>
---
Documentation/keys.txt | 27 ++++++++++++--------
fs/proc/base.c | 6 ++++
security/selinux/hooks.c | 35 ++++++++++++++++++++++----
security/selinux/include/av_perm_to_string.h | 2 +
security/selinux/include/av_permissions.h | 2 +
security/selinux/include/objsec.h | 1 +
6 files changed, 56 insertions(+), 17 deletions(-)
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index 70e83cf..61c0fad 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -241,25 +241,30 @@ The security class "key" has been added
controls can be applied to keys created within various contexts. This support
is preliminary, and is likely to change quite significantly in the near future.
Currently, all of the basic permissions explained above are provided in SELinux
-as well; SE Linux is simply invoked after all basic permission checks have been
+as well; SELinux is simply invoked after all basic permission checks have been
performed.
-Each key is labeled with the same context as the task to which it belongs.
-Typically, this is the same task that was running when the key was created.
-The default keyrings are handled differently, but in a way that is very
-intuitive:
+The value of the file /proc/self/attr/keycreate influences the labeling of
+newly-created keys. If the contents of that file correspond to an SELinux
+security context, then the key will be assigned that context. Otherwise, the
+key will be assigned the current context of the task that invoked the key
+creation request. Tasks must be granted explicit permission to assign a
+particular context to newly-created keys, using the "create" permission in the
+key security class.
- (*) The user and user session keyrings that are created when the user logs in
- are currently labeled with the context of the login manager.
-
- (*) The keyrings associated with new threads are each labeled with the context
- of their associated thread, and both session and process keyrings are
- handled similarly.
+The default keyrings associated with users will be labeled with the default
+context of the user if and only if the login programs have been instrumented to
+properly initialize keycreate during the login process. Otherwise, they will
+be labeled with the context of the login program itself.
Note, however, that the default keyrings associated with the root user are
labeled with the default kernel context, since they are created early in the
boot process, before root has a chance to log in.
+The keyrings associated with new threads are each labeled with the context of
+their associated thread, and both session and process keyrings are handled
+similarly.
+
================
NEW PROCFS FILES
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 6cc77dc..5334e07 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -121,6 +121,7 @@ #ifdef CONFIG_SECURITY
PROC_TGID_ATTR_PREV,
PROC_TGID_ATTR_EXEC,
PROC_TGID_ATTR_FSCREATE,
+ PROC_TGID_ATTR_KEYCREATE,
#endif
#ifdef CONFIG_AUDITSYSCALL
PROC_TGID_LOGINUID,
@@ -162,6 +163,7 @@ #ifdef CONFIG_SECURITY
PROC_TID_ATTR_PREV,
PROC_TID_ATTR_EXEC,
PROC_TID_ATTR_FSCREATE,
+ PROC_TID_ATTR_KEYCREATE,
#endif
#ifdef CONFIG_AUDITSYSCALL
PROC_TID_LOGINUID,
@@ -275,6 +277,7 @@ static struct pid_entry tgid_attr_stuff[
E(PROC_TGID_ATTR_PREV, "prev", S_IFREG|S_IRUGO),
E(PROC_TGID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO),
E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
+ E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
{0,0,NULL,0}
};
static struct pid_entry tid_attr_stuff[] = {
@@ -282,6 +285,7 @@ static struct pid_entry tid_attr_stuff[]
E(PROC_TID_ATTR_PREV, "prev", S_IFREG|S_IRUGO),
E(PROC_TID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO),
E(PROC_TID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
+ E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
{0,0,NULL,0}
};
#endif
@@ -1800,6 +1804,8 @@ #ifdef CONFIG_SECURITY
case PROC_TGID_ATTR_EXEC:
case PROC_TID_ATTR_FSCREATE:
case PROC_TGID_ATTR_FSCREATE:
+ case PROC_TID_ATTR_KEYCREATE:
+ case PROC_TGID_ATTR_KEYCREATE:
inode->i_fop = &proc_pid_attr_operations;
break;
#endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f80c74d..8c1e1d5 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -1099,6 +1099,17 @@ static int may_create(struct inode *dir,
FILESYSTEM__ASSOCIATE, &ad);
}
+/* Check whether a task can create a key. */
+static int may_create_key(u32 ksid,
+ struct task_struct *ctx)
+{
+ struct task_security_struct *tsec;
+
+ tsec = ctx->security;
+
+ return avc_has_perm(tsec->sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL);
+}
+
#define MAY_LINK 0
#define MAY_UNLINK 1
#define MAY_RMDIR 2
@@ -4140,6 +4151,8 @@ static int selinux_getprocattr(struct ta
sid = tsec->exec_sid;
else if (!strcmp(name, "fscreate"))
sid = tsec->create_sid;
+ else if (!strcmp(name, "keycreate"))
+ sid = tsec->keycreate_sid;
else
return -EINVAL;
@@ -4172,6 +4185,8 @@ static int selinux_setprocattr(struct ta
error = task_has_perm(current, p, PROCESS__SETEXEC);
else if (!strcmp(name, "fscreate"))
error = task_has_perm(current, p, PROCESS__SETFSCREATE);
+ else if (!strcmp(name, "keycreate"))
+ error = task_has_perm(current, p, PROCESS__SETKEYCREATE);
else if (!strcmp(name, "current"))
error = task_has_perm(current, p, PROCESS__SETCURRENT);
else
@@ -4201,7 +4216,12 @@ static int selinux_setprocattr(struct ta
tsec->exec_sid = sid;
else if (!strcmp(name, "fscreate"))
tsec->create_sid = sid;
- else if (!strcmp(name, "current")) {
+ else if (!strcmp(name, "keycreate")) {
+ error = may_create_key(sid, p);
+ if (error)
+ return error;
+ tsec->keycreate_sid = sid;
+ } else if (!strcmp(name, "current")) {
struct av_decision avd;
if (sid == 0)
@@ -4265,7 +4285,10 @@ static int selinux_key_alloc(struct key
return -ENOMEM;
ksec->obj = k;
- ksec->sid = tsec->sid;
+ if (tsec->keycreate_sid)
+ ksec->sid = tsec->keycreate_sid;
+ else
+ ksec->sid = tsec->sid;
k->security = ksec;
return 0;
@@ -4502,10 +4525,10 @@ static __init int selinux_init(void)
#ifdef CONFIG_KEYS
/* Add security information to initial keyrings */
- security_key_alloc(&root_user_keyring, current,
- KEY_ALLOC_NOT_IN_QUOTA);
- security_key_alloc(&root_session_keyring, current,
- KEY_ALLOC_NOT_IN_QUOTA);
+ selinux_key_alloc(&root_user_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
+ selinux_key_alloc(&root_session_keyring, current,
+ KEY_ALLOC_NOT_IN_QUOTA);
#endif
return 0;
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index bc020bd..e777578 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -72,6 +72,7 @@
S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
+ S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
S_(SECCLASS_MSG, MSG__SEND, "send")
S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
@@ -248,3 +249,4 @@
S_(SECCLASS_KEY, KEY__SEARCH, "search")
S_(SECCLASS_KEY, KEY__LINK, "link")
S_(SECCLASS_KEY, KEY__SETATTR, "setattr")
+ S_(SECCLASS_KEY, KEY__CREATE, "create")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index b108dda..ba5ef05 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -467,6 +467,7 @@ #define PROCESS__SETCURRENT
#define PROCESS__EXECMEM 0x02000000UL
#define PROCESS__EXECSTACK 0x04000000UL
#define PROCESS__EXECHEAP 0x08000000UL
+#define PROCESS__SETKEYCREATE 0x10000000UL
#define IPC__CREATE 0x00000001UL
#define IPC__DESTROY 0x00000002UL
@@ -965,3 +966,4 @@ #define KEY__WRITE
#define KEY__SEARCH 0x00000008UL
#define KEY__LINK 0x00000010UL
#define KEY__SETATTR 0x00000020UL
+#define KEY__CREATE 0x00000040UL
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 8f5547a..191b3e4 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -32,6 +32,7 @@ struct task_security_struct {
u32 sid; /* current SID */
u32 exec_sid; /* exec SID */
u32 create_sid; /* fscreate SID */
+ u32 keycreate_sid; /* keycreate SID */
u32 ptrace_sid; /* SID of ptrace parent */
};
^ permalink raw reply [flat|nested] 9+ messages in thread