Commit 3925e6fc authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of...

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6:
  security: fix up documentation for security_module_enable
  Security: Introduce security= boot parameter
  Audit: Final renamings and cleanup
  SELinux: use new audit hooks, remove redundant exports
  Audit: internally use the new LSM audit hooks
  LSM/Audit: Introduce generic Audit LSM hooks
  SELinux: remove redundant exports
  Netlink: Use generic LSM hook
  Audit: use new LSM hooks instead of SELinux exports
  SELinux: setup new inode/ipc getsecid hooks
  LSM: Introduce inode_getsecid and ipc_getsecid hooks
parents 334d0945 7cea51be
......@@ -366,6 +366,12 @@ and is between 256 and 4096 characters. It is defined in the file
possible to determine what the correct size should be.
This option provides an override for these situations.
security= [SECURITY] Choose a security module to enable at boot.
If this boot parameter is not specified, only the first
security module asking for security registration will be
loaded. An invalid security module name will be treated
as if no module has been chosen.
capability.disable=
[SECURITY] Disable capabilities. This would normally
be used only if an alternative security model is to be
......
......@@ -353,6 +353,33 @@ struct netlink_skb_parms;
struct linux_binprm;
struct mq_attr;
struct mqstat;
struct audit_watch;
struct audit_tree;
struct audit_krule {
int vers_ops;
u32 flags;
u32 listnr;
u32 action;
u32 mask[AUDIT_BITMASK_SIZE];
u32 buflen; /* for data alloc on list rules */
u32 field_count;
char *filterkey; /* ties events to rules */
struct audit_field *fields;
struct audit_field *arch_f; /* quick access to arch field */
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct audit_tree *tree; /* associated watched tree */
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
};
struct audit_field {
u32 type;
u32 val;
u32 op;
char *lsm_str;
void *lsm_rule;
};
#define AUDITSC_INVALID 0
#define AUDITSC_SUCCESS 1
......@@ -536,6 +563,8 @@ extern void audit_log_d_path(struct audit_buffer *ab,
const char *prefix,
struct path *path);
extern void audit_log_lost(const char *message);
extern int audit_update_lsm_rules(void);
/* Private API (for audit.c only) */
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
extern int audit_filter_type(int type);
......
......@@ -36,7 +36,11 @@
extern unsigned securebits;
/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10
struct ctl_table;
struct audit_krule;
/*
* These functions are in security/capability.c and are used
......@@ -136,6 +140,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
/**
* struct security_operations - main security structure
*
* Security module identifier.
*
* @name:
* A string that acts as a unique identifeir for the LSM with max number
* of characters = SECURITY_NAME_MAX.
*
* Security hooks for program execution operations.
*
* @bprm_alloc_security:
......@@ -468,6 +478,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @dentry is the dentry being changed.
* Return 0 on success. If error is returned, then the operation
* causing setuid bit removal is failed.
* @inode_getsecid:
* Get the secid associated with the node.
* @inode contains a pointer to the inode.
* @secid contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
*
* Security hooks for file operations
*
......@@ -636,6 +651,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @task_getsecid:
* Retrieve the security identifier of the process @p.
* @p contains the task_struct for the process and place is into @secid.
* In case of failure, @secid will be set to zero.
*
* @task_setgroups:
* Check permission before setting the supplementary group set of the
* current process.
......@@ -997,6 +1014,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @ipcp contains the kernel IPC permission structure
* @flag contains the desired (requested) permission set
* Return 0 if permission is granted.
* @ipc_getsecid:
* Get the secid associated with the ipc object.
* @ipcp contains the kernel IPC permission structure.
* @secid contains a pointer to the location where result will be saved.
* In case of failure, @secid will be set to zero.
*
* Security hooks for individual messages held in System V IPC message queues
* @msg_msg_alloc_security:
......@@ -1223,9 +1245,42 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @secdata contains the security context.
* @seclen contains the length of the security context.
*
* Security hooks for Audit
*
* @audit_rule_init:
* Allocate and initialize an LSM audit rule structure.
* @field contains the required Audit action. Fields flags are defined in include/linux/audit.h
* @op contains the operator the rule uses.
* @rulestr contains the context where the rule will be applied to.
* @lsmrule contains a pointer to receive the result.
* Return 0 if @lsmrule has been successfully set,
* -EINVAL in case of an invalid rule.
*
* @audit_rule_known:
* Specifies whether given @rule contains any fields related to current LSM.
* @rule contains the audit rule of interest.
* Return 1 in case of relation found, 0 otherwise.
*
* @audit_rule_match:
* Determine if given @secid matches a rule previously approved
* by @audit_rule_known.
* @secid contains the security id in question.
* @field contains the field which relates to current LSM.
* @op contains the operator that will be used for matching.
* @rule points to the audit rule that will be checked against.
* @actx points to the audit context associated with the check.
* Return 1 if secid matches the rule, 0 if it does not, -ERRNO on failure.
*
* @audit_rule_free:
* Deallocate the LSM audit rule structure previously allocated by
* audit_rule_init.
* @rule contains the allocated rule
*
* This is the main security structure.
*/
struct security_operations {
char name[SECURITY_NAME_MAX + 1];
int (*ptrace) (struct task_struct * parent, struct task_struct * child);
int (*capget) (struct task_struct * target,
kernel_cap_t * effective,
......@@ -1317,6 +1372,7 @@ struct security_operations {
int (*inode_getsecurity)(const struct inode *inode, const char *name, void **buffer, bool alloc);
int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
void (*inode_getsecid)(const struct inode *inode, u32 *secid);
int (*file_permission) (struct file * file, int mask);
int (*file_alloc_security) (struct file * file);
......@@ -1369,6 +1425,7 @@ struct security_operations {
void (*task_to_inode)(struct task_struct *p, struct inode *inode);
int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
void (*ipc_getsecid) (struct kern_ipc_perm *ipcp, u32 *secid);
int (*msg_msg_alloc_security) (struct msg_msg * msg);
void (*msg_msg_free_security) (struct msg_msg * msg);
......@@ -1480,10 +1537,18 @@ struct security_operations {
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
int (*audit_rule_init)(u32 field, u32 op, char *rulestr, void **lsmrule);
int (*audit_rule_known)(struct audit_krule *krule);
int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule,
struct audit_context *actx);
void (*audit_rule_free)(void *lsmrule);
#endif /* CONFIG_AUDIT */
};
/* prototypes */
extern int security_init (void);
extern int security_module_enable(struct security_operations *ops);
extern int register_security (struct security_operations *ops);
extern int mod_reg_security (const char *name, struct security_operations *ops);
extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
......@@ -1578,6 +1643,7 @@ int security_inode_killpriv(struct dentry *dentry);
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags);
int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size);
void security_inode_getsecid(const struct inode *inode, u32 *secid);
int security_file_permission(struct file *file, int mask);
int security_file_alloc(struct file *file);
void security_file_free(struct file *file);
......@@ -1622,6 +1688,7 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
void security_task_reparent_to_init(struct task_struct *p);
void security_task_to_inode(struct task_struct *p, struct inode *inode);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
int security_msg_msg_alloc(struct msg_msg *msg);
void security_msg_msg_free(struct msg_msg *msg);
int security_msg_queue_alloc(struct msg_queue *msq);
......@@ -2022,6 +2089,11 @@ static inline int security_inode_listsecurity(struct inode *inode, char *buffer,
return 0;
}
static inline void security_inode_getsecid(const struct inode *inode, u32 *secid)
{
*secid = 0;
}
static inline int security_file_permission (struct file *file, int mask)
{
return 0;
......@@ -2137,7 +2209,9 @@ static inline int security_task_getsid (struct task_struct *p)
}
static inline void security_task_getsecid (struct task_struct *p, u32 *secid)
{ }
{
*secid = 0;
}
static inline int security_task_setgroups (struct group_info *group_info)
{
......@@ -2216,6 +2290,11 @@ static inline int security_ipc_permission (struct kern_ipc_perm *ipcp,
return 0;
}
static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
{
*secid = 0;
}
static inline int security_msg_msg_alloc (struct msg_msg * msg)
{
return 0;
......@@ -2672,5 +2751,38 @@ static inline int security_key_permission(key_ref_t key_ref,
#endif
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
#ifdef CONFIG_SECURITY
int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule);
int security_audit_rule_known(struct audit_krule *krule);
int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
struct audit_context *actx);
void security_audit_rule_free(void *lsmrule);
#else
static inline int security_audit_rule_init(u32 field, u32 op, char *rulestr,
void **lsmrule)
{
return 0;
}
static inline int security_audit_rule_known(struct audit_krule *krule)
{
return 0;
}
static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
void *lsmrule, struct audit_context *actx)
{
return 0;
}
static inline void security_audit_rule_free(void *lsmrule)
{ }
#endif /* CONFIG_SECURITY */
#endif /* CONFIG_AUDIT */
#endif /* ! __LINUX_SECURITY_H */
......@@ -16,98 +16,10 @@
struct selinux_audit_rule;
struct audit_context;
struct inode;
struct kern_ipc_perm;
#ifdef CONFIG_SECURITY_SELINUX
/**
* selinux_audit_rule_init - alloc/init an selinux audit rule structure.
* @field: the field this rule refers to
* @op: the operater the rule uses
* @rulestr: the text "target" of the rule
* @rule: pointer to the new rule structure returned via this
*
* Returns 0 if successful, -errno if not. On success, the rule structure
* will be allocated internally. The caller must free this structure with
* selinux_audit_rule_free() after use.
*/
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
struct selinux_audit_rule **rule);
/**
* selinux_audit_rule_free - free an selinux audit rule structure.
* @rule: pointer to the audit rule to be freed
*
* This will free all memory associated with the given rule.
* If @rule is NULL, no operation is performed.
*/
void selinux_audit_rule_free(struct selinux_audit_rule *rule);
/**
* selinux_audit_rule_match - determine if a context ID matches a rule.
* @sid: the context ID to check
* @field: the field this rule refers to
* @op: the operater the rule uses
* @rule: pointer to the audit rule to check against
* @actx: the audit context (can be NULL) associated with the check
*
* Returns 1 if the context id matches the rule, 0 if it does not, and
* -errno on failure.
*/
int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
struct selinux_audit_rule *rule,
struct audit_context *actx);
/**
* selinux_audit_set_callback - set the callback for policy reloads.
* @callback: the function to call when the policy is reloaded
*
* This sets the function callback function that will update the rules
* upon policy reloads. This callback should rebuild all existing rules
* using selinux_audit_rule_init().
*/
void selinux_audit_set_callback(int (*callback)(void));
/**
* selinux_sid_to_string - map a security context ID to a string
* @sid: security context ID to be converted.
* @ctx: address of context string to be returned
* @ctxlen: length of returned context string.
*
* Returns 0 if successful, -errno if not. On success, the context
* string will be allocated internally, and the caller must call
* kfree() on it after use.
*/
int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen);
/**
* selinux_get_inode_sid - get the inode's security context ID
* @inode: inode structure to get the sid from.
* @sid: pointer to security context ID to be filled in.
*
* Returns nothing
*/
void selinux_get_inode_sid(const struct inode *inode, u32 *sid);
/**
* selinux_get_ipc_sid - get the ipc security context ID
* @ipcp: ipc structure to get the sid from.
* @sid: pointer to security context ID to be filled in.
*
* Returns nothing
*/
void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid);
/**
* selinux_get_task_sid - return the SID of task
* @tsk: the task whose SID will be returned
* @sid: pointer to security context ID to be filled in.
*
* Returns nothing
*/
void selinux_get_task_sid(struct task_struct *tsk, u32 *sid);
/**
* selinux_string_to_sid - map a security context string to a security ID
* @str: the security context string to be mapped
......@@ -151,52 +63,6 @@ void selinux_secmark_refcount_inc(void);
void selinux_secmark_refcount_dec(void);
#else
static inline int selinux_audit_rule_init(u32 field, u32 op,
char *rulestr,
struct selinux_audit_rule **rule)
{
return -EOPNOTSUPP;
}
static inline void selinux_audit_rule_free(struct selinux_audit_rule *rule)
{
return;
}
static inline int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
struct selinux_audit_rule *rule,
struct audit_context *actx)
{
return 0;
}
static inline void selinux_audit_set_callback(int (*callback)(void))
{
return;
}
static inline int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
{
*ctx = NULL;
*ctxlen = 0;
return 0;
}
static inline void selinux_get_inode_sid(const struct inode *inode, u32 *sid)
{
*sid = 0;
}
static inline void selinux_get_ipc_sid(const struct kern_ipc_perm *ipcp, u32 *sid)
{
*sid = 0;
}
static inline void selinux_get_task_sid(struct task_struct *tsk, u32 *sid)
{
*sid = 0;
}
static inline int selinux_string_to_sid(const char *str, u32 *sid)
{
*sid = 0;
......
......@@ -21,7 +21,7 @@
*
* Written by Rickard E. (Rik) Faith <faith@redhat.com>
*
* Goals: 1) Integrate fully with SELinux.
* Goals: 1) Integrate fully with Security Modules.
* 2) Minimal run-time overhead:
* a) Minimal when syscall auditing is disabled (audit_enable=0).
* b) Small when syscall auditing is enabled and no audit record
......@@ -55,7 +55,6 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/selinux.h>
#include <linux/inotify.h>
#include <linux/freezer.h>
#include <linux/tty.h>
......@@ -265,13 +264,13 @@ static int audit_log_config_change(char *function_name, int new, int old,
char *ctx = NULL;
u32 len;
rc = selinux_sid_to_string(sid, &ctx, &len);
rc = security_secid_to_secctx(sid, &ctx, &len);
if (rc) {
audit_log_format(ab, " sid=%u", sid);
allow_changes = 0; /* Something weird, deny request */
} else {
audit_log_format(ab, " subj=%s", ctx);
kfree(ctx);
security_release_secctx(ctx, len);
}
}
audit_log_format(ab, " res=%d", allow_changes);
......@@ -550,12 +549,13 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
pid, uid, auid);
if (sid) {
rc = selinux_sid_to_string(sid, &ctx, &len);
rc = security_secid_to_secctx(sid, &ctx, &len);
if (rc)
audit_log_format(*ab, " ssid=%u", sid);
else
else {
audit_log_format(*ab, " subj=%s", ctx);
kfree(ctx);
security_release_secctx(ctx, len);
}
}
return rc;
......@@ -758,18 +758,18 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
break;
}
case AUDIT_SIGNAL_INFO:
err = selinux_sid_to_string(audit_sig_sid, &ctx, &len);
err = security_secid_to_secctx(audit_sig_sid, &ctx, &len);
if (err)
return err;
sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL);
if (!sig_data) {
kfree(ctx);
security_release_secctx(ctx, len);
return -ENOMEM;
}
sig_data->uid = audit_sig_uid;
sig_data->pid = audit_sig_pid;
memcpy(sig_data->ctx, ctx, len);
kfree(ctx);
security_release_secctx(ctx, len);
audit_send_reply(NETLINK_CB(skb).pid, seq, AUDIT_SIGNAL_INFO,
0, 0, sig_data, sizeof(*sig_data) + len);
kfree(sig_data);
......@@ -881,10 +881,6 @@ static int __init audit_init(void)
audit_enabled = audit_default;
audit_ever_enabled |= !!audit_default;
/* Register the callback with selinux. This callback will be invoked
* when a new policy is loaded. */
selinux_audit_set_callback(&selinux_audit_rule_update);
audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized");
#ifdef CONFIG_AUDITSYSCALL
......
......@@ -65,34 +65,9 @@ struct audit_watch {
struct list_head rules; /* associated rules */
};
struct audit_field {
u32 type;
u32 val;
u32 op;
char *se_str;
struct selinux_audit_rule *se_rule;
};
struct audit_tree;
struct audit_chunk;
struct audit_krule {
int vers_ops;
u32 flags;
u32 listnr;
u32 action;
u32 mask[AUDIT_BITMASK_SIZE];
u32 buflen; /* for data alloc on list rules */
u32 field_count;
char *filterkey; /* ties events to rules */
struct audit_field *fields;
struct audit_field *arch_f; /* quick access to arch field */
struct audit_field *inode_f; /* quick access to an inode field */
struct audit_watch *watch; /* associated watch */
struct audit_tree *tree; /* associated watched tree */
struct list_head rlist; /* entry in audit_{watch,tree}.rules list */
};
struct audit_entry {
struct list_head list;
struct rcu_head rcu;
......
......@@ -28,7 +28,7 @@
#include <linux/netlink.h>
#include <linux/sched.h>
#include <linux/inotify.h>
#include <linux/selinux.h>
#include <linux/security.h>
#include "audit.h"
/*
......@@ -38,7 +38,7 @@
* Synchronizes writes and blocking reads of audit's filterlist
* data. Rcu is used to traverse the filterlist and access
* contents of structs audit_entry, audit_watch and opaque
* selinux rules during filtering. If modified, these structures
* LSM rules during filtering. If modified, these structures
* must be copied and replace their counterparts in the filterlist.
* An audit_parent struct is not accessed during filtering, so may
* be written directly provided audit_filter_mutex is held.
......@@ -139,8 +139,8 @@ static inline void audit_free_rule(struct audit_entry *e)
if (e->rule.fields)
for (i = 0; i < e->rule.field_count; i++) {
struct audit_field *f = &e->rule.fields[i];
kfree(f->se_str);
selinux_audit_rule_free(f->se_rule);
kfree(f->lsm_str);
security_audit_rule_free(f->lsm_rule);
}
kfree(e->rule.fields);
kfree(e->rule.filterkey);
......@@ -554,8 +554,8 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
f->op = data->fieldflags[i] & AUDIT_OPERATORS;
f->type = data->fields[i];
f->val = data->values[i];
f->se_str = NULL;
f->se_rule = NULL;
f->lsm_str = NULL;
f->lsm_rule = NULL;
switch(f->type) {
case AUDIT_PID:
case AUDIT_UID:
......@@ -597,12 +597,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
goto exit_free;
entry->rule.buflen += f->val;
err = selinux_audit_rule_init(f->type, f->op, str,
&f->se_rule);
err = security_audit_rule_init(f->type, f->op, str,
(void **)&f->lsm_rule);
/* Keep currently invalid fields around in case they
* become valid after a policy reload. */
if (err == -EINVAL) {
printk(KERN_WARNING "audit rule for selinux "
printk(KERN_WARNING "audit rule for LSM "
"\'%s\' is invalid\n", str);
err = 0;
}
......@@ -610,7 +610,7 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
kfree(str);
goto exit_free;
} else
f->se_str = str;
f->lsm_str = str;
break;
case AUDIT_WATCH:
str = audit_unpack_string(&bufp, &remain, f->val);
......@@ -754,7 +754,7 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
case AUDIT_OBJ_LEV_LOW:
case AUDIT_OBJ_LEV_HIGH:
data->buflen += data->values[i] =
audit_pack_string(&bufp, f->se_str);
audit_pack_string(&bufp, f->lsm_str);
break;
case AUDIT_WATCH:
data->buflen += data->values[i] =
......@@ -806,7 +806,7 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
case AUDIT_OBJ_TYPE:
case AUDIT_OBJ_LEV_LOW:
case AUDIT_OBJ_LEV_HIGH:
if (strcmp(a->fields[i].se_str, b->fields[i].se_str))
if (strcmp(a->fields[i].lsm_str, b->fields[i].lsm_str))
return 1;
break;
case AUDIT_WATCH:
......@@ -862,28 +862,28 @@ out: