if (!(flags & UMOUNT_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
+ lookup_flags |= LOOKUP_NO_EVAL;
+
retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
if (retval)
goto out;
if (!access_ok(from, n))
return n;
- current->kernel_uaccess_faults_ok++;
while (n) {
if (__get_user(c, f)) {
memset(t, 0, n);
f++;
n--;
}
- current->kernel_uaccess_faults_ok--;
return n;
}
char *copy_mount_string(const void __user *data)
{
- return data ? strndup_user(data, PAGE_SIZE) : NULL;
+ return data ? strndup_user(data, PATH_MAX) : NULL;
}
/*
#define REG(NAME, MODE, fops) \
NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
#define ONE(NAME, MODE, show) \
- NOD(NAME, (S_IFREG|(MODE)), \
+ NOD(NAME, (S_IFREG|(MODE)), \
NULL, &proc_single_file_operations, \
{ .proc_show = show } )
+#define ATTR(LSM, NAME, MODE) \
+ NOD(NAME, (S_IFREG|(MODE)), \
+ NULL, &proc_pid_attr_operations, \
+ { .lsm = LSM })
/*
* Count the number of hardlinks for the pid_entry table, excluding the .
struct pid *pid, struct task_struct *task)
{
if (unlikely(!sched_info_on()))
- seq_printf(m, "0 0 0\n");
+ seq_puts(m, "0 0 0\n");
else
seq_printf(m, "%llu %llu %lu\n",
(unsigned long long)task->se.sum_exec_runtime,
task_lock(p);
if (!p->vfork_done && process_shares_mm(p, mm)) {
- pr_info("updating oom_score_adj for %d (%s) from %d to %d because it shares mm with %d (%s). Report if this is unexpected.\n",
- task_pid_nr(p), p->comm,
- p->signal->oom_score_adj, oom_adj,
- task_pid_nr(task), task->comm);
p->signal->oom_score_adj = oom_adj;
if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE))
p->signal->oom_score_adj_min = (short)oom_adj;
.llseek = default_llseek,
};
- #ifdef CONFIG_AUDITSYSCALL
+ #ifdef CONFIG_AUDIT
#define TMPBUFLEN 11
static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
if (!task)
return -ESRCH;
- length = security_getprocattr(task,
+ length = security_getprocattr(task, PROC_I(inode)->op.lsm,
(char*)file->f_path.dentry->d_name.name,
&p);
put_task_struct(task);
if (rv < 0)
goto out_free;
- rv = security_setprocattr(file->f_path.dentry->d_name.name, page, count);
+ rv = security_setprocattr(PROC_I(inode)->op.lsm,
+ file->f_path.dentry->d_name.name, page,
+ count);
mutex_unlock(¤t->signal->cred_guard_mutex);
out_free:
kfree(page);
.llseek = generic_file_llseek,
};
+#define LSM_DIR_OPS(LSM) \
+static int proc_##LSM##_attr_dir_iterate(struct file *filp, \
+ struct dir_context *ctx) \
+{ \
+ return proc_pident_readdir(filp, ctx, \
+ LSM##_attr_dir_stuff, \
+ ARRAY_SIZE(LSM##_attr_dir_stuff)); \
+} \
+\
+static const struct file_operations proc_##LSM##_attr_dir_ops = { \
+ .read = generic_read_dir, \
+ .iterate = proc_##LSM##_attr_dir_iterate, \
+ .llseek = default_llseek, \
+}; \
+\
+static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \
+ struct dentry *dentry, unsigned int flags) \
+{ \
+ return proc_pident_lookup(dir, dentry, \
+ LSM##_attr_dir_stuff, \
+ ARRAY_SIZE(LSM##_attr_dir_stuff)); \
+} \
+\
+static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
+ .lookup = proc_##LSM##_attr_dir_lookup, \
+ .getattr = pid_getattr, \
+ .setattr = proc_setattr, \
+}
+
+#ifdef CONFIG_SECURITY_SMACK
+static const struct pid_entry smack_attr_dir_stuff[] = {
+ ATTR("smack", "current", 0666),
+};
+LSM_DIR_OPS(smack);
+#endif
+
static const struct pid_entry attr_dir_stuff[] = {
- REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
- REG("prev", S_IRUGO, proc_pid_attr_operations),
- REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
- REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
- REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
- REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
+ ATTR(NULL, "current", 0666),
+ ATTR(NULL, "prev", 0444),
+ ATTR(NULL, "exec", 0666),
+ ATTR(NULL, "fscreate", 0666),
+ ATTR(NULL, "keycreate", 0666),
+ ATTR(NULL, "sockcreate", 0666),
+#ifdef CONFIG_SECURITY_SMACK
+ DIR("smack", 0555,
+ proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
+#endif
};
static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
ONE("oom_score", S_IRUGO, proc_oom_score),
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
- #ifdef CONFIG_AUDITSYSCALL
+ #ifdef CONFIG_AUDIT
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUGO, proc_sessionid_operations),
#endif
return d_splice_alias(inode, dentry);
}
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
+struct dentry *proc_pid_lookup(struct dentry *dentry, unsigned int flags)
{
struct task_struct *task;
unsigned tgid;
ONE("oom_score", S_IRUGO, proc_oom_score),
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
- #ifdef CONFIG_AUDITSYSCALL
+ #ifdef CONFIG_AUDIT
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
REG("sessionid", S_IRUGO, proc_sessionid_operations),
#endif
#define _LINUX_CAPABILITY_H
#include <uapi/linux/capability.h>
-
+ #include <linux/uidgid.h>
#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3
#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3
__u32 cap[_KERNEL_CAPABILITY_U32S];
} kernel_cap_t;
- /* exact same as vfs_cap_data but in cpu endian and always filled completely */
+ /* same as vfs_ns_cap_data but in cpu endian and always filled completely */
struct cpu_vfs_cap_data {
__u32 magic_etc;
kernel_cap_t permitted;
kernel_cap_t inheritable;
+ kuid_t rootid;
};
#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct))
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);
+extern bool ns_capable_setid(struct user_namespace *ns, int cap);
#else
static inline bool has_capability(struct task_struct *t, int cap)
{
{
return true;
}
+static inline bool ns_capable_setid(struct user_namespace *ns, int cap)
+{
+ return true;
+}
#endif /* CONFIG_MULTIUSER */
extern bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode);
extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap);
* @cred contains the credentials to use.
* @ns contains the user namespace we want the capability in
* @cap contains the capability <include/linux/capability.h>.
- * @audit contains whether to write an audit message or not
+ * @opts contains options for the capable check <include/linux/security.h>
* Return 0 if the capability is granted for @tsk.
* @syslog:
* Check permission before accessing the kernel message ring or changing
* @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:
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
- int (*capable)(const struct cred *cred, struct user_namespace *ns,
- int cap, int audit);
+ int (*capable)(const struct cred *cred,
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts);
int (*quotactl)(int cmds, int type, int id, struct super_block *sb);
int (*quota_on)(struct dentry *dentry);
int (*syslog)(int type);
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);
+ int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule);
void (*audit_rule_free)(void *lsmrule);
#endif /* CONFIG_AUDIT */
char *lsm;
} __randomize_layout;
+/*
+ * Security blob size or offset data.
+ */
+struct lsm_blob_sizes {
+ int lbs_cred;
+ int lbs_file;
+ int lbs_inode;
+ int lbs_ipc;
+ int lbs_msg_msg;
+ int lbs_task;
+};
+
/*
* Initializing a security_hook_list structure takes
* up a lot of space in a source file. This macro takes
extern void security_add_hooks(struct security_hook_list *hooks, int count,
char *lsm);
+#define LSM_FLAG_LEGACY_MAJOR BIT(0)
+#define LSM_FLAG_EXCLUSIVE BIT(1)
+
+enum lsm_order {
+ LSM_ORDER_FIRST = -1, /* This is only for capabilities. */
+ LSM_ORDER_MUTABLE = 0,
+};
+
struct lsm_info {
const char *name; /* Required. */
+ enum lsm_order order; /* Optional: default is LSM_ORDER_MUTABLE */
+ unsigned long flags; /* Optional: flags describing LSM */
+ int *enabled; /* Optional: controlled by CONFIG_LSM */
int (*init)(void); /* Required. */
+ struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */
};
extern struct lsm_info __start_lsm_info[], __end_lsm_info[];
#define __lsm_ro_after_init __ro_after_init
#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
-extern int __init security_module_enable(const char *module);
-extern void __init capability_add_hooks(void);
-#ifdef CONFIG_SECURITY_YAMA
-extern void __init yama_add_hooks(void);
-#else
-static inline void __init yama_add_hooks(void) { }
-#endif
-#ifdef CONFIG_SECURITY_LOADPIN
-void __init loadpin_add_hooks(void);
-#else
-static inline void loadpin_add_hooks(void) { };
-#endif
+extern int lsm_inode_alloc(struct inode *inode);
#endif /* ! __LINUX_LSM_HOOKS_H */
#include <linux/seccomp.h>
#include <linux/nodemask.h>
#include <linux/rcupdate.h>
+#include <linux/refcount.h>
#include <linux/resource.h>
#include <linux/latencytop.h>
#include <linux/sched/prio.h>
struct pipe_inode_info;
struct rcu_node;
struct reclaim_state;
+struct capture_control;
struct robust_list_head;
struct sched_attr;
struct sched_param;
* For cfs_rq, it is the aggregated load_avg of all runnable and
* blocked sched_entities.
*
- * load_avg may also take frequency scaling into account:
- *
- * load_avg = runnable% * scale_load_down(load) * freq%
- *
- * where freq% is the CPU frequency normalized to the highest frequency.
- *
* [util_avg definition]
*
* util_avg = running% * SCHED_CAPACITY_SCALE
* a CPU. For cfs_rq, it is the aggregated util_avg of all runnable
* and blocked sched_entities.
*
- * util_avg may also factor frequency scaling and CPU capacity scaling:
- *
- * util_avg = running% * SCHED_CAPACITY_SCALE * freq% * capacity%
+ * load_avg and util_avg don't direcly factor frequency scaling and CPU
+ * capacity scaling. The scaling is done through the rq_clock_pelt that
+ * is used for computing those signals (see update_rq_clock_pelt())
*
- * where freq% is the same as above, and capacity% is the CPU capacity
- * normalized to the greatest capacity (due to uarch differences, etc).
- *
- * N.B., the above ratios (runnable%, running%, freq%, and capacity%)
- * themselves are in the range of [0, 1]. To do fixed point arithmetics,
- * we therefore scale them to as large a range as necessary. This is for
- * example reflected by util_avg's SCHED_CAPACITY_SCALE.
+ * N.B., the above ratios (runnable% and running%) themselves are in the
+ * range of [0, 1]. To do fixed point arithmetics, we therefore scale them
+ * to as large a range as necessary. This is for example reflected by
+ * util_avg's SCHED_CAPACITY_SCALE.
*
* [Overflow issue]
*
randomized_struct_fields_start
void *stack;
- atomic_t usage;
+ refcount_t usage;
/* Per task flags (PF_*), defined further below: */
unsigned int flags;
unsigned int ptrace;
unsigned use_memdelay:1;
#endif
- /*
- * May usercopy functions fault on kernel addresses?
- * This is not just a single bit because this can potentially nest.
- */
- unsigned int kernel_uaccess_faults_ok;
-
unsigned long atomic_flags; /* Flags requiring atomic access. */
struct restart_block restart_block;
struct callback_head *task_works;
- struct audit_context *audit_context;
+ #ifdef CONFIG_AUDIT
#ifdef CONFIG_AUDITSYSCALL
+ struct audit_context *audit_context;
+ #endif
kuid_t loginuid;
unsigned int sessionid;
#endif
struct io_context *io_context;
+#ifdef CONFIG_COMPACTION
+ struct capture_control *capture_control;
+#endif
/* Ptrace state: */
unsigned long ptrace_message;
kernel_siginfo_t *last_siginfo;
/* cg_list protected by css_set_lock and tsk->alloc_lock: */
struct list_head cg_list;
#endif
-#ifdef CONFIG_RESCTRL
+#ifdef CONFIG_X86_CPU_RESCTRL
u32 closid;
u32 rmid;
#endif
#endif
#ifdef CONFIG_THREAD_INFO_IN_TASK
/* A live task holds one reference: */
- atomic_t stack_refcount;
+ refcount_t stack_refcount;
#endif
#ifdef CONFIG_LIVEPATCH
int patch_state;
#define PF_RANDOMIZE 0x00400000 /* Randomize virtual address space */
#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */
#define PF_MEMSTALL 0x01000000 /* Stalled due to lack of memory */
+#define PF_UMH 0x02000000 /* I'm an Usermodehelper process */
#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */
-#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */
+#define PF_MEMALLOC_NOCMA 0x10000000 /* All allocation request will have _GFP_MOVABLE cleared */
#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK 0x80000000 /* This thread called freeze_processes() and should not be frozen */
#define PFA_SPEC_SSB_FORCE_DISABLE 4 /* Speculative Store Bypass force disabled*/
#define PFA_SPEC_IB_DISABLE 5 /* Indirect branch speculation restricted */
#define PFA_SPEC_IB_FORCE_DISABLE 6 /* Indirect branch speculation permanently restricted */
+#define PFA_SPEC_SSB_NOEXEC 7 /* Speculative Store Bypass clear on execve() */
#define TASK_PFA_TEST(name, func) \
static inline bool task_##func(struct task_struct *p) \
TASK_PFA_SET(SPEC_SSB_DISABLE, spec_ssb_disable)
TASK_PFA_CLEAR(SPEC_SSB_DISABLE, spec_ssb_disable)
+TASK_PFA_TEST(SPEC_SSB_NOEXEC, spec_ssb_noexec)
+TASK_PFA_SET(SPEC_SSB_NOEXEC, spec_ssb_noexec)
+TASK_PFA_CLEAR(SPEC_SSB_NOEXEC, spec_ssb_noexec)
+
TASK_PFA_TEST(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
TASK_PFA_SET(SPEC_SSB_FORCE_DISABLE, spec_ssb_force_disable)
static inline unsigned int task_cpu(const struct task_struct *p)
{
#ifdef CONFIG_THREAD_INFO_IN_TASK
- return p->cpu;
+ return READ_ONCE(p->cpu);
#else
- return task_thread_info(p)->cpu;
+ return READ_ONCE(task_thread_info(p)->cpu);
#endif
}
#endif
+void __exit_umh(struct task_struct *tsk);
+
+static inline void exit_umh(struct task_struct *tsk)
+{
+ if (unlikely(tsk->flags & PF_UMH))
+ __exit_umh(tsk);
+}
+
#ifdef CONFIG_DEBUG_RSEQ
void rseq_syscall(struct pt_regs *regs);
struct xfrm_sec_ctx;
struct mm_struct;
+/* Default (no) options for the capable function */
+#define CAP_OPT_NONE 0x0
/* If capable should audit the security request */
-#define SECURITY_CAP_NOAUDIT 0
-#define SECURITY_CAP_AUDIT 1
+#define CAP_OPT_NOAUDIT BIT(1)
+/* If capable is being called by a setid function */
+#define CAP_OPT_INSETID BIT(2)
/* LSM Agnostic defines for sb_set_mnt_opts */
#define SECURITY_LSM_NATIVE_LABELS 1
/* These functions are in security/commoncap.c */
extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
- int cap, int audit);
+ int cap, unsigned int opts);
extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
const kernel_cap_t *permitted);
-int security_capable(const struct cred *cred, struct user_namespace *ns,
- int cap);
-int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
- int cap);
+int security_capable(const struct cred *cred,
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts);
int security_quotactl(int cmds, int type, int id, struct super_block *sb);
int security_quota_on(struct dentry *dentry);
int security_syslog(int type);
int security_sem_semop(struct kern_ipc_perm *sma, struct sembuf *sops,
unsigned nsops, int alter);
void security_d_instantiate(struct dentry *dentry, struct inode *inode);
-int security_getprocattr(struct task_struct *p, char *name, char **value);
-int security_setprocattr(const char *name, void *value, size_t size);
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+ char **value);
+int security_setprocattr(const char *lsm, const char *name, void *value,
+ size_t size);
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_ismaclabel(const char *name);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
}
static inline int security_capable(const struct cred *cred,
- struct user_namespace *ns, int cap)
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts)
{
- return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT);
-}
-
-static inline int security_capable_noaudit(const struct cred *cred,
- struct user_namespace *ns, int cap) {
- return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT);
+ return cap_capable(cred, ns, cap, opts);
}
static inline int security_quotactl(int cmds, int type, int id,
return 0;
}
-static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
+static inline void security_d_instantiate(struct dentry *dentry,
+ struct inode *inode)
{ }
-static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
+static inline int security_getprocattr(struct task_struct *p, const char *lsm,
+ char *name, char **value)
{
return -EINVAL;
}
-static inline int security_setprocattr(char *name, void *value, size_t size)
+static inline int security_setprocattr(const char *lsm, char *name,
+ void *value, size_t size)
{
return -EINVAL;
}
#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);
+ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule);
void security_audit_rule_free(void *lsmrule);
#else
}
static inline int security_audit_rule_match(u32 secid, u32 field, u32 op,
- void *lsmrule, struct audit_context *actx)
+ void *lsmrule)
{
return 0;
}
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/audit.h>
+#include <linux/numa.h>
#include <asm/pgtable.h>
#include <linux/uaccess.h>
};
static struct sighand_struct init_sighand = {
- .count = ATOMIC_INIT(1),
+ .count = REFCOUNT_INIT(1),
.action = { { { .sa_handler = SIG_DFL, } }, },
.siglock = __SPIN_LOCK_UNLOCKED(init_sighand.siglock),
.signalfd_wqh = __WAIT_QUEUE_HEAD_INITIALIZER(init_sighand.signalfd_wqh),
= {
#ifdef CONFIG_THREAD_INFO_IN_TASK
.thread_info = INIT_THREAD_INFO(init_task),
- .stack_refcount = ATOMIC_INIT(1),
+ .stack_refcount = REFCOUNT_INIT(1),
#endif
.state = 0,
.stack = init_stack,
- .usage = ATOMIC_INIT(2),
+ .usage = REFCOUNT_INIT(2),
.flags = PF_KTHREAD,
.prio = MAX_PRIO - 20,
.static_prio = MAX_PRIO - 20,
.thread_pid = &init_struct_pid,
.thread_group = LIST_HEAD_INIT(init_task.thread_group),
.thread_node = LIST_HEAD_INIT(init_signals.thread_head),
- #ifdef CONFIG_AUDITSYSCALL
+ #ifdef CONFIG_AUDIT
.loginuid = INVALID_UID,
.sessionid = AUDIT_SID_UNSET,
#endif
.vtime.state = VTIME_SYS,
#endif
#ifdef CONFIG_NUMA_BALANCING
- .numa_preferred_nid = -1,
+ .numa_preferred_nid = NUMA_NO_NODE,
.numa_group = NULL,
.numa_faults = NULL,
#endif
* @cred: The credentials to use
* @ns: The user namespace in which we need the capability
* @cap: The capability to check for
- * @audit: Whether to write an audit message or not
+ * @opts: Bitmask of options defined in include/linux/security.h
*
* Determine whether the nominated task has the specified capability amongst
* its effective set, returning 0 if it does, -ve if it does not.
* kernel's capable() and has_capability() returns 1 for this case.
*/
int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
- int cap, int audit)
+ int cap, unsigned int opts)
{
struct user_namespace *ns = targ_ns;
*/
static inline int cap_inh_is_capped(void)
{
-
/* they are so limited unless the current task has the CAP_SETPCAP
* capability
*/
if (cap_capable(current_cred(), current_cred()->user_ns,
- CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0)
+ CAP_SETPCAP, CAP_OPT_NONE) == 0)
return 0;
return 1;
}
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
+ cpu_caps->rootid = rootkuid;
+
return 0;
}
|| ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|| (cap_capable(current_cred(),
- current_cred()->user_ns, CAP_SETPCAP,
- SECURITY_CAP_AUDIT) != 0) /*[4]*/
+ current_cred()->user_ns,
+ CAP_SETPCAP,
+ CAP_OPT_NONE) != 0) /*[4]*/
/*
* [1] no changing of bits that are locked
* [2] no unlocking of locks
{
int cap_sys_admin = 0;
- if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN,
- SECURITY_CAP_NOAUDIT) == 0)
+ if (cap_capable(current_cred(), &init_user_ns,
+ CAP_SYS_ADMIN, CAP_OPT_NOAUDIT) == 0)
cap_sys_admin = 1;
+
return cap_sys_admin;
}
if (addr < dac_mmap_min_addr) {
ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO,
- SECURITY_CAP_AUDIT);
+ CAP_OPT_NONE);
/* set PF_SUPERPRIV if it turns out we allow the low mmap */
if (ret == 0)
current->flags |= PF_SUPERPRIV;
LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory),
};
-void __init capability_add_hooks(void)
+static int __init capability_init(void)
{
security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
"capability");
+ return 0;
}
+DEFINE_LSM(capability) = {
+ .name = "capability",
+ .order = LSM_ORDER_FIRST,
+ .init = capability_init,
+};
+
#endif /* CONFIG_SECURITY */
rc = security_filter_rule_match(osid,
rule->lsm[i].type,
Audit_equal,
- rule->lsm[i].rule,
- NULL);
+ rule->lsm[i].rule);
break;
case LSM_SUBJ_USER:
case LSM_SUBJ_ROLE:
rc = security_filter_rule_match(secid,
rule->lsm[i].type,
Audit_equal,
- rule->lsm[i].rule,
- NULL);
+ rule->lsm[i].rule);
default:
break;
}
case Opt_uid_gt:
case Opt_euid_gt:
entry->uid_op = &uid_gt;
+ /* fall through */
case Opt_uid_lt:
case Opt_euid_lt:
if ((token == Opt_uid_lt) || (token == Opt_euid_lt))
entry->uid_op = &uid_lt;
+ /* fall through */
case Opt_uid_eq:
case Opt_euid_eq:
uid_token = (token == Opt_uid_eq) ||
break;
case Opt_fowner_gt:
entry->fowner_op = &uid_gt;
+ /* fall through */
case Opt_fowner_lt:
if (token == Opt_fowner_lt)
entry->fowner_op = &uid_lt;
+ /* fall through */
case Opt_fowner_eq:
ima_log_string_op(ab, "fowner", args[0].from,
entry->fowner_op);
#include <linux/personality.h>
#include <linux/backing-dev.h>
#include <linux/string.h>
+#include <linux/msg.h>
#include <net/flow.h>
#define MAX_LSM_EVM_XATTR 2
-/* Maximum number of letters for an LSM name string */
-#define SECURITY_NAME_MAX 10
+/* How many LSMs were built into the kernel? */
+#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
struct security_hook_heads security_hook_heads __lsm_ro_after_init;
static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain);
+static struct kmem_cache *lsm_file_cache;
+static struct kmem_cache *lsm_inode_cache;
+
char *lsm_names;
+static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init;
+
/* Boot-time LSM user choice */
-static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
- CONFIG_DEFAULT_SECURITY;
+static __initdata const char *chosen_lsm_order;
+static __initdata const char *chosen_major_lsm;
+
+static __initconst const char * const builtin_lsm_order = CONFIG_LSM;
+
+/* Ordered list of LSMs to initialize. */
+static __initdata struct lsm_info **ordered_lsms;
+static __initdata struct lsm_info *exclusive;
static __initdata bool debug;
#define init_debug(...) \
pr_info(__VA_ARGS__); \
} while (0)
-static void __init major_lsm_init(void)
+static bool __init is_enabled(struct lsm_info *lsm)
{
- struct lsm_info *lsm;
- int ret;
+ if (!lsm->enabled)
+ return false;
+
+ return *lsm->enabled;
+}
+
+/* Mark an LSM's enabled flag. */
+static int lsm_enabled_true __initdata = 1;
+static int lsm_enabled_false __initdata = 0;
+static void __init set_enabled(struct lsm_info *lsm, bool enabled)
+{
+ /*
+ * When an LSM hasn't configured an enable variable, we can use
+ * a hard-coded location for storing the default enabled state.
+ */
+ if (!lsm->enabled) {
+ if (enabled)
+ lsm->enabled = &lsm_enabled_true;
+ else
+ lsm->enabled = &lsm_enabled_false;
+ } else if (lsm->enabled == &lsm_enabled_true) {
+ if (!enabled)
+ lsm->enabled = &lsm_enabled_false;
+ } else if (lsm->enabled == &lsm_enabled_false) {
+ if (enabled)
+ lsm->enabled = &lsm_enabled_true;
+ } else {
+ *lsm->enabled = enabled;
+ }
+}
+
+/* Is an LSM already listed in the ordered LSMs list? */
+static bool __init exists_ordered_lsm(struct lsm_info *lsm)
+{
+ struct lsm_info **check;
+
+ for (check = ordered_lsms; *check; check++)
+ if (*check == lsm)
+ return true;
+
+ return false;
+}
+
+/* Append an LSM to the list of ordered LSMs to initialize. */
+static int last_lsm __initdata;
+static void __init append_ordered_lsm(struct lsm_info *lsm, const char *from)
+{
+ /* Ignore duplicate selections. */
+ if (exists_ordered_lsm(lsm))
+ return;
+
+ if (WARN(last_lsm == LSM_COUNT, "%s: out of LSM slots!?\n", from))
+ return;
+
+ /* Enable this LSM, if it is not already set. */
+ if (!lsm->enabled)
+ lsm->enabled = &lsm_enabled_true;
+ ordered_lsms[last_lsm++] = lsm;
+
+ init_debug("%s ordering: %s (%sabled)\n", from, lsm->name,
+ is_enabled(lsm) ? "en" : "dis");
+}
+
+/* Is an LSM allowed to be initialized? */
+static bool __init lsm_allowed(struct lsm_info *lsm)
+{
+ /* Skip if the LSM is disabled. */
+ if (!is_enabled(lsm))
+ return false;
+
+ /* Not allowed if another exclusive LSM already initialized. */
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && exclusive) {
+ init_debug("exclusive disabled: %s\n", lsm->name);
+ return false;
+ }
+
+ return true;
+}
+
+static void __init lsm_set_blob_size(int *need, int *lbs)
+{
+ int offset;
+
+ if (*need > 0) {
+ offset = *lbs;
+ *lbs += *need;
+ *need = offset;
+ }
+}
+
+static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
+{
+ if (!needed)
+ return;
+
+ lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred);
+ lsm_set_blob_size(&needed->lbs_file, &blob_sizes.lbs_file);
+ /*
+ * The inode blob gets an rcu_head in addition to
+ * what the modules might need.
+ */
+ if (needed->lbs_inode && blob_sizes.lbs_inode == 0)
+ blob_sizes.lbs_inode = sizeof(struct rcu_head);
+ lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
+ lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
+ lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
+ lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
+}
+
+/* Prepare LSM for initialization. */
+static void __init prepare_lsm(struct lsm_info *lsm)
+{
+ int enabled = lsm_allowed(lsm);
+
+ /* Record enablement (to handle any following exclusive LSMs). */
+ set_enabled(lsm, enabled);
+
+ /* If enabled, do pre-initialization work. */
+ if (enabled) {
+ if ((lsm->flags & LSM_FLAG_EXCLUSIVE) && !exclusive) {
+ exclusive = lsm;
+ init_debug("exclusive chosen: %s\n", lsm->name);
+ }
+
+ lsm_set_blob_sizes(lsm->blobs);
+ }
+}
+
+/* Initialize a given LSM, if it is enabled. */
+static void __init initialize_lsm(struct lsm_info *lsm)
+{
+ if (is_enabled(lsm)) {
+ int ret;
- for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
init_debug("initializing %s\n", lsm->name);
ret = lsm->init();
WARN(ret, "%s failed to initialize: %d\n", lsm->name, ret);
}
}
+/* Populate ordered LSMs list from comma-separated LSM name list. */
+static void __init ordered_lsm_parse(const char *order, const char *origin)
+{
+ struct lsm_info *lsm;
+ char *sep, *name, *next;
+
+ /* LSM_ORDER_FIRST is always first. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (lsm->order == LSM_ORDER_FIRST)
+ append_ordered_lsm(lsm, "first");
+ }
+
+ /* Process "security=", if given. */
+ if (chosen_major_lsm) {
+ struct lsm_info *major;
+
+ /*
+ * To match the original "security=" behavior, this
+ * explicitly does NOT fallback to another Legacy Major
+ * if the selected one was separately disabled: disable
+ * all non-matching Legacy Major LSMs.
+ */
+ for (major = __start_lsm_info; major < __end_lsm_info;
+ major++) {
+ if ((major->flags & LSM_FLAG_LEGACY_MAJOR) &&
+ strcmp(major->name, chosen_major_lsm) != 0) {
+ set_enabled(major, false);
+ init_debug("security=%s disabled: %s\n",
+ chosen_major_lsm, major->name);
+ }
+ }
+ }
+
+ sep = kstrdup(order, GFP_KERNEL);
+ next = sep;
+ /* Walk the list, looking for matching LSMs. */
+ while ((name = strsep(&next, ",")) != NULL) {
+ bool found = false;
+
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (lsm->order == LSM_ORDER_MUTABLE &&
+ strcmp(lsm->name, name) == 0) {
+ append_ordered_lsm(lsm, origin);
+ found = true;
+ }
+ }
+
+ if (!found)
+ init_debug("%s ignored: %s\n", origin, name);
+ }
+
+ /* Process "security=", if given. */
+ if (chosen_major_lsm) {
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (exists_ordered_lsm(lsm))
+ continue;
+ if (strcmp(lsm->name, chosen_major_lsm) == 0)
+ append_ordered_lsm(lsm, "security=");
+ }
+ }
+
+ /* Disable all LSMs not in the ordered list. */
+ for (lsm = __start_lsm_info; lsm < __end_lsm_info; lsm++) {
+ if (exists_ordered_lsm(lsm))
+ continue;
+ set_enabled(lsm, false);
+ init_debug("%s disabled: %s\n", origin, lsm->name);
+ }
+
+ kfree(sep);
+}
+
+static void __init lsm_early_cred(struct cred *cred);
+static void __init lsm_early_task(struct task_struct *task);
+
+static void __init ordered_lsm_init(void)
+{
+ struct lsm_info **lsm;
+
+ ordered_lsms = kcalloc(LSM_COUNT + 1, sizeof(*ordered_lsms),
+ GFP_KERNEL);
+
+ if (chosen_lsm_order) {
+ if (chosen_major_lsm) {
+ pr_info("security= is ignored because it is superseded by lsm=\n");
+ chosen_major_lsm = NULL;
+ }
+ ordered_lsm_parse(chosen_lsm_order, "cmdline");
+ } else
+ ordered_lsm_parse(builtin_lsm_order, "builtin");
+
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ prepare_lsm(*lsm);
+
+ init_debug("cred blob size = %d\n", blob_sizes.lbs_cred);
+ init_debug("file blob size = %d\n", blob_sizes.lbs_file);
+ init_debug("inode blob size = %d\n", blob_sizes.lbs_inode);
+ init_debug("ipc blob size = %d\n", blob_sizes.lbs_ipc);
+ init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
+ init_debug("task blob size = %d\n", blob_sizes.lbs_task);
+
+ /*
+ * Create any kmem_caches needed for blobs
+ */
+ if (blob_sizes.lbs_file)
+ lsm_file_cache = kmem_cache_create("lsm_file_cache",
+ blob_sizes.lbs_file, 0,
+ SLAB_PANIC, NULL);
+ if (blob_sizes.lbs_inode)
+ lsm_inode_cache = kmem_cache_create("lsm_inode_cache",
+ blob_sizes.lbs_inode, 0,
+ SLAB_PANIC, NULL);
+
+ lsm_early_cred((struct cred *) current->cred);
+ lsm_early_task(current);
+ for (lsm = ordered_lsms; *lsm; lsm++)
+ initialize_lsm(*lsm);
+
+ kfree(ordered_lsms);
+}
+
/**
* security_init - initializes the security framework
*
i++)
INIT_HLIST_HEAD(&list[i]);
- /*
- * Load minor LSMs, with the capability module always first.
- */
- capability_add_hooks();
- yama_add_hooks();
- loadpin_add_hooks();
-
- /*
- * Load all the remaining security modules.
- */
- major_lsm_init();
+ /* Load LSMs in specified order. */
+ ordered_lsm_init();
return 0;
}
/* Save user chosen LSM */
-static int __init choose_lsm(char *str)
+static int __init choose_major_lsm(char *str)
{
- strncpy(chosen_lsm, str, SECURITY_NAME_MAX);
+ chosen_major_lsm = str;
return 1;
}
-__setup("security=", choose_lsm);
+__setup("security=", choose_major_lsm);
+
+/* Explicitly choose LSM initialization order. */
+static int __init choose_lsm_order(char *str)
+{
+ chosen_lsm_order = str;
+ return 1;
+}
+__setup("lsm=", choose_lsm_order);
/* Enable LSM order debugging. */
static int __init enable_debug(char *str)
return 0;
}
-/**
- * security_module_enable - Load given security module on boot ?
- * @module: the name of the module
- *
- * Each LSM must pass this method before registering its own operations
- * to avoid security registration races. This method may also be used
- * to check if your LSM is currently loaded during kernel initialization.
- *
- * Returns:
- *
- * true if:
- *
- * - The passed LSM is the one chosen by user at boot time,
- * - or the passed LSM is configured as the default and the user did not
- * choose an alternate LSM at boot time.
- *
- * Otherwise, return false.
- */
-int __init security_module_enable(const char *module)
-{
- return !strcmp(module, chosen_lsm);
-}
-
/**
* security_add_hooks - Add a modules hooks to the hook lists.
* @hooks: the hooks to add
}
EXPORT_SYMBOL(unregister_lsm_notifier);
+/**
+ * lsm_cred_alloc - allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ * @gfp: allocation type
+ *
+ * Allocate the cred blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_cred_alloc(struct cred *cred, gfp_t gfp)
+{
+ if (blob_sizes.lbs_cred == 0) {
+ cred->security = NULL;
+ return 0;
+ }
+
+ cred->security = kzalloc(blob_sizes.lbs_cred, gfp);
+ if (cred->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_early_cred - during initialization allocate a composite cred blob
+ * @cred: the cred that needs a blob
+ *
+ * Allocate the cred blob for all the modules
+ */
+static void __init lsm_early_cred(struct cred *cred)
+{
+ int rc = lsm_cred_alloc(cred, GFP_KERNEL);
+
+ if (rc)
+ panic("%s: Early cred alloc failed.\n", __func__);
+}
+
+/**
+ * lsm_file_alloc - allocate a composite file blob
+ * @file: the file that needs a blob
+ *
+ * Allocate the file blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_file_alloc(struct file *file)
+{
+ if (!lsm_file_cache) {
+ file->f_security = NULL;
+ return 0;
+ }
+
+ file->f_security = kmem_cache_zalloc(lsm_file_cache, GFP_KERNEL);
+ if (file->f_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_inode_alloc - allocate a composite inode blob
+ * @inode: the inode that needs a blob
+ *
+ * Allocate the inode blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+int lsm_inode_alloc(struct inode *inode)
+{
+ if (!lsm_inode_cache) {
+ inode->i_security = NULL;
+ return 0;
+ }
+
+ inode->i_security = kmem_cache_zalloc(lsm_inode_cache, GFP_NOFS);
+ if (inode->i_security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_task_alloc - allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_task_alloc(struct task_struct *task)
+{
+ if (blob_sizes.lbs_task == 0) {
+ task->security = NULL;
+ return 0;
+ }
+
+ task->security = kzalloc(blob_sizes.lbs_task, GFP_KERNEL);
+ if (task->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_ipc_alloc - allocate a composite ipc blob
+ * @kip: the ipc that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_ipc_alloc(struct kern_ipc_perm *kip)
+{
+ if (blob_sizes.lbs_ipc == 0) {
+ kip->security = NULL;
+ return 0;
+ }
+
+ kip->security = kzalloc(blob_sizes.lbs_ipc, GFP_KERNEL);
+ if (kip->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_msg_msg_alloc - allocate a composite msg_msg blob
+ * @mp: the msg_msg that needs a blob
+ *
+ * Allocate the ipc blob for all the modules
+ *
+ * Returns 0, or -ENOMEM if memory can't be allocated.
+ */
+static int lsm_msg_msg_alloc(struct msg_msg *mp)
+{
+ if (blob_sizes.lbs_msg_msg == 0) {
+ mp->security = NULL;
+ return 0;
+ }
+
+ mp->security = kzalloc(blob_sizes.lbs_msg_msg, GFP_KERNEL);
+ if (mp->security == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/**
+ * lsm_early_task - during initialization allocate a composite task blob
+ * @task: the task that needs a blob
+ *
+ * Allocate the task blob for all the modules
+ */
+static void __init lsm_early_task(struct task_struct *task)
+{
+ int rc = lsm_task_alloc(task);
+
+ if (rc)
+ panic("%s: Early task alloc failed.\n", __func__);
+}
+
/*
* Hook list operation macros.
*
effective, inheritable, permitted);
}
-int security_capable(const struct cred *cred, struct user_namespace *ns,
- int cap)
-{
- return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_AUDIT);
-}
-
-int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns,
- int cap)
+int security_capable(const struct cred *cred,
+ struct user_namespace *ns,
+ int cap,
+ unsigned int opts)
{
- return call_int_hook(capable, 0, cred, ns, cap, SECURITY_CAP_NOAUDIT);
+ return call_int_hook(capable, 0, cred, ns, cap, opts);
}
int security_quotactl(int cmds, int type, int id, struct super_block *sb)
int security_inode_alloc(struct inode *inode)
{
- inode->i_security = NULL;
- return call_int_hook(inode_alloc_security, 0, inode);
+ int rc = lsm_inode_alloc(inode);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(inode_alloc_security, 0, inode);
+ if (unlikely(rc))
+ security_inode_free(inode);
+ return rc;
+}
+
+static void inode_free_by_rcu(struct rcu_head *head)
+{
+ /*
+ * The rcu head is at the start of the inode blob
+ */
+ kmem_cache_free(lsm_inode_cache, head);
}
void security_inode_free(struct inode *inode)
{
integrity_inode_free(inode);
call_void_hook(inode_free_security, inode);
+ /*
+ * The inode may still be referenced in a path walk and
+ * a call to security_inode_permission() can be made
+ * after inode_free_security() is called. Ideally, the VFS
+ * wouldn't do this, but fixing that is a much harder
+ * job. For now, simply free the i_security via RCU, and
+ * leave the current inode->i_security pointer intact.
+ * The inode will be freed after the RCU grace period too.
+ */
+ if (inode->i_security)
+ call_rcu((struct rcu_head *)inode->i_security,
+ inode_free_by_rcu);
}
int security_dentry_init_security(struct dentry *dentry, int mode,
int security_file_alloc(struct file *file)
{
- return call_int_hook(file_alloc_security, 0, file);
+ int rc = lsm_file_alloc(file);
+
+ if (rc)
+ return rc;
+ rc = call_int_hook(file_alloc_security, 0, file);
+ if (unlikely(rc))
+ security_file_free(file);
+ return rc;
}
void security_file_free(struct file *file)
{
+ void *blob;
+
call_void_hook(file_free_security, file);
+
+ blob = file->f_security;
+ if (blob) {
+ file->f_security = NULL;
+ kmem_cache_free(lsm_file_cache, blob);
+ }
}
int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int security_task_alloc(struct task_struct *task, unsigned long clone_flags)
{
- return call_int_hook(task_alloc, 0, task, clone_flags);
+ int rc = lsm_task_alloc(task);
+
+ if (rc)
+ return rc;
+ rc = call_int_hook(task_alloc, 0, task, clone_flags);
+ if (unlikely(rc))
+ security_task_free(task);
+ return rc;
}
void security_task_free(struct task_struct *task)
{
call_void_hook(task_free, task);
+
+ kfree(task->security);
+ task->security = NULL;
}
int security_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
- return call_int_hook(cred_alloc_blank, 0, cred, gfp);
+ int rc = lsm_cred_alloc(cred, gfp);
+
+ if (rc)
+ return rc;
+
+ rc = call_int_hook(cred_alloc_blank, 0, cred, gfp);
+ if (unlikely(rc))
+ security_cred_free(cred);
+ return rc;
}
void security_cred_free(struct cred *cred)
{
+ /*
+ * There is a failure case in prepare_creds() that
+ * may result in a call here with ->security being NULL.
+ */
+ if (unlikely(cred->security == NULL))
+ return;
+
call_void_hook(cred_free, cred);
+
+ kfree(cred->security);
+ cred->security = NULL;
}
int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp)
{
- return call_int_hook(cred_prepare, 0, new, old, gfp);
+ int rc = lsm_cred_alloc(new, gfp);
+
+ if (rc)
+ return rc;
+
+ rc = call_int_hook(cred_prepare, 0, new, old, gfp);
+ if (unlikely(rc))
+ security_cred_free(new);
+ return rc;
}
void security_transfer_creds(struct cred *new, const struct cred *old)
int security_msg_msg_alloc(struct msg_msg *msg)
{
- return call_int_hook(msg_msg_alloc_security, 0, msg);
+ int rc = lsm_msg_msg_alloc(msg);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(msg_msg_alloc_security, 0, msg);
+ if (unlikely(rc))
+ security_msg_msg_free(msg);
+ return rc;
}
void security_msg_msg_free(struct msg_msg *msg)
{
call_void_hook(msg_msg_free_security, msg);
+ kfree(msg->security);
+ msg->security = NULL;
}
int security_msg_queue_alloc(struct kern_ipc_perm *msq)
{
- return call_int_hook(msg_queue_alloc_security, 0, msq);
+ int rc = lsm_ipc_alloc(msq);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(msg_queue_alloc_security, 0, msq);
+ if (unlikely(rc))
+ security_msg_queue_free(msq);
+ return rc;
}
void security_msg_queue_free(struct kern_ipc_perm *msq)
{
call_void_hook(msg_queue_free_security, msq);
+ kfree(msq->security);
+ msq->security = NULL;
}
int security_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
int security_shm_alloc(struct kern_ipc_perm *shp)
{
- return call_int_hook(shm_alloc_security, 0, shp);
+ int rc = lsm_ipc_alloc(shp);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(shm_alloc_security, 0, shp);
+ if (unlikely(rc))
+ security_shm_free(shp);
+ return rc;
}
void security_shm_free(struct kern_ipc_perm *shp)
{
call_void_hook(shm_free_security, shp);
+ kfree(shp->security);
+ shp->security = NULL;
}
int security_shm_associate(struct kern_ipc_perm *shp, int shmflg)
int security_sem_alloc(struct kern_ipc_perm *sma)
{
- return call_int_hook(sem_alloc_security, 0, sma);
+ int rc = lsm_ipc_alloc(sma);
+
+ if (unlikely(rc))
+ return rc;
+ rc = call_int_hook(sem_alloc_security, 0, sma);
+ if (unlikely(rc))
+ security_sem_free(sma);
+ return rc;
}
void security_sem_free(struct kern_ipc_perm *sma)
{
call_void_hook(sem_free_security, sma);
+ kfree(sma->security);
+ sma->security = NULL;
}
int security_sem_associate(struct kern_ipc_perm *sma, int semflg)
}
EXPORT_SYMBOL(security_d_instantiate);
-int security_getprocattr(struct task_struct *p, char *name, char **value)
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+ char **value)
{
- return call_int_hook(getprocattr, -EINVAL, p, name, value);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+ if (lsm != NULL && strcmp(lsm, hp->lsm))
+ continue;
+ return hp->hook.getprocattr(p, name, value);
+ }
+ return -EINVAL;
}
-int security_setprocattr(const char *name, void *value, size_t size)
+int security_setprocattr(const char *lsm, const char *name, void *value,
+ size_t size)
{
- return call_int_hook(setprocattr, -EINVAL, name, value, size);
+ struct security_hook_list *hp;
+
+ hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+ if (lsm != NULL && strcmp(lsm, hp->lsm))
+ continue;
+ return hp->hook.setprocattr(name, value, size);
+ }
+ return -EINVAL;
}
int security_netlink_send(struct sock *sk, struct sk_buff *skb)
call_void_hook(audit_rule_free, lsmrule);
}
- int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
- struct audit_context *actx)
+ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule)
{
- return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule,
- actx);
+ return call_int_hook(audit_rule_match, 0, secid, field, op, lsmrule);
}
#endif /* CONFIG_AUDIT */
/*
* SELinux support for the Audit LSM hooks
*
- * Most of below header was moved from include/linux/selinux.h which
- * is released under below copyrights:
- *
*
* @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, void *rule,
- struct audit_context *actx);
+ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *rule);
/**
* selinux_audit_rule_known - check to see if rule contains selinux fields.
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/mutex.h>
-#include <linux/selinux.h>
#include <linux/flex_array.h>
#include <linux/vmalloc.h>
#include <net/netlabel.h>
static int security_sid_to_context_core(struct selinux_state *state,
u32 sid, char **scontext,
- u32 *scontext_len, int force)
+ u32 *scontext_len, int force,
+ int only_invalid)
{
struct policydb *policydb;
struct sidtab *sidtab;
rc = -EINVAL;
goto out_unlock;
}
- rc = context_struct_to_string(policydb, context, scontext,
- scontext_len);
+ if (only_invalid && !context->len) {
+ scontext = NULL;
+ scontext_len = 0;
+ rc = 0;
+ } else {
+ rc = context_struct_to_string(policydb, context, scontext,
+ scontext_len);
+ }
out_unlock:
read_unlock(&state->ss->policy_rwlock);
out:
u32 sid, char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
- scontext_len, 0);
+ scontext_len, 0, 0);
}
int security_sid_to_context_force(struct selinux_state *state, u32 sid,
char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(state, sid, scontext,
- scontext_len, 1);
+ scontext_len, 1, 0);
+}
+
+/**
+ * security_sid_to_context_inval - Obtain a context for a given SID if it
+ * is invalid.
+ * @sid: security identifier, SID
+ * @scontext: security context
+ * @scontext_len: length in bytes
+ *
+ * Write the string representation of the context associated with @sid
+ * into a dynamically allocated string of the correct size, but only if the
+ * context is invalid in the current policy. Set @scontext to point to
+ * this string (or NULL if the context is valid) and set @scontext_len to
+ * the length of the string (or 0 if the context is valid).
+ */
+int security_sid_to_context_inval(struct selinux_state *state, u32 sid,
+ char **scontext, u32 *scontext_len)
+{
+ return security_sid_to_context_core(state, sid, scontext,
+ scontext_len, 1, 1);
}
/*
return 0;
}
- int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
- struct audit_context *actx)
+ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
{
struct selinux_state *state = &selinux_state;
struct context *ctxt;
static int smk_bu_current(char *note, struct smack_known *oskp,
int mode, int rc)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (rc <= 0)
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_task(struct task_struct *otp, int mode, int rc)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
struct smack_known *smk_task = smk_of_task_struct(otp);
char acc[SMK_NUM_ACCESS_TYPE + 1];
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_inode(struct inode *inode, int mode, int rc)
{
- struct task_smack *tsp = current_security();
- struct inode_smack *isp = inode->i_security;
+ struct task_smack *tsp = smack_cred(current_cred());
+ struct inode_smack *isp = smack_inode(inode);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (isp->smk_flags & SMK_INODE_IMPURE)
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
static int smk_bu_file(struct file *file, int mode, int rc)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
struct smack_known *sskp = tsp->smk_task;
struct inode *inode = file_inode(file);
- struct inode_smack *isp = inode->i_security;
+ struct inode_smack *isp = smack_inode(inode);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (isp->smk_flags & SMK_INODE_IMPURE)
static int smk_bu_credfile(const struct cred *cred, struct file *file,
int mode, int rc)
{
- struct task_smack *tsp = cred->security;
+ struct task_smack *tsp = smack_cred(cred);
struct smack_known *sskp = tsp->smk_task;
struct inode *inode = file_inode(file);
- struct inode_smack *isp = inode->i_security;
+ struct inode_smack *isp = smack_inode(inode);
char acc[SMK_NUM_ACCESS_TYPE + 1];
if (isp->smk_flags & SMK_INODE_IMPURE)
}
/**
- * new_inode_smack - allocate an inode security blob
+ * init_inode_smack - initialize an inode security blob
+ * @isp: the blob to initialize
* @skp: a pointer to the Smack label entry to use in the blob
*
- * Returns the new blob or NULL if there's no memory available
*/
-static struct inode_smack *new_inode_smack(struct smack_known *skp)
+static void init_inode_smack(struct inode *inode, struct smack_known *skp)
{
- struct inode_smack *isp;
-
- isp = kmem_cache_zalloc(smack_inode_cache, GFP_NOFS);
- if (isp == NULL)
- return NULL;
+ struct inode_smack *isp = smack_inode(inode);
isp->smk_inode = skp;
isp->smk_flags = 0;
mutex_init(&isp->smk_lock);
-
- return isp;
}
/**
- * new_task_smack - allocate a task security blob
+ * init_task_smack - initialize a task security blob
+ * @tsp: blob to initialize
* @task: a pointer to the Smack label for the running task
* @forked: a pointer to the Smack label for the forked task
- * @gfp: type of the memory for the allocation
*
- * Returns the new blob or NULL if there's no memory available
*/
-static struct task_smack *new_task_smack(struct smack_known *task,
- struct smack_known *forked, gfp_t gfp)
+static void init_task_smack(struct task_smack *tsp, struct smack_known *task,
+ struct smack_known *forked)
{
- struct task_smack *tsp;
-
- tsp = kzalloc(sizeof(struct task_smack), gfp);
- if (tsp == NULL)
- return NULL;
-
tsp->smk_task = task;
tsp->smk_forked = forked;
INIT_LIST_HEAD(&tsp->smk_rules);
INIT_LIST_HEAD(&tsp->smk_relabel);
mutex_init(&tsp->smk_rules_lock);
-
- return tsp;
}
/**
rcu_read_lock();
tracercred = __task_cred(tracer);
- tsp = tracercred->security;
+ tsp = smack_cred(tracercred);
tracer_known = smk_of_task(tsp);
if ((mode & PTRACE_MODE_ATTACH) &&
int rc;
struct smack_known *skp;
- skp = smk_of_task(current_security());
+ skp = smk_of_task(smack_cred(current_cred()));
rc = smk_ptrace_rule_check(ptp, skp, PTRACE_MODE_ATTACH, __func__);
return rc;
if (sp->smk_flags & SMK_SB_INITIALIZED)
return 0;
+ if (inode->i_security == NULL) {
+ int rc = lsm_inode_alloc(inode);
+
+ if (rc)
+ return rc;
+ }
+
if (!smack_privileged(CAP_MAC_ADMIN)) {
/*
* Unprivileged mounts don't get to specify Smack values.
/*
* Initialize the root inode.
*/
- isp = inode->i_security;
- if (isp == NULL) {
- isp = new_inode_smack(sp->smk_root);
- if (isp == NULL)
- return -ENOMEM;
- inode->i_security = isp;
- } else
- isp->smk_inode = sp->smk_root;
+ init_inode_smack(inode, sp->smk_root);
- if (transmute)
+ if (transmute) {
+ isp = smack_inode(inode);
isp->smk_flags |= SMK_INODE_TRANSMUTE;
+ }
return 0;
}
static int smack_bprm_set_creds(struct linux_binprm *bprm)
{
struct inode *inode = file_inode(bprm->file);
- struct task_smack *bsp = bprm->cred->security;
+ struct task_smack *bsp = smack_cred(bprm->cred);
struct inode_smack *isp;
struct superblock_smack *sbsp;
int rc;
if (bprm->called_set_creds)
return 0;
- isp = inode->i_security;
+ isp = smack_inode(inode);
if (isp->smk_task == NULL || isp->smk_task == bsp->smk_task)
return 0;
{
struct smack_known *skp = smk_of_current();
- inode->i_security = new_inode_smack(skp);
- if (inode->i_security == NULL)
- return -ENOMEM;
+ init_inode_smack(inode, skp);
return 0;
}
-/**
- * smack_inode_free_rcu - Free inode_smack blob from cache
- * @head: the rcu_head for getting inode_smack pointer
- *
- * Call back function called from call_rcu() to free
- * the i_security blob pointer in inode
- */
-static void smack_inode_free_rcu(struct rcu_head *head)
-{
- struct inode_smack *issp;
-
- issp = container_of(head, struct inode_smack, smk_rcu);
- kmem_cache_free(smack_inode_cache, issp);
-}
-
-/**
- * smack_inode_free_security - free an inode blob using call_rcu()
- * @inode: the inode with a blob
- *
- * Clears the blob pointer in inode using RCU
- */
-static void smack_inode_free_security(struct inode *inode)
-{
- struct inode_smack *issp = inode->i_security;
-
- /*
- * The inode may still be referenced in a path walk and
- * a call to smack_inode_permission() can be made
- * after smack_inode_free_security() is called.
- * To avoid race condition free the i_security via RCU
- * and leave the current inode->i_security pointer intact.
- * The inode will be freed after the RCU grace period too.
- */
- call_rcu(&issp->smk_rcu, smack_inode_free_rcu);
-}
-
/**
* smack_inode_init_security - copy out the smack from an inode
* @inode: the newly created inode
const struct qstr *qstr, const char **name,
void **value, size_t *len)
{
- struct inode_smack *issp = inode->i_security;
+ struct inode_smack *issp = smack_inode(inode);
struct smack_known *skp = smk_of_current();
struct smack_known *isp = smk_of_inode(inode);
struct smack_known *dsp = smk_of_inode(dir);
const void *value, size_t size, int flags)
{
struct smack_known *skp;
- struct inode_smack *isp = d_backing_inode(dentry)->i_security;
+ struct inode_smack *isp = smack_inode(d_backing_inode(dentry));
if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
isp->smk_flags |= SMK_INODE_TRANSMUTE;
if (rc != 0)
return rc;
- isp = d_backing_inode(dentry)->i_security;
+ isp = smack_inode(d_backing_inode(dentry));
/*
* Don't do anything special for these.
* XATTR_NAME_SMACKIPIN
*/
static int smack_file_alloc_security(struct file *file)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_file(file);
- file->f_security = skp;
+ *blob = smk_of_current();
return 0;
}
-/**
- * smack_file_free_security - clear a file security blob
- * @file: the object
- *
- * The security blob for a file is a pointer to the master
- * label list, so no memory is freed.
- */
-static void smack_file_free_security(struct file *file)
-{
- file->f_security = NULL;
-}
-
/**
* smack_file_ioctl - Smack check on ioctls
* @file: the object
if (unlikely(IS_PRIVATE(file_inode(file))))
return 0;
- isp = file_inode(file)->i_security;
+ isp = smack_inode(file_inode(file));
if (isp->smk_mmap == NULL)
return 0;
sbsp = file_inode(file)->i_sb->s_security;
return -EACCES;
mkp = isp->smk_mmap;
- tsp = current_security();
+ tsp = smack_cred(current_cred());
skp = smk_of_current();
rc = 0;
*/
static void smack_file_set_fowner(struct file *file)
{
- file->f_security = smk_of_current();
+ struct smack_known **blob = smack_file(file);
+
+ *blob = smk_of_current();
}
/**
static int smack_file_send_sigiotask(struct task_struct *tsk,
struct fown_struct *fown, int signum)
{
+ struct smack_known **blob;
struct smack_known *skp;
- struct smack_known *tkp = smk_of_task(tsk->cred->security);
+ struct smack_known *tkp = smk_of_task(smack_cred(tsk->cred));
const struct cred *tcred;
struct file *file;
int rc;
file = container_of(fown, struct file, f_owner);
/* we don't log here as rc can be overriden */
- skp = file->f_security;
+ blob = smack_file(file);
+ skp = *blob;
rc = smk_access(skp, tkp, MAY_DELIVER, NULL);
rc = smk_bu_note("sigiotask", skp, tkp, MAY_DELIVER, rc);
if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
sock = SOCKET_I(inode);
ssp = sock->sk->sk_security;
- tsp = current_security();
+ tsp = smack_cred(current_cred());
/*
* If the receiving process can't write to the
* passed socket or if the passed socket can't
*/
static int smack_file_open(struct file *file)
{
- struct task_smack *tsp = file->f_cred->security;
+ struct task_smack *tsp = smack_cred(file->f_cred);
struct inode *inode = file_inode(file);
struct smk_audit_info ad;
int rc;
*/
static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{
- struct task_smack *tsp;
-
- tsp = new_task_smack(NULL, NULL, gfp);
- if (tsp == NULL)
- return -ENOMEM;
-
- cred->security = tsp;
-
+ init_task_smack(smack_cred(cred), NULL, NULL);
return 0;
}
*/
static void smack_cred_free(struct cred *cred)
{
- struct task_smack *tsp = cred->security;
+ struct task_smack *tsp = smack_cred(cred);
struct smack_rule *rp;
struct list_head *l;
struct list_head *n;
- if (tsp == NULL)
- return;
- cred->security = NULL;
-
smk_destroy_label_list(&tsp->smk_relabel);
list_for_each_safe(l, n, &tsp->smk_rules) {
list_del(&rp->list);
kfree(rp);
}
- kfree(tsp);
}
/**
static int smack_cred_prepare(struct cred *new, const struct cred *old,
gfp_t gfp)
{
- struct task_smack *old_tsp = old->security;
- struct task_smack *new_tsp;
+ struct task_smack *old_tsp = smack_cred(old);
+ struct task_smack *new_tsp = smack_cred(new);
int rc;
- new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp);
- if (new_tsp == NULL)
- return -ENOMEM;
-
- new->security = new_tsp;
+ init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task);
rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp);
if (rc != 0)
rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel,
gfp);
- if (rc != 0)
- return rc;
-
- return 0;
+ return rc;
}
/**
*/
static void smack_cred_transfer(struct cred *new, const struct cred *old)
{
- struct task_smack *old_tsp = old->security;
- struct task_smack *new_tsp = new->security;
+ struct task_smack *old_tsp = smack_cred(old);
+ struct task_smack *new_tsp = smack_cred(new);
new_tsp->smk_task = old_tsp->smk_task;
new_tsp->smk_forked = old_tsp->smk_task;
mutex_init(&new_tsp->smk_rules_lock);
INIT_LIST_HEAD(&new_tsp->smk_rules);
-
/* cbs copy rule list */
}
*
* Sets the secid to contain a u32 version of the smack label.
*/
-static void smack_cred_getsecid(const struct cred *c, u32 *secid)
+static void smack_cred_getsecid(const struct cred *cred, u32 *secid)
{
struct smack_known *skp;
rcu_read_lock();
- skp = smk_of_task(c->security);
+ skp = smk_of_task(smack_cred(cred));
*secid = skp->smk_secid;
rcu_read_unlock();
}
*/
static int smack_kernel_act_as(struct cred *new, u32 secid)
{
- struct task_smack *new_tsp = new->security;
+ struct task_smack *new_tsp = smack_cred(new);
new_tsp->smk_task = smack_from_secid(secid);
return 0;
static int smack_kernel_create_files_as(struct cred *new,
struct inode *inode)
{
- struct inode_smack *isp = inode->i_security;
- struct task_smack *tsp = new->security;
+ struct inode_smack *isp = smack_inode(inode);
+ struct task_smack *tsp = smack_cred(new);
tsp->smk_forked = isp->smk_inode;
tsp->smk_task = tsp->smk_forked;
* specific behavior. This is not clean. For one thing
* we can't take privilege into account.
*/
- skp = smk_of_task(cred->security);
+ skp = smk_of_task(smack_cred(cred));
rc = smk_access(skp, tkp, MAY_DELIVER, &ad);
rc = smk_bu_note("USB signal", skp, tkp, MAY_DELIVER, rc);
return rc;
*/
static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
{
- struct inode_smack *isp = inode->i_security;
+ struct inode_smack *isp = smack_inode(inode);
struct smack_known *skp = smk_of_task_struct(p);
isp->smk_inode = skp;
const void *value, size_t size, int flags)
{
struct smack_known *skp;
- struct inode_smack *nsp = inode->i_security;
+ struct inode_smack *nsp = smack_inode(inode);
struct socket_smack *ssp;
struct socket *sock;
int rc = 0;
*/
static int smack_msg_msg_alloc_security(struct msg_msg *msg)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_msg_msg(msg);
- msg->security = skp;
+ *blob = smk_of_current();
return 0;
}
-/**
- * smack_msg_msg_free_security - Clear the security blob for msg_msg
- * @msg: the object
- *
- * Clears the blob pointer
- */
-static void smack_msg_msg_free_security(struct msg_msg *msg)
-{
- msg->security = NULL;
-}
-
/**
* smack_of_ipc - the smack pointer for the ipc
* @isp: the object
*/
static struct smack_known *smack_of_ipc(struct kern_ipc_perm *isp)
{
- return (struct smack_known *)isp->security;
+ struct smack_known **blob = smack_ipc(isp);
+
+ return *blob;
}
/**
*/
static int smack_ipc_alloc_security(struct kern_ipc_perm *isp)
{
- struct smack_known *skp = smk_of_current();
+ struct smack_known **blob = smack_ipc(isp);
- isp->security = skp;
+ *blob = smk_of_current();
return 0;
}
-/**
- * smack_ipc_free_security - Clear the security blob for ipc
- * @isp: the object
- *
- * Clears the blob pointer
- */
-static void smack_ipc_free_security(struct kern_ipc_perm *isp)
-{
- isp->security = NULL;
-}
-
/**
* smk_curacc_shm : check if current has access on shm
* @isp : the object
*/
static int smack_ipc_permission(struct kern_ipc_perm *ipp, short flag)
{
- struct smack_known *iskp = ipp->security;
+ struct smack_known **blob = smack_ipc(ipp);
+ struct smack_known *iskp = *blob;
int may = smack_flags_to_may(flag);
struct smk_audit_info ad;
int rc;
*/
static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
{
- struct smack_known *iskp = ipp->security;
+ struct smack_known **blob = smack_ipc(ipp);
+ struct smack_known *iskp = *blob;
*secid = iskp->smk_secid;
}
if (inode == NULL)
return;
- isp = inode->i_security;
+ isp = smack_inode(inode);
mutex_lock(&isp->smk_lock);
/*
*/
final = &smack_known_star;
/*
- * Fall through.
- *
* If a smack value has been set we want to use it,
* but since tmpfs isn't giving us the opportunity
* to set mount options simulate setting the
* superblock default.
*/
+ /* Fall through */
default:
/*
* This isn't an understood special case.
*/
static int smack_setprocattr(const char *name, void *value, size_t size)
{
- struct task_smack *tsp = current_security();
+ struct task_smack *tsp = smack_cred(current_cred());
struct cred *new;
struct smack_known *skp;
struct smack_known_list_elem *sklep;
if (new == NULL)
return -ENOMEM;
- tsp = new->security;
+ tsp = smack_cred(new);
tsp->smk_task = skp;
/*
* process can change its label only once
static int smack_key_alloc(struct key *key, const struct cred *cred,
unsigned long flags)
{
- struct smack_known *skp = smk_of_task(cred->security);
+ struct smack_known *skp = smk_of_task(smack_cred(cred));
key->security = skp;
return 0;
{
struct key *keyp;
struct smk_audit_info ad;
- struct smack_known *tkp = smk_of_task(cred->security);
+ struct smack_known *tkp = smk_of_task(smack_cred(cred));
int request = 0;
int rc;
* @field: audit rule flags given from user-space
* @op: required testing operator
* @vrule: smack internal rule presentation
- * @actx: audit context associated with the check
*
* The core Audit hook. It's used to take the decision of
* whether to audit or not to audit a given object.
*/
- static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
- struct audit_context *actx)
+ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule)
{
struct smack_known *skp;
char *rule = vrule;
return -ENOMEM;
}
- tsp = new_creds->security;
+ tsp = smack_cred(new_creds);
/*
* Get label from overlay inode and set it in create_sid
*/
- isp = d_inode(dentry->d_parent)->i_security;
+ isp = smack_inode(d_inode(dentry->d_parent));
skp = isp->smk_inode;
tsp->smk_task = skp;
*new = new_creds;
const struct cred *old,
struct cred *new)
{
- struct task_smack *otsp = old->security;
- struct task_smack *ntsp = new->security;
+ struct task_smack *otsp = smack_cred(old);
+ struct task_smack *ntsp = smack_cred(new);
struct inode_smack *isp;
int may;
/*
* the attribute of the containing directory
*/
- isp = d_inode(dentry->d_parent)->i_security;
+ isp = smack_inode(d_inode(dentry->d_parent));
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
rcu_read_lock();
return 0;
}
+struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
+ .lbs_cred = sizeof(struct task_smack),
+ .lbs_file = sizeof(struct smack_known *),
+ .lbs_inode = sizeof(struct inode_smack),
+ .lbs_ipc = sizeof(struct smack_known *),
+ .lbs_msg_msg = sizeof(struct smack_known *),
+};
+
static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds),
LSM_HOOK_INIT(inode_alloc_security, smack_inode_alloc_security),
- LSM_HOOK_INIT(inode_free_security, smack_inode_free_security),
LSM_HOOK_INIT(inode_init_security, smack_inode_init_security),
LSM_HOOK_INIT(inode_link, smack_inode_link),
LSM_HOOK_INIT(inode_unlink, smack_inode_unlink),
LSM_HOOK_INIT(inode_getsecid, smack_inode_getsecid),
LSM_HOOK_INIT(file_alloc_security, smack_file_alloc_security),
- LSM_HOOK_INIT(file_free_security, smack_file_free_security),
LSM_HOOK_INIT(file_ioctl, smack_file_ioctl),
LSM_HOOK_INIT(file_lock, smack_file_lock),
LSM_HOOK_INIT(file_fcntl, smack_file_fcntl),
LSM_HOOK_INIT(ipc_getsecid, smack_ipc_getsecid),
LSM_HOOK_INIT(msg_msg_alloc_security, smack_msg_msg_alloc_security),
- LSM_HOOK_INIT(msg_msg_free_security, smack_msg_msg_free_security),
LSM_HOOK_INIT(msg_queue_alloc_security, smack_ipc_alloc_security),
- LSM_HOOK_INIT(msg_queue_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(msg_queue_associate, smack_msg_queue_associate),
LSM_HOOK_INIT(msg_queue_msgctl, smack_msg_queue_msgctl),
LSM_HOOK_INIT(msg_queue_msgsnd, smack_msg_queue_msgsnd),
LSM_HOOK_INIT(msg_queue_msgrcv, smack_msg_queue_msgrcv),
LSM_HOOK_INIT(shm_alloc_security, smack_ipc_alloc_security),
- LSM_HOOK_INIT(shm_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(shm_associate, smack_shm_associate),
LSM_HOOK_INIT(shm_shmctl, smack_shm_shmctl),
LSM_HOOK_INIT(shm_shmat, smack_shm_shmat),
LSM_HOOK_INIT(sem_alloc_security, smack_ipc_alloc_security),
- LSM_HOOK_INIT(sem_free_security, smack_ipc_free_security),
LSM_HOOK_INIT(sem_associate, smack_sem_associate),
LSM_HOOK_INIT(sem_semctl, smack_sem_semctl),
LSM_HOOK_INIT(sem_semop, smack_sem_semop),
*/
static __init int smack_init(void)
{
- struct cred *cred;
+ struct cred *cred = (struct cred *) current->cred;
struct task_smack *tsp;
- if (!security_module_enable("smack"))
- return 0;
-
smack_inode_cache = KMEM_CACHE(inode_smack, 0);
if (!smack_inode_cache)
return -ENOMEM;
- tsp = new_task_smack(&smack_known_floor, &smack_known_floor,
- GFP_KERNEL);
- if (tsp == NULL) {
- kmem_cache_destroy(smack_inode_cache);
- return -ENOMEM;
- }
+ /*
+ * Set the security state for the initial task.
+ */
+ tsp = smack_cred(cred);
+ init_task_smack(tsp, &smack_known_floor, &smack_known_floor);
+ /*
+ * Register with LSM
+ */
+ security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
smack_enabled = 1;
pr_info("Smack: Initializing.\n");
pr_info("Smack: IPv6 Netfilter enabled.\n");
#endif
- /*
- * Set the security state for the initial task.
- */
- cred = (struct cred *) current->cred;
- cred->security = tsp;
-
/* initialize the smack_known_list */
init_smack_known_list();
- /*
- * Register with LSM
- */
- security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
-
return 0;
}
*/
DEFINE_LSM(smack) = {
.name = "smack",
+ .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
+ .blobs = &smack_blob_sizes,
.init = smack_init,
};