Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-2.0-only
config SECURITY_SMACK
bool "Simplified Mandatory Access Control Kernel Support"
depends on NET
depends on INET
depends on SECURITY
select NETLABEL
select SECURITY_NETWORK
default n
help
This selects the Simplified Mandatory Access Control Kernel.
Smack is useful for sensitivity, integrity, and a variety
of other mandatory security schemes.
If you are unsure how to answer this question, answer N.
config SECURITY_SMACK_BRINGUP
bool "Reporting on access granted by Smack rules"
depends on SECURITY_SMACK
default n
help
Enable the bring-up ("b") access mode in Smack rules.
When access is granted by a rule with the "b" mode a
message about the access requested is generated. The
intention is that a process can be granted a wide set
of access initially with the bringup mode set on the
rules. The developer can use the information to
identify which rules are necessary and what accesses
may be inappropriate. The developer can reduce the
access rule set once the behavior is well understood.
This is a superior mechanism to the oft abused
"permissive" mode of other systems.
If you are unsure how to answer this question, answer N.
config SECURITY_SMACK_NETFILTER
bool "Packet marking using secmarks for netfilter"
depends on SECURITY_SMACK
depends on NETWORK_SECMARK
depends on NETFILTER
default n
help
This enables security marking of network packets using
Smack labels.
If you are unsure how to answer this question, answer N.
config SECURITY_SMACK_APPEND_SIGNALS
bool "Treat delivering signals as an append operation"
depends on SECURITY_SMACK
default n
help
Sending a signal has been treated as a write operation to the
receiving process. If this option is selected, the delivery
will be an append operation instead. This makes it possible
to differentiate between delivering a network packet and
delivering a signal in the Smack rules.
If you are unsure how to answer this question, answer N.
+9
View File
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
#
# Makefile for the SMACK LSM
#
obj-$(CONFIG_SECURITY_SMACK) := smack.o
smack-y := smack_lsm.o smack_access.o smackfs.o
smack-$(CONFIG_SECURITY_SMACK_NETFILTER) += smack_netfilter.o
+541
View File
@@ -0,0 +1,541 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
*
* Author:
* Casey Schaufler <casey@schaufler-ca.com>
*/
#ifndef _SECURITY_SMACK_H
#define _SECURITY_SMACK_H
#include <linux/capability.h>
#include <linux/spinlock.h>
#include <linux/lsm_hooks.h>
#include <linux/in.h>
#if IS_ENABLED(CONFIG_IPV6)
#include <linux/in6.h>
#endif /* CONFIG_IPV6 */
#include <net/netlabel.h>
#include <linux/list.h>
#include <linux/rculist.h>
#include <linux/lsm_audit.h>
#include <linux/msg.h>
/*
* Use IPv6 port labeling if IPv6 is enabled and secmarks
* are not being used.
*/
#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER)
#define SMACK_IPV6_PORT_LABELING 1
#endif
#if IS_ENABLED(CONFIG_IPV6) && defined(CONFIG_SECURITY_SMACK_NETFILTER)
#define SMACK_IPV6_SECMARK_LABELING 1
#endif
/*
* Smack labels were limited to 23 characters for a long time.
*/
#define SMK_LABELLEN 24
#define SMK_LONGLABEL 256
/*
* This is the repository for labels seen so that it is
* not necessary to keep allocating tiny chunks of memory
* and so that they can be shared.
*
* Labels are never modified in place. Anytime a label
* is imported (e.g. xattrset on a file) the list is checked
* for it and it is added if it doesn't exist. The address
* is passed out in either case. Entries are added, but
* never deleted.
*
* Since labels are hanging around anyway it doesn't
* hurt to maintain a secid for those awkward situations
* where kernel components that ought to use LSM independent
* interfaces don't. The secid should go away when all of
* these components have been repaired.
*
* The cipso value associated with the label gets stored here, too.
*
* Keep the access rules for this subject label here so that
* the entire set of rules does not need to be examined every
* time.
*/
struct smack_known {
struct list_head list;
struct hlist_node smk_hashed;
char *smk_known;
u32 smk_secid;
struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */
struct list_head smk_rules; /* access rules */
struct mutex smk_rules_lock; /* lock for rules */
};
/*
* Maximum number of bytes for the levels in a CIPSO IP option.
* Why 23? CIPSO is constrained to 30, so a 32 byte buffer is
* bigger than can be used, and 24 is the next lower multiple
* of 8, and there are too many issues if there isn't space set
* aside for the terminating null byte.
*/
#define SMK_CIPSOLEN 24
struct superblock_smack {
struct smack_known *smk_root;
struct smack_known *smk_floor;
struct smack_known *smk_hat;
struct smack_known *smk_default;
int smk_flags;
};
/*
* Superblock flags
*/
#define SMK_SB_INITIALIZED 0x01
#define SMK_SB_UNTRUSTED 0x02
struct socket_smack {
struct smack_known *smk_out; /* outbound label */
struct smack_known *smk_in; /* inbound label */
struct smack_known *smk_packet; /* TCP peer label */
int smk_state; /* netlabel socket states */
};
#define SMK_NETLBL_UNSET 0
#define SMK_NETLBL_UNLABELED 1
#define SMK_NETLBL_LABELED 2
#define SMK_NETLBL_REQSKB 3
/*
* Inode smack data
*/
struct inode_smack {
struct smack_known *smk_inode; /* label of the fso */
struct smack_known *smk_task; /* label of the task */
struct smack_known *smk_mmap; /* label of the mmap domain */
int smk_flags; /* smack inode flags */
};
struct task_smack {
struct smack_known *smk_task; /* label for access control */
struct smack_known *smk_forked; /* label when forked */
struct smack_known *smk_transmuted;/* label when transmuted */
struct list_head smk_rules; /* per task access rules */
struct mutex smk_rules_lock; /* lock for the rules */
struct list_head smk_relabel; /* transit allowed labels */
};
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
#define SMK_INODE_CHANGED 0x04 /* smack was transmuted (unused) */
#define SMK_INODE_IMPURE 0x08 /* involved in an impure transaction */
/*
* A label access rule.
*/
struct smack_rule {
struct list_head list;
struct smack_known *smk_subject;
struct smack_known *smk_object;
int smk_access;
};
/*
* An entry in the table identifying IPv4 hosts.
*/
struct smk_net4addr {
struct list_head list;
struct in_addr smk_host; /* network address */
struct in_addr smk_mask; /* network mask */
int smk_masks; /* mask size */
struct smack_known *smk_label; /* label */
};
#if IS_ENABLED(CONFIG_IPV6)
/*
* An entry in the table identifying IPv6 hosts.
*/
struct smk_net6addr {
struct list_head list;
struct in6_addr smk_host; /* network address */
struct in6_addr smk_mask; /* network mask */
int smk_masks; /* mask size */
struct smack_known *smk_label; /* label */
};
#endif /* CONFIG_IPV6 */
#ifdef SMACK_IPV6_PORT_LABELING
/*
* An entry in the table identifying ports.
*/
struct smk_port_label {
struct list_head list;
struct sock *smk_sock; /* socket initialized on */
unsigned short smk_port; /* the port number */
struct smack_known *smk_in; /* inbound label */
struct smack_known *smk_out; /* outgoing label */
short smk_sock_type; /* Socket type */
short smk_can_reuse;
};
#endif /* SMACK_IPV6_PORT_LABELING */
struct smack_known_list_elem {
struct list_head list;
struct smack_known *smk_label;
};
enum {
Opt_error = -1,
Opt_fsdefault = 0,
Opt_fsfloor = 1,
Opt_fshat = 2,
Opt_fsroot = 3,
Opt_fstransmute = 4,
};
#define SMACK_DELETE_OPTION "-DELETE"
#define SMACK_CIPSO_OPTION "-CIPSO"
/*
* CIPSO defaults.
*/
#define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */
#define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */
#define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */
#define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */
#define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */
/*
* CIPSO 2.2 standard is 239, but Smack wants to use the
* categories in a structured way that limits the value to
* the bits in 23 bytes, hence the unusual number.
*/
#define SMACK_CIPSO_MAXCATNUM 184 /* 23 * 8 */
/*
* Ptrace rules
*/
#define SMACK_PTRACE_DEFAULT 0
#define SMACK_PTRACE_EXACT 1
#define SMACK_PTRACE_DRACONIAN 2
#define SMACK_PTRACE_MAX SMACK_PTRACE_DRACONIAN
/*
* Flags for untraditional access modes.
* It shouldn't be necessary to avoid conflicts with definitions
* in fs.h, but do so anyway.
*/
#define MAY_TRANSMUTE 0x00001000 /* Controls directory labeling */
#define MAY_LOCK 0x00002000 /* Locks should be writes, but ... */
#define MAY_BRINGUP 0x00004000 /* Report use of this rule */
/*
* The policy for delivering signals is configurable.
* It is usually "write", but can be "append".
*/
#ifdef CONFIG_SECURITY_SMACK_APPEND_SIGNALS
#define MAY_DELIVER MAY_APPEND /* Signal delivery requires append */
#else
#define MAY_DELIVER MAY_WRITE /* Signal delivery requires write */
#endif
#define SMACK_BRINGUP_ALLOW 1 /* Allow bringup mode */
#define SMACK_UNCONFINED_SUBJECT 2 /* Allow unconfined label */
#define SMACK_UNCONFINED_OBJECT 3 /* Allow unconfined label */
/*
* Just to make the common cases easier to deal with
*/
#define MAY_ANYREAD (MAY_READ | MAY_EXEC)
#define MAY_READWRITE (MAY_READ | MAY_WRITE)
#define MAY_NOT 0
/*
* Number of access types used by Smack (rwxatlb)
*/
#define SMK_NUM_ACCESS_TYPE 7
/* SMACK data */
struct smack_audit_data {
const char *function;
char *subject;
char *object;
char *request;
int result;
};
/*
* Smack audit data; is empty if CONFIG_AUDIT not set
* to save some stack
*/
struct smk_audit_info {
#ifdef CONFIG_AUDIT
struct common_audit_data a;
struct smack_audit_data sad;
#endif
};
/*
* Initialization
*/
#if defined(CONFIG_SECURITY_SMACK_NETFILTER)
int smack_nf_ip_init(void);
#else
static inline int smack_nf_ip_init(void)
{
return 0;
}
#endif
int init_smk_fs(void);
int smack_initcall(void);
/*
* These functions are in smack_access.c
*/
int smk_access_entry(char *, char *, struct list_head *);
int smk_access(struct smack_known *, struct smack_known *,
int, struct smk_audit_info *);
int smk_tskacc(struct task_smack *, struct smack_known *,
u32, struct smk_audit_info *);
int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
int smack_str_from_perm(char *string, int access);
struct smack_known *smack_from_secid(const u32);
int smk_parse_label_len(const char *string, int len);
char *smk_parse_smack(const char *string, int len);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
struct smack_known *smk_import_valid_label(const char *label, int label_len,
gfp_t gfp);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
bool smack_privileged(int cap);
bool smack_privileged_cred(int cap, const struct cred *cred);
void smk_destroy_label_list(struct list_head *list);
int smack_populate_secattr(struct smack_known *skp);
/*
* Shared data.
*/
extern int smack_enabled __initdata;
extern int smack_cipso_direct;
extern int smack_cipso_mapped;
extern struct smack_known *smack_net_ambient;
extern struct smack_known *smack_syslog_label;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
extern struct smack_known *smack_unconfined;
#endif
extern int smack_ptrace_rule;
extern struct lsm_blob_sizes smack_blob_sizes;
extern struct smack_known smack_known_floor;
extern struct smack_known smack_known_hat;
extern struct smack_known smack_known_huh;
extern struct smack_known smack_known_star;
extern struct smack_known smack_known_web;
extern struct mutex smack_known_lock;
extern struct list_head smack_known_list;
extern struct list_head smk_net4addr_list;
#if IS_ENABLED(CONFIG_IPV6)
extern struct list_head smk_net6addr_list;
#endif /* CONFIG_IPV6 */
extern struct mutex smack_onlycap_lock;
extern struct list_head smack_onlycap_list;
#define SMACK_HASH_SLOTS 16
extern struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
extern struct kmem_cache *smack_rule_cache;
static inline struct task_smack *smack_cred(const struct cred *cred)
{
return cred->security + smack_blob_sizes.lbs_cred;
}
static inline struct smack_known **smack_file(const struct file *file)
{
return (struct smack_known **)(file->f_security +
smack_blob_sizes.lbs_file);
}
static inline struct inode_smack *smack_inode(const struct inode *inode)
{
return inode->i_security + smack_blob_sizes.lbs_inode;
}
static inline struct smack_known **smack_msg_msg(const struct msg_msg *msg)
{
return msg->security + smack_blob_sizes.lbs_msg_msg;
}
static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
{
return ipc->security + smack_blob_sizes.lbs_ipc;
}
static inline struct superblock_smack *smack_superblock(
const struct super_block *superblock)
{
return superblock->s_security + smack_blob_sizes.lbs_superblock;
}
static inline struct socket_smack *smack_sock(const struct sock *sock)
{
return sock->sk_security + smack_blob_sizes.lbs_sock;
}
#ifdef CONFIG_KEYS
static inline struct smack_known **smack_key(const struct key *key)
{
return key->security + smack_blob_sizes.lbs_key;
}
#endif /* CONFIG_KEYS */
/*
* Is the directory transmuting?
*/
static inline int smk_inode_transmutable(const struct inode *isp)
{
struct inode_smack *sip = smack_inode(isp);
return (sip->smk_flags & SMK_INODE_TRANSMUTE) != 0;
}
/*
* Present a pointer to the smack label entry in an inode blob.
*/
static inline struct smack_known *smk_of_inode(const struct inode *isp)
{
struct inode_smack *sip = smack_inode(isp);
return sip->smk_inode;
}
/*
* Present a pointer to the smack label entry in an task blob.
*/
static inline struct smack_known *smk_of_task(const struct task_smack *tsp)
{
return tsp->smk_task;
}
static inline struct smack_known *smk_of_task_struct_obj(
const struct task_struct *t)
{
struct smack_known *skp;
const struct cred *cred;
rcu_read_lock();
cred = __task_cred(t);
skp = smk_of_task(smack_cred(cred));
rcu_read_unlock();
return skp;
}
/*
* Present a pointer to the forked smack label entry in an task blob.
*/
static inline struct smack_known *smk_of_forked(const struct task_smack *tsp)
{
return tsp->smk_forked;
}
/*
* Present a pointer to the smack label in the current task blob.
*/
static inline struct smack_known *smk_of_current(void)
{
return smk_of_task(smack_cred(current_cred()));
}
void smack_log(char *subject_label, char *object_label,
int request,
int result, struct smk_audit_info *auditdata);
#ifdef CONFIG_AUDIT
/*
* logging functions
*/
#define SMACK_AUDIT_DENIED 0x1
#define SMACK_AUDIT_ACCEPT 0x2
extern int log_policy;
/*
* some inline functions to set up audit data
* they do nothing if CONFIG_AUDIT is not set
*
*/
static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
char type)
{
memset(&a->sad, 0, sizeof(a->sad));
a->a.type = type;
a->a.smack_audit_data = &a->sad;
a->a.smack_audit_data->function = func;
}
static inline void smk_ad_init_net(struct smk_audit_info *a, const char *func,
char type, struct lsm_network_audit *net)
{
smk_ad_init(a, func, type);
memset(net, 0, sizeof(*net));
a->a.u.net = net;
}
static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
struct task_struct *t)
{
a->a.u.tsk = t;
}
static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
struct dentry *d)
{
a->a.u.dentry = d;
}
static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
struct inode *i)
{
a->a.u.inode = i;
}
static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
struct path p)
{
a->a.u.path = p;
}
static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
struct sock *sk)
{
a->a.u.net->sk = sk;
}
#else /* no AUDIT */
static inline void smk_ad_init(struct smk_audit_info *a, const char *func,
char type)
{
}
static inline void smk_ad_setfield_u_tsk(struct smk_audit_info *a,
struct task_struct *t)
{
}
static inline void smk_ad_setfield_u_fs_path_dentry(struct smk_audit_info *a,
struct dentry *d)
{
}
static inline void smk_ad_setfield_u_fs_inode(struct smk_audit_info *a,
struct inode *i)
{
}
static inline void smk_ad_setfield_u_fs_path(struct smk_audit_info *a,
struct path p)
{
}
static inline void smk_ad_setfield_u_net_sk(struct smk_audit_info *a,
struct sock *sk)
{
}
#endif
#endif /* _SECURITY_SMACK_H */
+756
View File
@@ -0,0 +1,756 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com>
*
* Author:
* Casey Schaufler <casey@schaufler-ca.com>
*/
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include "smack.h"
struct smack_known smack_known_huh = {
.smk_known = "?",
.smk_secid = 2,
};
struct smack_known smack_known_hat = {
.smk_known = "^",
.smk_secid = 3,
};
struct smack_known smack_known_star = {
.smk_known = "*",
.smk_secid = 4,
};
struct smack_known smack_known_floor = {
.smk_known = "_",
.smk_secid = 5,
};
struct smack_known smack_known_web = {
.smk_known = "@",
.smk_secid = 7,
};
LIST_HEAD(smack_known_list);
/*
* The initial value needs to be bigger than any of the
* known values above.
*/
static u32 smack_next_secid = 10;
#ifdef CONFIG_AUDIT
/*
* what events do we log
* can be overwritten at run-time by /smack/logging
*/
int log_policy = SMACK_AUDIT_DENIED;
#endif /* CONFIG_AUDIT */
/**
* smk_access_entry - look up matching access rule
* @subject_label: a pointer to the subject's Smack label
* @object_label: a pointer to the object's Smack label
* @rule_list: the list of rules to search
*
* This function looks up the subject/object pair in the
* access rule list and returns the access mode. If no
* entry is found returns -ENOENT.
*
* NOTE:
*
* Earlier versions of this function allowed for labels that
* were not on the label list. This was done to allow for
* labels to come over the network that had never been seen
* before on this host. Unless the receiving socket has the
* star label this will always result in a failure check. The
* star labeled socket case is now handled in the networking
* hooks so there is no case where the label is not on the
* label list. Checking to see if the address of two labels
* is the same is now a reliable test.
*
* Do the object check first because that is more
* likely to differ.
*
* Allowing write access implies allowing locking.
*/
int smk_access_entry(char *subject_label, char *object_label,
struct list_head *rule_list)
{
struct smack_rule *srp;
list_for_each_entry_rcu(srp, rule_list, list) {
if (srp->smk_object->smk_known == object_label &&
srp->smk_subject->smk_known == subject_label) {
int may = srp->smk_access;
/*
* MAY_WRITE implies MAY_LOCK.
*/
if ((may & MAY_WRITE) == MAY_WRITE)
may |= MAY_LOCK;
return may;
}
}
return -ENOENT;
}
/**
* smk_access - determine if a subject has a specific access to an object
* @subject: a pointer to the subject's Smack label entry
* @object: a pointer to the object's Smack label entry
* @request: the access requested, in "MAY" format
* @a : a pointer to the audit data
*
* This function looks up the subject/object pair in the
* access rule list and returns 0 if the access is permitted,
* non zero otherwise.
*
* Smack labels are shared on smack_list
*/
int smk_access(struct smack_known *subject, struct smack_known *object,
int request, struct smk_audit_info *a)
{
int may = MAY_NOT;
int rc = 0;
/*
* Hardcoded comparisons.
*/
/*
* A star subject can't access any object.
*/
if (subject == &smack_known_star) {
rc = -EACCES;
goto out_audit;
}
/*
* An internet object can be accessed by any subject.
* Tasks cannot be assigned the internet label.
* An internet subject can access any object.
*/
if (object == &smack_known_web || subject == &smack_known_web)
goto out_audit;
/*
* A star object can be accessed by any subject.
*/
if (object == &smack_known_star)
goto out_audit;
/*
* An object can be accessed in any way by a subject
* with the same label.
*/
if (subject->smk_known == object->smk_known)
goto out_audit;
/*
* A hat subject can read or lock any object.
* A floor object can be read or locked by any subject.
*/
if ((request & MAY_ANYREAD) == request ||
(request & MAY_LOCK) == request) {
if (object == &smack_known_floor)
goto out_audit;
if (subject == &smack_known_hat)
goto out_audit;
}
/*
* Beyond here an explicit relationship is required.
* If the requested access is contained in the available
* access (e.g. read is included in readwrite) it's
* good. A negative response from smk_access_entry()
* indicates there is no entry for this pair.
*/
rcu_read_lock();
may = smk_access_entry(subject->smk_known, object->smk_known,
&subject->smk_rules);
rcu_read_unlock();
if (may <= 0 || (request & may) != request) {
rc = -EACCES;
goto out_audit;
}
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
/*
* Return a positive value if using bringup mode.
* This allows the hooks to identify checks that
* succeed because of "b" rules.
*/
if (may & MAY_BRINGUP)
rc = SMACK_BRINGUP_ALLOW;
#endif
out_audit:
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
if (rc < 0) {
if (object == smack_unconfined)
rc = SMACK_UNCONFINED_OBJECT;
if (subject == smack_unconfined)
rc = SMACK_UNCONFINED_SUBJECT;
}
#endif
#ifdef CONFIG_AUDIT
if (a)
smack_log(subject->smk_known, object->smk_known,
request, rc, a);
#endif
return rc;
}
/**
* smk_tskacc - determine if a task has a specific access to an object
* @tsp: a pointer to the subject's task
* @obj_known: a pointer to the object's label entry
* @mode: the access requested, in "MAY" format
* @a : common audit data
*
* This function checks the subject task's label/object label pair
* in the access rule list and returns 0 if the access is permitted,
* non zero otherwise. It allows that the task may have the capability
* to override the rules.
*/
int smk_tskacc(struct task_smack *tsp, struct smack_known *obj_known,
u32 mode, struct smk_audit_info *a)
{
struct smack_known *sbj_known = smk_of_task(tsp);
int may;
int rc;
/*
* Check the global rule list
*/
rc = smk_access(sbj_known, obj_known, mode, NULL);
if (rc >= 0) {
/*
* If there is an entry in the task's rule list
* it can further restrict access.
*/
may = smk_access_entry(sbj_known->smk_known,
obj_known->smk_known,
&tsp->smk_rules);
if (may < 0)
goto out_audit;
if ((mode & may) == mode)
goto out_audit;
rc = -EACCES;
}
/*
* Allow for privileged to override policy.
*/
if (rc != 0 && smack_privileged(CAP_MAC_OVERRIDE))
rc = 0;
out_audit:
#ifdef CONFIG_AUDIT
if (a)
smack_log(sbj_known->smk_known, obj_known->smk_known,
mode, rc, a);
#endif
return rc;
}
/**
* smk_curacc - determine if current has a specific access to an object
* @obj_known: a pointer to the object's Smack label entry
* @mode: the access requested, in "MAY" format
* @a : common audit data
*
* This function checks the current subject label/object label pair
* in the access rule list and returns 0 if the access is permitted,
* non zero otherwise. It allows that current may have the capability
* to override the rules.
*/
int smk_curacc(struct smack_known *obj_known,
u32 mode, struct smk_audit_info *a)
{
struct task_smack *tsp = smack_cred(current_cred());
return smk_tskacc(tsp, obj_known, mode, a);
}
/**
* smack_str_from_perm : helper to translate an int to a
* readable string
* @string : the string to fill
* @access : the int
*
*/
int smack_str_from_perm(char *string, int access)
{
int i = 0;
if (access & MAY_READ)
string[i++] = 'r';
if (access & MAY_WRITE)
string[i++] = 'w';
if (access & MAY_EXEC)
string[i++] = 'x';
if (access & MAY_APPEND)
string[i++] = 'a';
if (access & MAY_TRANSMUTE)
string[i++] = 't';
if (access & MAY_LOCK)
string[i++] = 'l';
if (access & MAY_BRINGUP)
string[i++] = 'b';
if (i == 0)
string[i++] = '-';
string[i] = '\0';
return i;
}
#ifdef CONFIG_AUDIT
/**
* smack_log_callback - SMACK specific information
* will be called by generic audit code
* @ab : the audit_buffer
* @a : audit_data
*
*/
static void smack_log_callback(struct audit_buffer *ab, void *a)
{
struct common_audit_data *ad = a;
struct smack_audit_data *sad = ad->smack_audit_data;
audit_log_format(ab, "lsm=SMACK fn=%s action=%s",
ad->smack_audit_data->function,
sad->result ? "denied" : "granted");
audit_log_format(ab, " subject=");
audit_log_untrustedstring(ab, sad->subject);
audit_log_format(ab, " object=");
audit_log_untrustedstring(ab, sad->object);
if (sad->request[0] == '\0')
audit_log_format(ab, " labels_differ");
else
audit_log_format(ab, " requested=%s", sad->request);
}
/**
* smack_log - Audit the granting or denial of permissions.
* @subject_label : smack label of the requester
* @object_label : smack label of the object being accessed
* @request: requested permissions
* @result: result from smk_access
* @ad: auxiliary audit data
*
* Audit the granting or denial of permissions in accordance
* with the policy.
*/
void smack_log(char *subject_label, char *object_label, int request,
int result, struct smk_audit_info *ad)
{
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
char request_buffer[SMK_NUM_ACCESS_TYPE + 5];
#else
char request_buffer[SMK_NUM_ACCESS_TYPE + 1];
#endif
struct smack_audit_data *sad;
struct common_audit_data *a = &ad->a;
/* check if we have to log the current event */
if (result < 0 && (log_policy & SMACK_AUDIT_DENIED) == 0)
return;
if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0)
return;
sad = a->smack_audit_data;
if (sad->function == NULL)
sad->function = "unknown";
/* end preparing the audit data */
smack_str_from_perm(request_buffer, request);
sad->subject = subject_label;
sad->object = object_label;
#ifdef CONFIG_SECURITY_SMACK_BRINGUP
/*
* The result may be positive in bringup mode.
* A positive result is an allow, but not for normal reasons.
* Mark it as successful, but don't filter it out even if
* the logging policy says to do so.
*/
if (result == SMACK_UNCONFINED_SUBJECT)
strcat(request_buffer, "(US)");
else if (result == SMACK_UNCONFINED_OBJECT)
strcat(request_buffer, "(UO)");
if (result > 0)
result = 0;
#endif
sad->request = request_buffer;
sad->result = result;
common_lsm_audit(a, smack_log_callback, NULL);
}
#else /* #ifdef CONFIG_AUDIT */
void smack_log(char *subject_label, char *object_label, int request,
int result, struct smk_audit_info *ad)
{
}
#endif
DEFINE_MUTEX(smack_known_lock);
struct hlist_head smack_known_hash[SMACK_HASH_SLOTS];
/**
* smk_insert_entry - insert a smack label into a hash map,
* @skp: smack label
*
* this function must be called under smack_known_lock
*/
void smk_insert_entry(struct smack_known *skp)
{
unsigned int hash;
struct hlist_head *head;
hash = full_name_hash(NULL, skp->smk_known, strlen(skp->smk_known));
head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
hlist_add_head_rcu(&skp->smk_hashed, head);
list_add_rcu(&skp->list, &smack_known_list);
}
/**
* smk_find_entry - find a label on the list, return the list entry
* @string: a text string that might be a Smack label
*
* Returns a pointer to the entry in the label list that
* matches the passed string or NULL if not found.
*/
struct smack_known *smk_find_entry(const char *string)
{
unsigned int hash;
struct hlist_head *head;
struct smack_known *skp;
hash = full_name_hash(NULL, string, strlen(string));
head = &smack_known_hash[hash & (SMACK_HASH_SLOTS - 1)];
hlist_for_each_entry_rcu(skp, head, smk_hashed)
if (strcmp(skp->smk_known, string) == 0)
return skp;
return NULL;
}
/**
* smk_parse_label_len - calculate the length of the starting segment
* in the string that constitutes a valid smack label
* @string: a text string that might contain a Smack label at the beginning
* @len: the maximum size to look into, may be zero if string is null-terminated
*
* Returns the length of the segment (0 < L < SMK_LONGLABEL) or an error code.
*/
int smk_parse_label_len(const char *string, int len)
{
int i;
if (len <= 0 || len > SMK_LONGLABEL)
len = SMK_LONGLABEL;
/*
* Reserve a leading '-' as an indicator that
* this isn't a label, but an option to interfaces
* including /smack/cipso and /smack/cipso2
*/
if (string[0] == '-')
return -EINVAL;
for (i = 0; i < len; i++)
if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
string[i] == '"' || string[i] == '\\' || string[i] == '\'')
break;
if (i == 0 || i >= SMK_LONGLABEL)
return -EINVAL;
return i;
}
/**
* smk_parse_smack - copy the starting segment in the string
* that constitutes a valid smack label
* @string: a text string that might contain a Smack label at the beginning
* @len: the maximum size to look into, may be zero if string is null-terminated
*
* Returns a pointer to the copy of the label or an error code.
*/
char *smk_parse_smack(const char *string, int len)
{
char *smack;
int i = smk_parse_label_len(string, len);
if (i < 0)
return ERR_PTR(-EINVAL);
smack = kstrndup(string, i, GFP_NOFS);
if (!smack)
return ERR_PTR(-ENOMEM);
return smack;
}
/**
* smk_netlbl_mls - convert a catset to netlabel mls categories
* @level: MLS sensitivity level
* @catset: the Smack categories
* @sap: where to put the netlabel categories
* @len: number of bytes for the levels in a CIPSO IP option
*
* Allocates and fills attr.mls
* Returns 0 on success, error code on failure.
*/
int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
int len)
{
unsigned char *cp;
unsigned char m;
int cat;
int rc;
int byte;
sap->flags |= NETLBL_SECATTR_MLS_CAT;
sap->attr.mls.lvl = level;
sap->attr.mls.cat = NULL;
for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++)
for (m = 0x80; m != 0; m >>= 1, cat++) {
if ((m & *cp) == 0)
continue;
rc = netlbl_catmap_setbit(&sap->attr.mls.cat,
cat, GFP_NOFS);
if (rc < 0) {
netlbl_catmap_free(sap->attr.mls.cat);
return rc;
}
}
return 0;
}
/**
* smack_populate_secattr - fill in the smack_known netlabel information
* @skp: pointer to the structure to fill
*
* Populate the netlabel secattr structure for a Smack label.
*
* Returns 0 unless creating the category mapping fails
*/
int smack_populate_secattr(struct smack_known *skp)
{
int slen;
skp->smk_netlabel.attr.secid = skp->smk_secid;
skp->smk_netlabel.domain = skp->smk_known;
skp->smk_netlabel.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
if (skp->smk_netlabel.cache != NULL) {
skp->smk_netlabel.flags |= NETLBL_SECATTR_CACHE;
skp->smk_netlabel.cache->free = NULL;
skp->smk_netlabel.cache->data = skp;
}
skp->smk_netlabel.flags |= NETLBL_SECATTR_SECID |
NETLBL_SECATTR_MLS_LVL |
NETLBL_SECATTR_DOMAIN;
/*
* If direct labeling works use it.
* Otherwise use mapped labeling.
*/
slen = strlen(skp->smk_known);
if (slen < SMK_CIPSOLEN)
return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
&skp->smk_netlabel, slen);
return smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
&skp->smk_netlabel, sizeof(skp->smk_secid));
}
/**
* smk_import_valid_allocated_label - import a label, return the list entry
* @smack: a text string that is a valid Smack label and may be kfree()ed.
* It is consumed: either becomes a part of the entry or kfree'ed.
* @gfp: Allocation type
*
* Returns: see description of smk_import_entry()
*/
static struct smack_known *
smk_import_allocated_label(char *smack, gfp_t gfp)
{
struct smack_known *skp;
int rc;
mutex_lock(&smack_known_lock);
skp = smk_find_entry(smack);
if (skp != NULL)
goto freeout;
skp = kzalloc_obj(*skp, gfp);
if (skp == NULL) {
skp = ERR_PTR(-ENOMEM);
goto freeout;
}
skp->smk_known = smack;
skp->smk_secid = smack_next_secid++;
rc = smack_populate_secattr(skp);
if (rc >= 0) {
INIT_LIST_HEAD(&skp->smk_rules);
mutex_init(&skp->smk_rules_lock);
/*
* Make sure that the entry is actually
* filled before putting it on the list.
*/
smk_insert_entry(skp);
goto unlockout;
}
kfree(skp);
skp = ERR_PTR(rc);
freeout:
kfree(smack);
unlockout:
mutex_unlock(&smack_known_lock);
return skp;
}
/**
* smk_import_entry - import a label, return the list entry
* @string: a text string that might contain a Smack label at the beginning
* @len: the maximum size to look into, may be zero if string is null-terminated
*
* Returns a pointer to the entry in the label list that
* matches the passed string, adding it if necessary,
* or an error code.
*/
struct smack_known *smk_import_entry(const char *string, int len)
{
char *smack = smk_parse_smack(string, len);
if (IS_ERR(smack))
return ERR_CAST(smack);
return smk_import_allocated_label(smack, GFP_NOFS);
}
/**
* smk_import_valid_label - import a label, return the list entry
* @label: a text string that is a valid Smack label, not null-terminated
* @label_len: the length of the text string in the @label
* @gfp: the GFP mask used for allocating memory for the @label text string copy
*
* Return: see description of smk_import_entry()
*/
struct smack_known *
smk_import_valid_label(const char *label, int label_len, gfp_t gfp)
{
char *smack = kstrndup(label, label_len, gfp);
if (!smack)
return ERR_PTR(-ENOMEM);
return smk_import_allocated_label(smack, gfp);
}
/**
* smack_from_secid - find the Smack label associated with a secid
* @secid: an integer that might be associated with a Smack label
*
* Returns a pointer to the appropriate Smack label entry if there is one,
* otherwise a pointer to the invalid Smack label.
*/
struct smack_known *smack_from_secid(const u32 secid)
{
struct smack_known *skp;
rcu_read_lock();
list_for_each_entry_rcu(skp, &smack_known_list, list) {
if (skp->smk_secid == secid) {
rcu_read_unlock();
return skp;
}
}
/*
* If we got this far someone asked for the translation
* of a secid that is not on the list.
*/
rcu_read_unlock();
return &smack_known_huh;
}
/*
* Unless a process is running with one of these labels
* even having CAP_MAC_OVERRIDE isn't enough to grant
* privilege to violate MAC policy. If no labels are
* designated (the empty list case) capabilities apply to
* everyone.
*/
LIST_HEAD(smack_onlycap_list);
DEFINE_MUTEX(smack_onlycap_lock);
/**
* smack_privileged_cred - are all privilege requirements met by cred
* @cap: The requested capability
* @cred: the credential to use
*
* Is the task privileged and allowed to be privileged
* by the onlycap rule.
*
* Returns true if the task is allowed to be privileged, false if it's not.
*/
bool smack_privileged_cred(int cap, const struct cred *cred)
{
struct task_smack *tsp = smack_cred(cred);
struct smack_known *skp = tsp->smk_task;
struct smack_known_list_elem *sklep;
int rc;
rc = cap_capable(cred, &init_user_ns, cap, CAP_OPT_NONE);
if (rc)
return false;
rcu_read_lock();
if (list_empty(&smack_onlycap_list)) {
rcu_read_unlock();
return true;
}
list_for_each_entry_rcu(sklep, &smack_onlycap_list, list) {
if (sklep->smk_label == skp) {
rcu_read_unlock();
return true;
}
}
rcu_read_unlock();
return false;
}
/**
* smack_privileged - are all privilege requirements met
* @cap: The requested capability
*
* Is the task privileged and allowed to be privileged
* by the onlycap rule.
*
* Returns true if the task is allowed to be privileged, false if it's not.
*/
bool smack_privileged(int cap)
{
/*
* All kernel tasks are privileged
*/
if (unlikely(current->flags & PF_KTHREAD))
return true;
return smack_privileged_cred(cap, current_cred());
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Simplified MAC Kernel (smack) security module
*
* This file contains the Smack netfilter implementation
*
* Author:
* Casey Schaufler <casey@schaufler-ca.com>
*
* Copyright (C) 2014 Casey Schaufler <casey@schaufler-ca.com>
* Copyright (C) 2014 Intel Corporation.
*/
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netdevice.h>
#include <net/inet_sock.h>
#include <net/net_namespace.h>
#include "smack.h"
static unsigned int smack_ip_output(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
struct sock *sk = skb_to_full_sk(skb);
struct socket_smack *ssp;
struct smack_known *skp;
if (sk) {
ssp = smack_sock(sk);
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
}
return NF_ACCEPT;
}
static const struct nf_hook_ops smack_nf_ops[] = {
{
.hook = smack_ip_output,
.pf = NFPROTO_IPV4,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP_PRI_SELINUX_FIRST,
},
#if IS_ENABLED(CONFIG_IPV6)
{
.hook = smack_ip_output,
.pf = NFPROTO_IPV6,
.hooknum = NF_INET_LOCAL_OUT,
.priority = NF_IP6_PRI_SELINUX_FIRST,
},
#endif /* IPV6 */
};
static int __net_init smack_nf_register(struct net *net)
{
return nf_register_net_hooks(net, smack_nf_ops,
ARRAY_SIZE(smack_nf_ops));
}
static void __net_exit smack_nf_unregister(struct net *net)
{
nf_unregister_net_hooks(net, smack_nf_ops, ARRAY_SIZE(smack_nf_ops));
}
static struct pernet_operations smack_net_ops = {
.init = smack_nf_register,
.exit = smack_nf_unregister,
};
int __init smack_nf_ip_init(void)
{
if (smack_enabled == 0)
return 0;
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
return register_pernet_subsys(&smack_net_ops);
}
File diff suppressed because it is too large Load Diff