Commit f9274840 authored by Stephen D. Smalley's avatar Stephen D. Smalley Committed by Linus Torvalds

[PATCH] Base set of LSM hooks for SysV IPC

The patch below adds the base set of LSM hooks for System V IPC to the
2.5.41 kernel.  These hooks permit a security module to label
semaphore sets, message queues, and shared memory segments and to
perform security checks on these objects that parallel the existing
IPC access checks.  Additional LSM hooks for labeling and controlling
individual messages sent on a single message queue and for providing
fine-grained distinctions among IPC operations will be submitted
separately after this base set of LSM IPC hooks has been accepted.
parent c4f59ba5
...@@ -63,6 +63,7 @@ struct kern_ipc_perm ...@@ -63,6 +63,7 @@ struct kern_ipc_perm
gid_t cgid; gid_t cgid;
mode_t mode; mode_t mode;
unsigned long seq; unsigned long seq;
void *security;
}; };
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -572,6 +572,50 @@ struct swap_info_struct; ...@@ -572,6 +572,50 @@ struct swap_info_struct;
* is being reparented to the init task. * is being reparented to the init task.
* @p contains the task_struct for the kernel thread. * @p contains the task_struct for the kernel thread.
* *
* Security hooks affecting all System V IPC operations.
*
* @ipc_permission:
* Check permissions for access to IPC
* @ipcp contains the kernel IPC permission structure
* @flag contains the desired (requested) permission set
* Return 0 if permission is granted.
*
* Security hooks for System V IPC Message Queues
*
* @msg_queue_alloc_security:
* Allocate and attach a security structure to the
* msq->q_perm.security field. The security field is initialized to
* NULL when the structure is first created.
* @msq contains the message queue structure to be modified.
* Return 0 if operation was successful and permission is granted.
* @msg_queue_free_security:
* Deallocate security structure for this message queue.
* @msq contains the message queue structure to be modified.
*
* Security hooks for System V Shared Memory Segments
*
* @shm_alloc_security:
* Allocate and attach a security structure to the shp->shm_perm.security
* field. The security field is initialized to NULL when the structure is
* first created.
* @shp contains the shared memory structure to be modified.
* Return 0 if operation was successful and permission is granted.
* @shm_free_security:
* Deallocate the security struct for this memory segment.
* @shp contains the shared memory structure to be modified.
*
* Security hooks for System V Semaphores
*
* @sem_alloc_security:
* Allocate and attach a security structure to the sma->sem_perm.security
* field. The security field is initialized to NULL when the structure is
* first created.
* @sma contains the semaphore structure
* Return 0 if operation was successful and permission is granted.
* @sem_free_security:
* deallocate security struct for this semaphore
* @sma contains the semaphore structure.
*
* @ptrace: * @ptrace:
* Check permission before allowing the @parent process to trace the * Check permission before allowing the @parent process to trace the
* @child process. * @child process.
...@@ -786,6 +830,17 @@ struct security_operations { ...@@ -786,6 +830,17 @@ struct security_operations {
void (*task_kmod_set_label) (void); void (*task_kmod_set_label) (void);
void (*task_reparent_to_init) (struct task_struct * p); void (*task_reparent_to_init) (struct task_struct * p);
int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
int (*msg_queue_alloc_security) (struct msg_queue * msq);
void (*msg_queue_free_security) (struct msg_queue * msq);
int (*shm_alloc_security) (struct shmid_kernel * shp);
void (*shm_free_security) (struct shmid_kernel * shp);
int (*sem_alloc_security) (struct sem_array * sma);
void (*sem_free_security) (struct sem_array * sma);
/* allow module stacking */ /* allow module stacking */
int (*register_security) (const char *name, int (*register_security) (const char *name,
struct security_operations *ops); struct security_operations *ops);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.h" #include "util.h"
...@@ -89,6 +90,7 @@ void __init msg_init (void) ...@@ -89,6 +90,7 @@ void __init msg_init (void)
static int newque (key_t key, int msgflg) static int newque (key_t key, int msgflg)
{ {
int id; int id;
int retval;
struct msg_queue *msq; struct msg_queue *msq;
msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL); msq = (struct msg_queue *) kmalloc (sizeof (*msq), GFP_KERNEL);
...@@ -98,8 +100,16 @@ static int newque (key_t key, int msgflg) ...@@ -98,8 +100,16 @@ static int newque (key_t key, int msgflg)
msq->q_perm.mode = (msgflg & S_IRWXUGO); msq->q_perm.mode = (msgflg & S_IRWXUGO);
msq->q_perm.key = key; msq->q_perm.key = key;
msq->q_perm.security = NULL;
retval = security_ops->msg_queue_alloc_security(msq);
if (retval) {
kfree(msq);
return retval;
}
id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni); id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
if(id == -1) { if(id == -1) {
security_ops->msg_queue_free_security(msq);
kfree(msq); kfree(msq);
return -ENOSPC; return -ENOSPC;
} }
...@@ -271,6 +281,7 @@ static void freeque (int id) ...@@ -271,6 +281,7 @@ static void freeque (int id)
free_msg(msg); free_msg(msg);
} }
atomic_sub(msq->q_cbytes, &msg_bytes); atomic_sub(msq->q_cbytes, &msg_bytes);
security_ops->msg_queue_free_security(msq);
kfree(msq); kfree(msq);
} }
......
...@@ -63,6 +63,7 @@ ...@@ -63,6 +63,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.h" #include "util.h"
...@@ -115,6 +116,7 @@ void __init sem_init (void) ...@@ -115,6 +116,7 @@ void __init sem_init (void)
static int newary (key_t key, int nsems, int semflg) static int newary (key_t key, int nsems, int semflg)
{ {
int id; int id;
int retval;
struct sem_array *sma; struct sem_array *sma;
int size; int size;
...@@ -133,8 +135,16 @@ static int newary (key_t key, int nsems, int semflg) ...@@ -133,8 +135,16 @@ static int newary (key_t key, int nsems, int semflg)
sma->sem_perm.mode = (semflg & S_IRWXUGO); sma->sem_perm.mode = (semflg & S_IRWXUGO);
sma->sem_perm.key = key; sma->sem_perm.key = key;
sma->sem_perm.security = NULL;
retval = security_ops->sem_alloc_security(sma);
if (retval) {
ipc_free(sma, size);
return retval;
}
id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni); id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
if(id == -1) { if(id == -1) {
security_ops->sem_free_security(sma);
ipc_free(sma, size); ipc_free(sma, size);
return -ENOSPC; return -ENOSPC;
} }
...@@ -417,6 +427,7 @@ static void freeary (int id) ...@@ -417,6 +427,7 @@ static void freeary (int id)
used_sems -= sma->sem_nsems; used_sems -= sma->sem_nsems;
size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem); size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
security_ops->sem_free_security(sma);
ipc_free(sma, size); ipc_free(sma, size);
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/security.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.h" #include "util.h"
...@@ -115,6 +116,7 @@ static void shm_destroy (struct shmid_kernel *shp) ...@@ -115,6 +116,7 @@ static void shm_destroy (struct shmid_kernel *shp)
shm_unlock(shp->id); shm_unlock(shp->id);
shmem_lock(shp->shm_file, 0); shmem_lock(shp->shm_file, 0);
fput (shp->shm_file); fput (shp->shm_file);
security_ops->shm_free_security(shp);
kfree (shp); kfree (shp);
} }
...@@ -185,6 +187,13 @@ static int newseg (key_t key, int shmflg, size_t size) ...@@ -185,6 +187,13 @@ static int newseg (key_t key, int shmflg, size_t size)
shp->shm_perm.key = key; shp->shm_perm.key = key;
shp->shm_flags = (shmflg & S_IRWXUGO); shp->shm_flags = (shmflg & S_IRWXUGO);
shp->shm_perm.security = NULL;
error = security_ops->shm_alloc_security(shp);
if (error) {
kfree(shp);
return error;
}
sprintf (name, "SYSV%08x", key); sprintf (name, "SYSV%08x", key);
file = shmem_file_setup(name, size, VM_ACCOUNT); file = shmem_file_setup(name, size, VM_ACCOUNT);
error = PTR_ERR(file); error = PTR_ERR(file);
...@@ -213,6 +222,7 @@ static int newseg (key_t key, int shmflg, size_t size) ...@@ -213,6 +222,7 @@ static int newseg (key_t key, int shmflg, size_t size)
no_id: no_id:
fput(file); fput(file);
no_file: no_file:
security_ops->shm_free_security(shp);
kfree(shp); kfree(shp);
return error; return error;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/highuid.h> #include <linux/highuid.h>
#include <linux/security.h>
#if defined(CONFIG_SYSVIPC) #if defined(CONFIG_SYSVIPC)
...@@ -263,7 +264,7 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag) ...@@ -263,7 +264,7 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag)
!capable(CAP_IPC_OWNER)) !capable(CAP_IPC_OWNER))
return -1; return -1;
return 0; return security_ops->ipc_permission(ipcp, flag);
} }
/* /*
......
...@@ -679,6 +679,41 @@ static void cap_task_reparent_to_init (struct task_struct *p) ...@@ -679,6 +679,41 @@ static void cap_task_reparent_to_init (struct task_struct *p)
return; return;
} }
static int cap_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
{
return 0;
}
static int cap_msg_queue_alloc_security (struct msg_queue *msq)
{
return 0;
}
static void cap_msg_queue_free_security (struct msg_queue *msq)
{
return;
}
static int cap_shm_alloc_security (struct shmid_kernel *shp)
{
return 0;
}
static void cap_shm_free_security (struct shmid_kernel *shp)
{
return;
}
static int cap_sem_alloc_security (struct sem_array *sma)
{
return 0;
}
static void cap_sem_free_security (struct sem_array *sma)
{
return;
}
static int cap_register (const char *name, struct security_operations *ops) static int cap_register (const char *name, struct security_operations *ops)
{ {
return -EINVAL; return -EINVAL;
...@@ -782,6 +817,17 @@ static struct security_operations capability_ops = { ...@@ -782,6 +817,17 @@ static struct security_operations capability_ops = {
.task_kmod_set_label = cap_task_kmod_set_label, .task_kmod_set_label = cap_task_kmod_set_label,
.task_reparent_to_init = cap_task_reparent_to_init, .task_reparent_to_init = cap_task_reparent_to_init,
.ipc_permission = cap_ipc_permission,
.msg_queue_alloc_security = cap_msg_queue_alloc_security,
.msg_queue_free_security = cap_msg_queue_free_security,
.shm_alloc_security = cap_shm_alloc_security,
.shm_free_security = cap_shm_free_security,
.sem_alloc_security = cap_sem_alloc_security,
.sem_free_security = cap_sem_free_security,
.register_security = cap_register, .register_security = cap_register,
.unregister_security = cap_unregister, .unregister_security = cap_unregister,
}; };
......
...@@ -493,6 +493,42 @@ static void dummy_task_reparent_to_init (struct task_struct *p) ...@@ -493,6 +493,42 @@ static void dummy_task_reparent_to_init (struct task_struct *p)
return; return;
} }
static int dummy_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
{
return 0;
}
static int dummy_msg_queue_alloc_security (struct msg_queue *msq)
{
return 0;
}
static void dummy_msg_queue_free_security (struct msg_queue *msq)
{
return;
}
static int dummy_shm_alloc_security (struct shmid_kernel *shp)
{
return 0;
}
static void dummy_shm_free_security (struct shmid_kernel *shp)
{
return;
}
static int dummy_sem_alloc_security (struct sem_array *sma)
{
return 0;
}
static void dummy_sem_free_security (struct sem_array *sma)
{
return;
}
static int dummy_register (const char *name, struct security_operations *ops) static int dummy_register (const char *name, struct security_operations *ops)
{ {
return -EINVAL; return -EINVAL;
...@@ -596,6 +632,17 @@ struct security_operations dummy_security_ops = { ...@@ -596,6 +632,17 @@ struct security_operations dummy_security_ops = {
.task_kmod_set_label = dummy_task_kmod_set_label, .task_kmod_set_label = dummy_task_kmod_set_label,
.task_reparent_to_init = dummy_task_reparent_to_init, .task_reparent_to_init = dummy_task_reparent_to_init,
.ipc_permission = dummy_ipc_permission,
.msg_queue_alloc_security = dummy_msg_queue_alloc_security,
.msg_queue_free_security = dummy_msg_queue_free_security,
.shm_alloc_security = dummy_shm_alloc_security,
.shm_free_security = dummy_shm_free_security,
.sem_alloc_security = dummy_sem_alloc_security,
.sem_free_security = dummy_sem_free_security,
.register_security = dummy_register, .register_security = dummy_register,
.unregister_security = dummy_unregister, .unregister_security = dummy_unregister,
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment