⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 avc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	unsigned long flag;	if (avc_latest_notif_update(ae->avd.seqno, 1))		goto out;	node = avc_alloc_node();	if (node) {		hvalue = avc_hash(ssid, tsid, tclass);		avc_node_populate(node, ssid, tsid, tclass, ae);		spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);		list_for_each_entry(pos, &avc_cache.slots[hvalue], list) {			if (pos->ae.ssid == ssid &&			    pos->ae.tsid == tsid &&			    pos->ae.tclass == tclass) {			    	avc_node_replace(node, pos);				goto found;			}		}		list_add_rcu(&node->list, &avc_cache.slots[hvalue]);found:		spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);	}out:	return node;}static inline void avc_print_ipv6_addr(struct audit_buffer *ab,				       struct in6_addr *addr, __be16 port,				       char *name1, char *name2){	if (!ipv6_addr_any(addr))		audit_log_format(ab, " %s=" NIP6_FMT, name1, NIP6(*addr));	if (port)		audit_log_format(ab, " %s=%d", name2, ntohs(port));}static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr,				       __be16 port, char *name1, char *name2){	if (addr)		audit_log_format(ab, " %s=" NIPQUAD_FMT, name1, NIPQUAD(addr));	if (port)		audit_log_format(ab, " %s=%d", name2, ntohs(port));}/** * avc_audit - Audit the granting or denial of permissions. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @requested: requested permissions * @avd: access vector decisions * @result: result from avc_has_perm_noaudit * @a:  auxiliary audit data * * Audit the granting or denial of permissions in accordance * with the policy.  This function is typically called by * avc_has_perm() after a permission check, but can also be * called directly by callers who use avc_has_perm_noaudit() * in order to separate the permission check from the auditing. * For example, this separation is useful when the permission check must * be performed under a lock, to allow the lock to be released * before calling the auditing code. */void avc_audit(u32 ssid, u32 tsid,               u16 tclass, u32 requested,               struct av_decision *avd, int result, struct avc_audit_data *a){	struct task_struct *tsk = current;	struct inode *inode = NULL;	u32 denied, audited;	struct audit_buffer *ab;	denied = requested & ~avd->allowed;	if (denied) {		audited = denied;		if (!(audited & avd->auditdeny))			return;	} else if (result) {		audited = denied = requested;        } else {		audited = requested;		if (!(audited & avd->auditallow))			return;	}	ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);	if (!ab)		return;		/* audit_panic has been called */	audit_log_format(ab, "avc:  %s ", denied ? "denied" : "granted");	avc_dump_av(ab, tclass,audited);	audit_log_format(ab, " for ");	if (a && a->tsk)		tsk = a->tsk;	if (tsk && tsk->pid) {		audit_log_format(ab, " pid=%d comm=", tsk->pid);		audit_log_untrustedstring(ab, tsk->comm);	}	if (a) {		switch (a->type) {		case AVC_AUDIT_DATA_IPC:			audit_log_format(ab, " key=%d", a->u.ipc_id);			break;		case AVC_AUDIT_DATA_CAP:			audit_log_format(ab, " capability=%d", a->u.cap);			break;		case AVC_AUDIT_DATA_FS:			if (a->u.fs.dentry) {				struct dentry *dentry = a->u.fs.dentry;				if (a->u.fs.mnt) {					audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt);				} else {					audit_log_format(ab, " name=");					audit_log_untrustedstring(ab, dentry->d_name.name);				}				inode = dentry->d_inode;			} else if (a->u.fs.inode) {				struct dentry *dentry;				inode = a->u.fs.inode;				dentry = d_find_alias(inode);				if (dentry) {					audit_log_format(ab, " name=");					audit_log_untrustedstring(ab, dentry->d_name.name);					dput(dentry);				}			}			if (inode)				audit_log_format(ab, " dev=%s ino=%lu",						 inode->i_sb->s_id,						 inode->i_ino);			break;		case AVC_AUDIT_DATA_NET:			if (a->u.net.sk) {				struct sock *sk = a->u.net.sk;				struct unix_sock *u;				int len = 0;				char *p = NULL;				switch (sk->sk_family) {				case AF_INET: {					struct inet_sock *inet = inet_sk(sk);					avc_print_ipv4_addr(ab, inet->rcv_saddr,							    inet->sport,							    "laddr", "lport");					avc_print_ipv4_addr(ab, inet->daddr,							    inet->dport,							    "faddr", "fport");					break;				}				case AF_INET6: {					struct inet_sock *inet = inet_sk(sk);					struct ipv6_pinfo *inet6 = inet6_sk(sk);					avc_print_ipv6_addr(ab, &inet6->rcv_saddr,							    inet->sport,							    "laddr", "lport");					avc_print_ipv6_addr(ab, &inet6->daddr,							    inet->dport,							    "faddr", "fport");					break;				}				case AF_UNIX:					u = unix_sk(sk);					if (u->dentry) {						audit_log_d_path(ab, "path=",								 u->dentry, u->mnt);						break;					}					if (!u->addr)						break;					len = u->addr->len-sizeof(short);					p = &u->addr->name->sun_path[0];					audit_log_format(ab, " path=");					if (*p)						audit_log_untrustedstring(ab, p);					else						audit_log_hex(ab, p, len);					break;				}			}						switch (a->u.net.family) {			case AF_INET:				avc_print_ipv4_addr(ab, a->u.net.v4info.saddr,						    a->u.net.sport,						    "saddr", "src");				avc_print_ipv4_addr(ab, a->u.net.v4info.daddr,						    a->u.net.dport,						    "daddr", "dest");				break;			case AF_INET6:				avc_print_ipv6_addr(ab, &a->u.net.v6info.saddr,						    a->u.net.sport,						    "saddr", "src");				avc_print_ipv6_addr(ab, &a->u.net.v6info.daddr,						    a->u.net.dport,						    "daddr", "dest");				break;			}			if (a->u.net.netif)				audit_log_format(ab, " netif=%s",					a->u.net.netif);			break;		}	}	audit_log_format(ab, " ");	avc_dump_query(ab, ssid, tsid, tclass);	audit_log_end(ab);}/** * avc_add_callback - Register a callback for security events. * @callback: callback function * @events: security events * @ssid: source security identifier or %SECSID_WILD * @tsid: target security identifier or %SECSID_WILD * @tclass: target security class * @perms: permissions * * Register a callback function for events in the set @events * related to the SID pair (@ssid, @tsid) and * and the permissions @perms, interpreting * @perms based on @tclass.  Returns %0 on success or * -%ENOMEM if insufficient memory exists to add the callback. */int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,                                     u16 tclass, u32 perms,                                     u32 *out_retained),                     u32 events, u32 ssid, u32 tsid,                     u16 tclass, u32 perms){	struct avc_callback_node *c;	int rc = 0;	c = kmalloc(sizeof(*c), GFP_ATOMIC);	if (!c) {		rc = -ENOMEM;		goto out;	}	c->callback = callback;	c->events = events;	c->ssid = ssid;	c->tsid = tsid;	c->perms = perms;	c->next = avc_callbacks;	avc_callbacks = c;out:	return rc;}static inline int avc_sidcmp(u32 x, u32 y){	return (x == y || x == SECSID_WILD || y == SECSID_WILD);}/** * avc_update_node Update an AVC entry * @event : Updating event * @perms : Permission mask bits * @ssid,@tsid,@tclass : identifier of an AVC entry * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. * otherwise, this function update the AVC entry. The original AVC-entry object * will release later by RCU. */static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass){	int hvalue, rc = 0;	unsigned long flag;	struct avc_node *pos, *node, *orig = NULL;	node = avc_alloc_node();	if (!node) {		rc = -ENOMEM;		goto out;	}	/* Lock the target slot */	hvalue = avc_hash(ssid, tsid, tclass);	spin_lock_irqsave(&avc_cache.slots_lock[hvalue], flag);	list_for_each_entry(pos, &avc_cache.slots[hvalue], list){		if ( ssid==pos->ae.ssid &&		     tsid==pos->ae.tsid &&		     tclass==pos->ae.tclass ){			orig = pos;			break;		}	}	if (!orig) {		rc = -ENOENT;		avc_node_kill(node);		goto out_unlock;	}	/*	 * Copy and replace original node.	 */	avc_node_populate(node, ssid, tsid, tclass, &orig->ae);	switch (event) {	case AVC_CALLBACK_GRANT:		node->ae.avd.allowed |= perms;		break;	case AVC_CALLBACK_TRY_REVOKE:	case AVC_CALLBACK_REVOKE:		node->ae.avd.allowed &= ~perms;		break;	case AVC_CALLBACK_AUDITALLOW_ENABLE:		node->ae.avd.auditallow |= perms;		break;	case AVC_CALLBACK_AUDITALLOW_DISABLE:		node->ae.avd.auditallow &= ~perms;		break;	case AVC_CALLBACK_AUDITDENY_ENABLE:		node->ae.avd.auditdeny |= perms;		break;	case AVC_CALLBACK_AUDITDENY_DISABLE:		node->ae.avd.auditdeny &= ~perms;		break;	}	avc_node_replace(node, orig);out_unlock:	spin_unlock_irqrestore(&avc_cache.slots_lock[hvalue], flag);out:	return rc;}/** * avc_ss_reset - Flush the cache and revalidate migrated permissions. * @seqno: policy sequence number */int avc_ss_reset(u32 seqno){	struct avc_callback_node *c;	int i, rc = 0, tmprc;	unsigned long flag;	struct avc_node *node;	for (i = 0; i < AVC_CACHE_SLOTS; i++) {		spin_lock_irqsave(&avc_cache.slots_lock[i], flag);		list_for_each_entry(node, &avc_cache.slots[i], list)			avc_node_delete(node);		spin_unlock_irqrestore(&avc_cache.slots_lock[i], flag);	}	for (c = avc_callbacks; c; c = c->next) {		if (c->events & AVC_CALLBACK_RESET) {			tmprc = c->callback(AVC_CALLBACK_RESET,			                    0, 0, 0, 0, NULL);			/* save the first error encountered for the return			   value and continue processing the callbacks */			if (!rc)				rc = tmprc;		}	}	avc_latest_notif_update(seqno, 0);	return rc;}/** * avc_has_perm_noaudit - Check permissions but perform no auditing. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass * @flags:  AVC_STRICT or 0 * @avd: access vector decisions * * Check the AVC to determine whether the @requested permissions are granted * for the SID pair (@ssid, @tsid), interpreting the permissions * based on @tclass, and call the security server on a cache miss to obtain * a new decision and add it to the cache.  Return a copy of the decisions * in @avd.  Return %0 if all @requested permissions are granted, * -%EACCES if any permissions are denied, or another -errno upon * other errors.  This function is typically called by avc_has_perm(), * but may also be called directly to separate permission checking from * auditing, e.g. in cases where a lock must be held for the check but * should be released for the auditing. */int avc_has_perm_noaudit(u32 ssid, u32 tsid,			 u16 tclass, u32 requested,			 unsigned flags,			 struct av_decision *avd){	struct avc_node *node;	struct avc_entry entry, *p_ae;	int rc = 0;	u32 denied;	rcu_read_lock();	node = avc_lookup(ssid, tsid, tclass, requested);	if (!node) {		rcu_read_unlock();		rc = security_compute_av(ssid,tsid,tclass,requested,&entry.avd);		if (rc)			goto out;		rcu_read_lock();		node = avc_insert(ssid,tsid,tclass,&entry);	}	p_ae = node ? &node->ae : &entry;	if (avd)		memcpy(avd, &p_ae->avd, sizeof(*avd));	denied = requested & ~(p_ae->avd.allowed);	if (!requested || denied) {		if (selinux_enforcing || (flags & AVC_STRICT))			rc = -EACCES;		else			if (node)				avc_update_node(AVC_CALLBACK_GRANT,requested,						ssid,tsid,tclass);	}	rcu_read_unlock();out:	return rc;}/** * avc_has_perm - Check permissions and perform any appropriate auditing. * @ssid: source security identifier * @tsid: target security identifier * @tclass: target security class * @requested: requested permissions, interpreted based on @tclass * @auditdata: auxiliary audit data * * Check the AVC to determine whether the @requested permissions are granted * for the SID pair (@ssid, @tsid), interpreting the permissions * based on @tclass, and call the security server on a cache miss to obtain * a new decision and add it to the cache.  Audit the granting or denial of * permissions in accordance with the policy.  Return %0 if all @requested * 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 avc_audit_data *auditdata){	struct av_decision avd;	int rc;	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);	avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);	return rc;}u32 avc_policy_seqno(void){	return avc_cache.latest_notif;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -