Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: "Changes for this kernel include maintenance updates for Smack, SELinux (and several networking fixes), IMA and TPM" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (39 commits) SELinux: Fix memory leak upon loading policy tpm/tpm-sysfs: active_show() can be static tpm: tpm_tis: Fix compile problems with CONFIG_PM_SLEEP/CONFIG_PNP tpm: Make tpm-dev allocate a per-file structure tpm: Use the ops structure instead of a copy in tpm_vendor_specific tpm: Create a tpm_class_ops structure and use it in the drivers tpm: Pull all driver sysfs code into tpm-sysfs.c tpm: Move sysfs functions from tpm-interface to tpm-sysfs tpm: Pull everything related to /dev/tpmX into tpm-dev.c char: tpm: nuvoton: remove unused variable tpm: MAINTAINERS: Cleanup TPM Maintainers file tpm/tpm_i2c_atmel: fix coccinelle warnings tpm/tpm_ibmvtpm: fix unreachable code warning (smatch warning) tpm/tpm_i2c_stm_st33: Check return code of get_burstcount tpm/tpm_ppi: Check return value of acpi_get_name tpm/tpm_ppi: Do not compare strcmp(a,b) == -1 ima: remove unneeded size_limit argument from ima_eventdigest_init_common() ima: update IMA-templates.txt documentation ima: pass HASH_ALGO__LAST as hash algo in ima_eventdigest_init() ima: change the default hash algorithm to SHA1 in ima_eventdigest_ng_init() ...
This commit is contained in:
@@ -162,8 +162,7 @@ void ima_show_template_sig(struct seq_file *m, enum ima_show_type show,
|
||||
}
|
||||
|
||||
static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
||||
struct ima_field_data *field_data,
|
||||
bool size_limit)
|
||||
struct ima_field_data *field_data)
|
||||
{
|
||||
/*
|
||||
* digest formats:
|
||||
@@ -176,11 +175,10 @@ static int ima_eventdigest_init_common(u8 *digest, u32 digestsize, u8 hash_algo,
|
||||
enum data_formats fmt = DATA_FMT_DIGEST;
|
||||
u32 offset = 0;
|
||||
|
||||
if (!size_limit) {
|
||||
if (hash_algo < HASH_ALGO__LAST) {
|
||||
fmt = DATA_FMT_DIGEST_WITH_ALGO;
|
||||
if (hash_algo < HASH_ALGO__LAST)
|
||||
offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1,
|
||||
"%s", hash_algo_name[hash_algo]);
|
||||
offset += snprintf(buffer, CRYPTO_MAX_ALG_NAME + 1, "%s",
|
||||
hash_algo_name[hash_algo]);
|
||||
buffer[offset] = ':';
|
||||
offset += 2;
|
||||
}
|
||||
@@ -243,8 +241,8 @@ int ima_eventdigest_init(struct integrity_iint_cache *iint, struct file *file,
|
||||
cur_digest = hash.hdr.digest;
|
||||
cur_digestsize = hash.hdr.length;
|
||||
out:
|
||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize, -1,
|
||||
field_data, true);
|
||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||
HASH_ALGO__LAST, field_data);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -255,7 +253,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
|
||||
struct evm_ima_xattr_data *xattr_value,
|
||||
int xattr_len, struct ima_field_data *field_data)
|
||||
{
|
||||
u8 *cur_digest = NULL, hash_algo = HASH_ALGO__LAST;
|
||||
u8 *cur_digest = NULL, hash_algo = HASH_ALGO_SHA1;
|
||||
u32 cur_digestsize = 0;
|
||||
|
||||
/* If iint is NULL, we are recording a violation. */
|
||||
@@ -268,7 +266,7 @@ int ima_eventdigest_ng_init(struct integrity_iint_cache *iint,
|
||||
hash_algo = iint->ima_hash->algo;
|
||||
out:
|
||||
return ima_eventdigest_init_common(cur_digest, cur_digestsize,
|
||||
hash_algo, field_data, false);
|
||||
hash_algo, field_data);
|
||||
}
|
||||
|
||||
static int ima_eventname_init_common(struct integrity_iint_cache *iint,
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
#include <linux/syslog.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/msg.h>
|
||||
#include <linux/shm.h>
|
||||
|
||||
@@ -4490,14 +4489,10 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
|
||||
{
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
int err;
|
||||
u16 family = sk->sk_family;
|
||||
u16 family = req->rsk_ops->family;
|
||||
u32 connsid;
|
||||
u32 peersid;
|
||||
|
||||
/* handle mapped IPv4 packets arriving via IPv6 sockets */
|
||||
if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
|
||||
family = PF_INET;
|
||||
|
||||
err = selinux_skb_peerlbl_sid(skb, family, &peersid);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -33,13 +33,14 @@
|
||||
#define POLICYDB_VERSION_ROLETRANS 26
|
||||
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
|
||||
#define POLICYDB_VERSION_DEFAULT_TYPE 28
|
||||
#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
|
||||
|
||||
/* Range of policy versions we understand*/
|
||||
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
|
||||
#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
|
||||
#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
|
||||
#else
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE
|
||||
#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES
|
||||
#endif
|
||||
|
||||
/* Mask for just the mount related flags */
|
||||
|
||||
@@ -100,6 +100,32 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
|
||||
return secattr;
|
||||
}
|
||||
|
||||
/**
|
||||
* selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
|
||||
* @sk: the socket
|
||||
* @sid: the SID
|
||||
*
|
||||
* Query the socket's cached secattr and if the SID matches the cached value
|
||||
* return the cache, otherwise return NULL.
|
||||
*
|
||||
*/
|
||||
static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
|
||||
const struct sock *sk,
|
||||
u32 sid)
|
||||
{
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
|
||||
|
||||
if (secattr == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((secattr->flags & NETLBL_SECATTR_SECID) &&
|
||||
(secattr->attr.secid == sid))
|
||||
return secattr;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
|
||||
*
|
||||
@@ -224,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
|
||||
struct sk_security_struct *sksec = sk->sk_security;
|
||||
if (sksec->nlbl_state != NLBL_REQSKB)
|
||||
return 0;
|
||||
secattr = sksec->nlbl_secattr;
|
||||
secattr = selinux_netlbl_sock_getattr(sk, sid);
|
||||
}
|
||||
if (secattr == NULL) {
|
||||
secattr = &secattr_storage;
|
||||
@@ -410,6 +436,9 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
|
||||
sksec->nlbl_state == NLBL_CONNLABELED)) {
|
||||
netlbl_secattr_init(&secattr);
|
||||
lock_sock(sk);
|
||||
/* call the netlabel function directly as we want to see the
|
||||
* on-the-wire label that is assigned via the socket's options
|
||||
* and not the cached netlabel/lsm attributes */
|
||||
rc = netlbl_sock_getattr(sk, &secattr);
|
||||
release_sock(sk);
|
||||
if (rc == 0)
|
||||
|
||||
@@ -48,6 +48,7 @@ struct constraint_expr {
|
||||
u32 op; /* operator */
|
||||
|
||||
struct ebitmap names; /* names */
|
||||
struct type_set *type_names;
|
||||
|
||||
struct constraint_expr *next; /* next expression */
|
||||
};
|
||||
|
||||
+100
-10
@@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = {
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
{
|
||||
.version = POLICYDB_VERSION_CONSTRAINT_NAMES,
|
||||
.sym_num = SYM_NUM,
|
||||
.ocon_num = OCON_NUM,
|
||||
},
|
||||
};
|
||||
|
||||
static struct policydb_compat_info *policydb_lookup_compat(int version)
|
||||
@@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void constraint_expr_destroy(struct constraint_expr *expr)
|
||||
{
|
||||
if (expr) {
|
||||
ebitmap_destroy(&expr->names);
|
||||
if (expr->type_names) {
|
||||
ebitmap_destroy(&expr->type_names->types);
|
||||
ebitmap_destroy(&expr->type_names->negset);
|
||||
kfree(expr->type_names);
|
||||
}
|
||||
kfree(expr);
|
||||
}
|
||||
}
|
||||
|
||||
static int cls_destroy(void *key, void *datum, void *p)
|
||||
{
|
||||
struct class_datum *cladatum;
|
||||
@@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p)
|
||||
while (constraint) {
|
||||
e = constraint->expr;
|
||||
while (e) {
|
||||
ebitmap_destroy(&e->names);
|
||||
etmp = e;
|
||||
e = e->next;
|
||||
kfree(etmp);
|
||||
constraint_expr_destroy(etmp);
|
||||
}
|
||||
ctemp = constraint;
|
||||
constraint = constraint->next;
|
||||
@@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p)
|
||||
while (constraint) {
|
||||
e = constraint->expr;
|
||||
while (e) {
|
||||
ebitmap_destroy(&e->names);
|
||||
etmp = e;
|
||||
e = e->next;
|
||||
kfree(etmp);
|
||||
constraint_expr_destroy(etmp);
|
||||
}
|
||||
ctemp = constraint;
|
||||
constraint = constraint->next;
|
||||
kfree(ctemp);
|
||||
}
|
||||
|
||||
kfree(cladatum->comkey);
|
||||
}
|
||||
kfree(datum);
|
||||
@@ -1156,8 +1171,34 @@ bad:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int read_cons_helper(struct constraint_node **nodep, int ncons,
|
||||
int allowxtarget, void *fp)
|
||||
static void type_set_init(struct type_set *t)
|
||||
{
|
||||
ebitmap_init(&t->types);
|
||||
ebitmap_init(&t->negset);
|
||||
}
|
||||
|
||||
static int type_set_read(struct type_set *t, void *fp)
|
||||
{
|
||||
__le32 buf[1];
|
||||
int rc;
|
||||
|
||||
if (ebitmap_read(&t->types, fp))
|
||||
return -EINVAL;
|
||||
if (ebitmap_read(&t->negset, fp))
|
||||
return -EINVAL;
|
||||
|
||||
rc = next_entry(buf, fp, sizeof(u32));
|
||||
if (rc < 0)
|
||||
return -EINVAL;
|
||||
t->flags = le32_to_cpu(buf[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int read_cons_helper(struct policydb *p,
|
||||
struct constraint_node **nodep,
|
||||
int ncons, int allowxtarget, void *fp)
|
||||
{
|
||||
struct constraint_node *c, *lc;
|
||||
struct constraint_expr *e, *le;
|
||||
@@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
|
||||
rc = ebitmap_read(&e->names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >=
|
||||
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||
e->type_names = kzalloc(sizeof
|
||||
(*e->type_names),
|
||||
GFP_KERNEL);
|
||||
if (!e->type_names)
|
||||
return -ENOMEM;
|
||||
type_set_init(e->type_names);
|
||||
rc = type_set_read(e->type_names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
|
||||
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
|
||||
if (rc)
|
||||
goto bad;
|
||||
|
||||
@@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
|
||||
if (rc)
|
||||
goto bad;
|
||||
ncons = le32_to_cpu(buf[0]);
|
||||
rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
|
||||
rc = read_cons_helper(p, &cladatum->validatetrans,
|
||||
ncons, 1, fp);
|
||||
if (rc)
|
||||
goto bad;
|
||||
}
|
||||
@@ -1941,7 +1995,19 @@ static int filename_trans_read(struct policydb *p, void *fp)
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
hashtab_insert(p->filename_trans, ft, otype);
|
||||
rc = hashtab_insert(p->filename_trans, ft, otype);
|
||||
if (rc) {
|
||||
/*
|
||||
* Do not return -EEXIST to the caller, or the system
|
||||
* will not boot.
|
||||
*/
|
||||
if (rc != -EEXIST)
|
||||
goto out;
|
||||
/* But free memory to avoid memory leak. */
|
||||
kfree(ft);
|
||||
kfree(name);
|
||||
kfree(otype);
|
||||
}
|
||||
}
|
||||
hash_eval(p->filename_trans, "filenametr");
|
||||
return 0;
|
||||
@@ -2753,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int type_set_write(struct type_set *t, void *fp)
|
||||
{
|
||||
int rc;
|
||||
__le32 buf[1];
|
||||
|
||||
if (ebitmap_write(&t->types, fp))
|
||||
return -EINVAL;
|
||||
if (ebitmap_write(&t->negset, fp))
|
||||
return -EINVAL;
|
||||
|
||||
buf[0] = cpu_to_le32(t->flags);
|
||||
rc = put_entry(buf, sizeof(u32), 1, fp);
|
||||
if (rc)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
||||
void *fp)
|
||||
{
|
||||
@@ -2784,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,
|
||||
rc = ebitmap_write(&e->names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (p->policyvers >=
|
||||
POLICYDB_VERSION_CONSTRAINT_NAMES) {
|
||||
rc = type_set_write(e->type_names, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@@ -153,6 +153,17 @@ struct cond_bool_datum {
|
||||
|
||||
struct cond_node;
|
||||
|
||||
/*
|
||||
* type set preserves data needed to determine constraint info from
|
||||
* policy source. This is not used by the kernel policy but allows
|
||||
* utilities such as audit2allow to determine constraint denials.
|
||||
*/
|
||||
struct type_set {
|
||||
struct ebitmap types;
|
||||
struct ebitmap negset;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
/*
|
||||
* The configuration data includes security contexts for
|
||||
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
|
||||
|
||||
@@ -1831,7 +1831,7 @@ static int security_preserve_bools(struct policydb *p);
|
||||
*/
|
||||
int security_load_policy(void *data, size_t len)
|
||||
{
|
||||
struct policydb oldpolicydb, newpolicydb;
|
||||
struct policydb *oldpolicydb, *newpolicydb;
|
||||
struct sidtab oldsidtab, newsidtab;
|
||||
struct selinux_mapping *oldmap, *map = NULL;
|
||||
struct convert_context_args args;
|
||||
@@ -1840,12 +1840,19 @@ int security_load_policy(void *data, size_t len)
|
||||
int rc = 0;
|
||||
struct policy_file file = { data, len }, *fp = &file;
|
||||
|
||||
oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
|
||||
if (!oldpolicydb) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
newpolicydb = oldpolicydb + 1;
|
||||
|
||||
if (!ss_initialized) {
|
||||
avtab_cache_init();
|
||||
rc = policydb_read(&policydb, fp);
|
||||
if (rc) {
|
||||
avtab_cache_destroy();
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
policydb.len = len;
|
||||
@@ -1855,14 +1862,14 @@ int security_load_policy(void *data, size_t len)
|
||||
if (rc) {
|
||||
policydb_destroy(&policydb);
|
||||
avtab_cache_destroy();
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = policydb_load_isids(&policydb, &sidtab);
|
||||
if (rc) {
|
||||
policydb_destroy(&policydb);
|
||||
avtab_cache_destroy();
|
||||
return rc;
|
||||
goto out;
|
||||
}
|
||||
|
||||
security_load_policycaps();
|
||||
@@ -1874,36 +1881,36 @@ int security_load_policy(void *data, size_t len)
|
||||
selinux_status_update_policyload(seqno);
|
||||
selinux_netlbl_cache_invalidate();
|
||||
selinux_xfrm_notify_policyload();
|
||||
return 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if 0
|
||||
sidtab_hash_eval(&sidtab, "sids");
|
||||
#endif
|
||||
|
||||
rc = policydb_read(&newpolicydb, fp);
|
||||
rc = policydb_read(newpolicydb, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
goto out;
|
||||
|
||||
newpolicydb.len = len;
|
||||
newpolicydb->len = len;
|
||||
/* If switching between different policy types, log MLS status */
|
||||
if (policydb.mls_enabled && !newpolicydb.mls_enabled)
|
||||
if (policydb.mls_enabled && !newpolicydb->mls_enabled)
|
||||
printk(KERN_INFO "SELinux: Disabling MLS support...\n");
|
||||
else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
|
||||
else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
|
||||
printk(KERN_INFO "SELinux: Enabling MLS support...\n");
|
||||
|
||||
rc = policydb_load_isids(&newpolicydb, &newsidtab);
|
||||
rc = policydb_load_isids(newpolicydb, &newsidtab);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "SELinux: unable to load the initial SIDs\n");
|
||||
policydb_destroy(&newpolicydb);
|
||||
return rc;
|
||||
policydb_destroy(newpolicydb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
|
||||
rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
|
||||
if (rc)
|
||||
goto err;
|
||||
|
||||
rc = security_preserve_bools(&newpolicydb);
|
||||
rc = security_preserve_bools(newpolicydb);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "SELinux: unable to preserve booleans\n");
|
||||
goto err;
|
||||
@@ -1921,7 +1928,7 @@ int security_load_policy(void *data, size_t len)
|
||||
* in the new SID table.
|
||||
*/
|
||||
args.oldp = &policydb;
|
||||
args.newp = &newpolicydb;
|
||||
args.newp = newpolicydb;
|
||||
rc = sidtab_map(&newsidtab, convert_context, &args);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "SELinux: unable to convert the internal"
|
||||
@@ -1931,12 +1938,12 @@ int security_load_policy(void *data, size_t len)
|
||||
}
|
||||
|
||||
/* Save the old policydb and SID table to free later. */
|
||||
memcpy(&oldpolicydb, &policydb, sizeof policydb);
|
||||
memcpy(oldpolicydb, &policydb, sizeof(policydb));
|
||||
sidtab_set(&oldsidtab, &sidtab);
|
||||
|
||||
/* Install the new policydb and SID table. */
|
||||
write_lock_irq(&policy_rwlock);
|
||||
memcpy(&policydb, &newpolicydb, sizeof policydb);
|
||||
memcpy(&policydb, newpolicydb, sizeof(policydb));
|
||||
sidtab_set(&sidtab, &newsidtab);
|
||||
security_load_policycaps();
|
||||
oldmap = current_mapping;
|
||||
@@ -1946,7 +1953,7 @@ int security_load_policy(void *data, size_t len)
|
||||
write_unlock_irq(&policy_rwlock);
|
||||
|
||||
/* Free the old policydb and SID table. */
|
||||
policydb_destroy(&oldpolicydb);
|
||||
policydb_destroy(oldpolicydb);
|
||||
sidtab_destroy(&oldsidtab);
|
||||
kfree(oldmap);
|
||||
|
||||
@@ -1956,14 +1963,17 @@ int security_load_policy(void *data, size_t len)
|
||||
selinux_netlbl_cache_invalidate();
|
||||
selinux_xfrm_notify_policyload();
|
||||
|
||||
return 0;
|
||||
rc = 0;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
kfree(map);
|
||||
sidtab_destroy(&newsidtab);
|
||||
policydb_destroy(&newpolicydb);
|
||||
return rc;
|
||||
policydb_destroy(newpolicydb);
|
||||
|
||||
out:
|
||||
kfree(oldpolicydb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t security_policydb_len(void)
|
||||
|
||||
@@ -241,7 +241,8 @@ u32 smack_to_secid(const char *);
|
||||
extern int smack_cipso_direct;
|
||||
extern int smack_cipso_mapped;
|
||||
extern struct smack_known *smack_net_ambient;
|
||||
extern char *smack_onlycap;
|
||||
extern struct smack_known *smack_onlycap;
|
||||
extern struct smack_known *smack_syslog_label;
|
||||
extern const char *smack_cipso_option;
|
||||
|
||||
extern struct smack_known smack_known_floor;
|
||||
@@ -312,7 +313,7 @@ static inline int smack_privileged(int cap)
|
||||
|
||||
if (!capable(cap))
|
||||
return 0;
|
||||
if (smack_onlycap == NULL || smack_onlycap == skp->smk_known)
|
||||
if (smack_onlycap == NULL || smack_onlycap == skp)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+67
-73
@@ -219,8 +219,6 @@ static int smack_ptrace_traceme(struct task_struct *ptp)
|
||||
* smack_syslog - Smack approval on syslog
|
||||
* @type: message type
|
||||
*
|
||||
* Require that the task has the floor label
|
||||
*
|
||||
* Returns 0 on success, error code otherwise.
|
||||
*/
|
||||
static int smack_syslog(int typefrom_file)
|
||||
@@ -231,7 +229,7 @@ static int smack_syslog(int typefrom_file)
|
||||
if (smack_privileged(CAP_MAC_OVERRIDE))
|
||||
return 0;
|
||||
|
||||
if (skp != &smack_known_floor)
|
||||
if (smack_syslog_label != NULL && smack_syslog_label != skp)
|
||||
rc = -EACCES;
|
||||
|
||||
return rc;
|
||||
@@ -341,10 +339,12 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||
struct inode *inode = root->d_inode;
|
||||
struct superblock_smack *sp = sb->s_security;
|
||||
struct inode_smack *isp;
|
||||
struct smack_known *skp;
|
||||
char *op;
|
||||
char *commap;
|
||||
char *nsp;
|
||||
int transmute = 0;
|
||||
int specified = 0;
|
||||
|
||||
if (sp->smk_initialized)
|
||||
return 0;
|
||||
@@ -359,34 +359,56 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data)
|
||||
if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) {
|
||||
op += strlen(SMK_FSHAT);
|
||||
nsp = smk_import(op, 0);
|
||||
if (nsp != NULL)
|
||||
if (nsp != NULL) {
|
||||
sp->smk_hat = nsp;
|
||||
specified = 1;
|
||||
}
|
||||
} else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) {
|
||||
op += strlen(SMK_FSFLOOR);
|
||||
nsp = smk_import(op, 0);
|
||||
if (nsp != NULL)
|
||||
if (nsp != NULL) {
|
||||
sp->smk_floor = nsp;
|
||||
specified = 1;
|
||||
}
|
||||
} else if (strncmp(op, SMK_FSDEFAULT,
|
||||
strlen(SMK_FSDEFAULT)) == 0) {
|
||||
op += strlen(SMK_FSDEFAULT);
|
||||
nsp = smk_import(op, 0);
|
||||
if (nsp != NULL)
|
||||
if (nsp != NULL) {
|
||||
sp->smk_default = nsp;
|
||||
specified = 1;
|
||||
}
|
||||
} else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) {
|
||||
op += strlen(SMK_FSROOT);
|
||||
nsp = smk_import(op, 0);
|
||||
if (nsp != NULL)
|
||||
if (nsp != NULL) {
|
||||
sp->smk_root = nsp;
|
||||
specified = 1;
|
||||
}
|
||||
} else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) {
|
||||
op += strlen(SMK_FSTRANS);
|
||||
nsp = smk_import(op, 0);
|
||||
if (nsp != NULL) {
|
||||
sp->smk_root = nsp;
|
||||
transmute = 1;
|
||||
specified = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!smack_privileged(CAP_MAC_ADMIN)) {
|
||||
/*
|
||||
* Unprivileged mounts don't get to specify Smack values.
|
||||
*/
|
||||
if (specified)
|
||||
return -EPERM;
|
||||
/*
|
||||
* Unprivileged mounts get root and default from the caller.
|
||||
*/
|
||||
skp = smk_of_current();
|
||||
sp->smk_root = skp->smk_known;
|
||||
sp->smk_default = skp->smk_known;
|
||||
}
|
||||
/*
|
||||
* Initialize the root inode.
|
||||
*/
|
||||
@@ -423,53 +445,6 @@ static int smack_sb_statfs(struct dentry *dentry)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_sb_mount - Smack check for mounting
|
||||
* @dev_name: unused
|
||||
* @path: mount point
|
||||
* @type: unused
|
||||
* @flags: unused
|
||||
* @data: unused
|
||||
*
|
||||
* Returns 0 if current can write the floor of the filesystem
|
||||
* being mounted on, an error code otherwise.
|
||||
*/
|
||||
static int smack_sb_mount(const char *dev_name, struct path *path,
|
||||
const char *type, unsigned long flags, void *data)
|
||||
{
|
||||
struct superblock_smack *sbp = path->dentry->d_sb->s_security;
|
||||
struct smk_audit_info ad;
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||
smk_ad_setfield_u_fs_path(&ad, *path);
|
||||
|
||||
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
|
||||
}
|
||||
|
||||
/**
|
||||
* smack_sb_umount - Smack check for unmounting
|
||||
* @mnt: file system to unmount
|
||||
* @flags: unused
|
||||
*
|
||||
* Returns 0 if current can write the floor of the filesystem
|
||||
* being unmounted, an error code otherwise.
|
||||
*/
|
||||
static int smack_sb_umount(struct vfsmount *mnt, int flags)
|
||||
{
|
||||
struct superblock_smack *sbp;
|
||||
struct smk_audit_info ad;
|
||||
struct path path;
|
||||
|
||||
path.dentry = mnt->mnt_root;
|
||||
path.mnt = mnt;
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||
smk_ad_setfield_u_fs_path(&ad, path);
|
||||
|
||||
sbp = path.dentry->d_sb->s_security;
|
||||
return smk_curacc(sbp->smk_floor, MAY_WRITE, &ad);
|
||||
}
|
||||
|
||||
/*
|
||||
* BPRM hooks
|
||||
*/
|
||||
@@ -837,31 +812,43 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
struct smk_audit_info ad;
|
||||
struct smack_known *skp;
|
||||
int check_priv = 0;
|
||||
int check_import = 0;
|
||||
int check_star = 0;
|
||||
int rc = 0;
|
||||
|
||||
/*
|
||||
* Check label validity here so import won't fail in post_setxattr
|
||||
*/
|
||||
if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
/*
|
||||
* check label validity here so import wont fail on
|
||||
* post_setxattr
|
||||
*/
|
||||
if (size == 0 || size >= SMK_LONGLABEL ||
|
||||
smk_import(value, size) == NULL)
|
||||
rc = -EINVAL;
|
||||
strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
|
||||
check_priv = 1;
|
||||
check_import = 1;
|
||||
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
|
||||
strcmp(name, XATTR_NAME_SMACKMMAP) == 0) {
|
||||
check_priv = 1;
|
||||
check_import = 1;
|
||||
check_star = 1;
|
||||
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
|
||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
check_priv = 1;
|
||||
if (size != TRANS_TRUE_SIZE ||
|
||||
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
|
||||
rc = -EINVAL;
|
||||
} else
|
||||
rc = cap_inode_setxattr(dentry, name, value, size, flags);
|
||||
|
||||
if (check_priv && !smack_privileged(CAP_MAC_ADMIN))
|
||||
rc = -EPERM;
|
||||
|
||||
if (rc == 0 && check_import) {
|
||||
skp = smk_import_entry(value, size);
|
||||
if (skp == NULL || (check_star &&
|
||||
(skp == &smack_known_star || skp == &smack_known_web)))
|
||||
rc = -EINVAL;
|
||||
}
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_DENTRY);
|
||||
smk_ad_setfield_u_fs_path_dentry(&ad, dentry);
|
||||
|
||||
@@ -1364,7 +1351,7 @@ static int smack_file_receive(struct file *file)
|
||||
int may = 0;
|
||||
struct smk_audit_info ad;
|
||||
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_TASK);
|
||||
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_PATH);
|
||||
smk_ad_setfield_u_fs_path(&ad, file->f_path);
|
||||
/*
|
||||
* This code relies on bitmasks.
|
||||
@@ -2847,8 +2834,17 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
|
||||
if (rc >= 0)
|
||||
transflag = SMK_INODE_TRANSMUTE;
|
||||
}
|
||||
isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
|
||||
isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
|
||||
/*
|
||||
* Don't let the exec or mmap label be "*" or "@".
|
||||
*/
|
||||
skp = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp);
|
||||
if (skp == &smack_known_star || skp == &smack_known_web)
|
||||
skp = NULL;
|
||||
isp->smk_task = skp;
|
||||
skp = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp);
|
||||
if (skp == &smack_known_star || skp == &smack_known_web)
|
||||
skp = NULL;
|
||||
isp->smk_mmap = skp;
|
||||
|
||||
dput(dp);
|
||||
break;
|
||||
@@ -3743,8 +3739,6 @@ struct security_operations smack_ops = {
|
||||
.sb_copy_data = smack_sb_copy_data,
|
||||
.sb_kern_mount = smack_sb_kern_mount,
|
||||
.sb_statfs = smack_sb_statfs,
|
||||
.sb_mount = smack_sb_mount,
|
||||
.sb_umount = smack_sb_umount,
|
||||
|
||||
.bprm_set_creds = smack_bprm_set_creds,
|
||||
.bprm_committing_creds = smack_bprm_committing_creds,
|
||||
|
||||
+111
-23
@@ -52,6 +52,7 @@ enum smk_inos {
|
||||
SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */
|
||||
SMK_REVOKE_SUBJ = 18, /* set rules with subject label to '-' */
|
||||
SMK_CHANGE_RULE = 19, /* change or add rules (long labels) */
|
||||
SMK_SYSLOG = 20, /* change syslog label) */
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -59,6 +60,7 @@ enum smk_inos {
|
||||
*/
|
||||
static DEFINE_MUTEX(smack_cipso_lock);
|
||||
static DEFINE_MUTEX(smack_ambient_lock);
|
||||
static DEFINE_MUTEX(smack_syslog_lock);
|
||||
static DEFINE_MUTEX(smk_netlbladdr_lock);
|
||||
|
||||
/*
|
||||
@@ -90,7 +92,13 @@ int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT;
|
||||
* everyone. It is expected that the hat (^) label
|
||||
* will be used if any label is used.
|
||||
*/
|
||||
char *smack_onlycap;
|
||||
struct smack_known *smack_onlycap;
|
||||
|
||||
/*
|
||||
* If this value is set restrict syslog use to the label specified.
|
||||
* It can be reset via smackfs/syslog
|
||||
*/
|
||||
struct smack_known *smack_syslog_label;
|
||||
|
||||
/*
|
||||
* Certain IP addresses may be designated as single label hosts.
|
||||
@@ -301,7 +309,8 @@ static int smk_perm_from_str(const char *string)
|
||||
* @import: if non-zero, import labels
|
||||
* @len: label length limit
|
||||
*
|
||||
* Returns 0 on success, -1 on failure
|
||||
* Returns 0 on success, -EINVAL on failure and -ENOENT when either subject
|
||||
* or object is missing.
|
||||
*/
|
||||
static int smk_fill_rule(const char *subject, const char *object,
|
||||
const char *access1, const char *access2,
|
||||
@@ -314,28 +323,28 @@ static int smk_fill_rule(const char *subject, const char *object,
|
||||
if (import) {
|
||||
rule->smk_subject = smk_import_entry(subject, len);
|
||||
if (rule->smk_subject == NULL)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
|
||||
rule->smk_object = smk_import(object, len);
|
||||
if (rule->smk_object == NULL)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
} else {
|
||||
cp = smk_parse_smack(subject, len);
|
||||
if (cp == NULL)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
skp = smk_find_entry(cp);
|
||||
kfree(cp);
|
||||
if (skp == NULL)
|
||||
return -1;
|
||||
return -ENOENT;
|
||||
rule->smk_subject = skp;
|
||||
|
||||
cp = smk_parse_smack(object, len);
|
||||
if (cp == NULL)
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
skp = smk_find_entry(cp);
|
||||
kfree(cp);
|
||||
if (skp == NULL)
|
||||
return -1;
|
||||
return -ENOENT;
|
||||
rule->smk_object = skp->smk_known;
|
||||
}
|
||||
|
||||
@@ -381,6 +390,7 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
|
||||
{
|
||||
ssize_t cnt = 0;
|
||||
char *tok[4];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
@@ -405,10 +415,8 @@ static ssize_t smk_parse_long_rule(char *data, struct smack_parsed_rule *rule,
|
||||
while (i < 4)
|
||||
tok[i++] = NULL;
|
||||
|
||||
if (smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0))
|
||||
return -1;
|
||||
|
||||
return cnt;
|
||||
rc = smk_fill_rule(tok[0], tok[1], tok[2], tok[3], rule, import, 0);
|
||||
return rc == 0 ? cnt : rc;
|
||||
}
|
||||
|
||||
#define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */
|
||||
@@ -1603,7 +1611,7 @@ static const struct file_operations smk_ambient_ops = {
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_read_onlycap - read() for /smack/onlycap
|
||||
* smk_read_onlycap - read() for smackfs/onlycap
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to put the result
|
||||
* @cn: maximum to send along
|
||||
@@ -1622,7 +1630,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
|
||||
return 0;
|
||||
|
||||
if (smack_onlycap != NULL)
|
||||
smack = smack_onlycap;
|
||||
smack = smack_onlycap->smk_known;
|
||||
|
||||
asize = strlen(smack) + 1;
|
||||
|
||||
@@ -1633,7 +1641,7 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf,
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_onlycap - write() for /smack/onlycap
|
||||
* smk_write_onlycap - write() for smackfs/onlycap
|
||||
* @file: file pointer, not actually used
|
||||
* @buf: where to get the data from
|
||||
* @count: bytes sent
|
||||
@@ -1656,7 +1664,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
|
||||
* explicitly for clarity. The smk_access() implementation
|
||||
* would use smk_access(smack_onlycap, MAY_WRITE)
|
||||
*/
|
||||
if (smack_onlycap != NULL && smack_onlycap != skp->smk_known)
|
||||
if (smack_onlycap != NULL && smack_onlycap != skp)
|
||||
return -EPERM;
|
||||
|
||||
data = kzalloc(count, GFP_KERNEL);
|
||||
@@ -1676,7 +1684,7 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
|
||||
if (copy_from_user(data, buf, count) != 0)
|
||||
rc = -EFAULT;
|
||||
else
|
||||
smack_onlycap = smk_import(data, count);
|
||||
smack_onlycap = smk_import_entry(data, count);
|
||||
|
||||
kfree(data);
|
||||
return rc;
|
||||
@@ -1856,11 +1864,12 @@ static ssize_t smk_user_access(struct file *file, const char __user *buf,
|
||||
res = smk_parse_long_rule(data, &rule, 0, 3);
|
||||
}
|
||||
|
||||
if (res < 0)
|
||||
if (res >= 0)
|
||||
res = smk_access(rule.smk_subject, rule.smk_object,
|
||||
rule.smk_access1, NULL);
|
||||
else if (res != -ENOENT)
|
||||
return -EINVAL;
|
||||
|
||||
res = smk_access(rule.smk_subject, rule.smk_object,
|
||||
rule.smk_access1, NULL);
|
||||
data[0] = res == 0 ? '1' : '0';
|
||||
data[1] = '\0';
|
||||
|
||||
@@ -2143,7 +2152,7 @@ static ssize_t smk_write_change_rule(struct file *file, const char __user *buf,
|
||||
/*
|
||||
* Must have privilege.
|
||||
*/
|
||||
if (!capable(CAP_MAC_ADMIN))
|
||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
return smk_write_rules_list(file, buf, count, ppos, NULL, NULL,
|
||||
@@ -2158,12 +2167,89 @@ static const struct file_operations smk_change_rule_ops = {
|
||||
};
|
||||
|
||||
/**
|
||||
* smk_fill_super - fill the /smackfs superblock
|
||||
* smk_read_syslog - read() for smackfs/syslog
|
||||
* @filp: file pointer, not actually used
|
||||
* @buf: where to put the result
|
||||
* @cn: maximum to send along
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Returns number of bytes read or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_read_syslog(struct file *filp, char __user *buf,
|
||||
size_t cn, loff_t *ppos)
|
||||
{
|
||||
struct smack_known *skp;
|
||||
ssize_t rc = -EINVAL;
|
||||
int asize;
|
||||
|
||||
if (*ppos != 0)
|
||||
return 0;
|
||||
|
||||
if (smack_syslog_label == NULL)
|
||||
skp = &smack_known_star;
|
||||
else
|
||||
skp = smack_syslog_label;
|
||||
|
||||
asize = strlen(skp->smk_known) + 1;
|
||||
|
||||
if (cn >= asize)
|
||||
rc = simple_read_from_buffer(buf, cn, ppos, skp->smk_known,
|
||||
asize);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* smk_write_syslog - write() for smackfs/syslog
|
||||
* @file: file pointer, not actually used
|
||||
* @buf: where to get the data from
|
||||
* @count: bytes sent
|
||||
* @ppos: where to start
|
||||
*
|
||||
* Returns number of bytes written or error code, as appropriate
|
||||
*/
|
||||
static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
char *data;
|
||||
struct smack_known *skp;
|
||||
int rc = count;
|
||||
|
||||
if (!smack_privileged(CAP_MAC_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
data = kzalloc(count, GFP_KERNEL);
|
||||
if (data == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(data, buf, count) != 0)
|
||||
rc = -EFAULT;
|
||||
else {
|
||||
skp = smk_import_entry(data, count);
|
||||
if (skp == NULL)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
smack_syslog_label = smk_import_entry(data, count);
|
||||
}
|
||||
|
||||
kfree(data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations smk_syslog_ops = {
|
||||
.read = smk_read_syslog,
|
||||
.write = smk_write_syslog,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* smk_fill_super - fill the smackfs superblock
|
||||
* @sb: the empty superblock
|
||||
* @data: unused
|
||||
* @silent: unused
|
||||
*
|
||||
* Fill in the well known entries for /smack
|
||||
* Fill in the well known entries for the smack filesystem
|
||||
*
|
||||
* Returns 0 on success, an error code on failure
|
||||
*/
|
||||
@@ -2208,6 +2294,8 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent)
|
||||
S_IRUGO|S_IWUSR},
|
||||
[SMK_CHANGE_RULE] = {
|
||||
"change-rule", &smk_change_rule_ops, S_IRUGO|S_IWUSR},
|
||||
[SMK_SYSLOG] = {
|
||||
"syslog", &smk_syslog_ops, S_IRUGO|S_IWUSR},
|
||||
/* last one */
|
||||
{""}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user