summaryrefslogtreecommitdiff
path: root/security/selinux
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/avc.c63
-rw-r--r--security/selinux/hooks.c134
-rw-r--r--security/selinux/include/avc.h19
-rw-r--r--security/selinux/include/security.h9
-rw-r--r--security/selinux/netif.c18
-rw-r--r--security/selinux/netnode.c1
-rw-r--r--security/selinux/selinuxfs.c83
-rw-r--r--security/selinux/ss/policydb.c257
-rw-r--r--security/selinux/ss/policydb.h12
-rw-r--r--security/selinux/ss/services.c75
10 files changed, 434 insertions, 237 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 9da6420e2056..d515b2128a4e 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -38,11 +38,7 @@
#define AVC_CACHE_RECLAIM 16
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
-#define avc_cache_stats_incr(field) \
-do { \
- per_cpu(avc_cache_stats, get_cpu()).field++; \
- put_cpu(); \
-} while (0)
+#define avc_cache_stats_incr(field) this_cpu_inc(avc_cache_stats.field)
#else
#define avc_cache_stats_incr(field) do {} while (0)
#endif
@@ -347,11 +343,10 @@ static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
node = avc_search_node(ssid, tsid, tclass);
if (node)
- avc_cache_stats_incr(hits);
- else
- avc_cache_stats_incr(misses);
+ return node;
- return node;
+ avc_cache_stats_incr(misses);
+ return NULL;
}
static int avc_latest_notif_update(int seqno, int is_insert)
@@ -471,6 +466,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
* @avd: access vector decisions
* @result: result from avc_has_perm_noaudit
* @a: auxiliary audit data
+ * @flags: VFS walk flags
*
* Audit the granting or denial of permissions in accordance
* with the policy. This function is typically called by
@@ -481,9 +477,10 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
* be performed under a lock, to allow the lock to be released
* before calling the auditing code.
*/
-void avc_audit(u32 ssid, u32 tsid,
+int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
- struct av_decision *avd, int result, struct common_audit_data *a)
+ struct av_decision *avd, int result, struct common_audit_data *a,
+ unsigned flags)
{
struct common_audit_data stack_data;
u32 denied, audited;
@@ -515,11 +512,24 @@ void avc_audit(u32 ssid, u32 tsid,
else
audited = requested & avd->auditallow;
if (!audited)
- return;
+ return 0;
+
if (!a) {
a = &stack_data;
COMMON_AUDIT_DATA_INIT(a, NONE);
}
+
+ /*
+ * When in a RCU walk do the audit on the RCU retry. This is because
+ * the collection of the dname in an inode audit message is not RCU
+ * safe. Note this may drop some audits when the situation changes
+ * during retry. However this is logically just as if the operation
+ * happened a little later.
+ */
+ if ((a->type == LSM_AUDIT_DATA_INODE) &&
+ (flags & IPERM_FLAG_RCU))
+ return -ECHILD;
+
a->selinux_audit_data.tclass = tclass;
a->selinux_audit_data.requested = requested;
a->selinux_audit_data.ssid = ssid;
@@ -529,6 +539,7 @@ void avc_audit(u32 ssid, u32 tsid,
a->lsm_pre_audit = avc_audit_pre_callback;
a->lsm_post_audit = avc_audit_post_callback;
common_lsm_audit(a);
+ return 0;
}
/**
@@ -741,10 +752,9 @@ int avc_ss_reset(u32 seqno)
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
unsigned flags,
- struct av_decision *in_avd)
+ struct av_decision *avd)
{
struct avc_node *node;
- struct av_decision avd_entry, *avd;
int rc = 0;
u32 denied;
@@ -753,20 +763,13 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
rcu_read_lock();
node = avc_lookup(ssid, tsid, tclass);
- if (!node) {
+ if (unlikely(!node)) {
rcu_read_unlock();
-
- if (in_avd)
- avd = in_avd;
- else
- avd = &avd_entry;
-
security_compute_av(ssid, tsid, tclass, avd);
rcu_read_lock();
node = avc_insert(ssid, tsid, tclass, avd);
} else {
- if (in_avd)
- memcpy(in_avd, &node->ae.avd, sizeof(*in_avd));
+ memcpy(avd, &node->ae.avd, sizeof(*avd));
avd = &node->ae.avd;
}
@@ -793,6 +796,7 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
* @tclass: target security class
* @requested: requested permissions, interpreted based on @tclass
* @auditdata: auxiliary audit data
+ * @flags: VFS walk flags
*
* Check the AVC to determine whether the @requested permissions are granted
* for the SID pair (@ssid, @tsid), interpreting the permissions
@@ -802,14 +806,19 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
* permissions are granted, -%EACCES if any permissions are denied, or
* another -errno upon other errors.
*/
-int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
- u32 requested, struct common_audit_data *auditdata)
+int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
+ u32 requested, struct common_audit_data *auditdata,
+ unsigned flags)
{
struct av_decision avd;
- int rc;
+ int rc, rc2;
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
- avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+
+ rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata,
+ flags);
+ if (rc2)
+ return rc2;
return rc;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f9c3764e4859..20219ef5439a 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -990,6 +990,7 @@ static void selinux_write_opts(struct seq_file *m,
continue;
default:
BUG();
+ return;
};
/* we need a comma before each option */
seq_putc(m, ',');
@@ -1443,11 +1444,15 @@ static int task_has_capability(struct task_struct *tsk,
printk(KERN_ERR
"SELinux: out of range capability %d\n", cap);
BUG();
+ return -EINVAL;
}
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
- if (audit == SECURITY_CAP_AUDIT)
- avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
+ if (audit == SECURITY_CAP_AUDIT) {
+ int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
+ if (rc2)
+ return rc2;
+ }
return rc;
}
@@ -1467,10 +1472,10 @@ static int task_has_system(struct task_struct *tsk,
static int inode_has_perm(const struct cred *cred,
struct inode *inode,
u32 perms,
- struct common_audit_data *adp)
+ struct common_audit_data *adp,
+ unsigned flags)
{
struct inode_security_struct *isec;
- struct common_audit_data ad;
u32 sid;
validate_creds(cred);
@@ -1481,30 +1486,49 @@ static int inode_has_perm(const struct cred *cred,
sid = cred_sid(cred);
isec = inode->i_security;
- if (!adp) {
- adp = &ad;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.inode = inode;
- }
+ return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
+}
+
+static int inode_has_perm_noadp(const struct cred *cred,
+ struct inode *inode,
+ u32 perms,
+ unsigned flags)
+{
+ struct common_audit_data ad;
- return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
+ COMMON_AUDIT_DATA_INIT(&ad, INODE);
+ ad.u.inode = inode;
+ return inode_has_perm(cred, inode, perms, &ad, flags);
}
/* Same as inode_has_perm, but pass explicit audit data containing
the dentry to help the auditing code to more easily generate the
pathname if needed. */
static inline int dentry_has_perm(const struct cred *cred,
- struct vfsmount *mnt,
struct dentry *dentry,
u32 av)
{
struct inode *inode = dentry->d_inode;
struct common_audit_data ad;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path.mnt = mnt;
- ad.u.fs.path.dentry = dentry;
- return inode_has_perm(cred, inode, av, &ad);
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+ ad.u.dentry = dentry;
+ return inode_has_perm(cred, inode, av, &ad, 0);
+}
+
+/* Same as inode_has_perm, but pass explicit audit data containing
+ the path to help the auditing code to more easily generate the
+ pathname if needed. */
+static inline int path_has_perm(const struct cred *cred,
+ struct path *path,
+ u32 av)
+{
+ struct inode *inode = path->dentry->d_inode;
+ struct common_audit_data ad;
+
+ COMMON_AUDIT_DATA_INIT(&ad, PATH);
+ ad.u.path = *path;
+ return inode_has_perm(cred, inode, av, &ad, 0);
}
/* Check whether a task can use an open file descriptor to
@@ -1525,8 +1549,8 @@ static int file_has_perm(const struct cred *cred,
u32 sid = cred_sid(cred);
int rc;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path = file->f_path;
+ COMMON_AUDIT_DATA_INIT(&ad, PATH);
+ ad.u.path = file->f_path;
if (sid != fsec->sid) {
rc = avc_has_perm(sid, fsec->sid,
@@ -1540,7 +1564,7 @@ static int file_has_perm(const struct cred *cred,
/* av is zero if only checking access to the descriptor. */
rc = 0;
if (av)
- rc = inode_has_perm(cred, inode, av, &ad);
+ rc = inode_has_perm(cred, inode, av, &ad, 0);
out:
return rc;
@@ -1564,8 +1588,8 @@ static int may_create(struct inode *dir,
sid = tsec->sid;
newsid = tsec->create_sid;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path.dentry = dentry;
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+ ad.u.dentry = dentry;
rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
@@ -1574,7 +1598,8 @@ static int may_create(struct inode *dir,
return rc;
if (!newsid || !(sbsec->flags & SE_SBLABELSUPP)) {
- rc = security_transition_sid(sid, dsec->sid, tclass, NULL, &newsid);
+ rc = security_transition_sid(sid, dsec->sid, tclass,
+ &dentry->d_name, &newsid);
if (rc)
return rc;
}
@@ -1616,8 +1641,8 @@ static int may_link(struct inode *dir,
dsec = dir->i_security;
isec = dentry->d_inode->i_security;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path.dentry = dentry;
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+ ad.u.dentry = dentry;
av = DIR__SEARCH;
av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
@@ -1662,9 +1687,9 @@ static inline int may_rename(struct inode *old_dir,
old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
new_dsec = new_dir->i_security;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
- ad.u.fs.path.dentry = old_dentry;
+ ad.u.dentry = old_dentry;
rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
DIR__REMOVE_NAME | DIR__SEARCH, &ad);
if (rc)
@@ -1680,7 +1705,7 @@ static inline int may_rename(struct inode *old_dir,
return rc;
}
- ad.u.fs.path.dentry = new_dentry;
+ ad.u.dentry = new_dentry;
av = DIR__ADD_NAME | DIR__SEARCH;
if (new_dentry->d_inode)
av |= DIR__REMOVE_NAME;
@@ -1890,7 +1915,7 @@ static int selinux_quota_on(struct dentry *dentry)
{
const struct cred *cred = current_cred();
- return dentry_has_perm(cred, NULL, dentry, FILE__QUOTAON);
+ return dentry_has_perm(cred, dentry, FILE__QUOTAON);
}
static int selinux_syslog(int type)
@@ -1987,8 +2012,8 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm)
return rc;
}
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path = bprm->file->f_path;
+ COMMON_AUDIT_DATA_INIT(&ad, PATH);
+ ad.u.path = bprm->file->f_path;
if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
new_tsec->sid = old_tsec->sid;
@@ -2102,8 +2127,8 @@ static inline void flush_unauthorized_files(const struct cred *cred,
struct tty_file_private, list);
file = file_priv->file;
inode = file->f_path.dentry->d_inode;
- if (inode_has_perm(cred, inode,
- FILE__READ | FILE__WRITE, NULL)) {
+ if (inode_has_perm_noadp(cred, inode,
+ FILE__READ | FILE__WRITE, 0)) {
drop_tty = 1;
}
}
@@ -2116,7 +2141,7 @@ static inline void flush_unauthorized_files(const struct cred *cred,
/* Revalidate access to inherited open files. */
- COMMON_AUDIT_DATA_INIT(&ad, FS);
+ COMMON_AUDIT_DATA_INIT(&ad, INODE);
spin_lock(&files->file_lock);
for (;;) {
@@ -2464,8 +2489,8 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data)
if (flags & MS_KERNMOUNT)
return 0;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path.dentry = sb->s_root;
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+ ad.u.dentry = sb->s_root;
return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
}
@@ -2474,8 +2499,8 @@ static int selinux_sb_statfs(struct dentry *dentry)
const struct cred *cred = current_cred();
struct common_audit_data ad;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path.dentry = dentry->d_sb->s_root;
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+ ad.u.dentry = dentry->d_sb->s_root;
return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
}
@@ -2491,8 +2516,7 @@ static int selinux_mount(char *dev_name,
return superblock_has_perm(cred, path->mnt->mnt_sb,
FILESYSTEM__REMOUNT, NULL);
else
- return dentry_has_perm(cred, path->mnt, path->dentry,
- FILE__MOUNTON);
+ return path_has_perm(cred, path, FILE__MOUNTON);
}
static int selinux_umount(struct vfsmount *mnt, int flags)
@@ -2625,17 +2649,17 @@ static int selinux_inode_readlink(struct dentry *dentry)
{
const struct cred *cred = current_cred();
- return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+ return dentry_has_perm(cred, dentry, FILE__READ);
}
static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
{
const struct cred *cred = current_cred();
- return dentry_has_perm(cred, NULL, dentry, FILE__READ);
+ return dentry_has_perm(cred, dentry, FILE__READ);
}
-static int selinux_inode_permission(struct inode *inode, int mask)
+static int selinux_inode_permission(struct inode *inode, int mask, unsigned flags)
{
const struct cred *cred = current_cred();
struct common_audit_data ad;
@@ -2649,15 +2673,15 @@ static int selinux_inode_permission(struct inode *inode, int mask)
if (!mask)
return 0;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.inode = inode;
+ COMMON_AUDIT_DATA_INIT(&ad, INODE);
+ ad.u.inode = inode;
if (from_access)
ad.selinux_audit_data.auditdeny |= FILE__AUDIT_ACCESS;
perms = file_mask_to_av(inode->i_mode, mask);
- return inode_has_perm(cred, inode, perms, &ad);
+ return inode_has_perm(cred, inode, perms, &ad, flags);
}
static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
@@ -2675,16 +2699,20 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
- return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+ return dentry_has_perm(cred, dentry, FILE__SETATTR);
- return dentry_has_perm(cred, NULL, dentry, FILE__WRITE);
+ return dentry_has_perm(cred, dentry, FILE__WRITE);
}
static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry)
{
const struct cred *cred = current_cred();
+ struct path path;
+
+ path.dentry = dentry;
+ path.mnt = mnt;
- return dentry_has_perm(cred, mnt, dentry, FILE__GETATTR);
+ return path_has_perm(cred, &path, FILE__GETATTR);
}
static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
@@ -2705,7 +2733,7 @@ static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
/* Not an attribute we recognize, so just check the
ordinary setattr permission. */
- return dentry_has_perm(cred, NULL, dentry, FILE__SETATTR);
+ return dentry_has_perm(cred, dentry, FILE__SETATTR);
}
static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
@@ -2728,8 +2756,8 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
if (!inode_owner_or_capable(inode))
return -EPERM;
- COMMON_AUDIT_DATA_INIT(&ad, FS);
- ad.u.fs.path.dentry = dentry;
+ COMMON_AUDIT_DATA_INIT(&ad, DENTRY);
+ ad.u.dentry = dentry;
rc = avc_has_perm(sid, isec->sid, isec->sclass,
FILE__RELABELFROM, &ad);
@@ -2792,14 +2820,14 @@ static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
{
const struct cred *cred = current_cred();
- return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+ return dentry_has_perm(cred, dentry, FILE__GETATTR);
}
static int selinux_inode_listxattr(struct dentry *dentry)
{
const struct cred *cred = current_cred();
- return dentry_has_perm(cred, NULL, dentry, FILE__GETATTR);
+ return dentry_has_perm(cred, dentry, FILE__GETATTR);
}
static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
@@ -3205,7 +3233,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred)
* new inode label or new policy.
* This check is not redundant - do not remove.
*/
- return inode_has_perm(cred, inode, open_file_to_av(file), NULL);
+ return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0);
}
/* task security operations */
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h
index 5615081b73ec..47fda963495d 100644
--- a/security/selinux/include/avc.h
+++ b/security/selinux/include/avc.h
@@ -41,7 +41,6 @@ struct sk_buff;
*/
struct avc_cache_stats {
unsigned int lookups;
- unsigned int hits;
unsigned int misses;
unsigned int allocations;
unsigned int reclaims;
@@ -54,11 +53,11 @@ struct avc_cache_stats {
void __init avc_init(void);
-void avc_audit(u32 ssid, u32 tsid,
+int avc_audit(u32 ssid, u32 tsid,
u16 tclass, u32 requested,
struct av_decision *avd,
int result,
- struct common_audit_data *a);
+ struct common_audit_data *a, unsigned flags);
#define AVC_STRICT 1 /* Ignore permissive mode. */
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
@@ -66,9 +65,17 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
unsigned flags,
struct av_decision *avd);
-int avc_has_perm(u32 ssid, u32 tsid,
- u16 tclass, u32 requested,
- struct common_audit_data *auditdata);
+int avc_has_perm_flags(u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct common_audit_data *auditdata,
+ unsigned);
+
+static inline int avc_has_perm(u32 ssid, u32 tsid,
+ u16 tclass, u32 requested,
+ struct common_audit_data *auditdata)
+{
+ return avc_has_perm_flags(ssid, tsid, tclass, requested, auditdata, 0);
+}
u32 avc_policy_seqno(void);
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 348eb00cb668..3ba4feba048a 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -30,13 +30,14 @@
#define POLICYDB_VERSION_PERMISSIVE 23
#define POLICYDB_VERSION_BOUNDARY 24
#define POLICYDB_VERSION_FILENAME_TRANS 25
+#define POLICYDB_VERSION_ROLETRANS 26
/* 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_FILENAME_TRANS
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS
#endif
/* Mask for just the mount related flags */
@@ -85,7 +86,7 @@ extern int selinux_policycap_openperm;
int security_mls_enabled(void);
int security_load_policy(void *data, size_t len);
-int security_read_policy(void **data, ssize_t *len);
+int security_read_policy(void **data, size_t *len);
size_t security_policydb_len(void);
int security_policycap_supported(unsigned int req_cap);
@@ -111,8 +112,8 @@ void security_compute_av_user(u32 ssid, u32 tsid,
int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid);
-int security_transition_sid_user(u32 ssid, u32 tsid,
- u16 tclass, u32 *out_sid);
+int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+ const char *objname, u32 *out_sid);
int security_member_sid(u32 ssid, u32 tsid,
u16 tclass, u32 *out_sid);
diff --git a/security/selinux/netif.c b/security/selinux/netif.c
index d6095d63d831..58cc481c93d5 100644
--- a/security/selinux/netif.c
+++ b/security/selinux/netif.c
@@ -104,22 +104,6 @@ static int sel_netif_insert(struct sel_netif *netif)
}
/**
- * sel_netif_free - Frees an interface entry
- * @p: the entry's RCU field
- *
- * Description:
- * This function is designed to be used as a callback to the call_rcu()
- * function so that memory allocated to a hash table interface entry can be
- * released safely.
- *
- */
-static void sel_netif_free(struct rcu_head *p)
-{
- struct sel_netif *netif = container_of(p, struct sel_netif, rcu_head);
- kfree(netif);
-}
-
-/**
* sel_netif_destroy - Remove an interface record from the table
* @netif: the existing interface record
*
@@ -131,7 +115,7 @@ static void sel_netif_destroy(struct sel_netif *netif)
{
list_del_rcu(&netif->list);
sel_netif_total--;
- call_rcu(&netif->rcu_head, sel_netif_free);
+ kfree_rcu(netif, rcu_head);
}
/**
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index 65ebfe954f85..3618251d0fdb 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -141,6 +141,7 @@ static struct sel_netnode *sel_netnode_find(const void *addr, u16 family)
break;
default:
BUG();
+ return NULL;
}
list_for_each_entry_rcu(node, &sel_netnode_hash[idx].list, list)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index ea39cb742ae5..35459340019e 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -28,6 +28,8 @@
#include <linux/percpu.h>
#include <linux/audit.h>
#include <linux/uaccess.h>
+#include <linux/kobject.h>
+#include <linux/ctype.h>
/* selinuxfs pseudo filesystem for exporting the security policy API.
Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -280,7 +282,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
length = -ENOMEM;
if (count >= PAGE_SIZE)
- goto out;;
+ goto out;
/* No partial writes. */
length = -EINVAL;
@@ -750,14 +752,24 @@ out:
return length;
}
+static inline int hexcode_to_int(int code) {
+ if (code == '\0' || !isxdigit(code))
+ return -1;
+ if (isdigit(code))
+ return code - '0';
+ return tolower(code) - 'a' + 10;
+}
+
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
char *scon = NULL, *tcon = NULL;
+ char *namebuf = NULL, *objname = NULL;
u32 ssid, tsid, newsid;
u16 tclass;
ssize_t length;
char *newcon = NULL;
u32 len;
+ int nargs;
length = task_has_security(current, SECURITY__COMPUTE_CREATE);
if (length)
@@ -773,10 +785,44 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (!tcon)
goto out;
- length = -EINVAL;
- if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
+ length = -ENOMEM;
+ namebuf = kzalloc(size + 1, GFP_KERNEL);
+ if (!namebuf)
goto out;
+ length = -EINVAL;
+ nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
+ if (nargs < 3 || nargs > 4)
+ goto out;
+ if (nargs == 4) {
+ /*
+ * If and when the name of new object to be queried contains
+ * either whitespace or multibyte characters, they shall be
+ * encoded based on the percentage-encoding rule.
+ * If not encoded, the sscanf logic picks up only left-half
+ * of the supplied name; splitted by a whitespace unexpectedly.
+ */
+ char *r, *w;
+ int c1, c2;
+
+ r = w = namebuf;
+ do {
+ c1 = *r++;
+ if (c1 == '+')
+ c1 = ' ';
+ else if (c1 == '%') {
+ if ((c1 = hexcode_to_int(*r++)) < 0)
+ goto out;
+ if ((c2 = hexcode_to_int(*r++)) < 0)
+ goto out;
+ c1 = (c1 << 4) | c2;
+ }
+ *w++ = c1;
+ } while (c1 != '\0');
+
+ objname = namebuf;
+ }
+
length = security_context_to_sid(scon, strlen(scon) + 1, &ssid);
if (length)
goto out;
@@ -785,7 +831,8 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
if (length)
goto out;
- length = security_transition_sid_user(ssid, tsid, tclass, &newsid);
+ length = security_transition_sid_user(ssid, tsid, tclass,
+ objname, &newsid);
if (length)
goto out;
@@ -804,6 +851,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
length = len;
out:
kfree(newcon);
+ kfree(namebuf);
kfree(tcon);
kfree(scon);
return length;
@@ -876,12 +924,12 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
length = task_has_security(current, SECURITY__COMPUTE_USER);
if (length)
- goto out;;
+ goto out;
length = -ENOMEM;
con = kzalloc(size + 1, GFP_KERNEL);
if (!con)
- goto out;;
+ goto out;
length = -ENOMEM;
user = kzalloc(size + 1, GFP_KERNEL);
@@ -941,7 +989,7 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
length = -ENOMEM;
scon = kzalloc(size + 1, GFP_KERNEL);
if (!scon)
- goto out;;
+ goto out;
length = -ENOMEM;
tcon = kzalloc(size + 1, GFP_KERNEL);
@@ -1380,10 +1428,14 @@ static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
if (v == SEQ_START_TOKEN)
seq_printf(seq, "lookups hits misses allocations reclaims "
"frees\n");
- else
- seq_printf(seq, "%u %u %u %u %u %u\n", st->lookups,
- st->hits, st->misses, st->allocations,
+ else {
+ unsigned int lookups = st->lookups;
+ unsigned int misses = st->misses;
+ unsigned int hits = lookups - misses;
+ seq_printf(seq, "%u %u %u %u %u %u\n", lookups,
+ hits, misses, st->allocations,
st->reclaims, st->frees);
+ }
return 0;
}
@@ -1897,6 +1949,7 @@ static struct file_system_type sel_fs_type = {
};
struct vfsmount *selinuxfs_mount;
+static struct kobject *selinuxfs_kobj;
static int __init init_sel_fs(void)
{
@@ -1904,9 +1957,16 @@ static int __init init_sel_fs(void)
if (!selinux_enabled)
return 0;
+
+ selinuxfs_kobj = kobject_create_and_add("selinux", fs_kobj);
+ if (!selinuxfs_kobj)
+ return -ENOMEM;
+
err = register_filesystem(&sel_fs_type);
- if (err)
+ if (err) {
+ kobject_put(selinuxfs_kobj);
return err;
+ }
selinuxfs_mount = kern_mount(&sel_fs_type);
if (IS_ERR(selinuxfs_mount)) {
@@ -1923,6 +1983,7 @@ __initcall(init_sel_fs);
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void)
{
+ kobject_put(selinuxfs_kobj);
unregister_filesystem(&sel_fs_type);
}
#endif
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index e7b850ad57ee..d246aca3f4fb 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -128,6 +128,11 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_ROLETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -179,6 +184,43 @@ out:
return rc;
}
+static u32 filenametr_hash(struct hashtab *h, const void *k)
+{
+ const struct filename_trans *ft = k;
+ unsigned long hash;
+ unsigned int byte_num;
+ unsigned char focus;
+
+ hash = ft->stype ^ ft->ttype ^ ft->tclass;
+
+ byte_num = 0;
+ while ((focus = ft->name[byte_num++]))
+ hash = partial_name_hash(focus, hash);
+ return hash & (h->size - 1);
+}
+
+static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
+{
+ const struct filename_trans *ft1 = k1;
+ const struct filename_trans *ft2 = k2;
+ int v;
+
+ v = ft1->stype - ft2->stype;
+ if (v)
+ return v;
+
+ v = ft1->ttype - ft2->ttype;
+ if (v)
+ return v;
+
+ v = ft1->tclass - ft2->tclass;
+ if (v)
+ return v;
+
+ return strcmp(ft1->name, ft2->name);
+
+}
+
static u32 rangetr_hash(struct hashtab *h, const void *k)
{
const struct range_trans *key = k;
@@ -231,15 +273,22 @@ static int policydb_init(struct policydb *p)
if (rc)
goto out;
+ p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
+ if (!p->filename_trans)
+ goto out;
+
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
if (!p->range_tr)
goto out;
+ ebitmap_init(&p->filename_trans_ttypes);
ebitmap_init(&p->policycaps);
ebitmap_init(&p->permissive_map);
return 0;
out:
+ hashtab_destroy(p->filename_trans);
+ hashtab_destroy(p->range_tr);
for (i = 0; i < SYM_NUM; i++)
hashtab_destroy(p->symtab[i].table);
return rc;
@@ -417,32 +466,26 @@ static int (*index_f[SYM_NUM]) (void *key, void *datum, void *datap) =
};
#ifdef DEBUG_HASHES
-static void symtab_hash_eval(struct symtab *s)
+static void hash_eval(struct hashtab *h, const char *hash_name)
{
- int i;
-
- for (i = 0; i < SYM_NUM; i++) {
- struct hashtab *h = s[i].table;
- struct hashtab_info info;
+ struct hashtab_info info;
- hashtab_stat(h, &info);
- printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
- "longest chain length %d\n", symtab_name[i], h->nel,
- info.slots_used, h->size, info.max_chain_len);
- }
+ hashtab_stat(h, &info);
+ printk(KERN_DEBUG "SELinux: %s: %d entries and %d/%d buckets used, "
+ "longest chain length %d\n", hash_name, h->nel,
+ info.slots_used, h->size, info.max_chain_len);
}
-static void rangetr_hash_eval(struct hashtab *h)
+static void symtab_hash_eval(struct symtab *s)
{
- struct hashtab_info info;
+ int i;
- hashtab_stat(h, &info);
- printk(KERN_DEBUG "SELinux: rangetr: %d entries and %d/%d buckets used, "
- "longest chain length %d\n", h->nel,
- info.slots_used, h->size, info.max_chain_len);
+ for (i = 0; i < SYM_NUM; i++)
+ hash_eval(s[i].table, symtab_name[i]);
}
+
#else
-static inline void rangetr_hash_eval(struct hashtab *h)
+static inline void hash_eval(struct hashtab *h, char *hash_name)
{
}
#endif
@@ -502,7 +545,7 @@ static int policydb_index(struct policydb *p)
goto out;
rc = flex_array_prealloc(p->type_val_to_struct_array, 0,
- p->p_types.nprim - 1, GFP_KERNEL | __GFP_ZERO);
+ p->p_types.nprim, GFP_KERNEL | __GFP_ZERO);
if (rc)
goto out;
@@ -519,7 +562,7 @@ static int policydb_index(struct policydb *p)
goto out;
rc = flex_array_prealloc(p->sym_val_to_name[i],
- 0, p->symtab[i].nprim - 1,
+ 0, p->symtab[i].nprim,
GFP_KERNEL | __GFP_ZERO);
if (rc)
goto out;
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
cat_destroy,
};
+static int filenametr_destroy(void *key, void *datum, void *p)
+{
+ struct filename_trans *ft = key;
+ kfree(ft->name);
+ kfree(key);
+ kfree(datum);
+ cond_resched();
+ return 0;
+}
+
static int range_tr_destroy(void *key, void *datum, void *p)
{
struct mls_range *rt = datum;
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p)
int i;
struct role_allow *ra, *lra = NULL;
struct role_trans *tr, *ltr = NULL;
- struct filename_trans *ft, *nft;
for (i = 0; i < SYM_NUM; i++) {
cond_resched();
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
}
kfree(lra);
+ hashtab_map(p->filename_trans, filenametr_destroy, NULL);
+ hashtab_destroy(p->filename_trans);
+
hashtab_map(p->range_tr, range_tr_destroy, NULL);
hashtab_destroy(p->range_tr);
@@ -788,14 +843,7 @@ void policydb_destroy(struct policydb *p)
flex_array_free(p->type_attr_map_array);
}
- ft = p->filename_trans;
- while (ft) {
- nft = ft->next;
- kfree(ft->name);
- kfree(ft);
- ft = nft;
- }
-
+ ebitmap_destroy(&p->filename_trans_ttypes);
ebitmap_destroy(&p->policycaps);
ebitmap_destroy(&p->permissive_map);
@@ -1795,7 +1843,7 @@ static int range_read(struct policydb *p, void *fp)
rt = NULL;
r = NULL;
}
- rangetr_hash_eval(p->range_tr);
+ hash_eval(p->range_tr, "rangetr");
rc = 0;
out:
kfree(rt);
@@ -1805,9 +1853,10 @@ out:
static int filename_trans_read(struct policydb *p, void *fp)
{
- struct filename_trans *ft, *last;
- u32 nel, len;
+ struct filename_trans *ft;
+ struct filename_trans_datum *otype;
char *name;
+ u32 nel, len;
__le32 buf[4];
int rc, i;
@@ -1816,27 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
- goto out;
+ return rc;
nel = le32_to_cpu(buf[0]);
- printk(KERN_ERR "%s: nel=%d\n", __func__, nel);
-
- last = p->filename_trans;
- while (last && last->next)
- last = last->next;
-
for (i = 0; i < nel; i++) {
+ ft = NULL;
+ otype = NULL;
+ name = NULL;
+
rc = -ENOMEM;
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
if (!ft)
goto out;
- /* add it to the tail of the list */
- if (!last)
- p->filename_trans = ft;
- else
- last->next = ft;
- last = ft;
+ rc = -ENOMEM;
+ otype = kmalloc(sizeof(*otype), GFP_KERNEL);
+ if (!otype)
+ goto out;
/* length of the path component string */
rc = next_entry(buf, fp, sizeof(u32));
@@ -1857,8 +1902,6 @@ static int filename_trans_read(struct policydb *p, void *fp)
goto out;
name[len] = 0;
- printk(KERN_ERR "%s: ft=%p ft->name=%p ft->name=%s\n", __func__, ft, ft->name, ft->name);
-
rc = next_entry(buf, fp, sizeof(u32) * 4);
if (rc)
goto out;
@@ -1866,10 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
ft->stype = le32_to_cpu(buf[0]);
ft->ttype = le32_to_cpu(buf[1]);
ft->tclass = le32_to_cpu(buf[2]);
- ft->otype = le32_to_cpu(buf[3]);
+
+ otype->otype = le32_to_cpu(buf[3]);
+
+ rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
+ if (rc)
+ goto out;
+
+ hashtab_insert(p->filename_trans, ft, otype);
}
- rc = 0;
+ hash_eval(p->filename_trans, "filenametr");
+ return 0;
out:
+ kfree(ft);
+ kfree(name);
+ kfree(otype);
+
return rc;
}
@@ -2270,6 +2325,11 @@ int policydb_read(struct policydb *p, void *fp)
p->symtab[i].nprim = nprim;
}
+ rc = -EINVAL;
+ p->process_class = string_to_security_class(p, "process");
+ if (!p->process_class)
+ goto bad;
+
rc = avtab_read(&p->te_avtab, fp, p);
if (rc)
goto bad;
@@ -2302,8 +2362,17 @@ int policydb_read(struct policydb *p, void *fp)
tr->role = le32_to_cpu(buf[0]);
tr->type = le32_to_cpu(buf[1]);
tr->new_role = le32_to_cpu(buf[2]);
+ if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc)
+ goto bad;
+ tr->tclass = le32_to_cpu(buf[0]);
+ } else
+ tr->tclass = p->process_class;
+
if (!policydb_role_isvalid(p, tr->role) ||
!policydb_type_isvalid(p, tr->type) ||
+ !policydb_class_isvalid(p, tr->tclass) ||
!policydb_role_isvalid(p, tr->new_role))
goto bad;
ltr = tr;
@@ -2345,11 +2414,6 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
rc = -EINVAL;
- p->process_class = string_to_security_class(p, "process");
- if (!p->process_class)
- goto bad;
-
- rc = -EINVAL;
p->process_trans_perms = string_to_av_perm(p, p->process_class, "transition");
p->process_trans_perms |= string_to_av_perm(p, p->process_class, "dyntransition");
if (!p->process_trans_perms)
@@ -2375,7 +2439,7 @@ int policydb_read(struct policydb *p, void *fp)
goto bad;
/* preallocate so we don't have to worry about the put ever failing */
- rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim - 1,
+ rc = flex_array_prealloc(p->type_attr_map_array, 0, p->p_types.nprim,
GFP_KERNEL | __GFP_ZERO);
if (rc)
goto bad;
@@ -2521,8 +2585,9 @@ static int cat_write(void *vkey, void *datum, void *ptr)
return 0;
}
-static int role_trans_write(struct role_trans *r, void *fp)
+static int role_trans_write(struct policydb *p, void *fp)
{
+ struct role_trans *r = p->role_tr;
struct role_trans *tr;
u32 buf[3];
size_t nel;
@@ -2542,6 +2607,12 @@ static int role_trans_write(struct role_trans *r, void *fp)
rc = put_entry(buf, sizeof(u32), 3, fp);
if (rc)
return rc;
+ if (p->policyvers >= POLICYDB_VERSION_ROLETRANS) {
+ buf[0] = cpu_to_le32(tr->tclass);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
+ }
}
return 0;
@@ -3049,7 +3120,7 @@ static int genfs_write(struct policydb *p, void *fp)
return 0;
}
-static int range_count(void *key, void *data, void *ptr)
+static int hashtab_cnt(void *key, void *data, void *ptr)
{
int *cnt = ptr;
*cnt = *cnt + 1;
@@ -3097,7 +3168,7 @@ static int range_write(struct policydb *p, void *fp)
/* count the number of entries in the hashtab */
nel = 0;
- rc = hashtab_map(p->range_tr, range_count, &nel);
+ rc = hashtab_map(p->range_tr, hashtab_cnt, &nel);
if (rc)
return rc;
@@ -3114,43 +3185,63 @@ static int range_write(struct policydb *p, void *fp)
return 0;
}
-static int filename_trans_write(struct policydb *p, void *fp)
+static int filename_write_helper(void *key, void *data, void *ptr)
{
- struct filename_trans *ft;
- u32 len, nel = 0;
__le32 buf[4];
+ struct filename_trans *ft = key;
+ struct filename_trans_datum *otype = data;
+ void *fp = ptr;
int rc;
+ u32 len;
- for (ft = p->filename_trans; ft; ft = ft->next)
- nel++;
-
- buf[0] = cpu_to_le32(nel);
+ len = strlen(ft->name);
+ buf[0] = cpu_to_le32(len);
rc = put_entry(buf, sizeof(u32), 1, fp);
if (rc)
return rc;
- for (ft = p->filename_trans; ft; ft = ft->next) {
- len = strlen(ft->name);
- buf[0] = cpu_to_le32(len);
- rc = put_entry(buf, sizeof(u32), 1, fp);
- if (rc)
- return rc;
+ rc = put_entry(ft->name, sizeof(char), len, fp);
+ if (rc)
+ return rc;
- rc = put_entry(ft->name, sizeof(char), len, fp);
- if (rc)
- return rc;
+ buf[0] = ft->stype;
+ buf[1] = ft->ttype;
+ buf[2] = ft->tclass;
+ buf[3] = otype->otype;
- buf[0] = ft->stype;
- buf[1] = ft->ttype;
- buf[2] = ft->tclass;
- buf[3] = ft->otype;
+ rc = put_entry(buf, sizeof(u32), 4, fp);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int filename_trans_write(struct policydb *p, void *fp)
+{
+ u32 nel;
+ __le32 buf[1];
+ int rc;
+
+ if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS)
+ return 0;
+
+ nel = 0;
+ rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
+ if (rc)
+ return rc;
+
+ buf[0] = cpu_to_le32(nel);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return rc;
+
+ rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
+ if (rc)
+ return rc;
- rc = put_entry(buf, sizeof(u32), 4, fp);
- if (rc)
- return rc;
- }
return 0;
}
+
/*
* Write the configuration data in a policy database
* structure to a policy database binary representation
@@ -3253,7 +3344,7 @@ int policydb_write(struct policydb *p, void *fp)
if (rc)
return rc;
- rc = role_trans_write(p->role_tr, fp);
+ rc = role_trans_write(p, fp);
if (rc)
return rc;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index 732ea4a68682..b846c0387180 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -72,17 +72,20 @@ struct role_datum {
struct role_trans {
u32 role; /* current role */
- u32 type; /* program executable type */
+ u32 type; /* program executable type, or new object type */
+ u32 tclass; /* process class, or new object class */
u32 new_role; /* new role */
struct role_trans *next;
};
struct filename_trans {
- struct filename_trans *next;
u32 stype; /* current process */
u32 ttype; /* parent dir context */
u16 tclass; /* class of new object */
const char *name; /* last path component */
+};
+
+struct filename_trans_datum {
u32 otype; /* expected of new object */
};
@@ -227,7 +230,10 @@ struct policydb {
struct role_trans *role_tr;
/* file transitions with the last path component */
- struct filename_trans *filename_trans;
+ /* quickly exclude lookups when parent ttype has no rules */
+ struct ebitmap filename_trans_ttypes;
+ /* actual set of filename_trans rules */
+ struct hashtab *filename_trans;
/* bools indexed by (value - 1) */
struct cond_bool_datum **bool_val_to_struct;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 6ef4af47dac4..973e00e34fa9 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1359,26 +1359,35 @@ out:
}
static void filename_compute_type(struct policydb *p, struct context *newcontext,
- u32 scon, u32 tcon, u16 tclass,
- const struct qstr *qstr)
-{
- struct filename_trans *ft;
- for (ft = p->filename_trans; ft; ft = ft->next) {
- if (ft->stype == scon &&
- ft->ttype == tcon &&
- ft->tclass == tclass &&
- !strcmp(ft->name, qstr->name)) {
- newcontext->type = ft->otype;
- return;
- }
- }
+ u32 stype, u32 ttype, u16 tclass,
+ const char *objname)
+{
+ struct filename_trans ft;
+ struct filename_trans_datum *otype;
+
+ /*
+ * Most filename trans rules are going to live in specific directories
+ * like /dev or /var/run. This bitmap will quickly skip rule searches
+ * if the ttype does not contain any rules.
+ */
+ if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
+ return;
+
+ ft.stype = stype;
+ ft.ttype = ttype;
+ ft.tclass = tclass;
+ ft.name = objname;
+
+ otype = hashtab_search(p->filename_trans, &ft);
+ if (otype)
+ newcontext->type = otype->otype;
}
static int security_compute_sid(u32 ssid,
u32 tsid,
u16 orig_tclass,
u32 specified,
- const struct qstr *qstr,
+ const char *objname,
u32 *out_sid,
bool kern)
{
@@ -1478,23 +1487,21 @@ static int security_compute_sid(u32 ssid,
newcontext.type = avdatum->data;
}
- /* if we have a qstr this is a file trans check so check those rules */
- if (qstr)
+ /* if we have a objname this is a file trans check so check those rules */
+ if (objname)
filename_compute_type(&policydb, &newcontext, scontext->type,
- tcontext->type, tclass, qstr);
+ tcontext->type, tclass, objname);
/* Check for class-specific changes. */
- if (tclass == policydb.process_class) {
- if (specified & AVTAB_TRANSITION) {
- /* Look for a role transition rule. */
- for (roletr = policydb.role_tr; roletr;
- roletr = roletr->next) {
- if (roletr->role == scontext->role &&
- roletr->type == tcontext->type) {
- /* Use the role transition rule. */
- newcontext.role = roletr->new_role;
- break;
- }
+ if (specified & AVTAB_TRANSITION) {
+ /* Look for a role transition rule. */
+ for (roletr = policydb.role_tr; roletr; roletr = roletr->next) {
+ if ((roletr->role == scontext->role) &&
+ (roletr->type == tcontext->type) &&
+ (roletr->tclass == tclass)) {
+ /* Use the role transition rule. */
+ newcontext.role = roletr->new_role;
+ break;
}
}
}
@@ -1541,13 +1548,14 @@ int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
const struct qstr *qstr, u32 *out_sid)
{
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
- qstr, out_sid, true);
+ qstr ? qstr->name : NULL, out_sid, true);
}
-int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, u32 *out_sid)
+int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
+ const char *objname, u32 *out_sid)
{
return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION,
- NULL, out_sid, false);
+ objname, out_sid, false);
}
/**
@@ -2209,10 +2217,11 @@ out_unlock:
goto out;
}
for (i = 0, j = 0; i < mynel; i++) {
+ struct av_decision dummy_avd;
rc = avc_has_perm_noaudit(fromsid, mysids[i],
SECCLASS_PROCESS, /* kernel value */
PROCESS__TRANSITION, AVC_STRICT,
- NULL);
+ &dummy_avd);
if (!rc)
mysids2[j++] = mysids[i];
cond_resched();
@@ -3190,7 +3199,7 @@ out:
* @len: length of data in bytes
*
*/
-int security_read_policy(void **data, ssize_t *len)
+int security_read_policy(void **data, size_t *len)
{
int rc;
struct policy_file fp;