Skip to contentSkip to conversation

An idea of thread/child-domain assignment

RFC Applied KaiGai Kohei 9 participants 97 messages Jul 15, 2008 – Oct 23, 2008 SELinux security module

lore
Share & tools
lore
#0 lore raw

Hi,

I'm now considering the way to apply SELinux from the bottom of LAPP stack to the head. But there is a fundamental matter. Web/Application server can execute a request come from users in a worker thread.

This idea enables to assign an indivisual domain on a thread under the paticular condition.
I'm sorry for a long description, but I thought it need to describe the background of this idea for well understanding.

Please comment anything.

Backend of the idea
-------------------
How do you define a user?

I consider a user is a human. In the most cases, a human is not good at communication with electronic circuit of computer system, so he makes a substitution of himself to obtain a result which he want.

A process on operating system is a typical substitution of the user. Thus, it has a user identifier and a security context for proper access controls as a substitution of a user.
I'm considering database instances, web backends and others are also the substitution of users, because they works according to the request come from users.

SELinux makes its decison on access controls based on security context of subject and various kind of objects. Now we have three options to assign a security context on a subject, as follows:

1. Authentication ... Operating System
2. Labeled Networking ... SE-PostgreSQL, X/SELinux, Xinetd
3. Do nothing ... Apache, Samba

However, the third option is uncomfortable for system security. It execute a user's request as a part of the server process, even if it is a substitution of the user.

LAPP stack and SELinux
----------------------
Nowaday, numerous of online services are available and most of them are implemented as a web application using PHP, Jservlet and so on. LAPP is a term to represent its system architecture. It shows web applications based on Linux, Apache, PostgreSQL and PHP is a popular combination.

Quoted 1 line

From the viewpoint of SELinux, we cannot apply inidividual access controls

for every request come from clients, because web/application server handle these requests without individual processes (except for CGI invocation). Apache typically assigns a pre-created process/thread with "httpd_t" domain to execute the request, independent from the peer's context.

Now SELinux can cover the lowest two layer of the LAPP stack (OS, RDBMS). It enables to apply consistent/mandatory access controls for them. I think it should be also expanded to whole of the stack to improve web-application security.
But we have a fundamental matter to achieve it.

[1] LAPP Stack and SELinux coverage

 +----------------------------+   <-----------------+
 |  Application (PHP, Tomcat) |                     |
 +----------------------------+                     |
 |    Web Server (Apache)     |                  Future
 +----------------------------+   <-----------+     |
 |  Database (SE-PostgreSQL)  |               |     |
 +----------------------------+   <-----+   Today   |
 | Operating System (SELinux) |       Past    |     |
 +----------------------------+   <-----+-----+-----+

An idea: thread/hierarchical-domain assignment
----------------------------------------------
If possible, Apache should change the security context of web backend during it executes a request come from users.
However, Apache can execute it on a worker thread. It conflicts a wired constraint of SELinux which does not allow a multi-threaded process dynamic domain transition.

It is a reasonable constraint, if the source and destination domains are completely independent. Because it shares a local memory, mixed security context within a process can make a violation in domain separation.

However, a characteristic relationship between hierarchical domains can help the situation. It restricts a child domain (like "httpd_t.staff") cannot over the boundary of its parent ("httpd_t"). It also means a multi-threaded process cannot over the (parent) domain boundary, even if a part of threads has different security context.

My suggestion is the hard-wired constraint should be modified. It allows to assign threads an indivisual domain, if the new domain is a child one of the current domain.

For example:

    httpd_t -> httpd_t.staff           = allowed
    httpd_t -> staff_t                 = disallowed
    httpd_t.staff -> httpd_t.staff.php = allowed

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

Issues: Domain Reverting
------------------------
There is a related issue. To change security context during user request execution also means that we have to revert its domain after executions, because Apache repeatedly uses worker thread/process for some reasons.

I don't have any good idea for this issue yet.
A one time cookie like AppArmor is an approach, but it is basically weak separation compared from execve() transition.

Thanks.

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#1 lore raw
Quoted 8 lines · KaiGai Kohei

Hi,

I'm now considering the way to apply SELinux from the bottom of LAPP stack to the head. But there is a fundamental matter. Web/Application server can execute a request come from users in a worker thread.

This idea enables to assign an indivisual domain on a thread under the paticular condition.

Yes, this came up recently, e.g.:
http://marc.info/?l=selinux&m=121320242220824&w=2

And James added it to the kernel todo list on selinuxproject.org.

Quoted 86 lines

I'm sorry for a long description, but I thought it need to describe the background of this idea for well understanding.

Please comment anything.

Backend of the idea
-------------------
How do you define a user?

I consider a user is a human. In the most cases, a human is not good at communication with electronic circuit of computer system, so he makes a substitution of himself to obtain a result which he want.

A process on operating system is a typical substitution of the user. Thus, it has a user identifier and a security context for proper access controls as a substitution of a user.
I'm considering database instances, web backends and others are also the substitution of users, because they works according to the request come from users.

SELinux makes its decison on access controls based on security context of subject and various kind of objects. Now we have three options to assign a security context on a subject, as follows:

1. Authentication ... Operating System
2. Labeled Networking ... SE-PostgreSQL, X/SELinux, Xinetd
3. Do nothing ... Apache, Samba

However, the third option is uncomfortable for system security. It execute a user's request as a part of the server process, even if it is a substitution of the user.

LAPP stack and SELinux
----------------------
Nowaday, numerous of online services are available and most of them are implemented as a web application using PHP, Jservlet and so on. LAPP is a term to represent its system architecture. It shows web applications based on Linux, Apache, PostgreSQL and PHP is a popular combination.

Quoted 1 line

From the viewpoint of SELinux, we cannot apply inidividual access controls

for every request come from clients, because web/application server handle these requests without individual processes (except for CGI invocation). Apache typically assigns a pre-created process/thread with "httpd_t" domain to execute the request, independent from the peer's context.

Now SELinux can cover the lowest two layer of the LAPP stack (OS, RDBMS). It enables to apply consistent/mandatory access controls for them. I think it should be also expanded to whole of the stack to improve web-application security.
But we have a fundamental matter to achieve it.

[1] LAPP Stack and SELinux coverage

 +----------------------------+   <-----------------+
 |  Application (PHP, Tomcat) |                     |
 +----------------------------+                     |
 |    Web Server (Apache)     |                  Future
 +----------------------------+   <-----------+     |
 |  Database (SE-PostgreSQL)  |               |     |
 +----------------------------+   <-----+   Today   |
 | Operating System (SELinux) |       Past    |     |
 +----------------------------+   <-----+-----+-----+

An idea: thread/hierarchical-domain assignment
----------------------------------------------
If possible, Apache should change the security context of web backend during it executes a request come from users.
However, Apache can execute it on a worker thread. It conflicts a wired constraint of SELinux which does not allow a multi-threaded process dynamic domain transition.

It is a reasonable constraint, if the source and destination domains are completely independent. Because it shares a local memory, mixed security context within a process can make a violation in domain separation.

However, a characteristic relationship between hierarchical domains can help the situation. It restricts a child domain (like "httpd_t.staff") cannot over the boundary of its parent ("httpd_t"). It also means a multi-threaded process cannot over the (parent) domain boundary, even if a part of threads has different security context.

My suggestion is the hard-wired constraint should be modified. It allows to assign threads an indivisual domain, if the new domain is a child one of the current domain.

Quoted 8 lines

For example:

    httpd_t -> httpd_t.staff           = allowed
    httpd_t -> staff_t                 = disallowed
    httpd_t.staff -> httpd_t.staff.php = allowed

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

I tend to agree that we should support such changes in the kernel mechanism and let the use of it be determined by the policy.

In terms of hierarchy though, the plan was to replace the current name-based hierarchy with an explicitly declared hierarchy.

Quoted 10 lines

Issues: Domain Reverting
------------------------
There is a related issue. To change security context during user request execution also means that we have to revert its domain after executions, because Apache repeatedly uses worker thread/process for some reasons.

I don't have any good idea for this issue yet.
A one time cookie like AppArmor is an approach, but it is basically weak separation compared from execve() transition.

Perhaps it could pre-populate different pools of threads for different client security contexts, and then just draw from the correct pool for each client. Then the thread context doesn't have to be reverted at all and we can make the transition unidirectional.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#2 lore raw
Quoted 7 lines · Stephen Smalley
Quoted 6 lines · KaiGai Kohei

Hi,

I'm now considering the way to apply SELinux from the bottom of LAPP stack to the head. But there is a fundamental matter. Web/Application server can execute a request come from users in a worker thread.

Quoted 7 lines
Quoted 2 lines

This idea enables to assign an indivisual domain on a thread under the paticular condition.

Yes, this came up recently, e.g.:
http://marc.info/?l=selinux&m=121320242220824&w=2

And James added it to the kernel todo list on selinuxproject.org.

Thanks, I overlooked this message.

Quoted 31 lines
Quoted 22 lines

An idea: thread/hierarchical-domain assignment
----------------------------------------------
If possible, Apache should change the security context of web backend during it executes a request come from users.
However, Apache can execute it on a worker thread. It conflicts a wired constraint of SELinux which does not allow a multi-threaded process dynamic domain transition.

It is a reasonable constraint, if the source and destination domains are completely independent. Because it shares a local memory, mixed security context within a process can make a violation in domain separation.

However, a characteristic relationship between hierarchical domains can help the situation. It restricts a child domain (like "httpd_t.staff") cannot over the boundary of its parent ("httpd_t"). It also means a multi-threaded process cannot over the (parent) domain boundary, even if a part of threads has different security context.

My suggestion is the hard-wired constraint should be modified. It allows to assign threads an indivisual domain, if the new domain is a child one of the current domain.

Quoted 8 lines

For example:

    httpd_t -> httpd_t.staff           = allowed
    httpd_t -> staff_t                 = disallowed
    httpd_t.staff -> httpd_t.staff.php = allowed

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

Quoted 5 lines

I tend to agree that we should support such changes in the kernel mechanism and let the use of it be determined by the policy.

In terms of hierarchy though, the plan was to replace the current name-based hierarchy with an explicitly declared hierarchy.

It needs a new policy statement like:

  TYPE <child domain> DOMBY <parent domain>;
    or
  TYPEDOMINANCE <parent domain> <child domain> [,<child domain>] ;

I guess these relationships are represented as a ebitmap structure in the kernel, and used to mask permissions during AVC entry creation.

Quoted 6 lines
Quoted 6 lines

Issues: Domain Reverting
------------------------
There is a related issue. To change security context during user request execution also means that we have to revert its domain after executions, because Apache repeatedly uses worker thread/process for some reasons.

Quoted 8 lines
Quoted 3 lines

I don't have any good idea for this issue yet.
A one time cookie like AppArmor is an approach, but it is basically weak separation compared from execve() transition.

Perhaps it could pre-populate different pools of threads for different client security contexts, and then just draw from the correct pool for each client. Then the thread context doesn't have to be reverted at all and we can make the transition unidirectional.

I think this approach requires two precondition.

(1) The number of client security context should be enough small. If we want to assign one of MCS categories, it requires 1024 of thread pool in maximum.

(2) We have to know what client security context should be assigned before the communication between client and backend thread. In the case when we use HTTP authentication to decide client security context, the authentication process has to be done in the backend process after the communication started.
It may also require major works in application updates.

In my impression, AA's approach is not perfect, but second best one...

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#3 lore raw
Quoted 9 lines
Quoted 8 lines
Quoted 3 lines

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

I tend to agree that we should support such changes in the kernel mechanism and let the use of it be determined by the policy.

In terms of hierarchy though, the plan was to replace the current name-based hierarchy with an explicitly declared hierarchy.

Quoted 8 lines

It needs a new policy statement like:

  TYPE <child domain> DOMBY <parent domain>;
    or
  TYPEDOMINANCE <parent domain> <child domain> [,<child domain>] ;

I guess these relationships are represented as a ebitmap structure in the kernel, and used to mask permissions during AVC entry creation.

Should it be possible to have multiple parent domains on the explicitly declared hierarchy?

The current name-based hierarchy only supports tree-shaped structure. (A child domain can have one parent at most.)
It implicitly enables to avoid a matter of loop of relationship between parents and children.

If we can define a domain with multiple parent, it makes the logic to detect the loop complicated.

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#4 lore raw
Quoted 21 lines · KaiGai Kohei
Quoted 9 lines
Quoted 8 lines
Quoted 3 lines

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

I tend to agree that we should support such changes in the kernel mechanism and let the use of it be determined by the policy.

In terms of hierarchy though, the plan was to replace the current name-based hierarchy with an explicitly declared hierarchy.

Quoted 8 lines

It needs a new policy statement like:

  TYPE <child domain> DOMBY <parent domain>;
    or
  TYPEDOMINANCE <parent domain> <child domain> [,<child domain>] ;

I guess these relationships are represented as a ebitmap structure in the kernel, and used to mask permissions during AVC entry creation.

Should it be possible to have multiple parent domains on the explicitly declared hierarchy?

Quoted 7 lines

The current name-based hierarchy only supports tree-shaped structure. (A child domain can have one parent at most.)
It implicitly enables to avoid a matter of loop of relationship between parents and children.

If we can define a domain with multiple parent, it makes the logic to detect the loop complicated.

I don't see a reason for supporting multiple parents.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#5 lore raw
In reply to KaiGai Kohei
Quoted 56 lines · KaiGai Kohei
Quoted 7 lines · Stephen Smalley
Quoted 6 lines · KaiGai Kohei

Hi,

I'm now considering the way to apply SELinux from the bottom of LAPP stack to the head. But there is a fundamental matter. Web/Application server can execute a request come from users in a worker thread.

Quoted 7 lines
Quoted 2 lines

This idea enables to assign an indivisual domain on a thread under the paticular condition.

Yes, this came up recently, e.g.:
http://marc.info/?l=selinux&m=121320242220824&w=2

And James added it to the kernel todo list on selinuxproject.org.

Thanks, I overlooked this message.

Quoted 31 lines
Quoted 22 lines

An idea: thread/hierarchical-domain assignment
----------------------------------------------
If possible, Apache should change the security context of web backend during it executes a request come from users.
However, Apache can execute it on a worker thread. It conflicts a wired constraint of SELinux which does not allow a multi-threaded process dynamic domain transition.

It is a reasonable constraint, if the source and destination domains are completely independent. Because it shares a local memory, mixed security context within a process can make a violation in domain separation.

However, a characteristic relationship between hierarchical domains can help the situation. It restricts a child domain (like "httpd_t.staff") cannot over the boundary of its parent ("httpd_t"). It also means a multi-threaded process cannot over the (parent) domain boundary, even if a part of threads has different security context.

My suggestion is the hard-wired constraint should be modified. It allows to assign threads an indivisual domain, if the new domain is a child one of the current domain.

Quoted 8 lines

For example:

    httpd_t -> httpd_t.staff           = allowed
    httpd_t -> staff_t                 = disallowed
    httpd_t.staff -> httpd_t.staff.php = allowed

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

Quoted 5 lines

I tend to agree that we should support such changes in the kernel mechanism and let the use of it be determined by the policy.

In terms of hierarchy though, the plan was to replace the current name-based hierarchy with an explicitly declared hierarchy.

Quoted 8 lines

It needs a new policy statement like:

  TYPE <child domain> DOMBY <parent domain>;
    or
  TYPEDOMINANCE <parent domain> <child domain> [,<child domain>] ;

I guess these relationships are represented as a ebitmap structure in the kernel, and used to mask permissions during AVC entry creation.

You don't necessarily have to represent the hierarchy in the kernel; it can be done entirely in the policy toolchain like the current type hierarchy.

Quoted 15 lines
Quoted 6 lines
Quoted 6 lines

Issues: Domain Reverting
------------------------
There is a related issue. To change security context during user request execution also means that we have to revert its domain after executions, because Apache repeatedly uses worker thread/process for some reasons.

Quoted 8 lines
Quoted 3 lines

I don't have any good idea for this issue yet.
A one time cookie like AppArmor is an approach, but it is basically weak separation compared from execve() transition.

Perhaps it could pre-populate different pools of threads for different client security contexts, and then just draw from the correct pool for each client. Then the thread context doesn't have to be reverted at all and we can make the transition unidirectional.

Quoted 5 lines

I think this approach requires two precondition.

(1) The number of client security context should be enough small. If we want to assign one of MCS categories, it requires 1024 of thread pool in maximum.

The main server thread could lazily create the thread pools as needed to avoid unnecessary pools. And we could possibly use a hybrid scheme (e.g. one pool per sensitivity or per equivalence class of categories, reuse within that pool).

Quoted 6 lines

(2) We have to know what client security context should be assigned before the communication between client and backend thread. In the case when we use HTTP authentication to decide client security context, the authentication process has to be done in the backend process after the communication started.
It may also require major works in application updates.

True, but not an issue when using labeled networking as the basis for determining the client security context.

Quoted 1 line

In my impression, AA's approach is not perfect, but second best one...

I'd have to hear an argument that there is a real security benefit from it. Do you just mean reverting domain transitions or do you specifically mean the cookie-based approach?

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#6 lore raw
Quoted 41 lines
Quoted 41 lines
Quoted 27 lines
Quoted 27 lines

An idea: thread/hierarchical-domain assignment
----------------------------------------------
If possible, Apache should change the security context of web backend during it executes a request come from users.
However, Apache can execute it on a worker thread. It conflicts a wired constraint of SELinux which does not allow a multi-threaded process dynamic domain transition.

It is a reasonable constraint, if the source and destination domains are completely independent. Because it shares a local memory, mixed security context within a process can make a violation in domain separation.

However, a characteristic relationship between hierarchical domains can help the situation. It restricts a child domain (like "httpd_t.staff") cannot over the boundary of its parent ("httpd_t"). It also means a multi-threaded process cannot over the (parent) domain boundary, even if a part of threads has different security context.

My suggestion is the hard-wired constraint should be modified. It allows to assign threads an indivisual domain, if the new domain is a child one of the current domain.

For example:

    httpd_t -> httpd_t.staff           = allowed
    httpd_t -> staff_t                 = disallowed
    httpd_t.staff -> httpd_t.staff.php = allowed
Quoted 8 lines
Quoted 3 lines

In other words, this idea requires to change our viewpoint for child domain. Previously, these are mutually independent domain, but a child domain will mean a state with restricted operations compared to its parent domain.

I tend to agree that we should support such changes in the kernel mechanism and let the use of it be determined by the policy.

In terms of hierarchy though, the plan was to replace the current name-based hierarchy with an explicitly declared hierarchy.

It needs a new policy statement like:

  TYPE <child domain> DOMBY <parent domain>;
    or
  TYPEDOMINANCE <parent domain> <child domain> [,<child domain>] ;
Quoted 6 lines
Quoted 2 lines

I guess these relationships are represented as a ebitmap structure in the kernel, and used to mask permissions during AVC entry creation.

You don't necessarily have to represent the hierarchy in the kernel; it can be done entirely in the policy toolchain like the current type hierarchy.

I think it is necessary to check whether required dynamic type transition should be allowed, or not.

This idea allows a thread to translate its domain, only if the destinated domain is a child one. Thus kernel has to check the relationship between both domains based on the hierarchy information.

In other expression:
ssid := current domain
tsid := new domain
if (is_multi_threaded(current)) {
+ if (!is_dominated_domain(ssid, tsid)) <-- requires hierarchy info

           return -EPERM;
   }
   avc_has_perm(ssid, tsid, SECCLASS_PROCESS,
                PROCESS__DYNTRANSITION, NULL);
Quoted 15 lines
Quoted 15 lines
Quoted 6 lines
Quoted 6 lines

Issues: Domain Reverting
------------------------
There is a related issue. To change security context during user request execution also means that we have to revert its domain after executions, because Apache repeatedly uses worker thread/process for some reasons.

Quoted 7 lines
Quoted 3 lines

I don't have any good idea for this issue yet.
A one time cookie like AppArmor is an approach, but it is basically weak separation compared from execve() transition.

Perhaps it could pre-populate different pools of threads for different client security contexts, and then just draw from the correct pool for each client. Then the thread context doesn't have to be reverted at all and we can make the transition unidirectional.

I think this approach requires two precondition.

Quoted 8 lines
Quoted 3 lines

(1) The number of client security context should be enough small. If we want to assign one of MCS categories, it requires 1024 of thread pool in maximum.

The main server thread could lazily create the thread pools as needed to avoid unnecessary pools. And we could possibly use a hybrid scheme (e.g. one pool per sensitivity or per equivalence class of categories, reuse within that pool).

I guess it requires massive reworks for Apache itself. :(

If so, it may be better to implement a SELinux specific multi processing module (MPM) which creates a child process with restricted domain per request?
(No need to say, we will get some performance degradation.)

Quoted 9 lines
Quoted 6 lines

(2) We have to know what client security context should be assigned before the communication between client and backend thread. In the case when we use HTTP authentication to decide client security context, the authentication process has to be done in the backend process after the communication started.
It may also require major works in application updates.

True, but not an issue when using labeled networking as the basis for determining the client security context.

In web based services, we have to assume a case when client system is running on windows with no labeled networking support.

I think it can be also possible to associate a user and a security context of his substitution on authentication, as operating system doing.

Quoted 5 lines
Quoted 1 line

In my impression, AA's approach is not perfect, but second best one...

I'd have to hear an argument that there is a real security benefit from it. Do you just mean reverting domain transitions or do you specifically mean the cookie-based approach?

The cookie-based approach means a process/thread dynamically translated into child domain is allowed to revert its domain into original one, only if the submitted cookie is matched.

It can protect from script flaws as long as the cookie cannot be accessed from script program. But it depends on the correctness of script language processor, because the cookie has to be placed within the translated domain.

If PHP language processor itself has a bug to expose a discretional value, a malicious one can revert its domain to "httpd_t" from "httpd_t.staff" using the cookie illegally obtained.

So, we can find its benefit at preventing harms from buggy scripts. However, this idea is the best one in I could flash on unfortunatelly.

Is there any other elegant design?

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#7 lore raw
Quoted 1 line · KaiGai Kohei
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

An idea: thread/hierarchical-domain assignment

Now, under constracting a patch.

Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line

Issues: Domain Reverting

- snip -

Quoted 8 lines
Quoted 7 lines
Quoted 3 lines

(1) The number of client security context should be enough small. If we want to assign one of MCS categories, it requires 1024 of thread pool in maximum.

The main server thread could lazily create the thread pools as needed to avoid unnecessary pools. And we could possibly use a hybrid scheme (e.g. one pool per sensitivity or per equivalence class of categories, reuse within that pool).

Quoted 6 lines

I guess it requires massive reworks for Apache itself. :(

If so, it may be better to implement a SELinux specific multi processing module (MPM) which creates a child process with restricted domain per request?
(No need to say, we will get some performance degradation.)

I reconsidered that SELinux awared MPM is better way than reverting domain of backend processes/threads.

It requires a certain level of performance degrading compared to existing MPMs (prefork/worker), but forking a child process for a single request and existing later model is suitable for SELinux.
I have an assumption here that performance is not the first priority for users of SELinux awared Apache.

I like to add it to my TODO list.

BTW, is there anyone good at the behavior of Tomcat?

Quoted 1 line

From its documentation, Tomcat create a thread for a single request and

kills it after processing, when thread pooling is disabled. It seems to me that here is no domain reverting issues. Is it correct?

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#8 lore raw

cover Thread/Child-Domain Assignment

The series of patches enable to assign a thread a "weaker" hierarchical domain, even if the process is multithreaded.

We can use this feature to implement server application which handles user's request within more restricted domain, to protect harms from potential application bugs. SELinux awared server application can voluntarily minimize the permissions set of its backend thread at the begining of processing request.

No need to say, thread shares local memory, so mixed security context within a process can make a violation in domain separation. However, a characteristic relationship between hierarchical domains can help the situation. It restricts a child domain (like "httpd_t.staff") cannot over the boundary of its parent ("httpd_t"). It also means a multi-threaded process cannot over the (parent) domain boundary, even if a part of threads has different security context.

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

[2/3] thread-context-checkpolicy.1.patch
This patch add a new statement of TYPEDOMINATE for policy language.

    TYPEDOMINATE <parent type>  <chile type> [, <child type> ...] ;

It defines expilct hierarchical relationship between two types. Existing name based hierarchy is dealt as TYPEDOMINATE is described implicitly.

[3/3] thread-context-libsepol.1.patch
This patch add support of new policy version of POLICYDB_VERSION_HIERARCHY. It keeps child-parent relationship between two types, and used to make a decision whether required dynamic type transition within multithreaded process can be allowed, or not, in the kernel space.

---- Examples ------------
[kaigai@saba ~]$ gcc thread-context.c -lselinux -lpthread
[kaigai@saba ~]$ ./a.out
12864: Now leader is running at unconfined_u:unconfined_r:unconfined_t:SystemLow-SystemHigh 12865: setcon(unconfined_u:unconfined_r:unconfined_red_t:s0) = 0 (Success) 12865: Now I'm running in unconfined_u:unconfined_r:unconfined_red_t
12866: setcon(unconfined_u:unconfined_r:unconfined_blue_t:s0) = 0 (Success) 12866: Now I'm running in unconfined_u:unconfined_r:unconfined_blue_t
12867: setcon(unconfined_u:unconfined_r:unconfined_green_t:s0) = -1 (Operation not permitted) 12868: setcon(unconfined_u:unconfined_r:unconfined_t:s0) = 0 (Success)
12868: Now I'm running in unconfined_u:unconfined_r:unconfined_t
[kaigai@saba ~]$

This sample program makes four threads, and they tries to change its domain. The number in leftside shows its thread id. Three of them succeeded to change, but rest of them cannot.
The unconfined_red_t and unconfined_blue_t is a hierarchical child domain of unconfined_t and the forth thread (12868) does not change its domain, so they are allowed to have its security context different from others.

Please review them, Thanks.

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#9 lore raw

PATCH 1/3 Thread/Child-Domain Assignment

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

----

 security/selinux/hooks.c            |   11 +++++-
 security/selinux/include/security.h |    5 ++-
 security/selinux/ss/policydb.c      |   75 ++++++++++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    2 +
 security/selinux/ss/services.c      |   60 ++++++++++++++++++++++++++++
 5 files changed, 146 insertions(+), 7 deletions(-)
security/selinux/hooks.c +10 -1
index bc1c3ae..d4c1c5c 100644
@@ -5181,7 +5181,12 @@ static int selinux_setprocattr(struct task_struct *p,
 		if (sid == 0)
 			return -EINVAL;
 
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    lower or same domain in hierarchy relationship.
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5189,11 +5194,15 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+
+					if (!security_check_hierarchy(tsec->sid, sid))
+						goto hierarchy_ok;
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+hierarchy_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/security.h +4 -1
index ad30ac4..97fa9bb 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_HIERARCHY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_HIERARCHY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -118,6 +119,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
 				 u32 xfrm_sid,
 				 u32 *peer_sid);
 
+int security_check_hierarchy(u32 old_sid, u32 new_sid);
+
 int security_get_classes(char ***classes, int *nclasses);
 int security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
security/selinux/ss/policydb.c +70 -5

131 lines not on this page · raw message

security/selinux/ss/policydb.h +2 -0
index 4253370..f3484d4 100644
@@ -81,6 +81,7 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 parent;		/* parent type, if hierarchy related */
 	unsigned char primary;	/* primary name? */
 };
 
@@ -209,6 +210,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +60 -0

66 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#24 lore raw

PATCH 2/3 Thread/Child-Domain Assignment

In reply to KaiGai Kohei

[2/3] thread-context-checkpolicy.1.patch
This patch add a new statement of TYPEDOMINATE for policy language.

    TYPEDOMINATE <parent type>  <chile type> [, <child type> ...] ;

It defines expilct hierarchical relationship between two types. Existing name based hierarchy is dealt as TYPEDOMINATE is described implicitly.

----

 policy_define.c |   95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 policy_define.h |    1
 policy_parse.y  |    5 ++
 policy_scan.l   |    2 +
 4 files changed, 102 insertions(+), 1 deletion(-)
policy_define.c +94 -1
Index: checkpolicy/policy_define.c
===================================================================
@@ -1127,6 +1127,74 @@
 	return 0;
 }
 
+static int define_typedominate_helper(char *parent_id, char *child_id)
+{
+	type_datum_t *parent, *child;
+
+	if (!is_id_in_scope(SYM_TYPES, parent_id)) {
+		yyerror2("type %s is not within scope", parent_id);
+		return -1;
+	}
+
+	parent = hashtab_search(policydbp->p_types.table, parent_id);
+	if (!parent || parent->flavor == TYPE_ATTRIB) {
+		yyerror2("unknown type %s", parent_id);
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_TYPES, child_id)) {
+		yyerror2("type %s is not within scope", child_id);
+		return -1;
+	}
+
+	child = hashtab_search(policydbp->p_types.table, child_id);
+	if (!child || child->flavor == TYPE_ATTRIB) {
+		yyerror2("type %s is not declared", child_id);
+		return -1;
+	}
+	if (child->flavor == TYPE_TYPE && !child->primary) {
+		child = policydbp->type_val_to_struct[child->s.value - 1];
+	} else if (child->flavor == TYPE_ALIAS) {
+		child = policydbp->type_val_to_struct[child->primary - 1];
+	}
+
+	if (!child->parent)
+		child->parent = parent->s.value;
+	else if (child->parent != parent->s.value) {
+		yyerror2("type %s has inconsistent parent %s", child_id, parent_id);
+		return -1;
+	}
+
+	return 0;
+}
+
+int define_typedominate(void)
+{
+	char *id, *parent, *child;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	parent = (char *) queue_remove(id_queue);
+	if (!parent) {
+		yyerror("no type name for typedominate definition?");
+		return -1;
+	}
+
+	while ((child = queue_remove(id_queue))) {
+		if (define_typedominate_helper(parent, child))
+			return -1;
+
+		free(child);
+	}
+	free(parent);
+
+	return 0;
+}
+
 int define_type(int alias)
 {
 	char *id;
@@ -1134,8 +1202,33 @@
 	int newattr = 0;
 
 	if (pass == 2) {
-		while ((id = queue_remove(id_queue)))
+		char *tmp, *child;
+		int first = 1;
+
+		while ((id = queue_remove(id_queue))) {
+			/*
+			 * If type name contains ".", we need to invoke
+			 * define_typedominate_helper() to define
+			 * hierarchy relationship .
+			 */
+			if (!first)
+				goto skip;
+
+			tmp = strrchr(id, '.');
+			if (!tmp)
+				goto skip;
+
+			child = strdup(id);
+			if (!child)
+				goto skip;
+
+			*tmp = '\0';
+			define_typedominate_helper(id, child);
+			free(child);
+		skip:
+			first = 1;
 			free(id);
+		}
 		if (alias) {
 			while ((id = queue_remove(id_queue)))
 				free(id);
policy_scan.l +2 -0
Index: checkpolicy/policy_scan.l
===================================================================
@@ -82,6 +82,8 @@
 typealias			{ return(TYPEALIAS); }
 TYPEATTRIBUTE |
 typeattribute			{ return(TYPEATTRIBUTE); }
+TYPEDOMINATE |
+typedominate			{ return(TYPEDOMINATE); }
 TYPE |
 type				{ return(TYPE); }
 BOOL |
policy_define.h +1 -0
Index: checkpolicy/policy_define.h
===================================================================
@@ -47,6 +47,7 @@
 int define_te_avtab(int which);
 int define_typealias(void);
 int define_typeattribute(void);
+int define_typedominate(void);
 int define_type(int alias);
 int define_user(void);
 int define_validatetrans(constraint_expr_t *expr);
policy_parse.y +5 -0
Index: checkpolicy/policy_parse.y
===================================================================
@@ -92,6 +92,7 @@
 %token ROLES
 %token TYPEALIAS
 %token TYPEATTRIBUTE
+%token TYPEDOMINATE
 %token TYPE
 %token TYPES
 %token ALIAS
@@ -258,6 +259,7 @@
                         | type_def
                         | typealias_def
                         | typeattribute_def
+                        | typedominate_def
                         | bool_def
                         | transition_def
                         | range_trans_def
@@ -278,6 +280,9 @@
 typeattribute_def	: TYPEATTRIBUTE identifier id_comma_list ';'
 			{if (define_typeattribute()) return -1;}
 			;
+typedominate_def	: TYPEDOMINATE identifier id_comma_list ';'
+                        {if (define_typedominate()) return -1;}
+                        ;
 opt_attr_list           : ',' id_comma_list
 			|
 			;
Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#28 lore raw

PATCH 3/3 Thread/Child-Domain Assignment

In reply to KaiGai Kohei

[3/3] thread-context-libsepol.1.patch
This patch add support of new policy version of POLICYDB_VERSION_HIERARCHY. It keeps child-parent relationship between two types, and used to make a decision whether required dynamic type transition within multithreaded process can be allowed, or not, in the kernel space.

----

 include/sepol/policydb/policydb.h |    7 +++-
 src/expand.c                      |   33 +++++++++++++++++++++
 src/hierarchy.c                   |   50 ++++++++++++++++++++++++++------
 src/link.c                        |   33 +++++++++++++++++++++
 src/policydb.c                    |   59 +++++++++++++++++++++++++++++---------
 src/write.c                       |    9 +++++
 6 files changed, 166 insertions(+), 25 deletions(-)
include/sepol/policydb/policydb.h +5 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -145,6 +145,7 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t parent;	/* parent type in hierarchical representation */
 } type_datum_t;
 
 /* User attributes */
@@ -595,10 +596,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_HIERARCHY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_HIERARCHY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,9 +610,10 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_HIERARCHY	   9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_HIERARCHY
 
 #define POLICYDB_CONFIG_MLS    1
 
src/policydb.c +46 -13

94 lines not on this page · raw message

src/hierarchy.c +41 -9

110 lines not on this page · raw message

src/expand.c +33 -0
Index: libsepol/src/expand.c
===================================================================
@@ -538,6 +538,35 @@
 	return 0;
 }
 
+static int hierarchy_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	type_datum_t *type = (type_datum_t *) datum;
+	type_datum_t *target;
+	uint32_t parent_val;
+
+	if (!type->parent)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_TYPES))
+		return 0;
+
+	parent_val = state->typemap[type->parent - 1];
+
+	target = hashtab_search(state->out->p_types.table, (char *)key);
+	if (!target) {
+		ERR(state->handle, "Type lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (target->parent > 0 && target->parent != parent_val) {
+		ERR(state->handle, "Inconsistent hierarchy for %s", (char *)key);
+		return -1;
+	}
+	target->parent = parent_val;
+
+	return 0;
+}
+
 static int role_remap_dominates(hashtab_key_t key __attribute__ ((unused)), hashtab_datum_t datum, void *data)
 {
 	ebitmap_t mapped_roles;
@@ -2393,6 +2422,10 @@
 		goto cleanup;
 	}
 
+	/* copy hierarchy */
+	if (hashtab_map(state.base->p_types.table, hierarchy_type_callback, &state))
+		goto cleanup;
+
 	/* copy aliases */
 	if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state))
 		goto cleanup;
src/write.c +8 -1
Index: libsepol/src/write.c
===================================================================
@@ -957,7 +957,14 @@
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(typdatum->s.value);
 	buf[items++] = cpu_to_le32(typdatum->primary);
-	if (p->policy_type != POLICY_KERN) {
+
+	if (p->policy_type == POLICY_KERN) {
+		if (p->policyvers >= POLICYDB_VERSION_HIERARCHY)
+			buf[items++] = cpu_to_le32(typdatum->parent);
+	} else {
+		if (p->policyvers >= MOD_POLICYDB_VERSION_HIERARCHY)
+			buf[items++] = cpu_to_le32(typdatum->parent);
+
 		buf[items++] = cpu_to_le32(typdatum->flavor);
 		if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
 			buf[items++] = cpu_to_le32(typdatum->flags);
src/link.c +33 -0
Index: libsepol/src/link.c
===================================================================
@@ -770,6 +770,35 @@
 	return -1;
 }
 
+static int hierarchy_type_callback(hashtab_key_t key, hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	type_datum_t *type = (type_datum_t *) datum;
+	type_datum_t *target;
+	uint32_t parent_val;
+
+	if (!type->parent)
+		return 0;
+
+	parent_val = state->cur->map[SYM_TYPES][type->parent - 1];
+
+	target = hashtab_search(state->base->p_types.table, key);
+	if (!target) {
+		ERR(state->handle,
+		    "Type lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (target->parent > 0 && target->parent != parent_val) {
+		ERR(state->handle,
+		    "Inconsistent domain hierarchy for %s", (char *)key);
+		return -1;
+	}
+	target->parent = parent_val;
+
+	return 0;
+}
+
+
 /*********** callbacks that fix bitmaps ***********/
 
 static int type_set_convert(type_set_t * types, type_set_t * dst,
@@ -1362,6 +1391,10 @@
 		}
 	}
 
+	if (hashtab_map(src_symtab[SYM_TYPES].table,
+			hierarchy_type_callback, state))
+		return -1;
+
 	if (hashtab_map
 	    (src_symtab[SYM_TYPES].table, alias_copy_callback, state)) {
 		return -1;
Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#29 lore raw

[PATCH 4/3] Thread/Child-Domain Assignment

In reply to KaiGai Kohei

[4/3] sample program and policy
The attached files are sample program and policy.

The policy provides definitions of unconfined_XXXX_t as child domains of unconfined_t. You can run this sample program on your shell (unconfined_t).

This sample program makes four threads, and they tries to change its domain. The number in leftside shows its thread id. Three of them succeeded to change, but rest of them cannot.
The unconfined_red_t and unconfined_blue_t is a hierarchical child domain of unconfined_t and the forth thread (12868) does not change its domain, so they are allowed to have its security context different from others.

Thanks,

Signature · 2 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <selinux/selinux.h>

static void *worker(void *arg)

{
	security_context_t context
		= (security_context_t) arg;
	int rc;

	rc = setcon(context);
	printf("%u: setcon(%s) = %d (%s)\n",
	       syscall(SYS_gettid), context, rc, strerror(errno));
	if (rc)
		return NULL;

	if (getcon(&context)) {
	    printf("%u: getcon() failed (%s)\n",
		   syscall(SYS_gettid), strerror(errno));
	    return NULL;
	}

	printf("%u: Now I'm running in %s\n",
	       syscall(SYS_gettid), context);

	freecon(context);

	sleep(1);	/* to keep mm->mm_users > 1 for a while */

	return NULL;
}

static char *test_contexts[] = {
"unconfined_u:unconfined_r:unconfined_red_t:s0", "unconfined_u:unconfined_r:unconfined_blue_t:s0", "unconfined_u:unconfined_r:unconfined_green_t:s0", "unconfined_u:unconfined_r:unconfined_t:s0",
};
#define NUM_TEST (sizeof(test_contexts) / sizeof(test_contexts[0]))

int main(int argc, char *argv[])

{
	security_context_t context;
	pthread_t thread[NUM_TEST];
	int i;

	if (!getcon(&context))
		printf("%u: Now leader is running at %s\n",
		       syscall(SYS_gettid), context);

	for (i=0; i < NUM_TEST; i++)
		pthread_create(&thread[i], NULL, worker, test_contexts[i]);

	for (i=0; i < NUM_TEST; i++)
		pthread_join(thread[i], NULL);

	return 0;
}

policy_module(thread-context, 1.0)

gen_require(`

	type unconfined_t;
	type unconfined_devpts_t;

	role unconfined_r;

')

attribute unconfined_colors;

#--- red ---
type unconfined_red_t, unconfined_colors;
domain_type(unconfined_red_t);
role unconfined_r types unconfined_red_t;

#--- blue ---
type unconfined_blue_t, unconfined_colors;
domain_type(unconfined_blue_t);
role unconfined_r types unconfined_blue_t;

#--- green ---
type unconfined_green_t, unconfined_colors;
domain_type(unconfined_green_t);
role unconfined_r types unconfined_green_t;

#--- hierarchy ---
typedominate unconfined_t unconfined_red_t;
typedominate unconfined_t unconfined_blue_t;

# typedominate unconfined_t unconfined_green_t;

#--- process:dyntransition
allow unconfined_t unconfined_colors : process { dyntransition }; allow unconfined_colors unconfined_t : fd { use }; allow unconfined_colors unconfined_devpts_t : chr_file { write };

#--- /proc permissions kernel_search_proc(unconfined_colors)
allow unconfined_colors unconfined_t : dir search_dir_perms; allow unconfined_colors self : file read_file_perms;

#10 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to KaiGai Kohei
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

And I think both the neverallow checking and the type hierarchy checking needs to move away from needing to do a full expansion in order to check; it is just too expensive these days.

Quoted 300 lines

----

 security/selinux/hooks.c            |   11 +++++-
 security/selinux/include/security.h |    5 ++-
 security/selinux/ss/policydb.c      |   75 ++++++++++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    2 +
 security/selinux/ss/services.c      |   60 ++++++++++++++++++++++++++++
 5 files changed, 146 insertions(+), 7 deletions(-)
security/selinux/hooks.c +10 -1
index bc1c3ae..d4c1c5c 100644
@@ -5181,7 +5181,12 @@ static int selinux_setprocattr(struct task_struct *p,
 		if (sid == 0)
 			return -EINVAL;
 
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    lower or same domain in hierarchy relationship.
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5189,11 +5194,15 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+
+					if (!security_check_hierarchy(tsec->sid, sid))
+						goto hierarchy_ok;
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+hierarchy_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/security.h +4 -1
index ad30ac4..97fa9bb 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_HIERARCHY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_HIERARCHY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -118,6 +119,8 @@ int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
 				 u32 xfrm_sid,
 				 u32 *peer_sid);
 
+int security_check_hierarchy(u32 old_sid, u32 new_sid);
+
 int security_get_classes(char ***classes, int *nclasses);
 int security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
security/selinux/ss/policydb.c +70 -5
index 84f8cc7..e388f7a 100644
@@ -116,7 +116,12 @@ static struct policydb_compat_info policydb_compat[] = {
 		.version	= POLICYDB_VERSION_PERMISSIVE,
 		.sym_num	= SYM_NUM,
 		.ocon_num	= OCON_NUM,
-	}
+	},
+	{
+		.version	= POLICYDB_VERSION_HIERARCHY,
+		.sym_num	= SYM_NUM,
+		.ocon_num	= OCON_NUM,
+	},
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -270,9 +275,12 @@ static int type_index(void *key, void *datum, void *datap)
 	p = datap;
 
 	if (typdatum->primary) {
-		if (!typdatum->value || typdatum->value > p->p_types.nprim)
+		if (!typdatum->value
+		    || typdatum->value > p->p_types.nprim
+		    || typdatum->parent > p->p_types.nprim)
 			return -EINVAL;
 		p->p_type_val_to_name[typdatum->value - 1] = key;
+		p->type_val_to_struct[typdatum->value - 1] = typdatum;
 	}
 
 	return 0;
@@ -397,6 +405,46 @@ static void symtab_hash_eval(struct symtab *s)
 }
 #endif
 
+static int type_hierarchy_sanity_checks(struct policydb *p)
+{
+	struct type_datum *type;
+	struct ebitmap e;
+	int rc = 0, i;
+
+	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
+		return 0;
+
+	for (i = 0; i < p->p_types.nprim; i++) {
+		type = p->type_val_to_struct[i];
+
+		if (!type || !type->parent)
+			continue;
+
+		ebitmap_init(&e);
+		while (type) {
+			if (ebitmap_get_bit(&e, type->value - 1)) {
+				printk(KERN_ERR "Hierarchy type looped at %s\n",
+				       p->p_type_val_to_name[type->value - 1]);
+				rc = -EINVAL;
+				break;
+			}
+
+			rc = ebitmap_set_bit(&e, type->value - 1, 1);
+			if (rc)
+				break;
+
+			if (!type->parent)
+				break;
+
+			type = p->type_val_to_struct[type->parent - 1];
+		}
+		ebitmap_destroy(&e);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
 /*
  * Define the other val_to_name and val_to_struct arrays
  * in a policy database structure.
@@ -438,6 +486,14 @@ static int policydb_index_others(struct policydb *p)
 		goto out;
 	}
 
+	p->type_val_to_struct =
+		kzalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
+			GFP_KERNEL);
+	if (!p->type_val_to_struct) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	if (cond_init_bool_indexes(p)) {
 		rc = -ENOMEM;
 		goto out;
@@ -455,6 +511,7 @@ static int policydb_index_others(struct policydb *p)
 			goto out;
 	}
 
+	rc = type_hierarchy_sanity_checks(p);
 out:
 	return rc;
 }
@@ -625,6 +682,7 @@ void policydb_destroy(struct policydb *p)
 	kfree(p->class_val_to_struct);
 	kfree(p->role_val_to_struct);
 	kfree(p->user_val_to_struct);
+	kfree(p->type_val_to_struct);
 
 	avtab_destroy(&p->te_avtab);
 
@@ -1236,8 +1294,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct type_datum *typdatum;
-	int rc;
-	__le32 buf[3];
+	int to_read, rc;
+	__le32 buf[4];
 	u32 len;
 
 	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
@@ -1246,13 +1304,20 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 		return rc;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
+		to_read = sizeof(u32) * 3;
+	else
+		to_read = sizeof(u32) * 4;
+
+	rc = next_entry(buf, fp, to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	typdatum->value = le32_to_cpu(buf[1]);
 	typdatum->primary = le32_to_cpu(buf[2]);
+	if (p->policyvers >= POLICYDB_VERSION_HIERARCHY)
+		typdatum->parent = le32_to_cpu(buf[3]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
security/selinux/ss/policydb.h +2 -0
index 4253370..f3484d4 100644
@@ -81,6 +81,7 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 parent;		/* parent type, if hierarchy related */
 	unsigned char primary;	/* primary name? */
 };
 
@@ -209,6 +210,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +53 -0
index dcc2e1c..3ecd793 100644
@@ -2160,6 +2160,66 @@ out_slowpath:
 	return rc;
 }
 
+/*
+ * security_check_hierarchy
+ *
+ * It returns 0, if @old_sid is same or upper type of @new_sid in hierarchy
+ * relationship directly/indirectly. 1 means @old_sid is not a child type
+ * of @new_sid, and negative returns are error.
+ */
+int security_check_hierarchy(u32 old_sid, u32 new_sid)
+{
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, old_sid);
+		goto out;
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, new_sid);
+		goto out;
+	}
+
+	/* domain unchanged */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	/* check domain hierarchy */
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		if (!type)
+			break;
+
+		/* No hierarchy relationship */
+		if (type->parent == 0) {
+			rc = 1;
+			break;
+		}
+		if (type->parent == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->parent;

security/selinux/ss/services.c out_slowpath: · line 2225

Quoted 10 lines
security/selinux/ss/services.c +7 -0
+	}
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
 static int get_classes_callback(void *k, void *d, void *args)
 {
 	struct class_datum *datum = d;

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#11 lore raw

RE: [PATCH 1/3] Thread/Child-Domain Assignment

Quoted 7 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version
24. This patch also enables to read the new version of policy.

Quoted 6 lines

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

If we are going to do this we also might as well implement the explicit hierarchy support and get away from name based hierarchy.

Quoted 4 lines

And I think both the neverallow checking and the type hierarchy checking needs to move away from needing to do a full expansion in order to check; it is just too expensive these days.

Do you think it will be faster to do attribute based lookups? It will certainly use significantly less memory.

Quoted 20 lines
Quoted 7 lines

----

 security/selinux/hooks.c            |   11 +++++-
 security/selinux/include/security.h |    5 ++-
 security/selinux/ss/policydb.c      |   75

++++++++++++++++++++++++++++++++--

Review

Quoted 6 lines
 security/selinux/ss/policydb.h      |    2 +
 security/selinux/ss/services.c      |   60

++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 7
deletions(-)

(quoted diff) +0 -0

b/security/selinux/hooks.c index

security/selinux/hooks.c static int

Quoted 4 lines

bc1c3ae..d4c1c5c 100644

security/selinux/hooks.c +0 -0
@@ -5181,7 +5181,12 @@ static int

selinux_setprocattr(struct task_struct *p,

Quoted 4 lines

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p,

Quoted 4 lines
security/selinux/hooks.c +0 -1
 		if (sid == 0)
 			return -EINVAL;
 
-		/* Only allow single threaded processes to change

context */ + /*

Quoted 1 line

security/selinux/hooks.c static int · line 5184

Quoted 1 line
security/selinux/hooks.c +1 -0
+		 * SELinux allows to change context in the following

case only.

Quoted 2 lines

security/selinux/hooks.c static int · line 5186

Quoted 2 lines
security/selinux/hooks.c +2 -0
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its

context into

Quoted 1 line

security/selinux/hooks.c static int · line 5187

Quoted 1 line
security/selinux/hooks.c +1 -0
+		 *    lower or same domain in hierarchy relationship. +

*/

Quoted 19 lines

security/selinux/hooks.c static int

Quoted 4 lines
security/selinux/hooks.c +0 -0
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5189,11 +5194,15 @@ static int

selinux_setprocattr(struct task_struct *p,

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p,

Quoted 5 lines
security/selinux/hooks.c +2 -0
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+
+					if

(!security_check_hierarchy(tsec->sid, sid))

Quoted 8 lines
security/selinux/hooks.c +2 -0
+						goto hierarchy_ok;
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+hierarchy_ok:
 
Quoted 2 lines

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p, · line 5208

Quoted 2 lines
security/selinux/hooks.c +0 -0
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,

diff --git

Quoted 11 lines
Quoted 11 lines

a/security/selinux/include/security.h
b/security/selinux/include/security.h
index ad30ac4..97fa9bb 100644

security/selinux/include/security.h +1 -0
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_HIERARCHY	24
 
Quoted 8 lines

security/selinux/include/security.h

Quoted 4 lines
security/selinux/include/security.h +0 -0
 /* 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

security/selinux/include/security.h line 37

Quoted 3 lines
security/selinux/include/security.h +1 -1
 #else
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_HIERARCHY

#endif

Quoted 4 lines

security/selinux/include/security.h int security_net_peersid_resolve(u32 nlbl_sid, · line 119

Quoted 4 lines
security/selinux/include/security.h +0 -0
 #define CONTEXT_MNT	0x01
@@ -118,6 +119,8 @@ int security_net_peersid_resolve(u32 nlbl_sid,
 				 u32 nlbl_type,

u32 xfrm_sid, u32 *peer_sid);

Quoted 11 lines

security/selinux/ss/policydb.c static struct policydb_compat_info · line 116

Quoted 11 lines
security/selinux/include/security.h +1 -0
+int security_check_hierarchy(u32 old_sid, u32 new_sid); +
 int security_get_classes(char ***classes, int *nclasses);  int
 security_get_permissions(char *class, char ***perms, int *nperms);
 int security_get_reject_unknown(void);
(quoted diff) +0 -0

b/security/selinux/ss/policydb.c index 84f8cc7..e388f7a 100644

security/selinux/ss/policydb.c +0 -0
@@ -116,7 +116,12 @@ static struct policydb_compat_info
 		policydb_compat[] = { .version	=

POLICYDB_VERSION_PERMISSIVE,

Quoted 11 lines
Quoted 11 lines
security/selinux/ss/policydb.c +6 -1
 		.sym_num	= SYM_NUM,
 		.ocon_num	= OCON_NUM,
-	}
+	},
+	{
+		.version	= POLICYDB_VERSION_HIERARCHY,
+		.sym_num	= SYM_NUM,
+		.ocon_num	= OCON_NUM,
+	},
 };
 
Quoted 7 lines
Quoted 2 lines
security/selinux/ss/policydb.c +0 -0
 static struct policydb_compat_info *policydb_lookup_compat(int

version) @@ -270,9 +275,12 @@ static int type_index(void

*key, void *datum, void *datap)

security/selinux/ss/policydb.c static int type_index(void *key, void *datum, void *datap)

Quoted 4 lines
security/selinux/ss/policydb.c +0 -1
 	p = datap;
 
 	if (typdatum->primary) {
-		if (!typdatum->value || typdatum->value >

p->p_types.nprim) + if

Quoted 1 line
Quoted 1 line

(!typdatum->value + || typdatum->value >

p->p_types.nprim

Quoted 4 lines

security/selinux/ss/policydb.c static int type_index(void *key, void *datum, void *datap) · line 283

Quoted 4 lines
security/selinux/ss/policydb.c +2 -0
+		    || typdatum->parent > p->p_types.nprim)
 			return -EINVAL;
 		p->p_type_val_to_name[typdatum->value - 1] = key;
+		p->type_val_to_struct[typdatum->value - 1] = typdatum;

}

Quoted 25 lines
Quoted 12 lines
security/selinux/ss/policydb.c +7 -0
 	return 0;
@@ -397,6 +405,46 @@ static void symtab_hash_eval(struct symtab *s) 
 } #endif 
 
+static int type_hierarchy_sanity_checks(struct policydb *p) {
+	struct type_datum *type; +	struct ebitmap e;
+	int rc = 0, i;
+
+	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
+		return 0;
+

security/selinux/ss/policydb.c static void symtab_hash_eval(struct symtab *s) · line 423

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+	for (i = 0; i < p->p_types.nprim; i++) {
+		type = p->type_val_to_struct[i];
+
+		if (!type || !type->parent)
+			continue;
+
+		ebitmap_init(&e);
+		while (type) {
+			if (ebitmap_get_bit(&e, type->value - 1)) {
+				printk(KERN_ERR "Hierarchy type

looped at %s\n",

security/selinux/ss/policydb.c static void symtab_hash_eval(struct symtab *s) · line 424

Quoted 1 line
security/selinux/ss/policydb.c +1 -0
+

p->p_type_val_to_name[type->value - 1]);

Quoted 12 lines

security/selinux/ss/policydb.c static void symtab_hash_eval(struct symtab *s) · line 439

Quoted 12 lines
security/selinux/ss/policydb.c +12 -0
+				rc = -EINVAL;
+				break;
+			}
+
+			rc = ebitmap_set_bit(&e, type->value - 1, 1);
+			if (rc)
+				break;
+
+			if (!type->parent)
+				break;
+
+			type = p->type_val_to_struct[type->parent - 1];

+ }

Quoted 153 lines

security/selinux/ss/policydb.c static int

Quoted 11 lines
security/selinux/ss/policydb.c +7 -0
+		ebitmap_destroy(&e);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
 /*
  * Define the other val_to_name and val_to_struct arrays
  * in a policy database structure.
@@ -438,6 +486,14 @@ static int

policydb_index_others(struct policydb *p)

security/selinux/ss/policydb.c static int policydb_index_others(struct policydb *p)

Quoted 5 lines
security/selinux/ss/policydb.c +2 -0
 		goto out;
 	}
 
+	p->type_val_to_struct =
+		kzalloc(p->p_types.nprim *

sizeof(*(p->type_val_to_struct)),

Quoted 135 lines
security/selinux/ss/policydb.c +19 -3
+			GFP_KERNEL);
+	if (!p->type_val_to_struct) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	if (cond_init_bool_indexes(p)) {
 		rc = -ENOMEM;
 		goto out;
@@ -455,6 +511,7 @@ static int policydb_index_others(struct policydb
 	*p)  			goto out; }
 
+	rc = type_hierarchy_sanity_checks(p);
 out:
 	return rc;
 }
@@ -625,6 +682,7 @@ void policydb_destroy(struct policydb *p)
 	kfree(p->class_val_to_struct);
 	kfree(p->role_val_to_struct);
 	kfree(p->user_val_to_struct);
+	kfree(p->type_val_to_struct);
 
 	avtab_destroy(&p->te_avtab);
 
@@ -1236,8 +1294,8 @@ static int type_read(struct policydb *p,
 	struct hashtab *h, void *fp)  { char *key = NULL;
 	struct type_datum *typdatum;
-	int rc;
-	__le32 buf[3];
+	int to_read, rc;
+	__le32 buf[4];
 	u32 len;
 
 	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); @@ -1246,13
+1304,20 @@ static int type_read(struct policydb *p, struct hashtab
 	*h, void *fp)  		return rc; }
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
+		to_read = sizeof(u32) * 3;
+	else
+		to_read = sizeof(u32) * 4;
+
+	rc = next_entry(buf, fp, to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	typdatum->value = le32_to_cpu(buf[1]);
 	typdatum->primary = le32_to_cpu(buf[2]);
+	if (p->policyvers >= POLICYDB_VERSION_HIERARCHY)
+		typdatum->parent = le32_to_cpu(buf[3]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
(quoted diff) +0 -0

b/security/selinux/ss/policydb.h index 4253370..f3484d4 100644

security/selinux/ss/policydb.h +2 -0
@@ -81,6 +81,7 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 parent;		/* parent type, if hierarchy related */
 	unsigned char primary;	/* primary name? */
 };
 
@@ -209,6 +210,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */  	struct

avtab te_avtab; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index dcc2e1c..3ecd793 100644

security/selinux/ss/services.c +5 -0
@@ -2160,6 +2160,66 @@ out_slowpath:
 	return rc;
 }
 
+/*
+ * security_check_hierarchy
+ *
+ * It returns 0, if @old_sid is same or upper type of @new_sid in
+hierarchy + * relationship directly/indirectly. 1 means @old_sid is

not a child +type + * of @new_sid, and negative returns are error.
+ */

security/selinux/ss/services.c +11 -0
+int security_check_hierarchy(u32 old_sid, u32 new_sid) {
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", +

__func__, old_sid); + goto out;

security/selinux/ss/services.c +5 -0
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", +

__func__, new_sid); + goto out;

security/selinux/ss/services.c +26 -0
+	}
+
+	/* domain unchanged */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	/* check domain hierarchy */
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		if (!type)
+			break;
+
+		/* No hierarchy relationship */
+		if (type->parent == 0) {
+			rc = 1;
+			break;
+		}
+		if (type->parent == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->parent;
+	}
Quoted 8 lines

security/selinux/ss/services.c out_slowpath: · line 2225

Quoted 8 lines
security/selinux/ss/services.c +6 -0
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
 static int get_classes_callback(void *k, void *d, void *args)  {
 	struct class_datum *datum = d;

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#13 lore raw

RE: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to Stephen Smalley
Quoted 15 lines · Joshua Brindle
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version
24. This patch also enables to read the new version of policy.

Quoted 6 lines

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

Quoted 3 lines

If we are going to do this we also might as well implement the explicit hierarchy support and get away from name based hierarchy.

Oops, I missed the patch that does this, disregard.

Quoted 28 lines
Quoted 4 lines

And I think both the neverallow checking and the type hierarchy checking needs to move away from needing to do a full expansion in order to check; it is just too expensive these days.

Do you think it will be faster to do attribute based lookups? It will certainly use significantly less memory.

Quoted 20 lines
Quoted 7 lines

----

 security/selinux/hooks.c            |   11 +++++-
 security/selinux/include/security.h |    5 ++-
 security/selinux/ss/policydb.c      |   75

++++++++++++++++++++++++++++++++--

Review

Quoted 6 lines
 security/selinux/ss/policydb.h      |    2 +
 security/selinux/ss/services.c      |   60

++++++++++++++++++++++++++++ 5 files changed, 146 insertions(+), 7
deletions(-)

(quoted diff) +0 -0

b/security/selinux/hooks.c index

security/selinux/hooks.c static int

Quoted 4 lines

bc1c3ae..d4c1c5c 100644

security/selinux/hooks.c +0 -0
@@ -5181,7 +5181,12 @@ static int

selinux_setprocattr(struct task_struct *p,

Quoted 4 lines
Quoted 4 lines

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p,

Quoted 4 lines
security/selinux/hooks.c +0 -1
 		if (sid == 0)
 			return -EINVAL;
 
-		/* Only allow single threaded processes to change

context */

Quoted 1 line
Quoted 1 line

security/selinux/hooks.c static int · line 5184

Quoted 1 line
security/selinux/hooks.c +1 -0
+		/* +		 * SELinux allows to change context in

the following case

Quoted 2 lines
Quoted 2 lines

security/selinux/hooks.c

Quoted 2 lines

only. + * - Single threaded processes.

security/selinux/hooks.c +1 -0
+		 *  - Multi threaded processes intend to change its

context into

Quoted 1 line
Quoted 1 line

security/selinux/hooks.c

Quoted 1 line
security/selinux/hooks.c +1 -0
+		 *    lower or same domain in hierarchy relationship. +

*/

Quoted 19 lines
Quoted 19 lines

security/selinux/hooks.c static int

Quoted 4 lines
security/selinux/hooks.c +0 -0
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5189,11 +5194,15 @@ static int

selinux_setprocattr(struct task_struct *p,

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p,

Quoted 5 lines
security/selinux/hooks.c +2 -0
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+
+					if

(!security_check_hierarchy(tsec->sid, sid))

Quoted 8 lines
security/selinux/hooks.c +2 -0
+						goto hierarchy_ok;
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+hierarchy_ok:
 
Quoted 2 lines
Quoted 2 lines

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p, · line 5208

Quoted 2 lines
security/selinux/hooks.c +0 -0
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,

diff --git

Quoted 26 lines
Quoted 11 lines
Quoted 11 lines

a/security/selinux/include/security.h
b/security/selinux/include/security.h
index ad30ac4..97fa9bb 100644

security/selinux/include/security.h +1 -0
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_HIERARCHY	24
 
Quoted 8 lines

security/selinux/include/security.h

Quoted 4 lines
security/selinux/include/security.h +0 -0
 /* 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

security/selinux/include/security.h

Quoted 3 lines
security/selinux/include/security.h +1 -1
 #else
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX

POLICYDB_VERSION_HIERARCHY #endif

Quoted 4 lines

security/selinux/include/security.h int security_net_peersid_resolve(u32 nlbl_sid, · line 119

Quoted 4 lines
security/selinux/include/security.h +0 -0
 #define CONTEXT_MNT	0x01
@@ -118,6 +119,8 @@ int security_net_peersid_resolve(u32 nlbl_sid,
 				 u32 nlbl_type,
		 u32 xfrm_sid, u32 *peer_sid);
Quoted 1 line
Quoted 1 line
Quoted 10 lines
Quoted 10 lines

security/selinux/ss/policydb.c static struct policydb_compat_info · line 116

Quoted 10 lines

+int security_check_hierarchy(u32 old_sid, u32 new_sid); +
int security_get_classes(char ***classes, int *nclasses); int
security_get_permissions(char *class, char ***perms, int *nperms); int security_get_reject_unknown(void);

(quoted diff) +0 -0

b/security/selinux/ss/policydb.c index 84f8cc7..e388f7a 100644

security/selinux/ss/policydb.c +0 -0
@@ -116,7 +116,12 @@ static struct policydb_compat_info
 		policydb_compat[] = { .version	=

POLICYDB_VERSION_PERMISSIVE,

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines
security/selinux/ss/policydb.c +6 -1
 		.sym_num	= SYM_NUM, .ocon_num	= OCON_NUM,
-	}
+	},
+	{
+		.version	= POLICYDB_VERSION_HIERARCHY,
+		.sym_num	= SYM_NUM,
+		.ocon_num	= OCON_NUM,
+	},
 };
 
Quoted 7 lines
Quoted 7 lines
Quoted 2 lines
security/selinux/ss/policydb.c +0 -0
 static struct policydb_compat_info *policydb_lookup_compat(int

version) @@ -270,9 +275,12 @@ static int type_index(void

*key, void *datum, void *datap)

security/selinux/ss/policydb.c static int type_index(void *key, void *datum, void *datap)

Quoted 4 lines
security/selinux/ss/policydb.c +0 -1
 	p = datap;
 
 	if (typdatum->primary) {
-		if (!typdatum->value || typdatum->value >

p->p_types.nprim) + if

Quoted 5 lines
Quoted 5 lines

security/selinux/ss/policydb.c static int type_index(void *key, void *datum, void *datap) · line 283

Quoted 5 lines

(!typdatum->value + || typdatum->value p->p_types.nprim

security/selinux/ss/policydb.c +2 -0
+		    || typdatum->parent > p->p_types.nprim)
 			return -EINVAL;
 		p->p_type_val_to_name[typdatum->value - 1] = key;
+		p->type_val_to_struct[typdatum->value - 1] = typdatum;

}

Quoted 189 lines
Quoted 25 lines
Quoted 12 lines
security/selinux/ss/policydb.c +7 -0
 	return 0;
@@ -397,6 +405,46 @@ static void symtab_hash_eval(struct symtab *s)
 } #endif 
 
+static int type_hierarchy_sanity_checks(struct policydb *p) {
+	struct type_datum *type; +	struct ebitmap e;
+	int rc = 0, i;
+
+	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
+		return 0;
+

security/selinux/ss/policydb.c static void symtab_hash_eval(struct symtab *s) · line 423

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+	for (i = 0; i < p->p_types.nprim; i++) {
+		type = p->type_val_to_struct[i];
+
+		if (!type || !type->parent)
+			continue;
+
+		ebitmap_init(&e);
+		while (type) {
+			if (ebitmap_get_bit(&e, type->value - 1)) {
+				printk(KERN_ERR "Hierarchy type

looped at %s\n",

security/selinux/ss/policydb.c static void symtab_hash_eval(struct symtab *s) · line 424

Quoted 1 line
security/selinux/ss/policydb.c +1 -0
+

p->p_type_val_to_name[type->value - 1]);

Quoted 12 lines

security/selinux/ss/policydb.c static void symtab_hash_eval(struct symtab *s)

Quoted 12 lines
security/selinux/ss/policydb.c +12 -0
+				rc = -EINVAL;
+				break;
+			}
+
+			rc = ebitmap_set_bit(&e, type->value - 1, 1);
+			if (rc)
+				break;
+
+			if (!type->parent)
+				break;
+
+			type =

p->type_val_to_struct[type->parent - 1]; + }

Quoted 18 lines

security/selinux/ss/policydb.c static int

Quoted 11 lines
security/selinux/ss/policydb.c +7 -0
+		ebitmap_destroy(&e);
+		if (rc)
+			return rc;
+	}
+	return 0;
+}
+
 /*
  * Define the other val_to_name and val_to_struct arrays
  * in a policy database structure.
@@ -438,6 +486,14 @@ static int

policydb_index_others(struct policydb *p)

security/selinux/ss/policydb.c static int policydb_index_others(struct policydb *p)

Quoted 5 lines
security/selinux/ss/policydb.c +2 -0
 		goto out;
 	}
 
+	p->type_val_to_struct =
+		kzalloc(p->p_types.nprim *

sizeof(*(p->type_val_to_struct)),

Quoted 10 lines

security/selinux/ss/policydb.c static int

Quoted 10 lines
security/selinux/ss/policydb.c +6 -0
+			GFP_KERNEL);
+	if (!p->type_val_to_struct) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	if (cond_init_bool_indexes(p)) {
 		rc = -ENOMEM;
 		goto out;
@@ -455,6 +511,7 @@ static int

policydb_index_others(struct policydb

Quoted 122 lines
Quoted 122 lines
security/selinux/ss/policydb.c +13 -3
 	*p)  			goto out; }
 
+	rc = type_hierarchy_sanity_checks(p);
 out:
 	return rc;
 }
@@ -625,6 +682,7 @@ void policydb_destroy(struct policydb *p)
 	kfree(p->class_val_to_struct);
 	kfree(p->role_val_to_struct);
 	kfree(p->user_val_to_struct);
+	kfree(p->type_val_to_struct);
 
 	avtab_destroy(&p->te_avtab);
 
@@ -1236,8 +1294,8 @@ static int type_read(struct policydb *p,
 	struct hashtab *h, void *fp)  { char *key = NULL;
 	struct type_datum *typdatum;
-	int rc;
-	__le32 buf[3];
+	int to_read, rc;
+	__le32 buf[4];
 	u32 len;
 
 	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL); @@ -1246,13
+1304,20 @@ static int type_read(struct policydb *p, struct hashtab
 	*h, void *fp)  		return rc; }
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers < POLICYDB_VERSION_HIERARCHY)
+		to_read = sizeof(u32) * 3;
+	else
+		to_read = sizeof(u32) * 4;
+
+	rc = next_entry(buf, fp, to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	typdatum->value = le32_to_cpu(buf[1]);
 	typdatum->primary = le32_to_cpu(buf[2]);
+	if (p->policyvers >= POLICYDB_VERSION_HIERARCHY)
+		typdatum->parent = le32_to_cpu(buf[3]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
(quoted diff) +0 -0

b/security/selinux/ss/policydb.h index 4253370..f3484d4 100644

security/selinux/ss/policydb.h +2 -0
@@ -81,6 +81,7 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 parent;		/* parent type, if hierarchy related */
 	unsigned char primary;	/* primary name? */
 };
 
@@ -209,6 +210,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */  	struct

avtab te_avtab; diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index dcc2e1c..3ecd793 100644

security/selinux/ss/services.c +5 -0
@@ -2160,6 +2160,66 @@ out_slowpath:
 	return rc;
 }
 
+/*
+ * security_check_hierarchy
+ *
+ * It returns 0, if @old_sid is same or upper type of @new_sid in
+hierarchy + * relationship directly/indirectly. 1 means @old_sid is

not a child +type + * of @new_sid, and negative returns are error.
+ */ +int security_check_hierarchy(u32 old_sid, u32 new_sid) {

security/selinux/ss/services.c +10 -0
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", +

__func__, old_sid); + goto out;

security/selinux/ss/services.c +5 -0
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", +

__func__, new_sid); + goto out;

security/selinux/ss/services.c +26 -0
+	}
+
+	/* domain unchanged */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	/* check domain hierarchy */
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		if (!type)
+			break;
+
+		/* No hierarchy relationship */
+		if (type->parent == 0) {
+			rc = 1;
+			break;
+		}
+		if (type->parent == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->parent;
+	}
Quoted 8 lines
Quoted 8 lines

security/selinux/ss/services.c out_slowpath: · line 2225

Quoted 8 lines
security/selinux/ss/services.c +6 -0
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
 static int get_classes_callback(void *k, void *d, void *args)  {
 	struct class_datum *datum = d;

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#14 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to Stephen Smalley
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

Quoted 5 lines

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Quoted 3 lines

And I think both the neverallow checking and the type hierarchy checking needs to move away from needing to do a full expansion in order to check; it is just too expensive these days.

I agree. expand-check=1 makes slow downed so much. :( It should be done on-demand.

Thanks,

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#12 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to Joshua Brindle
Quoted 17 lines · Joshua Brindle
Quoted 6 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version
24. This patch also enables to read the new version of policy.

Quoted 6 lines

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

If we are going to do this we also might as well implement the explicit hierarchy support and get away from name based hierarchy.

Quoted 7 lines
Quoted 4 lines

And I think both the neverallow checking and the type hierarchy checking needs to move away from needing to do a full expansion in order to check; it is just too expensive these days.

Do you think it will be faster to do attribute based lookups? It will certainly use significantly less memory.

What do you means the attribute based lookups?

In hierarchy checks, we should not expand any attribute of type without applying them to its parent type. We can check it by comparing type_attr_map of both types, without additional memory consumption.

In never allow checks, all we have to do is adding a "else if" block to check in context_struct_compute_av(), like:

------------

  ebitmap_for_each_positive_bit(sattr, snode, i) {
      ebitmap_for_each_positive_bit(tattr, tnode, j) {
          avkey.source_type = i + 1;
          avkey.target_type = j + 1;
          for (node = avtab_search_node(&policydb.te_avtab, &avkey);
               node != NULL;
               node = avtab_search_node_next(node, avkey.specified)) {
              if (node->key.specified == AVTAB_ALLOWED)
                  avd->allowed |= node->datum.data;
              else if (node->key.specified == AVTAB_AUDITALLOW)
                  avd->auditallow |= node->datum.data;
              else if (node->key.specified == AVTAB_AUDITDENY)
                  avd->auditdeny &= node->datum.data;
+             else if (node->key.specified == AVTAB_NEVERALLOW)
+                  avd->allowed &= ~node->datum.data;
+                  /* TODO: print logs to notice masked perms */
          }

          /* Check conditional av table for additional permissions */
          cond_compute_av(&policydb.te_cond_avtab, &avkey, avd);
      }

}
------------

Thanks,

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#15 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to KaiGai Kohei
Quoted 19 lines · KaiGai Kohei
Quoted 7 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

Quoted 5 lines

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

Quoted 9 lines
Quoted 4 lines

And I think both the neverallow checking and the type hierarchy checking needs to move away from needing to do a full expansion in order to check; it is just too expensive these days.

I agree. expand-check=1 makes slow downed so much. :( It should be done on-demand.

Thanks,

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#16 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

Quoted 23 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Quoted 5 lines

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)? Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#17 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

Quoted 19 lines · Joshua Brindle
Quoted 18 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 8 lines
Quoted 8 lines
Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

OK, it seems to me a reasonable approach that the userland toolchain also checks neverallow constraints.
What is a proper way to notice violations in neverallow constraint? I think audit messages are candidate. When user receives violation messages, he can check his policy with expand-check=1 for more detailed infomation.

Quoted 3 lines

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)?

Yes, I think the hierarchy constraints are applied on the creation of AVC entries at runtime. If violated, masked permissions and attributes should be noticed to userspace via audit messages.

Quoted 3 lines

Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

We can also apply these checks at policy module linking time, if configured. However, it is currently skipped in the default due to its expensiveness, isn't it? Could you consider the runtime checks give us a hint/change to enabls checks in the userland toolchain for more detailed information?

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#18 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to Joshua Brindle
Quoted 30 lines · Joshua Brindle
Quoted 23 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Quoted 5 lines

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

Quoted 6 lines

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)? Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

True. On the other hand, if we are going to make the hierarchy visible to the kernel so that it can directly leverage information from it, then it makes sense to let the kernel directly enforce the relationships, whether that happens at policy load time or at compute_av time.

If we can make the checking happen entirely at policy load time in a manner that isn't too expensive, then that is cleaner, I agree. If not, then lazy dynamic checking by the kernel and optional full static checking by the toolchain may be a compromise.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#19 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

Quoted 41 lines · Stephen Smalley
Quoted 28 lines · Joshua Brindle
Quoted 18 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 9 lines
Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

Quoted 6 lines

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)? Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

True. On the other hand, if we are going to make the hierarchy visible to the kernel so that it can directly leverage information from it, then it makes sense to let the kernel directly enforce the relationships, whether that happens at policy load time or at compute_av time.

Quoted 4 lines

If we can make the checking happen entirely at policy load time in a manner that isn't too expensive, then that is cleaner, I agree. If not, then lazy dynamic checking by the kernel and optional full static checking by the toolchain may be a compromise.

I guess we can reduce cost to check hierarchy constraint, because all we have to do is to scan/check avtabs of related types and ebitmaps of type_attr_maps.
However, I don't have a good idea to boost neverallow constraint so much due to its flexibility. :(

I have measured a performance to check hierarchy/neverallow constraint with patched libsepol as a trial. Unfortunatelly, about 80% of CPU time is consumed by check_assertions() for neverallows.

[root@saba ~]# time -p semodule -r kaigai
hierarchy_check_constraints: 37.32 [s]
check_assertions: 139.05 [s]
real 205.32
user 198.06
sys 3.75

These checks at policy load time gives us negative effect in system bootup time, unless remarkable improvements. So, I prefer lazy dynamic checking approach.

(*) System bootup time is one of the major topics for embedded Linux folks.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#25 lore raw

Re: [PATCH 2/3] Thread/Child-Domain Assignment

In reply to KaiGai Kohei
Quoted 8 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.1.patch
This patch add a new statement of TYPEDOMINATE for policy language.

    TYPEDOMINATE <parent type>  <chile type> [, <child type> ...] ;

It defines expilct hierarchical relationship between two types. Existing name based hierarchy is dealt as TYPEDOMINATE is described implicitly.

I reconsidered that the statement should be replaced as follows, because "DOMINATE" is an associated term with MLS and roles/users also have name based hierarchy ideas now.

  HIERARCHY <parent type> TYPES <child type> [, <child type> ...];
  HIERARCHY <parent role> ROLES <child role> [, <child role> ...];
  HIERARCHY <parent user> USERS <child user> [, <child user> ...];

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#20 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to KaiGai Kohei
Quoted 64 lines · KaiGai Kohei
Quoted 41 lines · Stephen Smalley
Quoted 28 lines · Joshua Brindle
Quoted 18 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 9 lines
Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

Quoted 6 lines

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)? Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

True. On the other hand, if we are going to make the hierarchy visible to the kernel so that it can directly leverage information from it, then it makes sense to let the kernel directly enforce the relationships, whether that happens at policy load time or at compute_av time.

Quoted 4 lines

If we can make the checking happen entirely at policy load time in a manner that isn't too expensive, then that is cleaner, I agree. If not, then lazy dynamic checking by the kernel and optional full static checking by the toolchain may be a compromise.

I guess we can reduce cost to check hierarchy constraint, because all we have to do is to scan/check avtabs of related types and ebitmaps of type_attr_maps.
However, I don't have a good idea to boost neverallow constraint so much due to its flexibility. :(

I have measured a performance to check hierarchy/neverallow constraint with patched libsepol as a trial. Unfortunatelly, about 80% of CPU time is consumed by check_assertions() for neverallows.

[root@saba ~]# time -p semodule -r kaigai
hierarchy_check_constraints: 37.32 [s]
check_assertions: 139.05 [s]
real 205.32
user 198.06
sys 3.75

Quoted 5 lines

These checks at policy load time gives us negative effect in system bootup time, unless remarkable improvements. So, I prefer lazy dynamic checking approach.

(*) System bootup time is one of the major topics for embedded Linux folks.

Ok. I'd be interested in seeing that libsepol patch nonetheless, and we may want to retain full checking there as an option for validation at policy build time (via make validate) while introducing lazy dynamic checking in the kernel.

BTW, we may need to revisit the policydb data structures in order to fully address concerns about policy load time.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#26 lore raw

Re: [PATCH 2/3] Thread/Child-Domain Assignment

In reply to KaiGai Kohei
Quoted 10 lines · KaiGai Kohei
Quoted 8 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.1.patch
This patch add a new statement of TYPEDOMINATE for policy language.

    TYPEDOMINATE <parent type>  <chile type> [, <child type> ...] ;

It defines expilct hierarchical relationship between two types. Existing name based hierarchy is dealt as TYPEDOMINATE is described implicitly.

Quoted 8 lines

I reconsidered that the statement should be replaced as follows, because "DOMINATE" is an associated term with MLS and roles/users also have name based hierarchy ideas now.

  HIERARCHY <parent type> TYPES <child type> [, <child type> ...];
  HIERARCHY <parent role> ROLES <child role> [, <child role> ...];
  HIERARCHY <parent user> USERS <child user> [, <child user> ...];

I agree that TYPEDOMINATE is not a good choice. In dominance, you're saying "whatever privileges x, y, & z have, give me those too."

I like to think of it as the parent type "circumscribing" or limiting its children -- the parent draws a line in the sand and says "<child>, you can grant yourself whatever permissions you want (hopefully no more than you need), but whatever you do, don't cross this line!" The terms used to should make that obvious. "Circumscribe" is fun to say, but awkward to type, so how about:

    TYPELIMIT <parent type> { <child type> [, <child type> ...] } ;
    ROLELIMIT <parent role> { <child role> [, <child role> ...] } ;

It would read better to say:

    TYPE <parent type> LIMITS { <child type> [, <child type> ...] } ;
    ROLE <parent role> LIMITS { <child role> [, <child role> ...] } ;

but that conflicts with existing syntax. Hence the patterning after attributes and aliasing.

I'm not sure what hierarchy for users implies, or why it's needed. If we have adequate support for hierarchy/dominance in roles, doesn't that suffice for users? After all, users can't do anything their roles don't permit them to. I guess I see users as a slightly different case because they are going to be more per-system than roles or types, so if you don't trust system administrators to set a user's roles correctly, you shouldn't make them a sysadmin. Or am I missing something?

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#27 lore raw

Re: [PATCH 2/3] Thread/Child-Domain Assignment

Quoted 33 lines · Scott Schmit
Quoted 10 lines · KaiGai Kohei
Quoted 8 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.1.patch
This patch add a new statement of TYPEDOMINATE for policy language.

    TYPEDOMINATE <parent type>  <chile type> [, <child type> ...] ;

It defines expilct hierarchical relationship between two types. Existing name based hierarchy is dealt as TYPEDOMINATE is described implicitly.

Quoted 8 lines

I reconsidered that the statement should be replaced as follows, because "DOMINATE" is an associated term with MLS and roles/users also have name based hierarchy ideas now.

  HIERARCHY <parent type> TYPES <child type> [, <child type> ...];
  HIERARCHY <parent role> ROLES <child role> [, <child role> ...];
  HIERARCHY <parent user> USERS <child user> [, <child user> ...];

I agree that TYPEDOMINATE is not a good choice. In dominance, you're saying "whatever privileges x, y, & z have, give me those too."

I like to think of it as the parent type "circumscribing" or limiting its children -- the parent draws a line in the sand and says "<child>, you can grant yourself whatever permissions you want (hopefully no more than you need), but whatever you do, don't cross this line!" The terms used to should make that obvious. "Circumscribe" is fun to say, but awkward to type, so how about:

    TYPELIMIT <parent type> { <child type> [, <child type> ...] } ;
    ROLELIMIT <parent role> { <child role> [, <child role> ...] } ;
Quoted 7 lines

It would read better to say:

    TYPE <parent type> LIMITS { <child type> [, <child type> ...] } ;
    ROLE <parent role> LIMITS { <child role> [, <child role> ...] } ;

but that conflicts with existing syntax. Hence the patterning after attributes and aliasing.

I don't think we necessarily have to be constrained by existing syntax. Adding TYPE identifier LIMITS id_comma_list ';' to the grammar doesn't seem to present any problems. Not sure if LIMITS is the best term either though, maybe BOUNDS.

Quoted 7 lines

I'm not sure what hierarchy for users implies, or why it's needed. If we have adequate support for hierarchy/dominance in roles, doesn't that suffice for users? After all, users can't do anything their roles don't permit them to. I guess I see users as a slightly different case because they are going to be more per-system than roles or types, so if you don't trust system administrators to set a user's roles correctly, you shouldn't make them a sysadmin. Or am I missing something?

User identity in SELinux (in the security context) isn't quite the same thing as Linux usernames/accounts; there is a many-to-one mapping from the Linux usernames to SELinux user identities, and the SELinux user identity is in fact a "role authorization set".

In early SELinux, we did use a one-to-one mapping, but ran into problems with admins not wanting to add or remove users to their SELinux policy (requiring regenerating, distributing and reloading policy into the kernel on each system) when managing users on their network. That led first to a fallback SELinux user identity (user_u), and later to the seusers mapping. So today the SELinux user identity is an abstract identity (e.g. "user_u", "staff_u", "unconfined_u") that maps to a given role set.

There is also work investigating use of SELinux user identity as the role (see rbacsep and (u|r)bacsep threads).

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#21 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to Stephen Smalley
Quoted 67 lines · Stephen Smalley
Quoted 66 lines · KaiGai Kohei
Quoted 40 lines · Stephen Smalley
Quoted 28 lines · Joshua Brindle
Quoted 18 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 9 lines
Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

Quoted 6 lines

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)? Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

True. On the other hand, if we are going to make the hierarchy visible to the kernel so that it can directly leverage information from it, then it makes sense to let the kernel directly enforce the relationships, whether that happens at policy load time or at compute_av time.

Quoted 4 lines

If we can make the checking happen entirely at policy load time in a manner that isn't too expensive, then that is cleaner, I agree. If not, then lazy dynamic checking by the kernel and optional full static checking by the toolchain may be a compromise.

I guess we can reduce cost to check hierarchy constraint, because all we have to do is to scan/check avtabs of related types and ebitmaps of type_attr_maps.
However, I don't have a good idea to boost neverallow constraint so much due to its flexibility. :(

I have measured a performance to check hierarchy/neverallow constraint with patched libsepol as a trial. Unfortunatelly, about 80% of CPU time is consumed by check_assertions() for neverallows.

[root@saba ~]# time -p semodule -r kaigai
hierarchy_check_constraints: 37.32 [s]
check_assertions: 139.05 [s]
real 205.32
user 198.06
sys 3.75

These checks at policy load time gives us negative effect in system bootup time, unless remarkable improvements. So, I prefer lazy dynamic checking approach.

Quoted 7 lines
Quoted 1 line

(*) System bootup time is one of the major topics for embedded Linux folks.

Ok. I'd be interested in seeing that libsepol patch nonetheless, and we may want to retain full checking there as an option for validation at policy build time (via make validate) while introducing lazy dynamic checking in the kernel.

This sounds reasonable.

Quoted 2 lines

BTW, we may need to revisit the policydb data structures in order to fully address concerns about policy load time.

Do you have ideas here?

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#22 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

Quoted 76 lines · Joshua Brindle
Quoted 67 lines · Stephen Smalley
Quoted 66 lines · KaiGai Kohei
Quoted 40 lines · Stephen Smalley
Quoted 28 lines · Joshua Brindle
Quoted 18 lines · Stephen Smalley
Quoted 17 lines · KaiGai Kohei
Quoted 11 lines · Stephen Smalley
Quoted 5 lines · KaiGai Kohei

[1/3] thread-context-kernel.1.patch
This patch enables to assign a thread a "weaker" hierarchical domain, only if the destinated domain is a child of the current domain. Hierachy relationships are defined in the policy version 24. This patch also enables to read the new version of policy.

If you are going to take type hierarchy support into the kernel, then it seems like it should be completely taken into the kernel, i.e. the hierarchy checking should be applied by the kernel rather than by the toolchain. That is what the Flask security server did for its extensible policy mechanism.

When the checks are applied in the kernel?
One candidate is policy loading time, and the other is AVC entry creation time. I prefers the later one, because checks in policy loading time will require the expensive checks in kernel space.

Quoted 9 lines
Quoted 4 lines

In my idea, violated permission bits on AVC entries are masked by ones of its parent types, with/without printing logs.
Now hierarchy/neverallow constraint makes abort whole of policy loading. It can be a significant difference.

Yes, it makes sense to apply the hierarchy restrictions at computation time. Neverallows are a bit different though - we want those to flag bugs in policy. Thus, we likely should leave neverallow checking in the userland toolchain.

Quoted 6 lines

So you want to deny at runtime based on the hierarchy? Won't that create another confusing way SELinux can deny something without any clue why (aside from running the denial through audit2why)? Further, this is something we can understand and reject ahead of time, I don't know why it makes sense to wait until later when we can tell now that something is wrong with the policy.

True. On the other hand, if we are going to make the hierarchy visible to the kernel so that it can directly leverage information from it, then it makes sense to let the kernel directly enforce the relationships, whether that happens at policy load time or at compute_av time.

Quoted 4 lines

If we can make the checking happen entirely at policy load time in a manner that isn't too expensive, then that is cleaner, I agree. If not, then lazy dynamic checking by the kernel and optional full static checking by the toolchain may be a compromise.

I guess we can reduce cost to check hierarchy constraint, because all we have to do is to scan/check avtabs of related types and ebitmaps of type_attr_maps.
However, I don't have a good idea to boost neverallow constraint so much due to its flexibility. :(

I have measured a performance to check hierarchy/neverallow constraint with patched libsepol as a trial. Unfortunatelly, about 80% of CPU time is consumed by check_assertions() for neverallows.

[root@saba ~]# time -p semodule -r kaigai
hierarchy_check_constraints: 37.32 [s]
check_assertions: 139.05 [s]
real 205.32
user 198.06
sys 3.75

These checks at policy load time gives us negative effect in system bootup time, unless remarkable improvements. So, I prefer lazy dynamic checking approach.

Quoted 7 lines
Quoted 1 line

(*) System bootup time is one of the major topics for embedded Linux folks.

Ok. I'd be interested in seeing that libsepol patch nonetheless, and we may want to retain full checking there as an option for validation at policy build time (via make validate) while introducing lazy dynamic checking in the kernel.

Quoted 6 lines

This sounds reasonable.

Quoted 2 lines

BTW, we may need to revisit the policydb data structures in order to fully address concerns about policy load time.

Do you have ideas here?

I think it is mostly due to long hash chains, which costs us both in populating the new policydb during load and in tearing down the old one (measurable latency which led to cond_resched calls in the policydb_destroy code path) and of course on compute_av when walking the chains.

So we either need to reduce policy size or store it more compactly or both. For example, being able to store a single avtab entry for all file classes when they have identical permissions in common might be helpful.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#23 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment

In reply to Stephen Smalley
Quoted 15 lines
Quoted 15 lines

I have measured a performance to check hierarchy/neverallow constraint with patched libsepol as a trial. Unfortunatelly, about 80% of CPU time is consumed by check_assertions() for neverallows.

[root@saba ~]# time -p semodule -r kaigai
hierarchy_check_constraints: 37.32 [s]
check_assertions: 139.05 [s]
real 205.32
user 198.06
sys 3.75

These checks at policy load time gives us negative effect in system bootup time, unless remarkable improvements. So, I prefer lazy dynamic checking approach.

Quoted 6 lines
Quoted 1 line

(*) System bootup time is one of the major topics for embedded Linux folks.

Ok. I'd be interested in seeing that libsepol patch nonetheless, and we may want to retain full checking there as an option for validation at policy build time (via make validate) while introducing lazy dynamic checking in the kernel.

I tries to run semodule with patched libsepol to deliver NEVERALLOW rules into kernel space, however, it cost was extremely expensive and unacceptable.

Some of NEVERALLOWs covers wide range of types, like:

    neverallow ~{ domain unlabeled_t } *:process *;

It is finally translated massive amount of avtab structure, and it makes grow the size of security policy. In my estimation, the above single NEVERALLOW constraint makes about 4,000,000 of avtab and it will consume 48Mb of additional memory and storage for nonsense purpose in most cases.

So, I reconsidered the feature to check NEVERALLOW should not be ported into kernelspace.

(*) I killed semodule due to its long processes...
[root@saba libsepol]# ls -lh /etc/selinux/targeted/modules/tmp/policy.kern -rw-r--r-- 1 root root 29M 2008-08-01 15:08 /etc/selinux/targeted/modules/tmp/policy.kern

                       ^^^

[root@saba libsepol]# ls -lh /etc/selinux/targeted/policy/ total 11M
-rw-r--r-- 1 root root 3.4M 2008-04-03 15:19 policy.22 -rw-r--r-- 1 root root 3.7M 2008-07-22 19:27 policy.23 -rw-r--r-- 1 root root 3.7M 2008-08-01 13:45 policy.24

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#30 lore raw

cover Thread/Child-Domain Assignment (rev.2)

In reply to KaiGai Kohei

The series of patches enables to assign a thread an indivisual "more bounded" domain, even if the process is multithreaded.

We can apply this feature to set up a server application which handles user's request withing more restricted domain, to protect potential harms come from application bugs.

It also adds a new binary policy format (version 24). This version allows each definitions of user/role/type to have its bounds. The bounds restrict capabilities of bounded one with similar rules compared to existing name based hierarchy support.
The following rules are enhanced from existing hierarchy stuff.
- A bounded type cannot have any attribute which does not assigned to the upper type.
- CONSTRAIN/MLSCONSTRAIN rules are enhanced to pay attention the boundary relationships.

I adds a new statement of TYPEBOUNDS as follows:

  TYPEBOUNDS <parent type>  <child type 1> [, <child type 2> ...] ;

It defines boundary relationships between two types, and these are loaded to the kernelspace via policy version 24. (*) The existing hierarchy is implicitly expanded to bounds.

I don't provide a statement to define boundary relationships between roles/users, although existing hierarchy supports them, because its purpose/worth is unclear now.
The policy format version 24 has a field to represent boundary relationship between users/roles, but it is only used to ship existing hierarhies.

[1/3] thread-context-kernel.1.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

[2/3] thread-context-checkpolicy.2.patch
It enables to support TYPEBOUNDS statement and to expand existing hierarchies implicitly.

[3/3] thread-context-libsepol.2.patch
It enables to support binary policy format version 24.

The series of patches does not contains facilities to support lazy NEVERALLOW support, due to enlarged policy size, as I noted before.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#31 lore raw

PATCH 1/3 Thread/Child-Domain Assignment (rev.2)

[1/3] thread-context-kernel.2.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   12 +-
 security/selinux/include/security.h |    6 +-
 security/selinux/ss/policydb.c      |  244 +++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    4 +
 security/selinux/ss/services.c      |  324 +++++++++++++++++++++++++++++++----
 6 files changed, 541 insertions(+), 51 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +10 -2
index bc1c3ae..2c2fad3 100644
@@ -5180,8 +5180,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5189,11 +5193,15 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+					if (!security_bounded_transition(tsec->sid, sid))
+						goto boundary_ok;
+
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/security.h +5 -1
index ad30ac4..ef6b3db 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -112,6 +113,9 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +230 -14

365 lines not on this page · raw message

security/selinux/ss/policydb.h +4 -0
index 4253370..320fa23 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,14 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +212,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +291 -33

385 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#61 lore raw

PATCH 2/3 Thread/Child-Domain Assignment (rev.2)

In reply to KaiGai Kohei

[2/3] thread-context-checkpolicy.2.patch
It enables to support TYPEBOUNDS statement and to expand existing hierarchies implicitly.

--

 module_compiler.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++++
 policy_define.c   |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 policy_define.h   |    1
 policy_parse.y    |    5 ++
 policy_scan.l     |    2 +
 5 files changed, 186 insertions(+), 1 deletion(-)
policy_define.c +92 -1
Index: checkpolicy/policy_define.c
===================================================================
@@ -1127,6 +1127,77 @@
 	return 0;
 }
 
+static int define_typebounds_helper(char *bounds_id, char *type_id)
+{
+	type_datum_t *bounds, *type;
+
+	if (!is_id_in_scope(SYM_TYPES, bounds_id)) {
+		yyerror2("type %s is not within scope", bounds_id);
+		return -1;
+	}
+
+	bounds = hashtab_search(policydbp->p_types.table, bounds_id);
+	if (!bounds || bounds->flavor == TYPE_ATTRIB) {
+		yyerror2("hoge unknown type %s", bounds_id);
+		return -1;
+	}
+
+	if (!is_id_in_scope(SYM_TYPES, type_id)) {
+		yyerror2("type %s is not within scope", type_id);
+		return -1;
+	}
+
+	type = hashtab_search(policydbp->p_types.table, type_id);
+	if (!type || type->flavor == TYPE_ATTRIB) {
+		yyerror2("type %s is not declared", type_id);
+		return -1;
+	}
+
+	if (type->flavor == TYPE_TYPE && !type->primary) {
+		type = policydbp->type_val_to_struct[type->s.value - 1];
+	} else if (type->flavor == TYPE_ALIAS) {
+		type = policydbp->type_val_to_struct[type->primary - 1];
+	}
+
+	if (!type->bounds)
+		type->bounds = bounds->s.value;
+	else if (type->bounds != bounds->s.value) {
+		yyerror2("type %s has inconsistent master {%s,%s}",
+			 type_id,
+			 policydbp->p_type_val_to_name[type->bounds - 1],
+			 policydbp->p_type_val_to_name[bounds->s.value - 1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+int define_typebounds(void)
+{
+	char *bounds, *id;
+
+	if (pass == 1) {
+		while ((id = queue_remove(id_queue)))
+			free(id);
+		return 0;
+	}
+
+	bounds = (char *) queue_remove(id_queue);
+	if (!bounds) {
+		yyerror("no type name for typebounds definition?");
+		return -1;
+	}
+
+	while ((id = queue_remove(id_queue))) {
+		if (define_typebounds_helper(bounds, id))
+			return -1;
+		free(id);
+	}
+	free(bounds);
+
+	return 0;
+}
+
 int define_type(int alias)
 {
 	char *id;
@@ -1134,12 +1205,32 @@
 	int newattr = 0;
 
 	if (pass == 2) {
-		while ((id = queue_remove(id_queue)))
+		/*
+		 * If type name contains ".", we have to define boundary
+		 * relationship implicitly to keep compatibility with
+		 * old name based hierarchy.
+		 */
+		if ((id = queue_remove(id_queue))) {
+			char *bounds, *delim;
+
+			if ((delim = strrchr(id, '.'))
+			    && (bounds = strdup(id))) {
+				bounds[(size_t)(delim - id)] = '\0';
+
+				if (define_typebounds_helper(bounds, id))
+					return -1;
+				free(bounds);
+			}
 			free(id);
+		}
+
 		if (alias) {
 			while ((id = queue_remove(id_queue)))
 				free(id);
 		}
+
+		while ((id = queue_remove(id_queue)))
+			free(id);
 		return 0;
 	}
 
policy_scan.l +2 -0
Index: checkpolicy/policy_scan.l
===================================================================
@@ -82,6 +82,8 @@
 typealias			{ return(TYPEALIAS); }
 TYPEATTRIBUTE |
 typeattribute			{ return(TYPEATTRIBUTE); }
+TYPEBOUNDS |
+typebounds			{ return(TYPEBOUNDS); }
 TYPE |
 type				{ return(TYPE); }
 BOOL |
policy_define.h +1 -0
Index: checkpolicy/policy_define.h
===================================================================
@@ -47,6 +47,7 @@
 int define_te_avtab(int which);
 int define_typealias(void);
 int define_typeattribute(void);
+int define_typebounds(void);
 int define_type(int alias);
 int define_user(void);
 int define_validatetrans(constraint_expr_t *expr);
policy_parse.y +5 -0
Index: checkpolicy/policy_parse.y
===================================================================
@@ -92,6 +92,7 @@
 %token ROLES
 %token TYPEALIAS
 %token TYPEATTRIBUTE
+%token TYPEBOUNDS
 %token TYPE
 %token TYPES
 %token ALIAS
@@ -258,6 +259,7 @@
                         | type_def
                         | typealias_def
                         | typeattribute_def
+                        | typebounds_def
                         | bool_def
                         | transition_def
                         | range_trans_def
@@ -278,6 +280,9 @@
 typeattribute_def	: TYPEATTRIBUTE identifier id_comma_list ';'
 			{if (define_typeattribute()) return -1;}
 			;
+typebounds_def          : TYPEBOUNDS identifier id_comma_list ';'
+                        {if (define_typebounds()) return -1;}
+                        ;
 opt_attr_list           : ',' id_comma_list
 			|
 			;
module_compiler.c +86 -0

110 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#66 lore raw

PATCH 3/3 Thread/Child-Domain Assignment (rev.2)

In reply to KaiGai Kohei

[3/3] thread-context-libsepol.2.patch
It enables to support binary policy format version 24.

--

 include/sepol/policydb/policydb.h |   19 +++++-
 src/expand.c                      |  105 ++++++++++++++++++++++++++++++++++++
 src/link.c                        |  108 ++++++++++++++++++++++++++++++++++++--
 src/policydb.c                    |   80 +++++++++++++++++++++-------
 src/write.c                       |    6 ++
 5 files changed, 294 insertions(+), 24 deletions(-)
include/sepol/policydb/policydb.h +17 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,6 +146,7 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
 /* User attributes */
@@ -156,6 +158,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +598,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +612,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +61 -19

149 lines not on this page · raw message

src/expand.c +105 -0

129 lines not on this page · raw message

src/write.c +6 -0
Index: libsepol/src/write.c
===================================================================
@@ -920,6 +920,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(role->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(role->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
@@ -957,6 +959,8 @@
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(typdatum->s.value);
 	buf[items++] = cpu_to_le32(typdatum->primary);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(typdatum->bounds);
 	if (p->policy_type != POLICY_KERN) {
 		buf[items++] = cpu_to_le32(typdatum->flavor);
 		if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
@@ -997,6 +1001,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(usrdatum->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(usrdatum->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
src/link.c +105 -3

122 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#32 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.2)

In reply to KaiGai Kohei
Quoted 28 lines · KaiGai Kohei

[1/3] thread-context-kernel.2.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   12 +-
 security/selinux/include/security.h |    6 +-
 security/selinux/ss/policydb.c      |  244 +++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    4 +
 security/selinux/ss/services.c      |  324 +++++++++++++++++++++++++++++++----
 6 files changed, 541 insertions(+), 51 deletions(-)
security/selinux/ss/policydb.c +2 -2
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct role_datum *role;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	role = kzalloc(sizeof(*role), GFP_KERNEL);

security/selinux/ss/policydb.c static int role_read(struct policydb *p, struct hashtab *h, void *fp) · line 1214

Quoted 7 lines
security/selinux/ss/policydb.c +3 -0
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 		goto out;
 	}
 
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
 	rc = next_entry(buf, fp, sizeof buf);

Doesn't this also need to be changed to pass sizeof(buf[0]) * to_read rather than sizeof buf?
Did you try loading an old policy on your new kernel?

Quoted 48 lines
security/selinux/ss/policydb.c +35 -0
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	role->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		role->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1465,6 +1502,181 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
 	cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct user_datum *upper, *user;
+	struct policydb *p = datap;
+	int rc, depth = 0;
+
+	upper = user = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR
+			       "SELinux: user %s: too deep bounds\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->user_val_to_struct[upper->bounds - 1];
+		if (!upper) {
+			printk(KERN_ERR
+			       "SELinux: user %s: broken boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+		/* drop bounded bit from user->roles */
+retry:
+		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+			if (ebitmap_get_bit(&upper->roles, bit))
+				continue;
+
+			audit_log(current->audit_context, GFP_KERNEL,
+				  AUDIT_SELINUX_ERR,

security/selinux/ss/policydb.c static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) · line 1547

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+				  "boundary violation: "
+				  "user=%s role=%s bounds=%s",
+				  p->p_user_val_to_name[user->value - 1],
+				  p->p_role_val_to_name[bit],
+				  p->p_user_val_to_name[upper->value - 1]);
+
+			rc = ebitmap_set_bit(&user->roles, bit, 0);
+			if (rc)
+				return rc;
+			goto retry;

I would just return an error and abort the policy load on any boundary violations detected at load time rather than mutating the policy.

Quoted 38 lines
security/selinux/ss/policydb.c +38 -0
+		}
+	}
+	return 0;
+}
+
+static int role_bounds_sanity_check(void *key, void *datum, void *poldbp)
+{
+	struct role_datum *upper, *role;
+	struct policydb *p = poldbp;
+	int rc, depth = 0;
+
+	upper = role = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR
+			       "SELinux: role %s: too deep bounds\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->role_val_to_struct[upper->bounds - 1];
+		if (!upper) {
+			printk(KERN_ERR
+			       "SELinux: role %s: broken boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+		/* drop bounded bit from user->roles */
+retry:
+		ebitmap_for_each_positive_bit(&role->types, node, bit) {
+			if (ebitmap_get_bit(&upper->types, bit))
+				continue;
+
+			audit_log(current->audit_context, GFP_KERNEL,
+				  AUDIT_SELINUX_ERR,

security/selinux/ss/policydb.c static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) · line 1595

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+				  "boundary violation: "
+				  "role=%s type=%s bounds=%s",
+				  p->p_role_val_to_name[role->value - 1],
+				  p->p_type_val_to_name[bit],
+				  p->p_role_val_to_name[upper->value - 1]);
+
+			rc = ebitmap_set_bit(&role->types, bit, 0);
+			if (rc)
+				return rc;
+			goto retry;

Ditto.

Quoted 44 lines
security/selinux/ss/policydb.c +44 -0
+		}
+	}
+	return 0;
+}
+
+static int type_bounds_sanity_check(void *key, void *datum, void *poldbp)
+{
+	struct type_datum *upper, *type;
+	struct policydb *p = poldbp;
+	int rc, depth = 0;
+
+	upper = type = datum;
+	while (upper->bounds) {
+		struct ebitmap *type_attrs, *upper_attrs;
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR
+			       "SELinux: type %s: too deep boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->type_val_to_struct[upper->bounds - 1];
+		if (!upper) {
+			printk(KERN_ERR
+			       "SELinux: type %s: broken boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+		/* drop bounded bit from type_attr_map */
+retry:
+		type_attrs = &p->type_attr_map[type->value - 1];
+		upper_attrs = &p->type_attr_map[upper->value - 1];
+		ebitmap_for_each_positive_bit(type_attrs, node, bit) {
+			if (type->value == bit + 1)
+				continue;
+
+			if (ebitmap_get_bit(upper_attrs, bit))
+				continue;
+
+			audit_log(current->audit_context, GFP_KERNEL,
+				  AUDIT_SELINUX_ERR,

security/selinux/ss/policydb.c static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) · line 1649

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+				  "boundary violation: "
+				  "type=%s attribute=%lu bounds=%s",
+				  p->p_type_val_to_name[type->value - 1],
+				  bit + 1,
+				  p->p_type_val_to_name[upper->value - 1]);
+
+			rc = ebitmap_set_bit(type_attrs, bit, 0);
+			if (rc)
+				return rc;
+			goto retry;

And again.

security/selinux/ss/policydb.h struct role_allow { · line 87

Quoted 12 lines
security/selinux/ss/policydb.h +1 -0
index 4253370..320fa23 100644
@@ -61,6 +61,7 @@ struct class_datum {
@@ -81,12 +82,14 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
 };

An aside: Possibly we should add the attribute flag at the same time and leave the type attributes in the type symtab in the kernel policy, as previously discussed. Then the kernel policy won't be lacking any information needed for analysis. Just need to make sure that context_to_sid doesn't accept attributes in the type field.

Quoted 4 lines
security/selinux/ss/services.c +0 -0
index dcc2e1c..a584c1d 100644

<snip>

security/selinux/ss/services.c static int context_struct_to_string(struct context *context, char **scontext, · line 168

Quoted 7 lines
security/selinux/ss/services.c +7 -0
+static int cexpr_type_names_eval(struct ebitmap *names, u16 type_value)
+{
+	struct type_datum *type
+		= policydb.type_val_to_struct[type_value - 1];
+	int bit;
+
+	while (1) {

You were using while (true) in the prior functions. We should be consistent one way or the other.

Quoted 5 lines
security/selinux/ss/services.c +5 -0
+		bit = ebitmap_get_bit(names, type->value - 1);
+		if (!bit) {
+			if (type->value != type_value)
+				audit_log(current->audit_context,
+					  GFP_ATOMIC, AUDIT_SELINUX_ERR,

security/selinux/ss/services.c static int context_struct_to_string(struct context *context, char **scontext, · line 183

Quoted 10 lines
security/selinux/ss/services.c +10 -0
+					  "boundary violation: "
+					  "type=%s bounded=%s",
+					  policydb.p_type_val_to_name[type_value - 1],
+					  policydb.p_type_val_to_name[type->value - 1]);
+			break;
+		}
+		if (!type->bounds)
+			break;
+		type = policydb.type_val_to_struct[type->bounds - 1];
+	}

I don't think we ought to be doing this checking here, if at all. Either we vet the constraints for internal consistency at load time, or we view the bounds as purely a limit on the TE rules and not necessarily on the constraints.

security/selinux/ss/services.c out: · line 647

Quoted 5 lines
security/selinux/ss/services.c +1 -0
@@ -547,6 +644,167 @@ out:
 	return rc;
 }
 
+extern void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);

Move to avc.h, please.

Quoted 19 lines
security/selinux/ss/services.c +19 -0
+
+/*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void security_bounded_permission(u16 source_type,
+					u16 target_type,
+					u16 tclass,
+					struct av_decision *avd)
+{
+	struct type_datum *source
+		= policydb.type_val_to_struct[source_type - 1];
+	struct type_datum *target
+		= policydb.type_val_to_struct[target_type - 1];
+	struct av_decision lo_avd;
+	u32 masked = 0;
+
+	if (source->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));

security/selinux/ss/services.c out: · line 676

Quoted 10 lines
security/selinux/ss/services.c +10 -0
+
+		type_attribute_compute_av(source->bounds,
+					  target_type,
+					  tclass,
+					  AVTAB_ALLOWED,
+					  &lo_avd);
+
+		security_bounded_permission(source->bounds,
+					    target_type,
+					    tclass, &lo_avd);

Since you always call type_attribute_compute_av and security_bounded_permission together, you might as well collapse them or wrap them with a single interface, right? Less chance then of the (stype, ttype, tclass) arguments being inconsistent.

security/selinux/ss/services.c out: · line 745

Quoted 6 lines
security/selinux/ss/services.c +6 -0
+
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid. Otherwise,
+ * 1 or any other error code can be returned.

Seems somewhat confusing in its return code conventions. Either return a simple bool (true/false) or return 0 on success and -errno on failure.

Quoted 31 lines
security/selinux/ss/services.c +31 -0
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, old_sid);
+		goto out;
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, new_sid);
+		goto out;
+	}
+
+	/* type/domain unchaned */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;

security/selinux/ss/services.c out: · line 786

Quoted 10 lines
security/selinux/ss/services.c +10 -0
+	}
+
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		if (!type) {
+			printk(KERN_ERR "SELinux: broken type boundary.\n");
+			rc = -EINVAL;
+			break;
+		}

Are these legitimate runtime conditions or signs of kernel BUGs? val_to_struct arrays ought to be without holes unless I'm forgetting something.

Quoted 25 lines
security/selinux/ss/services.c +21 -0
+
+		/* not bounded anymore */
+		if (!type->bounds) {
+			rc = 1;
+			break;
+		}
+
+		/* @newsid is bounded by @oldsid */
+		if (type->bounds == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->bounds;
+	}
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#33 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.2)

Thanks for your reviewing.

Quoted 32 lines · Stephen Smalley
Quoted 31 lines · KaiGai Kohei

[1/3] thread-context-kernel.2.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   12 +-
 security/selinux/include/security.h |    6 +-
 security/selinux/ss/policydb.c      |  244 +++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    4 +
 security/selinux/ss/services.c      |  324 +++++++++++++++++++++++++++++++----
 6 files changed, 541 insertions(+), 51 deletions(-)
security/selinux/ss/policydb.c +2 -2
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct role_datum *role;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	role = kzalloc(sizeof(*role), GFP_KERNEL);
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 		goto out;
 	}
 
Quoted 8 lines

security/selinux/ss/policydb.c static int role_read(struct policydb *p, struct hashtab *h, void *fp) · line 1214

Quoted 4 lines
security/selinux/ss/policydb.c +3 -0
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
 	rc = next_entry(buf, fp, sizeof buf);

Doesn't this also need to be changed to pass sizeof(buf[0]) * to_read rather than sizeof buf?
Did you try loading an old policy on your new kernel?

It was a bug, fixed at revision 3.

Quoted 53 lines
Quoted 53 lines
security/selinux/ss/policydb.c +40 -0
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	role->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		role->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1465,6 +1502,181 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
 	cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct user_datum *upper, *user;
+	struct policydb *p = datap;
+	int rc, depth = 0;
+
+	upper = user = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR
+			       "SELinux: user %s: too deep bounds\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->user_val_to_struct[upper->bounds - 1];
+		if (!upper) {
+			printk(KERN_ERR
+			       "SELinux: user %s: broken boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+		/* drop bounded bit from user->roles */
+retry:
+		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+			if (ebitmap_get_bit(&upper->roles, bit))
+				continue;
+
+			audit_log(current->audit_context, GFP_KERNEL,
+				  AUDIT_SELINUX_ERR,
+				  "boundary violation: "
+				  "user=%s role=%s bounds=%s",
+				  p->p_user_val_to_name[user->value - 1],
+				  p->p_role_val_to_name[bit],
+				  p->p_user_val_to_name[upper->value - 1]);
Quoted 8 lines

security/selinux/ss/policydb.c static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) · line 1547

Quoted 5 lines
security/selinux/ss/policydb.c +5 -0
+
+			rc = ebitmap_set_bit(&user->roles, bit, 0);
+			if (rc)
+				return rc;
+			goto retry;

I would just return an error and abort the policy load on any boundary violations detected at load time rather than mutating the policy.

OK, XXXX_bounds_sanity_check() are reworked to return an error and to abort the policy load.

- snip -

Quoted 10 lines
Quoted 10 lines
security/selinux/ss/policydb.h +1 -0
index 4253370..320fa23 100644
@@ -61,6 +61,7 @@ struct class_datum {
@@ -81,12 +82,14 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
Quoted 8 lines

security/selinux/ss/policydb.h struct role_allow { · line 87

Quoted 2 lines
security/selinux/ss/policydb.h +0 -0
 	unsigned char primary;	/* primary name? */
 };

An aside: Possibly we should add the attribute flag at the same time and leave the type attributes in the type symtab in the kernel policy, as previously discussed. Then the kernel policy won't be lacking any information needed for analysis. Just need to make sure that context_to_sid doesn't accept attributes in the type field.

I updated the libsepol to deliver attribute entries into kernel space, and kernel type_datum got a new member to show it is an attribute. In the policy format, if bounds field of type equals 0xffffffff means this entry is an attribute.
However, it might be an ad-hoc usage. An alternatice way to deliver this information is to utilize the "primary" field of type to put various kind of flags, because it consume 32bit width to represent 1bit information, and rest of 31bit is free.

This reworking also enables to fill up the hole of type_val_to_struct array, so we don't need to allocate it with kzalloc(). I reverted it to kmalloc() from kzalloc().
(In the previous revision, we can find NULL for attributes.)

Quoted 5 lines
Quoted 4 lines
security/selinux/ss/services.c +0 -0
index dcc2e1c..a584c1d 100644

<snip>

Quoted 10 lines

security/selinux/ss/services.c static int context_struct_to_string(struct context *context, char **scontext, · line 168

Quoted 7 lines
security/selinux/ss/services.c +7 -0
+static int cexpr_type_names_eval(struct ebitmap *names, u16 type_value)
+{
+	struct type_datum *type
+		= policydb.type_val_to_struct[type_value - 1];
+	int bit;
+
+	while (1) {

You were using while (true) in the prior functions. We should be consistent one way or the other.

Oops, I left it as integer value unawares.
However, cexpr_XXXX_names_eval() were reverted on the next revision. :-)

Quoted 12 lines
Quoted 12 lines
security/selinux/ss/services.c +12 -0
+		bit = ebitmap_get_bit(names, type->value - 1);
+		if (!bit) {
+			if (type->value != type_value)
+				audit_log(current->audit_context,
+					  GFP_ATOMIC, AUDIT_SELINUX_ERR,
+					  "boundary violation: "
+					  "type=%s bounded=%s",
+					  policydb.p_type_val_to_name[type_value - 1],
+					  policydb.p_type_val_to_name[type->value - 1]);
+			break;
+		}
+		if (!type->bounds)
Quoted 8 lines

security/selinux/ss/services.c static int context_struct_to_string(struct context *context, char **scontext, · line 183

Quoted 3 lines
security/selinux/ss/services.c +3 -0
+			break;
+		type = policydb.type_val_to_struct[type->bounds - 1];
+	}

I don't think we ought to be doing this checking here, if at all. Either we vet the constraints for internal consistency at load time, or we view the bounds as purely a limit on the TE rules and not necessarily on the constraints.

I think the boundary rules also should be applied on the constraints. For example, we can assume a case when a bounded type can have "mcssetcats" attribute, even if its bounds type does not have the attribute. It seems to me a bit strange behavior.

I reverted it and put a code to check boundary consistency at the policy load time. (constraint_bounds_sanity_check())

Quoted 7 lines

security/selinux/ss/services.c out: · line 647

Quoted 5 lines
security/selinux/ss/services.c +1 -0
@@ -547,6 +644,167 @@ out:
 	return rc;
 }
 
+extern void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);

Move to avc.h, please.

OK, moved.

Quoted 26 lines
Quoted 26 lines
security/selinux/ss/services.c +26 -0
+
+/*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void security_bounded_permission(u16 source_type,
+					u16 target_type,
+					u16 tclass,
+					struct av_decision *avd)
+{
+	struct type_datum *source
+		= policydb.type_val_to_struct[source_type - 1];
+	struct type_datum *target
+		= policydb.type_val_to_struct[target_type - 1];
+	struct av_decision lo_avd;
+	u32 masked = 0;
+
+	if (source->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		type_attribute_compute_av(source->bounds,
+					  target_type,
+					  tclass,
+					  AVTAB_ALLOWED,
+					  &lo_avd);
+
Quoted 8 lines

security/selinux/ss/services.c out: · line 676

Quoted 3 lines
security/selinux/ss/services.c +3 -0
+		security_bounded_permission(source->bounds,
+					    target_type,
+					    tclass, &lo_avd);

Since you always call type_attribute_compute_av and security_bounded_permission together, you might as well collapse them or wrap them with a single interface, right? Less chance then of the (stype, ttype, tclass) arguments being inconsistent.

I moved the boundary checks into type_attribute_compute_av().

Quoted 10 lines

security/selinux/ss/services.c out: · line 745

Quoted 6 lines
security/selinux/ss/services.c +6 -0
+
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid. Otherwise,
+ * 1 or any other error code can be returned.

Seems somewhat confusing in its return code conventions. Either return a simple bool (true/false) or return 0 on success and -errno on failure.

OK, it was reworked to return 0 (success) or negative error code.

Quoted 37 lines
Quoted 37 lines
security/selinux/ss/services.c +37 -0
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, old_sid);
+		goto out;
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, new_sid);
+		goto out;
+	}
+
+	/* type/domain unchaned */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		if (!type) {
Quoted 8 lines

security/selinux/ss/services.c out: · line 786

Quoted 4 lines
security/selinux/ss/services.c +4 -0
+			printk(KERN_ERR "SELinux: broken type boundary.\n");
+			rc = -EINVAL;
+			break;
+		}

Are these legitimate runtime conditions or signs of kernel BUGs? val_to_struct arrays ought to be without holes unless I'm forgetting something.

There was no guarantee the bounds does not indicate the hole of type_val_to_struct array due to attributes.
However, delivering attribute into kernelspace kills the hole.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#34 lore raw

PATCH 1/3 Thread/Child-Domain Assignment (rev.3)

In reply to Stephen Smalley

The following patch is the revised one for the kernel. It is reworked for anything reviewed, and add a support to represent attributes of types in kernelspace.

[1/3] thread-context-kernel.3.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   12 +-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   16 ++-
 security/selinux/ss/policydb.c      |  322 +++++++++++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  228 +++++++++++++++++++++----
 7 files changed, 541 insertions(+), 48 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +10 -2
index bc1c3ae..2c2fad3 100644
@@ -5180,8 +5180,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5189,11 +5193,15 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+					if (!security_bounded_transition(tsec->sid, sid))
+						goto boundary_ok;
+
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/avc.h +4 -0
index 8e23d7a..7c4caf2 100644
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -127,6 +128,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
security/selinux/include/security.h +15 -1
index ad30ac4..3773eb6 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,17 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/* boundary related definitions */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+#define POLICYDB_BOUNDS_ATTRIBUTE_FLAG	0xffffffff
+/*
+ * NOTE: When "bounds" field equals POLICYDB_BOUNDS_ATTRIBUTE_FLAG,
+ * it means this entry is attribute, not a normal type.
+ * Boundary feature also requires to deliver attribute info into
+ * kernel space, because it has to notice boundary violation related
+ * to type/attribute relationships.
+ */
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -112,6 +124,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +309 -13

430 lines not on this page · raw message

security/selinux/ss/policydb.h +5 -0
index 4253370..55152d4 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +197 -31

266 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#67 lore raw

PATCH 3/3 Thread/Child-Domain Assignment (rev.3)

In reply to KaiGai Kohei

The following patch is the revised one for the libsepol. It is reworked to deliver entries of attributes into kernelspace. It enables to show boundary violation at policy load time in human readable form.

[3/3] thread-context-libsepol.3.patch
It enables to support binary policy format version 24.

--

 include/sepol/policydb/policydb.h |   21 +++++-
 src/expand.c                      |  132 ++++++++++++++++++++++++++++++--------
 src/link.c                        |  108 ++++++++++++++++++++++++++++++-
 src/policydb.c                    |   80 +++++++++++++++++------
 src/write.c                       |   15 ++++
 5 files changed, 305 insertions(+), 51 deletions(-)
include/sepol/policydb/policydb.h +19 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,6 +146,7 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
 /* User attributes */
@@ -156,6 +158,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +598,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +612,25 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
+#define POLICYDB_BOUNDS_ATTRIBUTE_FLAG	0xffffffff
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +61 -19

151 lines not on this page · raw message

src/expand.c +105 -27

168 lines not on this page · raw message

src/write.c +15 -0
Index: libsepol/src/write.c
===================================================================
@@ -920,6 +920,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(role->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(role->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
@@ -952,11 +954,22 @@
 
 	typdatum = (type_datum_t *) datum;
 
+	if (p->policy_type == POLICY_KERN
+	    && p->policyvers < POLICYDB_VERSION_BOUNDARY
+	    && typdatum->flavor == TYPE_ATTRIB)
+		return POLICYDB_SUCCESS;
+
 	len = strlen(key);
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(typdatum->s.value);
 	buf[items++] = cpu_to_le32(typdatum->primary);
+	if (policydb_has_boundary_feature(p)) {
+		if (typdatum->flavor == TYPE_ATTRIB)
+			buf[items++] = cpu_to_le32(POLICYDB_BOUNDS_ATTRIBUTE_FLAG);
+		else
+			buf[items++] = cpu_to_le32(typdatum->bounds);
+	}
 	if (p->policy_type != POLICY_KERN) {
 		buf[items++] = cpu_to_le32(typdatum->flavor);
 		if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
@@ -997,6 +1010,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(usrdatum->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(usrdatum->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
src/link.c +105 -3

122 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#62 lore raw

PATCH 2/3 Thread/Child-Domain Assignment (rev.3)

In reply to KaiGai Kohei
Quoted 4 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.2.patch
It enables to support TYPEBOUNDS statement and to expand existing hierarchies implicitly.

Quoted 8 lines

--

 module_compiler.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++++
 policy_define.c   |   93 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 policy_define.h   |    1
 policy_parse.y    |    5 ++
 policy_scan.l     |    2 +
 5 files changed, 186 insertions(+), 1 deletion(-)

The patch for checkpolicy is unchanged at revision 3. Please apply the previous version, as is.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#94 lore raw

RE: [PATCH 0/3] Thread/Child-Domain Assignment (rev.2)

In reply to KaiGai Kohei
Quoted 8 lines · KaiGai Kohei

The series of patches enables to assign a thread an indivisual "more bounded" domain, even if the process is multithreaded.

We can apply this feature to set up a server application which handles user's request withing more restricted domain, to protect potential harms come from application bugs.

Quoted 8 lines

It also adds a new binary policy format (version 24). This version allows each definitions of user/role/type to have its bounds. The bounds restrict capabilities of bounded one with similar rules compared to existing name based hierarchy support.
The following rules are enhanced from existing hierarchy stuff.
- A bounded type cannot have any attribute which does not assigned to the upper type.

I don't think this is necessary. The original hierarchy implementation only cared about the net effect of the rules, not how they were granted. For example, if I have 2 attributes, one that is given more privilege and one that is given a subset of the first why should I have to assign both to the 'parent' type? I don't agree with this constraint.

Quoted 7 lines

- CONSTRAIN/MLSCONSTRAIN rules are enhanced to pay attention the
boundary relationships.

I adds a new statement of TYPEBOUNDS as follows:

  TYPEBOUNDS <parent type>  <child type 1> [, <child type 2> ...] ;
Quoted 7 lines

It defines boundary relationships between two types, and these are loaded to the kernelspace via policy version 24. (*) The existing hierarchy is implicitly expanded to bounds.

I don't provide a statement to define boundary relationships between roles/users, although existing hierarchy supports them, because its purpose/worth is unclear now.

Its purpose was the same as the original purpose for the hierarchy. The hierarchy was developed for policy access control using the policy management server. One would 'label' policy objects using the hierarchy and could constrain the permissions (or roles or types) using the hierarchical constraints. I request that you not remove this support in your version.

Additionally, if you are enforcing hierarchy on types in constrain statements you should also do this for roles and users, for consistency.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#95 lore raw

Re: [PATCH 0/3] Thread/Child-Domain Assignment (rev.2)

Quoted 18 lines · Joshua Brindle
Quoted 8 lines · KaiGai Kohei

The series of patches enables to assign a thread an indivisual "more bounded" domain, even if the process is multithreaded.

We can apply this feature to set up a server application which handles user's request withing more restricted domain, to protect potential harms come from application bugs.

Quoted 8 lines

It also adds a new binary policy format (version 24). This version allows each definitions of user/role/type to have its bounds. The bounds restrict capabilities of bounded one with similar rules compared to existing name based hierarchy support.
The following rules are enhanced from existing hierarchy stuff.
- A bounded type cannot have any attribute which does not assigned to the upper type.

Quoted 5 lines

I don't think this is necessary. The original hierarchy implementation only cared about the net effect of the rules, not how they were granted. For example, if I have 2 attributes, one that is given more privilege and one that is given a subset of the first why should I have to assign both to the 'parent' type? I don't agree with this constraint.

The major purpose of attribute bounds was a restriction for CONSTRAIN or MLSCONSTRAINT rules. However, I reconsidered it can be implemented by sanity checks at policy load time, without any attribute bounds.

I agree what you pointed out.
In the next patch, I'll remove the code to check attribute bounds.

Quoted 15 lines
Quoted 7 lines

- CONSTRAIN/MLSCONSTRAIN rules are enhanced to pay attention the
boundary relationships.

I adds a new statement of TYPEBOUNDS as follows:

  TYPEBOUNDS <parent type>  <child type 1> [, <child type 2> ...] ;
Quoted 7 lines

It defines boundary relationships between two types, and these are loaded to the kernelspace via policy version 24. (*) The existing hierarchy is implicitly expanded to bounds.

I don't provide a statement to define boundary relationships between roles/users, although existing hierarchy supports them, because its purpose/worth is unclear now.

Quoted 6 lines

Its purpose was the same as the original purpose for the hierarchy. The hierarchy was developed for policy access control using the policy management server. One would 'label' policy objects using the hierarchy and could constrain the permissions (or roles or types) using the hierarchical constraints. I request that you not remove this support in your version.

Sorry, my explanation might be misleadable. :(

The new facilities can have a data structure to represent boundary relationships between two types/roles/users. However, I didn't add a new syntax in policy language statement, like USERBOUNDS/ROLEBOUNDS. If the checkmodule founds existing name based hierarhies, implicit boundary relationships are assigned to them, and these are shipped into kernelspace later.

For example, a definition of "staff_u.kaigai" does not define a SElinux user only, but a boundary relationship between "staff_u" and "staff_u.kaigai" is also defined automatically.

I consider this behavior can follows existing name based hierarchies.

Quoted 2 lines

Additionally, if you are enforcing hierarchy on types in constrain statements you should also do this for roles and users, for consistency.

The latest kernel patch enables to check (MLS)CONSTRAINT statement for users, roles and types. Please show constraint_bounds_sanity_check() which is invoked at policy load time.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#35 lore raw

PATCH 1/3 Thread/Child-Domain Assignment (rev.4)

In reply to KaiGai Kohei

The following patch is the revised one for the kernel.

Joshua suggested it is not necessary to bound type attributes based on boundary relationship, and I also agreed this opinion. The related code is dropped in this patch, and several code cleanup contained.

This change makes it unnecessary to deliver text represented attributes into kernelspace, but related codes are still remained for ...

| Stephen Smalley wrote:
| An aside:  Possibly we should add the attribute flag at the same time
| and leave the type attributes in the type symtab in the kernel policy,
| as previously discussed.  Then the kernel policy won't be lacking any
| information needed for analysis.  Just need to make sure that
| context_to_sid doesn't accept attributes in the type field.

Stephen, could you point out the previous discussion?

Thanks,

[1/3] thread-context-kernel.4.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   11 +-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   16 ++-
 security/selinux/ss/policydb.c      |  298 +++++++++++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  227 +++++++++++++++++++++++----
 7 files changed, 515 insertions(+), 48 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +8 -3
index bc1c3ae..0201227 100644
@@ -5180,9 +5180,14 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
-		if (atomic_read(&p->mm->mm_users) != 1) {
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
+		if (atomic_read(&p->mm->mm_users) != 1
+		    && security_bounded_transition(tsec->sid, sid) != 0) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
 			read_lock(&tasklist_lock);
security/selinux/include/avc.h +4 -0
index 8e23d7a..7c4caf2 100644
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -127,6 +128,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
security/selinux/include/security.h +15 -1
index ad30ac4..3773eb6 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,17 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/* boundary related definitions */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+#define POLICYDB_BOUNDS_ATTRIBUTE_FLAG	0xffffffff
+/*
+ * NOTE: When "bounds" field equals POLICYDB_BOUNDS_ATTRIBUTE_FLAG,
+ * it means this entry is attribute, not a normal type.
+ * Boundary feature also requires to deliver attribute info into
+ * kernel space, because it has to notice boundary violation related
+ * to type/attribute relationships.
+ */
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -112,6 +124,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +285 -13

406 lines not on this page · raw message

security/selinux/ss/policydb.h +5 -0
index 4253370..55152d4 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +197 -30

265 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#96 lore raw

A toy of SQL injection (Re: [PATCH 0/3] Thread/Child-Domain Assignment)

In reply to KaiGai Kohei

The following PHP script is an example to assign individual security context. A modified version of Apache kicks a child thread for each requirests and assign its security context based on authenticated username via HTTP basic authentication.

http://kaigai.myhome.cx/index.php

Three users are set up (curry, sushi and noodle) with same password of "selinux", to confirm they have individual security context.

No need to say, this script has a vulnerability of SQL injection. It can help to image how SELinux aware LAPP stack protect from web application bugs.

(*) The above URL and environment is temporary one, so I'll close
it without any notices after a week. :-)

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#36 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.4)

In reply to KaiGai Kohei
Quoted 11 lines · KaiGai Kohei

The following patch is the revised one for the kernel.

Joshua suggested it is not necessary to bound type attributes based on boundary relationship, and I also agreed this opinion. The related code is dropped in this patch, and several code cleanup contained.

This change makes it unnecessary to deliver text represented attributes into kernelspace, but related codes are still remained for ...

Quoted 8 lines
| Stephen Smalley wrote:
| An aside:  Possibly we should add the attribute flag at the same time
| and leave the type attributes in the type symtab in the kernel policy,
| as previously discussed.  Then the kernel policy won't be lacking any
| information needed for analysis.  Just need to make sure that
| context_to_sid doesn't accept attributes in the type field.

Stephen, could you point out the previous discussion?

Keeping the type attribute names in the types symtab in the kernel policy allows tools like audit2why and apol to extract the original attribute names and display them. I originally shed them because the kernel didn't need to use that information and we don't want attribute names to be used in security contexts, but it costs us little to save them and check for them, and it benefits the tools.

Quoted 27 lines

Thanks,

[1/3] thread-context-kernel.4.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   11 +-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   16 ++-
 security/selinux/ss/policydb.c      |  298 +++++++++++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  227 +++++++++++++++++++++++----
 7 files changed, 515 insertions(+), 48 deletions(-)
security/selinux/hooks.c +0 -1
index bc1c3ae..0201227 100644
@@ -5180,9 +5180,14 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p, · line 5190

Quoted 10 lines
security/selinux/hooks.c +8 -2
-		/* Only allow single threaded processes to change context */
-		if (atomic_read(&p->mm->mm_users) != 1) {
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
+		if (atomic_read(&p->mm->mm_users) != 1
+		    && security_bounded_transition(tsec->sid, sid) != 0) {

Alternatively you could defer the security_bounded_transition() check until the if (t->mm == mm && t != p) block. The mm_users check is a merely a quick check to see whether we need to probe further to determine whether or not there are any other threads sharing the mm.

Quoted 28 lines
security/selinux/hooks.c +0 -0
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
 			read_lock(&tasklist_lock);
security/selinux/include/security.h +2 -1
index ad30ac4..3773eb6 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,17 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 

security/selinux/include/security.h enum { · line 75

Quoted 10 lines
security/selinux/include/security.h +10 -0
+/* boundary related definitions */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+#define POLICYDB_BOUNDS_ATTRIBUTE_FLAG	0xffffffff
+/*
+ * NOTE: When "bounds" field equals POLICYDB_BOUNDS_ATTRIBUTE_FLAG,
+ * it means this entry is attribute, not a normal type.
+ * Boundary feature also requires to deliver attribute info into
+ * kernel space, because it has to notice boundary violation related
+ * to type/attribute relationships.
+ */

It seems a bit ugly to overload the bounds field for this purpose vs. encoding it into the primary field as you suggest elsewhere.

Quoted 4 lines
security/selinux/ss/policydb.c +0 -0
index 84f8cc7..f134322 100644

<snip>

Quoted 18 lines
security/selinux/ss/policydb.c +18 -0
+static int constraint_bounds_sanity_check(struct policydb *p,
+					  struct constraint_expr *cexpr)
+{
+	struct user_datum *user;
+	struct role_datum *role;
+	struct type_datum *type;
+	struct ebitmap_node *node;
+	unsigned long bit;
+
+	/* no need to check boundary constraint */
+	if (cexpr->expr_type != CEXPR_NAMES)
+		return 0;
+
+	ebitmap_for_each_positive_bit(&cexpr->names, node, bit) {
+		if (cexpr->attr & CEXPR_USER) {
+			if (bit >= p->p_users.nprim)
+				goto broken_ebitmap;
+

security/selinux/ss/policydb.c static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) · line 1640

Quoted 10 lines
security/selinux/ss/policydb.c +10 -0
+			user = p->user_val_to_struct[bit];
+			if (user->bounds &&
+			    !ebitmap_get_bit(&cexpr->names, user->bounds - 1)) {
+				printk(KERN_ERR
+				       "SELinux: boundary violated cexpr:"
+				       " CEXPR_NAMES: user:%s bounds:%s\n",
+				       p->p_user_val_to_name[user->value - 1],
+				       p->p_user_val_to_name[user->bounds - 1]);
+				return -EINVAL;
+			}

What if cexpr->op is CEXPR_NEQ, e.g. the clause was something like (u1 != untrusteduser)? Or the entire clause is negated? I'm not sure you want to apply these bounds checks on constraints at all.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#37 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.4)

Quoted 62 lines · Stephen Smalley
Quoted 11 lines · KaiGai Kohei

The following patch is the revised one for the kernel.

Joshua suggested it is not necessary to bound type attributes based on boundary relationship, and I also agreed this opinion. The related code is dropped in this patch, and several code cleanup contained.

This change makes it unnecessary to deliver text represented attributes into kernelspace, but related codes are still remained for ...

Quoted 8 lines
| Stephen Smalley wrote:
| An aside:  Possibly we should add the attribute flag at the same time
| and leave the type attributes in the type symtab in the kernel policy,
| as previously discussed.  Then the kernel policy won't be lacking any
| information needed for analysis.  Just need to make sure that
| context_to_sid doesn't accept attributes in the type field.

Stephen, could you point out the previous discussion?

Keeping the type attribute names in the types symtab in the kernel policy allows tools like audit2why and apol to extract the original attribute names and display them. I originally shed them because the kernel didn't need to use that information and we don't want attribute names to be used in security contexts, but it costs us little to save them and check for them, and it benefits the tools.

Quoted 34 lines

Thanks,

[1/3] thread-context-kernel.4.patch
It allows a multithreaded process to assign an individual "more bounded" security context, and it also enables to handle binary policy format version 24 in kernel space.

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   11 +-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   16 ++-
 security/selinux/ss/policydb.c      |  298 +++++++++++++++++++++++++++++++++--
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  227 +++++++++++++++++++++++----
 7 files changed, 515 insertions(+), 48 deletions(-)
security/selinux/hooks.c +5 -3
index bc1c3ae..0201227 100644
@@ -5180,9 +5180,14 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
-		if (atomic_read(&p->mm->mm_users) != 1) {
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
Quoted 8 lines

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p, · line 5190

Quoted 3 lines
security/selinux/hooks.c +3 -0
+		 */
+		if (atomic_read(&p->mm->mm_users) != 1
+		    && security_bounded_transition(tsec->sid, sid) != 0) {

Alternatively you could defer the security_bounded_transition() check until the if (t->mm == mm && t != p) block. The mm_users check is a merely a quick check to see whether we need to probe further to determine whether or not there are any other threads sharing the mm.

The reason why I moved it to front of the block is we can skip the checks whether the given process is multithreaded or not, if security_bounded_transition() returns success.
However, I have no preference here. There may be a bit performance gain, but this code is not invoked so frequently.
So, I'll revert it on the next revision.

Quoted 4 lines
Quoted 4 lines
security/selinux/hooks.c +0 -0
@@ -62,6 +63,17 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
Quoted 13 lines

security/selinux/hooks.c enum { · line 75

Quoted 10 lines
security/selinux/hooks.c +10 -0
+/* boundary related definitions */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+#define POLICYDB_BOUNDS_ATTRIBUTE_FLAG	0xffffffff
+/*
+ * NOTE: When "bounds" field equals POLICYDB_BOUNDS_ATTRIBUTE_FLAG,
+ * it means this entry is attribute, not a normal type.
+ * Boundary feature also requires to deliver attribute info into
+ * kernel space, because it has to notice boundary violation related
+ * to type/attribute relationships.
+ */

It seems a bit ugly to overload the bounds field for this purpose vs. encoding it into the primary field as you suggest elsewhere.

OK, I'll encode these properties of type_datum into the primary field.

Quoted 29 lines
Quoted 4 lines
security/selinux/ss/policydb.c +0 -0
index 84f8cc7..f134322 100644

<snip>

Quoted 24 lines
security/selinux/ss/policydb.c +24 -0
+static int constraint_bounds_sanity_check(struct policydb *p,
+					  struct constraint_expr *cexpr)
+{
+	struct user_datum *user;
+	struct role_datum *role;
+	struct type_datum *type;
+	struct ebitmap_node *node;
+	unsigned long bit;
+
+	/* no need to check boundary constraint */
+	if (cexpr->expr_type != CEXPR_NAMES)
+		return 0;
+
+	ebitmap_for_each_positive_bit(&cexpr->names, node, bit) {
+		if (cexpr->attr & CEXPR_USER) {
+			if (bit >= p->p_users.nprim)
+				goto broken_ebitmap;
+
+			user = p->user_val_to_struct[bit];
+			if (user->bounds &&
+			    !ebitmap_get_bit(&cexpr->names, user->bounds - 1)) {
+				printk(KERN_ERR
+				       "SELinux: boundary violated cexpr:"
+				       " CEXPR_NAMES: user:%s bounds:%s\n",
Quoted 8 lines

security/selinux/ss/policydb.c static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp) · line 1640

Quoted 4 lines
security/selinux/ss/policydb.c +4 -0
+				       p->p_user_val_to_name[user->value - 1],
+				       p->p_user_val_to_name[user->bounds - 1]);
+				return -EINVAL;
+			}

What if cexpr->op is CEXPR_NEQ, e.g. the clause was something like (u1 != untrusteduser)? Or the entire clause is negated? I'm not sure you want to apply these bounds checks on constraints at all.

CEXPR_NEQ is dealt as simply negated ebitmap in the current implementation. For example, (u1 != untrusteduser) requires a user is not "untrusteduser" and its parent is not "untrusteduser" also.

Hmm, however, it may be a bit complicated/hard to understand rule. The purpose of this check is to prevent to attach wider permissions on bounded types, like mcssetcats attribute which means a privilege.

Here is an idea.
If the type_attribute_bounds_av() is put after constraint checks on avc computing, we can make sure the purpose of bounds checks. It simply means a bounded type cannot have wider permissions than its parent in TE rules and constraints.

Thanks,

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#38 lore raw

PATCH 1/3 Thread/Child-Domain Assignment (rev.6)

In reply to Stephen Smalley

The following patch is revised one for kernel.

Updates:
- This patch is rebased on James's security-testing-2.6 tree.
- security_bounded_transition() is deployed just after read_unlock() within do_each_thread() { ... } while_each_thread() loop again.
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
- Bounds checks on constraints are integrated within avc creation. Lazy bounds checks are invoked at the tail of context_struct_compute_av(), and it drops all of boundary violated permissions. It compares permissions of a bounded type based on both of TE and constraints by a bounds type in same time, so the bounded type always cannot have any wider permission than its parent.
e.g)
When a type of child_t is bounded by parent_t and has mcssetcats attribute, we cannot assign undominated categories because parent_t is not allowed to assign them and it bounds permissions of child_t.
- Sanity checks for constraints are removed by the above reason.

Thanks,

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   11 ++-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   15 +++-
 security/selinux/ss/policydb.c      |  205 ++++++++++++++++++++++++++++++++---
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  172 +++++++++++++++++++++++++++++-
 7 files changed, 395 insertions(+), 19 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +9 -2
index 03fc6a8..e06e963 100644
@@ -5219,8 +5219,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5228,11 +5232,14 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+					if (!security_bounded_transition(tsec->sid, sid))
+						goto boundary_ok;
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/avc.h +4 -0
index 7b9769f..d12ff1a 100644
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
security/selinux/include/security.h +14 -1
index 7c54300..7244737 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,16 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +191 -14

312 lines not on this page · raw message

security/selinux/ss/policydb.h +5 -0
index 4253370..55152d4 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +171 -1

202 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#68 lore raw

PATCH 3/3 Thread/Child-Domain Assignment (rev.4)

In reply to KaiGai Kohei

The following patch is revised one for libsepol.

Updates:
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
The first bit (TYPEDATUM_PROPERTY_PRIMARY) means the entry is a primary type, and the second bit (TYPEDATUM_PROPERTY_ATTRIBUTE) means the entry is an attribute.

Thanks,

--

 include/sepol/policydb/policydb.h |   26 ++++++-
 src/expand.c                      |  132 ++++++++++++++++++++++++++++++--------
 src/link.c                        |  108 ++++++++++++++++++++++++++++++-
 src/policydb.c                    |   89 +++++++++++++++++++------
 src/write.c                       |   28 +++++++-
 5 files changed, 329 insertions(+), 54 deletions(-)
include/sepol/policydb/policydb.h +24 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,8 +146,16 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY      0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
+
 /* User attributes */
 typedef struct user_datum {
 	symtab_datum_t s;
@@ -156,6 +165,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +605,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +619,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +69 -20

159 lines not on this page · raw message

src/expand.c +105 -27

168 lines not on this page · raw message

src/write.c +26 -2
Index: libsepol/src/write.c
===================================================================
@@ -920,6 +920,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(role->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(role->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
@@ -952,12 +954,32 @@
 
 	typdatum = (type_datum_t *) datum;
 
+	if (p->policy_type == POLICY_KERN
+	    && p->policyvers < POLICYDB_VERSION_BOUNDARY
+	    && typdatum->flavor == TYPE_ATTRIB)
+		return POLICYDB_SUCCESS;
+
 	len = strlen(key);
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(typdatum->s.value);
-	buf[items++] = cpu_to_le32(typdatum->primary);
-	if (p->policy_type != POLICY_KERN) {
+	if (p->policy_type == POLICY_KERN) {
+		if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+			uint32_t prop = 0;
+
+			if (typdatum->primary)
+				prop |= TYPEDATUM_PROPERTY_PRIMARY;
+			if (typdatum->flavor == TYPE_ATTRIB)
+				prop |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+			buf[items++] = cpu_to_le32(prop);
+			buf[items++] = cpu_to_le32(typdatum->bounds);
+		} else {
+			buf[items++] = cpu_to_le32(typdatum->primary);
+		}
+	} else {
+		buf[items++] = cpu_to_le32(typdatum->primary);
+		if (p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)
+			buf[items++] = cpu_to_le32(typdatum->bounds);
 		buf[items++] = cpu_to_le32(typdatum->flavor);
 		if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
 			buf[items++] = cpu_to_le32(typdatum->flags);
@@ -997,6 +1019,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(usrdatum->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(usrdatum->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
src/link.c +105 -3

122 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#39 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei
Quoted 11 lines · KaiGai Kohei

The following patch is revised one for kernel.

Updates:
- This patch is rebased on James's security-testing-2.6 tree.
- security_bounded_transition() is deployed just after read_unlock() within do_each_thread() { ... } while_each_thread() loop again.
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
- Bounds checks on constraints are integrated within avc creation. Lazy bounds checks are invoked at the tail of context_struct_compute_av(), and it drops all of boundary violated permissions. It compares permissions

Quoted 8 lines

of a bounded type based on both of TE and constraints by a bounds type in same time, so the bounded type always cannot have any wider permission than its parent.
e.g)
When a type of child_t is bounded by parent_t and has mcssetcats attribute, we cannot assign undominated categories because parent_t is not allowed to assign them and it bounds permissions of child_t.
- Sanity checks for constraints are removed by the above reason.

This looks good to me in terms of the functionality. Have you run any benchmarks to assess the performance impact on AVC misses?

Quoted 708 lines

Thanks,

--

 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   11 ++-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   15 +++-
 security/selinux/ss/policydb.c      |  205 ++++++++++++++++++++++++++++++++---
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  172 +++++++++++++++++++++++++++++-
 7 files changed, 395 insertions(+), 19 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +9 -2
index 03fc6a8..e06e963 100644
@@ -5219,8 +5219,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5228,11 +5232,14 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+					if (!security_bounded_transition(tsec->sid, sid))
+						goto boundary_ok;
 					return -EPERM;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/avc.h +4 -0
index 7b9769f..d12ff1a 100644
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
security/selinux/include/security.h +14 -1
index 7c54300..7244737 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,16 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +191 -14
index 2391761..7dbe756 100644
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/audit.h>
 #include "security.h"
 
 #include "policydb.h"
@@ -116,7 +117,12 @@ static struct policydb_compat_info policydb_compat[] = {
 		.version	= POLICYDB_VERSION_PERMISSIVE,
 		.sym_num	= SYM_NUM,
 		.ocon_num	= OCON_NUM,
-	}
+	},
+	{
+		.version	= POLICYDB_VERSION_BOUNDARY,
+		.sym_num	= SYM_NUM,
+		.ocon_num	= OCON_NUM,
+	},
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -254,7 +260,9 @@ static int role_index(void *key, void *datum, void *datap)
 
 	role = datum;
 	p = datap;
-	if (!role->value || role->value > p->p_roles.nprim)
+	if (!role->value
+	    || role->value > p->p_roles.nprim
+	    || role->bounds > p->p_roles.nprim)
 		return -EINVAL;
 	p->p_role_val_to_name[role->value - 1] = key;
 	p->role_val_to_struct[role->value - 1] = role;
@@ -270,9 +278,12 @@ static int type_index(void *key, void *datum, void *datap)
 	p = datap;
 
 	if (typdatum->primary) {
-		if (!typdatum->value || typdatum->value > p->p_types.nprim)
+		if (!typdatum->value
+		    || typdatum->value > p->p_types.nprim
+		    || typdatum->bounds > p->p_types.nprim)
 			return -EINVAL;
 		p->p_type_val_to_name[typdatum->value - 1] = key;
+		p->type_val_to_struct[typdatum->value - 1] = typdatum;
 	}
 
 	return 0;
@@ -285,7 +296,9 @@ static int user_index(void *key, void *datum, void *datap)
 
 	usrdatum = datum;
 	p = datap;
-	if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
+	if (!usrdatum->value
+	    || usrdatum->value > p->p_users.nprim
+	    || usrdatum->bounds > p->p_users.nprim)
 		return -EINVAL;
 	p->p_user_val_to_name[usrdatum->value - 1] = key;
 	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
@@ -438,6 +451,14 @@ static int policydb_index_others(struct policydb *p)
 		goto out;
 	}
 
+	p->type_val_to_struct =
+		kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
+			GFP_KERNEL);
+	if (!p->type_val_to_struct) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	if (cond_init_bool_indexes(p)) {
 		rc = -ENOMEM;
 		goto out;
@@ -625,6 +646,7 @@ void policydb_destroy(struct policydb *p)
 	kfree(p->class_val_to_struct);
 	kfree(p->role_val_to_struct);
 	kfree(p->user_val_to_struct);
+	kfree(p->type_val_to_struct);
 
 	avtab_destroy(&p->te_avtab);
 
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct role_datum *role;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	role = kzalloc(sizeof(*role), GFP_KERNEL);
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 		goto out;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	role->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		role->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1236,8 +1263,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct type_datum *typdatum;
-	int rc;
-	__le32 buf[3];
+	int rc, to_read = 3;
+	__le32 buf[4];
 	u32 len;
 
 	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
@@ -1246,13 +1273,27 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 		return rc;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 4;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	typdatum->value = le32_to_cpu(buf[1]);
-	typdatum->primary = le32_to_cpu(buf[2]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+		u32 prop = le32_to_cpu(buf[2]);
+
+		if (prop & TYPEDATUM_PROPERTY_PRIMARY)
+			typdatum->primary = 1;
+		if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
+			typdatum->attribute = 1;
+
+		typdatum->bounds = le32_to_cpu(buf[3]);
+	} else {
+		typdatum->primary = le32_to_cpu(buf[2]);
+	}
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1309,8 +1350,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct user_datum *usrdatum;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
@@ -1319,12 +1360,17 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
 		goto out;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	usrdatum->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		usrdatum->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1465,6 +1511,133 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
 	cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct user_datum *upper, *user;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = user = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: user %s: "
+			       "too deep or looped boundary",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->user_val_to_struct[upper->bounds - 1];
+		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+			if (ebitmap_get_bit(&upper->roles, bit))
+				continue;
+
+			printk(KERN_ERR
+			       "SELinux: boundary violated policy: "
+			       "user=%s role=%s bounds=%s\n",
+			       p->p_user_val_to_name[user->value - 1],
+			       p->p_role_val_to_name[bit],
+			       p->p_user_val_to_name[upper->value - 1]);
+
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int role_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct role_datum *upper, *role;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = role = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: role %s: "
+			       "too deep or looped bounds\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->role_val_to_struct[upper->bounds - 1];
+		ebitmap_for_each_positive_bit(&role->types, node, bit) {
+			if (ebitmap_get_bit(&upper->types, bit))
+				continue;
+
+			printk(KERN_ERR
+			       "SELinux: boundary violated policy: "
+			       "role=%s type=%s bounds=%s\n",
+			       p->p_role_val_to_name[role->value - 1],
+			       p->p_type_val_to_name[bit],
+			       p->p_role_val_to_name[upper->value - 1]);
+
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int type_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct type_datum *upper, *type;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = type = datum;
+	while (upper->bounds) {
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: type %s: "
+			       "too deep or looped boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->type_val_to_struct[upper->bounds - 1];
+		if (upper->attribute) {
+			printk(KERN_ERR "SELinux: type %s: "
+			       "bounded by attribute %s",
+			       (char *) key,
+			       p->p_type_val_to_name[upper->value - 1]);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int policydb_bounds_sanity_check(struct policydb *p)
+{
+	int rc;
+
+	if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
+		return 0;
+
+	rc = hashtab_map(p->p_users.table,
+			 user_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	rc = hashtab_map(p->p_roles.table,
+			 role_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	rc = hashtab_map(p->p_types.table,
+			 type_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
 extern int ss_initialized;
 
 /*
@@ -1961,6 +2134,10 @@ int policydb_read(struct policydb *p, void *fp)
 				goto bad;
 	}
 
+	rc = policydb_bounds_sanity_check(p);
+	if (rc)
+		goto bad;
+
 	rc = 0;
 out:
 	return rc;
security/selinux/ss/policydb.h +5 -0
index 4253370..55152d4 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +171 -1
index b52f923..1ed94a3 100644
@@ -88,6 +88,11 @@ static u32 latest_granting;
 static int context_struct_to_string(struct context *context, char **scontext,
 				    u32 *scontext_len);
 
+static int context_struct_compute_av(struct context *scontext,
+				     struct context *tcontext,
+				     u16 tclass,
+				     u32 requested,
+				     struct av_decision *avd);
 /*
  * Return the boolean value of a constraint expression
  * when it is applied to the specified source and target
@@ -274,6 +279,100 @@ mls_ops:
 }
 
 /*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void type_attribute_bounds_av(struct context *scontext,
+				     struct context *tcontext,
+				     u16 tclass,
+				     u32 requested,
+				     struct av_decision *avd)
+{
+	struct context lo_scontext;
+	struct context lo_tcontext;
+	struct av_decision lo_avd;
+	struct type_datum *source
+		= policydb.type_val_to_struct[scontext->type - 1];
+	struct type_datum *target
+		= policydb.type_val_to_struct[tcontext->type - 1];
+	u32 masked = 0;
+
+	if (source->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
+		lo_scontext.type = source->bounds;
+
+		context_struct_compute_av(&lo_scontext,
+					  tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (target->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
+		lo_tcontext.type = target->bounds;
+
+		context_struct_compute_av(scontext,
+					  &lo_tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (source->bounds && target->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+		/*
+		 * lo_scontext and lo_tcontext are already
+		 * set up.
+		 */
+
+		context_struct_compute_av(&lo_scontext,
+					  &lo_tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (masked) {
+		struct audit_buffer *ab;
+		char *stype_name
+			= policydb.p_type_val_to_name[source->value - 1];
+		char *ttype_name
+			= policydb.p_type_val_to_name[target->value - 1];
+		char *tclass_name
+			= policydb.p_class_val_to_name[tclass - 1];
+
+		/* mask violated permissions */
+		avd->allowed &= ~masked;
+
+		/* notice to userspace via audit message */
+		ab = audit_log_start(current->audit_context,
+				     GFP_ATOMIC, AUDIT_SELINUX_ERR);
+		if (!ab)
+			return;
+
+		audit_log_format(ab, "av boundary violation: "
+				 "source=%s target=%s tclass=%s",
+				 stype_name, ttype_name, tclass_name);
+		avc_dump_av(ab, tclass, masked);
+		audit_log_end(ab);
+	}
+}
+
+/*
  * Compute access vectors based on a context structure pair for
  * the permissions in a particular class.
  */
@@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext,
 							PROCESS__DYNTRANSITION);
 	}
 
+	/*
+	 * If the given source and target types have boundary
+	 * constraint, lazy checks have to mask any violated
+	 * permission and notice it to userspace via audit.
+	 */
+	type_attribute_bounds_av(scontext, tcontext,
+				 tclass, requested, avd);
+
 	return 0;
 
 inval_class:
@@ -549,6 +656,69 @@ out:
 	return rc;
 }
 
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid.
+ * Otherwise, it returns error code.
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, old_sid);
+		goto out;
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, new_sid);
+		goto out;
+	}
+
+	/* type/domain unchaned */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		BUG_ON(!type);
+
+		/* not bounded anymore */
+		if (!type->bounds) {
+			rc = -EPERM;
+			break;
+		}
+
+		/* @newsid is bounded by @oldsid */
+		if (type->bounds == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->bounds;
+	}
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
@@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol,
 	*p++ = 0;
 
 	typdatum = hashtab_search(pol->p_types.table, scontextp);
-	if (!typdatum)
+	if (!typdatum || typdatum->attribute)
 		goto out;
 
 	ctx->type = typdatum->value;
Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#40 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

Quoted 21 lines · Stephen Smalley
Quoted 11 lines · KaiGai Kohei

The following patch is revised one for kernel.

Updates:
- This patch is rebased on James's security-testing-2.6 tree.
- security_bounded_transition() is deployed just after read_unlock() within do_each_thread() { ... } while_each_thread() loop again.
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
- Bounds checks on constraints are integrated within avc creation. Lazy bounds checks are invoked at the tail of context_struct_compute_av(), and it drops all of boundary violated permissions. It compares permissions

Quoted 8 lines

of a bounded type based on both of TE and constraints by a bounds type in same time, so the bounded type always cannot have any wider permission than its parent.
e.g)
When a type of child_t is bounded by parent_t and has mcssetcats attribute, we cannot assign undominated categories because parent_t is not allowed to assign them and it bounds permissions of child_t.
- Sanity checks for constraints are removed by the above reason.

Quoted 3 lines

This looks good to me in terms of the functionality. Have you run any benchmarks to assess the performance impact on AVC misses?

Not yet.
I'll measure it tomorrow, please wait for a while.

Thanks,

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#41 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

In reply to Stephen Smalley
Quoted 21 lines · Stephen Smalley
Quoted 11 lines · KaiGai Kohei

The following patch is revised one for kernel.

Updates:
- This patch is rebased on James's security-testing-2.6 tree.
- security_bounded_transition() is deployed just after read_unlock() within do_each_thread() { ... } while_each_thread() loop again.
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
- Bounds checks on constraints are integrated within avc creation. Lazy bounds checks are invoked at the tail of context_struct_compute_av(), and it drops all of boundary violated permissions. It compares permissions

Quoted 8 lines

of a bounded type based on both of TE and constraints by a bounds type in same time, so the bounded type always cannot have any wider permission than its parent.
e.g)
When a type of child_t is bounded by parent_t and has mcssetcats attribute, we cannot assign undominated categories because parent_t is not allowed to assign them and it bounds permissions of child_t.
- Sanity checks for constraints are removed by the above reason.

Quoted 3 lines

This looks good to me in terms of the functionality. Have you run any benchmarks to assess the performance impact on AVC misses?

I measured it with attached program named as "avc_misses.c". It invokes lstat() for given files, and iterates it 1,000 times. The given files have inidividually different categories, so we can see the performance impact on AVC misses when the number of files is greater than /selinux/avc/cache_threshold .

This program is executed in a domain with/without its boundary on pathed kernel, and did on vanilla kernel.

The following result shows elapsed times of avc_misses on the second time scale. Because lstat() is invoked for all given files, we guess the result is basically proportional to number of files (= # of categories).

| Number of  |  No bounds   |    Bounds    |  No bounds  |
| Files and  | 2.6.27-rc4   |  2.6.27-rc4  | 2.6.27-rc4  |
| Categories |   patched    |   patched    |   vanilla   |
+------------+--------------+--------------+-------------+
|     100    |     2.338    |     2.372    |     2.216   |
|     200    |     4.742    |     4.739    |     4.451   |
|     300    |     7.275    |     7.116    |     6.844   |
|     400    |     9.685    |     9.616    |     9.337   |
|     500    |    12.509    |    12.187    |    12.049   |___
|     600    |    28.532    |    29.736    |    26.092   | |  AVC misses for
|     700    |    45.554    |    50.631    |    40.878   | |  all lstat()
|     800    |    59.908    |    72.730    |    54.208   | V
+------------+--------------+--------------+-------------+
 (*)  /selinux/avc/cache_threshold is 512 (default)

CPU: Pentium4 (3.20Ghz), single core

When # of files is less than cache_threshold, it shows a little performance impact in both of Bounds/No-bounds cases.
When # of files is greater than cache_threshold, it shows a significant performance impact. The difference between No-bounds ans Bounds cases got grown. However, it is extremely artifactual measurement result.

In the typical case, the rate of AVC hits is greater than 99%.
I don't think we don't need to worry about such level of performance impact.

e.g) avcstat just after rawhide bootup.
[kaigai@saba ~]$ /usr/sbin/avcstat
lookups hits misses allocs reclaims frees
619277 614912 4365 4365 3840 3863

Thanks,

Signature · 2 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char *argv[])

{
	struct stat st_buf;
	struct timeval t1, t2;
	double delta;
	int nloops, rc, i, j;

	if (argc < 3) {
		fprintf(stderr, "usage: %s <# of loops> <files ...>\n", argv[0]);
		return 1;
	}

	nloops = atol(argv[1]);
	if (nloops < 1000)
		nloops = 1000;

	gettimeofday(&t1, NULL);
	for (i=0; i < nloops; i++) {
		for (j=2; argv[j]; j++) {
			rc = lstat(argv[j], &st_buf);
			if (rc < 0) {
				fprintf(stderr, "lstat(%s,...) : %s\n",
					argv[j], strerror(errno));
				return 1;
			}
		}
	}
	gettimeofday(&t2, NULL);

	delta = (((double)(t2.tv_sec - t1.tv_sec)) * 1000000.0
		 + ((double)(t2.tv_usec - t1.tv_usec))) / 1000000.0;
	printf("result: %.3f [s] (%d of files, %d of loops)\n",
	       delta, argc - 2, nloops);

	return 0;
}
#42 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei
Quoted 1 line · KaiGai Kohei

The following patch is revised one for kernel.

For future reference, the patch needs to have a description in the body of the email, and you can leave the updates under the '---' line.

See http://www.zipworld.com.au/~akpm/linux/patches/stuff/tpp.txt

Signature · 7 lines
James Morris
<[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#43 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p, · line 5237

Quoted 7 lines · KaiGai Kohei
security/selinux/hooks.c +2 -0
@@ -5228,11 +5232,14 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+					if (!security_bounded_transition(tsec->sid, sid))
+						goto boundary_ok;
 					return -EPERM;

Propagate the return value of security_bounded_transition().

Also, if the user/role bounds are not being used, should they be included in this? From the kernel point of view, unused code should never be added.

- James

Signature · 7 lines
James Morris
<[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#44 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Signature · 7 lines
James Morris
<[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#57 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

In reply to James Morris
Quoted 11 lines · James Morris

security/selinux/hooks.c static int selinux_setprocattr(struct task_struct *p, · line 5237

Quoted 7 lines · KaiGai Kohei
security/selinux/hooks.c +2 -0
@@ -5228,11 +5232,14 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
+					if (!security_bounded_transition(tsec->sid, sid))
+						goto boundary_ok;
 					return -EPERM;

Propagate the return value of security_bounded_transition().

OK, I'll fix it on the next.

Quoted 1 line

Also, if the user/role bounds are not being used, should they be included in this? From the kernel point of view, unused code should never be added.

Existing named based hierarchy on users/roles are implemented using bounds feature. If a user "staff_u.foo" is defined, the toolchain implicitly defines bounds relationship with "staff_u", for example.

I don't provide an explicit way to define bounds (like TYPEBOUNDS) between users/roles, but we can define it with existing grammar.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#45 lore raw

Re: [PATCH 1/3] Thread/Child-Domain Assignment (rev.6)

In reply to James Morris
Quoted 1 line · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

I checked out LTP CVS tree just now, and seeing it.

Please wait for a few days...

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#46 lore raw

PATCH 1/2 Replacement of deprecated interfaces

In reply to James Morris
Quoted 4 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

Thanks,

Signature · 2 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>
testcases/kernel/security/selinux-testsuite/refpolicy/test_ipc.te +3 -3
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_ipc.te
===================================================================
@@ -72,12 +72,12 @@
 # Allow all of these domains to be entered from user domains.
 # via a shell script in the test directory or by another program.
 miscfiles_domain_entry_test_files(ipcdomain)
-userdom_sysadm_entry_spec_domtrans_to(ipcdomain)
+sysadm_entry_spec_domtrans(ipcdomain)
 corecmd_bin_entry_type(ipcdomain)
-userdom_sysadm_bin_spec_domtrans_to(ipcdomain)
+sysadm_bin_spec_domtrans_to(ipcdomain)
 
 allow test_ipc_base_t self:sem create_sem_perms;
 allow test_ipc_base_t self:shm create_sem_perms;
 allow test_ipc_base_t self:shm lock;
 # ipcrm needs this... 
-userdom_search_generic_user_home_dirs(test_ipc_base_t)
+unprivuser_search_home_dirs(test_ipc_base_t)
testcases/kernel/security/selinux-testsuite/refpolicy/test_file.te +4 -5
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_file.te
===================================================================
@@ -43,7 +43,6 @@
 
 # Allow execution of helper programs.
 corecmd_exec_bin(fileopdomain)
-corecmd_exec_sbin(fileopdomain)
 domain_exec_all_entry_files(fileopdomain)
 libs_use_ld_so(fileopdomain)
 libs_use_shared_libs(fileopdomain)
@@ -52,13 +51,13 @@
 
 # Allow all of these domains to be entered from sysadm domain
 miscfiles_domain_entry_test_files(fileopdomain)
-userdom_sysadm_entry_spec_domtrans_to(fileopdomain)
+sysadm_entry_spec_domtrans(fileopdomain)
 
 corecmd_bin_entry_type(fileopdomain)
-userdom_sysadm_bin_spec_domtrans_to(fileopdomain)
+sysadm_bin_spec_domtrans_to(fileopdomain)
 
-corecmd_sbin_entry_type(fileopdomain)
-userdom_sysadm_sbin_spec_domtrans_to(fileopdomain)
+corecmd_bin_entry_type(fileopdomain)
+sysadm_bin_spec_domtrans_to(fileopdomain)
 
 allow fileop_t fileop_exec_t:file entrypoint;
 domain_auto_trans(test_fileop_t, fileop_exec_t, fileop_t)
testcases/kernel/security/selinux-testsuite/refpolicy/test_sysctl.te +2 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_sysctl.te
===================================================================
@@ -19,8 +19,8 @@
 
 # Allow all of these domains to be entered from sysadm domain
 # via /sbin/sysctl.
-corecmd_sbin_entry_type(sysctldomain)
-userdom_sysadm_sbin_spec_domtrans_to(sysctldomain)
+corecmd_bin_entry_type(sysctldomain)
+sysadm_bin_spec_domtrans_to(sysctldomain)
 
 # Allow the first domain to perform sysctl operations.
 kernel_rw_all_sysctls(test_sysctl_t)
testcases/kernel/security/selinux-testsuite/refpolicy/test_task_create.te +10 -10
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_task_create.te
===================================================================
@@ -24,10 +24,10 @@
 typeattribute test_create_no_t test_create_d;
 
 allow test_create_no_t self:process ~fork;
-allow test_create_no_t proc_t:dir r_dir_perms;
+allow test_create_no_t proc_t:dir list_dir_perms;
 allow test_create_no_t proc_t:lnk_file read;
-allow test_create_no_t self:dir r_dir_perms;
-allow test_create_no_t self:notdevfile_class_set r_file_perms;
+allow test_create_no_t self:dir list_dir_perms;
+allow test_create_no_t self:notdevfile_class_set read_file_perms;
 
 libs_use_ld_so(test_create_no_t)
 libs_use_shared_libs(test_create_no_t)
@@ -35,14 +35,14 @@
 allow test_create_no_t self:process setexec;
 selinux_get_fs_mount(test_create_no_t)
 
-allow test_create_no_t { root_t bin_t sbin_t lib_t locale_t usr_t devpts_t home_root_t }:dir r_dir_perms;
-allow test_create_no_t lib_t:lnk_file r_file_perms;
+allow test_create_no_t { root_t bin_t sbin_t lib_t locale_t usr_t devpts_t home_root_t }:dir list_dir_perms;
+allow test_create_no_t lib_t:lnk_file read_file_perms;
 allow test_create_no_t { devtty_t null_device_t zero_device_t }:chr_file rw_file_perms;
-allow test_create_no_t locale_t:dir r_dir_perms;
-allow test_create_no_t locale_t:{ file lnk_file } r_file_perms;
+allow test_create_no_t locale_t:dir list_dir_perms;
+allow test_create_no_t locale_t:{ file lnk_file } read_file_perms;
 allow test_create_no_t privfd:fd use;
-userdom_use_sysadm_ptys(test_create_no_t)
-userdom_use_sysadm_ttys(test_create_no_t)
+sysadm_use_ptys(test_create_no_t)
+sysadm_use_ttys(test_create_no_t)
 
 # General rules for the test_create_d
 
@@ -50,4 +50,4 @@
 role sysadm_r types test_create_d;
 role system_r types test_create_d;
 miscfiles_domain_entry_test_files(test_create_d)
-userdom_sysadm_entry_spec_domtrans_to(test_create_d)
+sysadm_entry_spec_domtrans(test_create_d)
testcases/kernel/security/selinux-testsuite/refpolicy/test_capable_file.te +2 -3
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_capable_file.te
===================================================================
@@ -35,7 +35,6 @@
 
 # Allow execution of helper programs.
 corecmd_exec_bin(capabledomain)
-corecmd_exec_sbin(capabledomain)
 domain_exec_all_entry_files(capabledomain)
 files_exec_etc_files(capabledomain)
 libs_use_ld_so(capabledomain)
@@ -45,9 +44,9 @@
 
 # Allow test_file_t and bin_t to be entered from sysadm role
 miscfiles_domain_entry_test_files(capabledomain)
-userdom_sysadm_entry_spec_domtrans_to(capabledomain)
+sysadm_entry_spec_domtrans(capabledomain)
 corecmd_bin_entry_type(capabledomain)
-userdom_sysadm_bin_spec_domtrans_to(capabledomain)
+sysadm_bin_spec_domtrans_to(capabledomain)
 
 # Allow these domains to create a temporay file.
 allow capabledomain test_file_t:file { setattr rw_file_perms };
testcases/kernel/security/selinux-testsuite/refpolicy/test_setnice.te +0 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_setnice.te
===================================================================
@@ -25,7 +25,6 @@
 
 # Allow execution of helper programs.
 corecmd_exec_bin(setnicedomain)
-corecmd_exec_sbin(setnicedomain)
 domain_exec_all_entry_files(setnicedomain)
 files_exec_etc_files(setnicedomain)
 libs_use_ld_so(setnicedomain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_fdreceive.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_fdreceive.te
===================================================================
@@ -35,7 +35,7 @@
 
 # Allow all of these domains to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(fdreceivedomain)
-userdom_sysadm_entry_spec_domtrans_to(fdreceivedomain)
+sysadm_entry_spec_domtrans(fdreceivedomain)
 
 # Grant the necessary permissions for the server domain.
 ## Create the Unix domain socket file.
testcases/kernel/security/selinux-testsuite/refpolicy/test_link.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_link.te
===================================================================
@@ -69,5 +69,5 @@
 
 # Allow all of these domains to be entered from sysadm domain
 corecmd_bin_entry_type(test_link_domain)
-userdom_sysadm_bin_spec_domtrans_to(test_link_domain)
+sysadm_bin_spec_domtrans_to(test_link_domain)
 
testcases/kernel/security/selinux-testsuite/refpolicy/test_sigkill.te +2 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_sigkill.te
===================================================================
@@ -43,7 +43,7 @@
 # Allow all of these domains to be entered from the sysadm domains,
 # via kill or a program in the test directory.
 miscfiles_domain_entry_test_files(killdomain)
-userdom_sysadm_entry_spec_domtrans_to(killdomain)
+sysadm_entry_spec_domtrans(killdomain)
 corecmd_bin_entry_type(killdomain)
-userdom_sysadm_bin_spec_domtrans_to(killdomain)
+sysadm_bin_spec_domtrans_to(killdomain)
 
testcases/kernel/security/selinux-testsuite/refpolicy/test_global.te +4 -4
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_global.te
===================================================================
@@ -13,7 +13,7 @@
 
 # Allow the test domains to access the sysadm terminal.
 # This allows read and write sysadm ttys and ptys.
-userdom_use_sysadm_terms(testdomain)
+sysadm_use_terms(testdomain)
 
 # Allow the test domains to access the test directory and files
 # even if they are not root owned.
@@ -64,9 +64,9 @@
 	type null_device_t;
 	type zero_device_t;
 }
-allow testdomain { root_t etc_t bin_t sbin_t lib_t usr_t devpts_t }:dir r_dir_perms;
-allow testdomain lib_t:{ file lnk_file } r_file_perms;
-allow testdomain etc_t:file r_file_perms;
+allow testdomain { root_t etc_t bin_t sbin_t lib_t usr_t devpts_t }:dir list_dir_perms;
+allow testdomain lib_t:{ file lnk_file } read_file_perms;
+allow testdomain etc_t:file read_file_perms;
 allow testdomain { devtty_t null_device_t zero_device_t }:chr_file rw_file_perms;
 miscfiles_read_localization(testdomain)
 domain_use_interactive_fds(testdomain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_open.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_open.te
===================================================================
@@ -32,4 +32,4 @@
 
 # Allow all of these domains to be entered from sysadm domain
 miscfiles_domain_entry_test_files(test_open_domain)
-userdom_sysadm_entry_spec_domtrans_to(test_open_domain)
+sysadm_entry_spec_domtrans(test_open_domain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_task_getsid.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_task_getsid.te
===================================================================
@@ -25,7 +25,7 @@
 
 # Allow domain to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(test_getsid_d)
-userdom_sysadm_entry_spec_domtrans_to(test_getsid_d)
+sysadm_entry_spec_domtrans(test_getsid_d)
 
 # Give test_getsid_yes_t the permission needed.
 allow test_getsid_yes_t test_getsid_target_t:process getsession;
testcases/kernel/security/selinux-testsuite/refpolicy/test_inherit.te +2 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_inherit.te
===================================================================
@@ -37,7 +37,7 @@
 
 # Allow all of these domains to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(inheritdomain)
-userdom_sysadm_entry_spec_domtrans_to(inheritdomain)
+sysadm_entry_spec_domtrans(inheritdomain)
 
 # Grant the necessary permissions for the parent domain.
 allow test_inherit_parent_t test_inherit_file_t:file rw_file_perms;
@@ -61,4 +61,4 @@
 allow test_inherit_nowrite_t test_inherit_parent_t:fd use;
 allow test_inherit_nowrite_t test_inherit_parent_t:fifo_file rw_file_perms;
 allow test_inherit_nowrite_t test_inherit_parent_t:process sigchld;
-allow test_inherit_nowrite_t test_inherit_file_t:file r_file_perms;
+allow test_inherit_nowrite_t test_inherit_file_t:file read_file_perms;
testcases/kernel/security/selinux-testsuite/refpolicy/test_task_getpgid.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_task_getpgid.te
===================================================================
@@ -25,7 +25,7 @@
 
 # Allow domain to be entered from the sysadm domain
 miscfiles_domain_entry_test_files(test_getpgid_d)
-userdom_sysadm_entry_spec_domtrans_to(test_getpgid_d)
+sysadm_entry_spec_domtrans(test_getpgid_d)
 
 # Give test_getpgid_yes_t the permission needed.
 allow test_getpgid_yes_t test_getpgid_target_t:process getpgid;
testcases/kernel/security/selinux-testsuite/refpolicy/test_relabel.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_relabel.te
===================================================================
@@ -40,5 +40,5 @@
 
 # Allow all of these domains to be entered from sysadm domain
 corecmd_bin_entry_type(test_relabel_domain)
-userdom_sysadm_bin_spec_domtrans_to(test_relabel_domain)
+sysadm_bin_spec_domtrans_to(test_relabel_domain)
 
testcases/kernel/security/selinux-testsuite/refpolicy/test_execshare.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_execshare.te
===================================================================
@@ -25,7 +25,7 @@
 
 # Allow all of these domains to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(execsharedomain)
-userdom_sysadm_entry_spec_domtrans_to(execsharedomain)
+sysadm_entry_spec_domtrans(execsharedomain)
 
 # Grant the necessary permissions for the child domain.
 domain_entry_file_spec_domtrans(test_execshare_parent_t, test_execshare_child_t)
testcases/kernel/security/selinux-testsuite/refpolicy/test_task_getsched.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_task_getsched.te
===================================================================
@@ -25,7 +25,7 @@
 
 # Allow domain to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(test_getsched_d)
-userdom_sysadm_entry_spec_domtrans_to(test_getsched_d)
+sysadm_entry_spec_domtrans(test_getsched_d)
 
 # Give test_getsched_yes_t the permission needed.
 allow test_getsched_yes_t test_getsched_target_t:process getsched;
testcases/kernel/security/selinux-testsuite/refpolicy/test_dyntrace.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_dyntrace.te
===================================================================
@@ -28,7 +28,7 @@
 
 # Allow test_files_t to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(dyntracedomain)
-userdom_sysadm_entry_spec_domtrans_to(dyntracedomain)
+sysadm_entry_spec_domtrans(dyntracedomain)
 miscfiles_exec_test_files(dyntracedomain)
 
 # Grant the necessary permissions for the child domain.
testcases/kernel/security/selinux-testsuite/refpolicy/test_ioctl.te +2 -3
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_ioctl.te
===================================================================
@@ -23,7 +23,6 @@
 
 # Allow execution of helper programs.
 corecmd_exec_bin(ioctldomain)
-corecmd_exec_sbin(ioctldomain)
 domain_exec_all_entry_files(ioctldomain)
 files_exec_etc_files(ioctldomain)
 libs_use_ld_so(ioctldomain)
@@ -34,9 +33,9 @@
 # Allow all of these domains to be entered from sysadm domain
 # via a shell script in the test directory or by....
 miscfiles_domain_entry_test_files(ioctldomain)
-userdom_sysadm_entry_spec_domtrans_to(ioctldomain)
+sysadm_entry_spec_domtrans(ioctldomain)
 corecmd_bin_entry_type(ioctldomain)
-userdom_sysadm_bin_spec_domtrans_to(ioctldomain)
+sysadm_bin_spec_domtrans_to(ioctldomain)
 
 # Allow the test domains some access to the temp file
 allow test_ioctl_t test_ioctl_file_t:file { read getattr setattr ioctl };
testcases/kernel/security/selinux-testsuite/refpolicy/test_entrypoint.te +1 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_entrypoint.te
===================================================================
@@ -17,5 +17,4 @@
 
 # Allow this domain to be entered via its entrypoint type.
 domain_entry_file(test_entrypoint_t, test_entrypoint_execute_t)
-userdom_sysadm_entry_spec_domtrans_to(test_entrypoint_t)
-
+sysadm_entry_spec_domtrans(test_entrypoint_t)
testcases/kernel/security/selinux-testsuite/refpolicy/test_ptrace.te +2 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_ptrace.te
===================================================================
@@ -27,7 +27,7 @@
 
 # Allow the tracer domain to trace the traced domain.
 allow test_ptrace_tracer_t test_ptrace_traced_t:process ptrace;
-userdom_search_generic_user_home_dirs(test_ptrace_traced_t)
+unprivuser_search_home_dirs(test_ptrace_traced_t)
 
 # Let the tracer wait on the traced domain.
 allow test_ptrace_traced_t test_ptrace_tracer_t:process sigchld;
@@ -35,4 +35,4 @@
 # Allow all of these domains to be entered from the sysadm domains.
 # via a program in the test directory.
 miscfiles_domain_entry_test_files(ptracedomain)
-userdom_sysadm_entry_spec_domtrans_to(ptracedomain)
+sysadm_entry_spec_domtrans(ptracedomain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_task_setpgid.te +11 -10
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_task_setpgid.te
===================================================================
@@ -18,27 +18,28 @@
 typeattribute test_setpgid_no_t test_setpgid_d;
 
 allow test_setpgid_no_t self:process ~{ setpgid setcurrent };
-allow test_setpgid_no_t proc_t:dir r_dir_perms;
+allow test_setpgid_no_t proc_t:dir list_dir_perms;
 allow test_setpgid_no_t proc_t:lnk_file read;
-allow test_setpgid_no_t self:dir r_dir_perms;
-allow test_setpgid_no_t self:notdevfile_class_set r_file_perms;
+allow test_setpgid_no_t self:dir list_dir_perms;
+allow test_setpgid_no_t self:notdevfile_class_set read_file_perms;
 
 libs_use_ld_so(test_setpgid_no_t)
 libs_use_shared_libs(test_setpgid_no_t)
 allow test_setpgid_no_t self:process setexec;
 selinux_get_fs_mount(test_setpgid_no_t)
 
-allow test_setpgid_no_t { root_t bin_t sbin_t lib_t locale_t usr_t devpts_t home_root_t }:dir r_dir_perms;
-allow test_setpgid_no_t lib_t:lnk_file r_file_perms;
+allow test_setpgid_no_t { root_t bin_t sbin_t lib_t locale_t usr_t devpts_t home_root_t }:dir list_dir_perms;
+allow test_setpgid_no_t lib_t:lnk_file read_file_perms;
 allow test_setpgid_no_t { devtty_t null_device_t zero_device_t }:chr_file rw_file_perms;
-allow test_setpgid_no_t locale_t:dir r_dir_perms;
-allow test_setpgid_no_t locale_t:{ file lnk_file } r_file_perms;
+allow test_setpgid_no_t locale_t:dir list_dir_perms;
+allow test_setpgid_no_t locale_t:{ file lnk_file } read_file_perms;
 allow test_setpgid_no_t privfd:fd use;
-userdom_use_sysadm_ptys(test_setpgid_no_t)
-userdom_use_sysadm_ttys(test_setpgid_no_t)
+sysadm_use_ptys(test_setpgid_no_t)
+sysadm_use_ttys(test_setpgid_no_t)
 
 # Allow domain to be entered from the sysadm domain.
 role sysadm_r types test_setpgid_d;
 role system_r types test_setpgid_d;
 miscfiles_domain_entry_test_files(test_setpgid_d)
-userdom_sysadm_entry_spec_domtrans_to(test_setpgid_d)
+sysadm_entry_spec_domtrans(test_setpgid_d)
+userdom_entry_spec_domtrans_unpriv_users(test_setpgid_d)
\ No newline at end of file
testcases/kernel/security/selinux-testsuite/refpolicy/test_task_setsched.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_task_setsched.te
===================================================================
@@ -26,7 +26,7 @@
 
 # Allow domain to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(test_setsched_d)
-userdom_sysadm_entry_spec_domtrans_to(test_setsched_d)
+sysadm_entry_spec_domtrans(test_setsched_d)
 
 # Allow these domains to execute renice.
 corecmd_bin_entry_type(test_setsched_d)
testcases/kernel/security/selinux-testsuite/refpolicy/test_setattr.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_setattr.te
===================================================================
@@ -27,5 +27,5 @@
 
 # Allow all of these domains to be entered from sysadm domain
 corecmd_bin_entry_type(test_setattr_domain)
-userdom_sysadm_bin_spec_domtrans_to(test_setattr_domain)
+sysadm_bin_spec_domtrans_to(test_setattr_domain)
 
testcases/kernel/security/selinux-testsuite/refpolicy/test_transition.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_transition.te
===================================================================
@@ -30,4 +30,4 @@
 allow test_transition_todomain_t test_transition_fromdomain_t:fd use;
 
 # Allow all of these domains to be entered from the sysadm domain.
-userdom_sysadm_entry_spec_domtrans_to(transitiondomain)
+sysadm_entry_spec_domtrans(transitiondomain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_capable_net.te +3 -3
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_capable_net.te
===================================================================
@@ -28,7 +28,7 @@
 corenet_raw_sendrecv_all_nodes(capabledomain)
 corenet_tcp_sendrecv_all_ports(capabledomain)
 corenet_udp_sendrecv_all_ports(capabledomain)
-corenet_non_ipsec_sendrecv(capabledomain)
+corenet_all_recvfrom_unlabeled(capabledomain)
 corenet_tcp_bind_all_nodes(capabledomain)
 corenet_udp_bind_all_nodes(capabledomain)
 sysnet_read_config(capabledomain)
@@ -44,8 +44,8 @@
 allow capabledomain hi_reserved_port_t:tcp_socket name_bind;
 
 # Allow sbin_t to be entered from admin via certain utils.
-corecmd_sbin_entry_type(capabledomain)
-userdom_sysadm_sbin_spec_domtrans_to(capabledomain)
+corecmd_bin_entry_type(capabledomain)
+sysadm_bin_spec_domtrans_to(capabledomain)
 
 require {
 	type ifconfig_exec_t;
testcases/kernel/security/selinux-testsuite/refpolicy/test_dyntrans.te +1 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_dyntrans.te
===================================================================
@@ -28,5 +28,4 @@
 
 # Allow all of these domains to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(dyntransdomain)
-userdom_sysadm_entry_spec_domtrans_to(dyntransdomain)
-
+sysadm_entry_spec_domtrans(dyntransdomain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_exectrace.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_exectrace.te
===================================================================
@@ -28,7 +28,7 @@
 
 # Allow all of these domains to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(exectracedomain)
-userdom_sysadm_entry_spec_domtrans_to(exectracedomain)
+sysadm_entry_spec_domtrans(exectracedomain)
 
 # Grant the necessary permissions for the child domain.
 domain_entry_file_spec_domtrans(test_exectrace_parent_t, test_exectrace_child_t)
testcases/kernel/security/selinux-testsuite/refpolicy/test_wait.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_wait.te
===================================================================
@@ -25,7 +25,7 @@
 
 # Allow all of these domains to be entered from the sysadm domain.
 miscfiles_domain_entry_test_files(waitdomain)
-userdom_sysadm_entry_spec_domtrans_to(waitdomain)
+sysadm_entry_spec_domtrans(waitdomain)
 
 # Grant permissions for a domain transition from parent to child,
 # including the ability to wait on the child.
testcases/kernel/security/selinux-testsuite/refpolicy/test_execute_no_trans.te +2 -2
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_execute_no_trans.te
===================================================================
@@ -19,8 +19,8 @@
 
 # Allow this domain to be entered via the shell.
 corecmd_shell_entry_type(test_execute_notrans_t)
-userdom_sysadm_entry_spec_domtrans_to(test_execute_notrans_t)
+sysadm_entry_spec_domtrans(test_execute_notrans_t)
 
 #Allow test_execute_notrans permissions to the allowed type
 can_exec(test_execute_notrans_t,test_execute_notrans_allowed_t)
-allow test_execute_notrans_t test_execute_notrans_denied_t:file rx_file_perms;
+allow test_execute_notrans_t test_execute_notrans_denied_t:file { mmap_file_perms ioctl lock };
testcases/kernel/security/selinux-testsuite/refpolicy/test_mkdir.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_mkdir.te
===================================================================
@@ -56,4 +56,4 @@
 
 # Allow all of these domains to be entered from sysadm domain
 corecmd_bin_entry_type(test_mkdir_domain)
-userdom_sysadm_bin_spec_domtrans_to(test_mkdir_domain)
+sysadm_bin_spec_domtrans_to(test_mkdir_domain)
testcases/kernel/security/selinux-testsuite/refpolicy/test_rename.te +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_rename.te
===================================================================
@@ -103,5 +103,5 @@
 
 # Allow all of these domains to be entered from sysadm domain
 corecmd_bin_entry_type(test_rename_domain)
-userdom_sysadm_bin_spec_domtrans_to(test_rename_domain)
+sysadm_bin_spec_domtrans_to(test_rename_domain)
 
#53 lore raw

PATCH 2/2 Add a new test case for bounds types

In reply to James Morris
Quoted 4 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

The attached patch adds a new test case to check correctness of boundary feature. It contains four sub tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, even if the bounded domain is allowed to write the file.

---- The result of execution
[root@saba tests]# ./runtest.sh bounds /home/kaigai/develop/ltp/testcases/kernel/security/selinux-testsuite/tests Running with security context=unconfined_u:unconfined_r:unconfined_t:SystemLow-SystemHigh 1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 8.6321e-05 s, 11.9 MB/s
All systems go
test01 PASS : thread dyntrans passed.
setcon() on multithread process failed: Operation not permitted
All systems go
test02 PASS : thread dyntrans to unbound domain failed.
2+0 records in
2+0 records out
1024 bytes (1.0 kB) copied, 4.2932e-05 s, 23.9 MB/s
test03 PASS : unbounded action to be allowed.
dd: opening `/tmp/selinux/test_file': Permission denied
test04 PASS : bounded action to be denied.
Done.
[root@saba tests]#

(*) I added a bit ad-hoc policy to invoke the script from the shell.

Signature · 2 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>
testcases/kernel/security/selinux-testsuite/tests/Makefile +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile
===================================================================
@@ -3,7 +3,7 @@
 ifeq (redhat-release-4, $(findstring redhat-release-4, $(REDHAT_RELEASE)))
     SUBDIRS=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys
 else
-    SUBDIRS=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans
+    SUBDIRS=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans bounds
 endif
 
 all: 
testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +82 -0

82 lines not on this page · raw message

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +123 -0

123 lines not on this page · raw message

Property changes on: ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
___________________________________________________________________
Added: svn:executable
+ *

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +11 -0
Index: ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile
===================================================================
@@ -0,0 +1,11 @@
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+LDLIBS += -lselinux -lpthread
+
+all: $(TARGETS)
+
+install:
+	@set -e; for i in $(TARGETS); do ln -f $$i ../../../../../bin/$$i; done
+	ln -f selinux_bounds.sh ../../../../../bin/
+
+clean:
+	rm -f $(TARGETS)
\ No newline at end of file
testcases/kernel/security/selinux-testsuite/refpolicy/Makefile +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile
===================================================================
@@ -1,7 +1,7 @@
 POLICYDEVEL = /usr/share/selinux/devel
 SEMODULE = /usr/sbin/semodule
 
-TARGETS=test_global.te test_capable_file.te test_capable_net.te \
+TARGETS=test_global.te test_bounds.te test_capable_file.te test_capable_net.te \
 test_capable_sys.te test_dyntrace.te test_dyntrans.te test_entrypoint.te \
 test_execshare.te test_exectrace.te test_execute_no_trans.te \
 test_fdreceive.te test_file.te test_inherit.te test_ioctl.te test_ipc.te \
testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +65 -0

65 lines not on this page · raw message

#47 lore raw

Re: [LTP][PATCH 1/2] Replacement of deprecated interfaces

In reply to KaiGai Kohei
Quoted 7 lines · KaiGai Kohei
Quoted 5 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Quoted 8 lines

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

I don't quite follow. Did you follow the instructions in the selinux-testsuite README? I can run the test scripts either using the test_selinux.sh script or by manually loading the policy and then individually running them as described in the README. Watch out that your patch doesn't disturb the existing misc/sbin_deprecated.patch that gets applied by test_selinux.sh. Keep in mind that this testsuite gets run on everything from RHEL4 to F9.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#48 lore raw

Re: [LTP][PATCH 1/2] Replacement of deprecated interfaces

Quoted 10 lines · Stephen Smalley
Quoted 9 lines · KaiGai Kohei
Quoted 5 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

Quoted 8 lines
Quoted 5 lines

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

I don't quite follow. Did you follow the instructions in the selinux-testsuite README?

I didn't read the README file carefully, Oops.

The update_refpolicy.sh fixes some of deprecated interfaces and inject an interface to kick test script from unconfined domain. So, I can run the testsuite which includs bounds test without any problems on Rawhide.

# However, I got some warnings for deprecated interfaces/macros

# like r_dir_perms, userdom_sysadm_bin_spec_domtrans_to or
# userdom_use_sysadm_ptys.

The attached patch is a new test case of the boundary feature, which contains six tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, because write permission is boundary violated.
test05: It tries to write a bounded type, even if the domain cannot write to
its bounds type. The expected result is fail.
test06: It makes a bounded domain try to set an attribute of bounded type.

Thanks,

Quoted 6 lines

I can run the test scripts either using the
test_selinux.sh script or by manually loading the policy and then individually running them as described in the README. Watch out that your patch doesn't disturb the existing misc/sbin_deprecated.patch that gets applied by test_selinux.sh. Keep in mind that this testsuite gets run on everything from RHEL4 to F9.

Signature · 2 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>
testcases/kernel/security/selinux-testsuite/tests/Makefile +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile
===================================================================
@@ -3,7 +3,7 @@
 ifeq (redhat-release-4, $(findstring redhat-release-4, $(REDHAT_RELEASE)))
     SUBDIRS=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys
 else
-    SUBDIRS=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans
+    SUBDIRS=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans bounds
 endif
 
 all: 
testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +84 -0

84 lines not on this page · raw message

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +166 -0

166 lines not on this page · raw message

Property changes on: ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
___________________________________________________________________
Added: svn:executable
+ *

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +11 -0
Index: ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile
===================================================================
@@ -0,0 +1,11 @@
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+LDLIBS += -lselinux -lpthread
+
+all: $(TARGETS)
+
+install:
+	@set -e; for i in $(TARGETS); do ln -f $$i ../../../../../bin/$$i; done
+	ln -f selinux_bounds.sh ../../../../../bin/
+
+clean:
+	rm -f $(TARGETS)
\ No newline at end of file
testcases/kernel/security/selinux-testsuite/refpolicy/Makefile +1 -1
Index: ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile
===================================================================
@@ -1,7 +1,7 @@
 POLICYDEVEL = /usr/share/selinux/devel
 SEMODULE = /usr/sbin/semodule
 
-TARGETS=test_global.te test_capable_file.te test_capable_net.te \
+TARGETS=test_global.te test_bounds.te test_capable_file.te test_capable_net.te \
 test_capable_sys.te test_dyntrace.te test_dyntrans.te test_entrypoint.te \
 test_execshare.te test_exectrace.te test_execute_no_trans.te \
 test_fdreceive.te test_file.te test_inherit.te test_ioctl.te test_ipc.te \
testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +57 -0

57 lines not on this page · raw message

#58 lore raw

PATCH 1/1 SELinux: add boundary support and thread context assignment

In reply to James Morris

The purpose of this patch is to assign per-thread security context under a constraint. It enables multi-threaded server application to kick a request handler with its fair security context, and helps some of userspace object managers to handle user's request.

When we assign a per-thread security context, it must not have wider permissions than the original one. Because a multi-threaded process shares a single local memory, an arbitary per-thread security context also means another thread can easily refer violated information.

The constraint on a per-thread security context requires a new domain has to be equal or weaker than its original one, when it tries to assign a per-thread security context.

Bounds relationship between two types is a way to ensure a domain can never have wider permission than its bounds. We can define it in two explicit or implicit ways.

The first way is using new TYPEBOUNDS statement. It enables to define a boundary of types explicitly. The other one expand the concept of existing named based hierarchy. If we defines a type with "." separated name like "httpd_t.php", toolchain implicitly set its bounds on "httpd_t".

This feature requires a new policy version.
The 24th version (POLICYDB_VERSION_BOUNDARY) enables to ship them into kernel space, and the following patch enables to handle it.

---
Updates:

* rev.7
- The return code of security_bounded_transition() is returned to userspace, if it makes an error.
* rev.6
- It reverrs the place of bounds checks for dyntrans on multithreaded.
- Kernel policy version.24 utilize the third word of type entries as a property fields.
- Check on type bounds are integrated with creation of avc entries. violated permissions are masked and reported via audit.
* rev.5
- A missing number
* rev.4
- It removes checks on the set relation of attributes at policy load time.
- Several cosmetic changes
* rev.3
- Kenel policy version.24 got support to load attributes into kernel space.
- Boundary checks on constraints are moved to policy load time.
* rev.2
- A new policy statement: TYPEBOUNDS
- Existing hierarchy checks are moved to kernel space from toolchain
* rev.1
- The initial version

---
 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   15 ++-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   15 +++-
 security/selinux/ss/policydb.c      |  205 ++++++++++++++++++++++++++++++++---
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  172 +++++++++++++++++++++++++++++-
 7 files changed, 398 insertions(+), 20 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +12 -3
index 03fc6a8..38dfca7 100644
@@ -5219,8 +5219,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5228,11 +5232,16 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
-					return -EPERM;
+					error = security_bounded_transition(tsec->sid, sid);
+					if (!error)
+						goto boundary_ok;
+
+					return error;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/avc.h +4 -0
index 7b9769f..d12ff1a 100644
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
security/selinux/include/security.h +14 -1
index 7c54300..7244737 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,16 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +191 -14

312 lines not on this page · raw message

security/selinux/ss/policydb.h +5 -0
index 4253370..55152d4 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +171 -1

202 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#49 lore raw

Re: [LTP][PATCH 1/2] Replacement of deprecated interfaces

In reply to KaiGai Kohei

Thanks KaiGai.

Stephen/James,

Would be ACK-ing these 2 patches ?

1) [LTP][PATCH 1/2] Replacement of deprecated interfaces, &
2) [LTP][PATCH 2/2] Add a new test case for bounds types,

Regards--
Subrata

Quoted 47 lines · KaiGai Kohei
Quoted 10 lines · Stephen Smalley
Quoted 9 lines · KaiGai Kohei
Quoted 5 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

Quoted 8 lines
Quoted 5 lines

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

I don't quite follow. Did you follow the instructions in the selinux-testsuite README?

I didn't read the README file carefully, Oops.

The update_refpolicy.sh fixes some of deprecated interfaces and inject an interface to kick test script from unconfined domain. So, I can run the testsuite which includs bounds test without any problems on Rawhide.

# However, I got some warnings for deprecated interfaces/macros

# like r_dir_perms, userdom_sysadm_bin_spec_domtrans_to or
# userdom_use_sysadm_ptys.

The attached patch is a new test case of the boundary feature, which contains six tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, because write permission is boundary violated.
test05: It tries to write a bounded type, even if the domain cannot write to
its bounds type. The expected result is fail.
test06: It makes a bounded domain try to set an attribute of bounded type.

Quoted 9 lines

Thanks,

Quoted 6 lines

I can run the test scripts either using the
test_selinux.sh script or by manually loading the policy and then individually running them as described in the README. Watch out that your patch doesn't disturb the existing misc/sbin_deprecated.patch that gets applied by test_selinux.sh. Keep in mind that this testsuite gets run on everything from RHEL4 to F9.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

Acked-by on v1 1/1
#59 lore raw

Re: [PATCH] SELinux: add boundary support and thread context assignment

In reply to KaiGai Kohei
Quoted 23 lines · KaiGai Kohei

The purpose of this patch is to assign per-thread security context under a constraint. It enables multi-threaded server application to kick a request handler with its fair security context, and helps some of userspace object managers to handle user's request.

When we assign a per-thread security context, it must not have wider permissions than the original one. Because a multi-threaded process shares a single local memory, an arbitary per-thread security context also means another thread can easily refer violated information.

The constraint on a per-thread security context requires a new domain has to be equal or weaker than its original one, when it tries to assign a per-thread security context.

Bounds relationship between two types is a way to ensure a domain can never have wider permission than its bounds. We can define it in two explicit or implicit ways.

The first way is using new TYPEBOUNDS statement. It enables to define a boundary of types explicitly. The other one expand the concept of existing named based hierarchy. If we defines a type with "." separated name like "httpd_t.php", toolchain implicitly set its bounds on "httpd_t".

Quoted 5 lines

This feature requires a new policy version.
The 24th version (POLICYDB_VERSION_BOUNDARY) enables to ship them into kernel space, and the following patch enables to handle it.

BTW, it seems like you should replace the hierarchy checking code in libsepol with one based on the new construct for static checking of hierarchies in userspace (only applied if expand-check=1 of course).

Quoted 735 lines

---
Updates:

* rev.7
- The return code of security_bounded_transition() is returned to userspace, if it makes an error.
* rev.6
- It reverrs the place of bounds checks for dyntrans on multithreaded.
- Kernel policy version.24 utilize the third word of type entries as a property fields.
- Check on type bounds are integrated with creation of avc entries. violated permissions are masked and reported via audit.
* rev.5
- A missing number
* rev.4
- It removes checks on the set relation of attributes at policy load time.
- Several cosmetic changes
* rev.3
- Kenel policy version.24 got support to load attributes into kernel space.
- Boundary checks on constraints are moved to policy load time.
* rev.2
- A new policy statement: TYPEBOUNDS
- Existing hierarchy checks are moved to kernel space from toolchain
* rev.1
- The initial version

---
 security/selinux/avc.c              |    2 +-
 security/selinux/hooks.c            |   15 ++-
 security/selinux/include/avc.h      |    4 +
 security/selinux/include/security.h |   15 +++-
 security/selinux/ss/policydb.c      |  205 ++++++++++++++++++++++++++++++++---
 security/selinux/ss/policydb.h      |    5 +
 security/selinux/ss/services.c      |  172 +++++++++++++++++++++++++++++-
 7 files changed, 398 insertions(+), 20 deletions(-)
security/selinux/avc.c +1 -1
index 114b4b4..cb30c7e 100644
@@ -136,7 +136,7 @@ static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
  * @tclass: target security class
  * @av: access vector
  */
-static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
 {
 	const char **common_pts = NULL;
 	u32 common_base = 0;
security/selinux/hooks.c +12 -3
index 03fc6a8..38dfca7 100644
@@ -5219,8 +5219,12 @@ static int selinux_setprocattr(struct task_struct *p,
 
 		if (sid == 0)
 			return -EINVAL;
-
-		/* Only allow single threaded processes to change context */
+		/*
+		 * SELinux allows to change context in the following case only.
+		 *  - Single threaded processes.
+		 *  - Multi threaded processes intend to change its context into
+		 *    more restricted domain (defined by TYPEBOUNDS statement).
+		 */
 		if (atomic_read(&p->mm->mm_users) != 1) {
 			struct task_struct *g, *t;
 			struct mm_struct *mm = p->mm;
@@ -5228,11 +5232,16 @@ static int selinux_setprocattr(struct task_struct *p,
 			do_each_thread(g, t) {
 				if (t->mm == mm && t != p) {
 					read_unlock(&tasklist_lock);
-					return -EPERM;
+					error = security_bounded_transition(tsec->sid, sid);
+					if (!error)
+						goto boundary_ok;
+
+					return error;
 				}
 			} while_each_thread(g, t);
 			read_unlock(&tasklist_lock);
 		}
+boundary_ok:
 
 		/* Check permissions for the transition. */
 		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
security/selinux/include/avc.h +4 -0
index 7b9769f..d12ff1a 100644
@@ -12,6 +12,7 @@
 #include <linux/kdev_t.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/audit.h>
 #include <linux/in6.h>
 #include <linux/path.h>
 #include <asm/system.h>
@@ -126,6 +127,9 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
 		     u32 events, u32 ssid, u32 tsid,
 		     u16 tclass, u32 perms);
 
+/* Shows permission in human readable form */
+void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av);
+
 /* Exported to selinuxfs */
 int avc_get_hash_stats(char *page);
 extern unsigned int avc_cache_threshold;
security/selinux/include/security.h +14 -1
index 7c54300..7244737 100644
@@ -27,13 +27,14 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* 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_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 #endif
 
 #define CONTEXT_MNT	0x01
@@ -62,6 +63,16 @@ enum {
 extern int selinux_policycap_netpeer;
 extern int selinux_policycap_openperm;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+
+/* limitation of boundary depth  */
+#define POLICYDB_BOUNDS_MAXDEPTH	4
+
 int security_load_policy(void *data, size_t len);
 
 int security_policycap_supported(unsigned int req_cap);
@@ -117,6 +128,8 @@ int security_node_sid(u16 domain, void *addr, u32 addrlen,
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
 				 u16 tclass);
 
+int security_bounded_transition(u32 oldsid, u32 newsid);
+
 int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid);
 
 int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
security/selinux/ss/policydb.c +191 -14
index 2391761..7dbe756 100644
@@ -30,6 +30,7 @@
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/errno.h>
+#include <linux/audit.h>
 #include "security.h"
 
 #include "policydb.h"
@@ -116,7 +117,12 @@ static struct policydb_compat_info policydb_compat[] = {
 		.version	= POLICYDB_VERSION_PERMISSIVE,
 		.sym_num	= SYM_NUM,
 		.ocon_num	= OCON_NUM,
-	}
+	},
+	{
+		.version	= POLICYDB_VERSION_BOUNDARY,
+		.sym_num	= SYM_NUM,
+		.ocon_num	= OCON_NUM,
+	},
 };
 
 static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -254,7 +260,9 @@ static int role_index(void *key, void *datum, void *datap)
 
 	role = datum;
 	p = datap;
-	if (!role->value || role->value > p->p_roles.nprim)
+	if (!role->value
+	    || role->value > p->p_roles.nprim
+	    || role->bounds > p->p_roles.nprim)
 		return -EINVAL;
 	p->p_role_val_to_name[role->value - 1] = key;
 	p->role_val_to_struct[role->value - 1] = role;
@@ -270,9 +278,12 @@ static int type_index(void *key, void *datum, void *datap)
 	p = datap;
 
 	if (typdatum->primary) {
-		if (!typdatum->value || typdatum->value > p->p_types.nprim)
+		if (!typdatum->value
+		    || typdatum->value > p->p_types.nprim
+		    || typdatum->bounds > p->p_types.nprim)
 			return -EINVAL;
 		p->p_type_val_to_name[typdatum->value - 1] = key;
+		p->type_val_to_struct[typdatum->value - 1] = typdatum;
 	}
 
 	return 0;
@@ -285,7 +296,9 @@ static int user_index(void *key, void *datum, void *datap)
 
 	usrdatum = datum;
 	p = datap;
-	if (!usrdatum->value || usrdatum->value > p->p_users.nprim)
+	if (!usrdatum->value
+	    || usrdatum->value > p->p_users.nprim
+	    || usrdatum->bounds > p->p_users.nprim)
 		return -EINVAL;
 	p->p_user_val_to_name[usrdatum->value - 1] = key;
 	p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
@@ -438,6 +451,14 @@ static int policydb_index_others(struct policydb *p)
 		goto out;
 	}
 
+	p->type_val_to_struct =
+		kmalloc(p->p_types.nprim * sizeof(*(p->type_val_to_struct)),
+			GFP_KERNEL);
+	if (!p->type_val_to_struct) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
 	if (cond_init_bool_indexes(p)) {
 		rc = -ENOMEM;
 		goto out;
@@ -625,6 +646,7 @@ void policydb_destroy(struct policydb *p)
 	kfree(p->class_val_to_struct);
 	kfree(p->role_val_to_struct);
 	kfree(p->user_val_to_struct);
+	kfree(p->type_val_to_struct);
 
 	avtab_destroy(&p->te_avtab);
 
@@ -1176,8 +1198,8 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct role_datum *role;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	role = kzalloc(sizeof(*role), GFP_KERNEL);
@@ -1186,12 +1208,17 @@ static int role_read(struct policydb *p, struct hashtab *h, void *fp)
 		goto out;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	role->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		role->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1236,8 +1263,8 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct type_datum *typdatum;
-	int rc;
-	__le32 buf[3];
+	int rc, to_read = 3;
+	__le32 buf[4];
 	u32 len;
 
 	typdatum = kzalloc(sizeof(*typdatum), GFP_KERNEL);
@@ -1246,13 +1273,27 @@ static int type_read(struct policydb *p, struct hashtab *h, void *fp)
 		return rc;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 4;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	typdatum->value = le32_to_cpu(buf[1]);
-	typdatum->primary = le32_to_cpu(buf[2]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+		u32 prop = le32_to_cpu(buf[2]);
+
+		if (prop & TYPEDATUM_PROPERTY_PRIMARY)
+			typdatum->primary = 1;
+		if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
+			typdatum->attribute = 1;
+
+		typdatum->bounds = le32_to_cpu(buf[3]);
+	} else {
+		typdatum->primary = le32_to_cpu(buf[2]);
+	}
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1309,8 +1350,8 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
 {
 	char *key = NULL;
 	struct user_datum *usrdatum;
-	int rc;
-	__le32 buf[2];
+	int rc, to_read = 2;
+	__le32 buf[3];
 	u32 len;
 
 	usrdatum = kzalloc(sizeof(*usrdatum), GFP_KERNEL);
@@ -1319,12 +1360,17 @@ static int user_read(struct policydb *p, struct hashtab *h, void *fp)
 		goto out;
 	}
 
-	rc = next_entry(buf, fp, sizeof buf);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(buf[0]) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	usrdatum->value = le32_to_cpu(buf[1]);
+	if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+		usrdatum->bounds = le32_to_cpu(buf[2]);
 
 	key = kmalloc(len + 1, GFP_KERNEL);
 	if (!key) {
@@ -1465,6 +1511,133 @@ static int (*read_f[SYM_NUM]) (struct policydb *p, struct hashtab *h, void *fp)
 	cat_read,
 };
 
+static int user_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct user_datum *upper, *user;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = user = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: user %s: "
+			       "too deep or looped boundary",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->user_val_to_struct[upper->bounds - 1];
+		ebitmap_for_each_positive_bit(&user->roles, node, bit) {
+			if (ebitmap_get_bit(&upper->roles, bit))
+				continue;
+
+			printk(KERN_ERR
+			       "SELinux: boundary violated policy: "
+			       "user=%s role=%s bounds=%s\n",
+			       p->p_user_val_to_name[user->value - 1],
+			       p->p_role_val_to_name[bit],
+			       p->p_user_val_to_name[upper->value - 1]);
+
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int role_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct role_datum *upper, *role;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = role = datum;
+	while (upper->bounds) {
+		struct ebitmap_node *node;
+		unsigned long bit;
+
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: role %s: "
+			       "too deep or looped bounds\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->role_val_to_struct[upper->bounds - 1];
+		ebitmap_for_each_positive_bit(&role->types, node, bit) {
+			if (ebitmap_get_bit(&upper->types, bit))
+				continue;
+
+			printk(KERN_ERR
+			       "SELinux: boundary violated policy: "
+			       "role=%s type=%s bounds=%s\n",
+			       p->p_role_val_to_name[role->value - 1],
+			       p->p_type_val_to_name[bit],
+			       p->p_role_val_to_name[upper->value - 1]);
+
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int type_bounds_sanity_check(void *key, void *datum, void *datap)
+{
+	struct type_datum *upper, *type;
+	struct policydb *p = datap;
+	int depth = 0;
+
+	upper = type = datum;
+	while (upper->bounds) {
+		if (++depth == POLICYDB_BOUNDS_MAXDEPTH) {
+			printk(KERN_ERR "SELinux: type %s: "
+			       "too deep or looped boundary\n",
+			       (char *) key);
+			return -EINVAL;
+		}
+
+		upper = p->type_val_to_struct[upper->bounds - 1];
+		if (upper->attribute) {
+			printk(KERN_ERR "SELinux: type %s: "
+			       "bounded by attribute %s",
+			       (char *) key,
+			       p->p_type_val_to_name[upper->value - 1]);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int policydb_bounds_sanity_check(struct policydb *p)
+{
+	int rc;
+
+	if (p->policyvers < POLICYDB_VERSION_BOUNDARY)
+		return 0;
+
+	rc = hashtab_map(p->p_users.table,
+			 user_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	rc = hashtab_map(p->p_roles.table,
+			 role_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	rc = hashtab_map(p->p_types.table,
+			 type_bounds_sanity_check, p);
+	if (rc)
+		return rc;
+
+	return 0;
+}
+
 extern int ss_initialized;
 
 /*
@@ -1961,6 +2134,10 @@ int policydb_read(struct policydb *p, void *fp)
 				goto bad;
 	}
 
+	rc = policydb_bounds_sanity_check(p);
+	if (rc)
+		goto bad;
+
 	rc = 0;
 out:
 	return rc;
security/selinux/ss/policydb.h +5 -0
index 4253370..55152d4 100644
@@ -61,6 +61,7 @@ struct class_datum {
 /* Role attributes */
 struct role_datum {
 	u32 value;			/* internal role value */
+	u32 bounds;			/* boundary of role */
 	struct ebitmap dominates;	/* set of roles dominated by this role */
 	struct ebitmap types;		/* set of authorized types for role */
 };
@@ -81,12 +82,15 @@ struct role_allow {
 /* Type attributes */
 struct type_datum {
 	u32 value;		/* internal type value */
+	u32 bounds;		/* boundary of type */
 	unsigned char primary;	/* primary name? */
+	unsigned char attribute;/* attribute ?*/
 };
 
 /* User attributes */
 struct user_datum {
 	u32 value;			/* internal user value */
+	u32 bounds;			/* bounds of user */
 	struct ebitmap roles;		/* set of authorized roles for user */
 	struct mls_range range;		/* MLS range (min - max) for user */
 	struct mls_level dfltlevel;	/* default login MLS level for user */
@@ -209,6 +213,7 @@ struct policydb {
 	struct class_datum **class_val_to_struct;
 	struct role_datum **role_val_to_struct;
 	struct user_datum **user_val_to_struct;
+	struct type_datum **type_val_to_struct;
 
 	/* type enforcement access vectors and transitions */
 	struct avtab te_avtab;
security/selinux/ss/services.c +171 -1
index b52f923..1ed94a3 100644
@@ -88,6 +88,11 @@ static u32 latest_granting;
 static int context_struct_to_string(struct context *context, char **scontext,
 				    u32 *scontext_len);
 
+static int context_struct_compute_av(struct context *scontext,
+				     struct context *tcontext,
+				     u16 tclass,
+				     u32 requested,
+				     struct av_decision *avd);
 /*
  * Return the boolean value of a constraint expression
  * when it is applied to the specified source and target
@@ -274,6 +279,100 @@ mls_ops:
 }
 
 /*
+ * security_boundary_permission - drops violated permissions
+ * on boundary constraint.
+ */
+static void type_attribute_bounds_av(struct context *scontext,
+				     struct context *tcontext,
+				     u16 tclass,
+				     u32 requested,
+				     struct av_decision *avd)
+{
+	struct context lo_scontext;
+	struct context lo_tcontext;
+	struct av_decision lo_avd;
+	struct type_datum *source
+		= policydb.type_val_to_struct[scontext->type - 1];
+	struct type_datum *target
+		= policydb.type_val_to_struct[tcontext->type - 1];
+	u32 masked = 0;
+
+	if (source->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
+		lo_scontext.type = source->bounds;
+
+		context_struct_compute_av(&lo_scontext,
+					  tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (target->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+
+		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
+		lo_tcontext.type = target->bounds;
+
+		context_struct_compute_av(scontext,
+					  &lo_tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (source->bounds && target->bounds) {
+		memset(&lo_avd, 0, sizeof(lo_avd));
+		/*
+		 * lo_scontext and lo_tcontext are already
+		 * set up.
+		 */
+
+		context_struct_compute_av(&lo_scontext,
+					  &lo_tcontext,
+					  tclass,
+					  requested,
+					  &lo_avd);
+		if ((lo_avd.allowed & avd->allowed) == avd->allowed)
+			return;		/* no masked permission */
+		masked = ~lo_avd.allowed & avd->allowed;
+	}
+
+	if (masked) {
+		struct audit_buffer *ab;
+		char *stype_name
+			= policydb.p_type_val_to_name[source->value - 1];
+		char *ttype_name
+			= policydb.p_type_val_to_name[target->value - 1];
+		char *tclass_name
+			= policydb.p_class_val_to_name[tclass - 1];
+
+		/* mask violated permissions */
+		avd->allowed &= ~masked;
+
+		/* notice to userspace via audit message */
+		ab = audit_log_start(current->audit_context,
+				     GFP_ATOMIC, AUDIT_SELINUX_ERR);
+		if (!ab)
+			return;
+
+		audit_log_format(ab, "av boundary violation: "
+				 "source=%s target=%s tclass=%s",
+				 stype_name, ttype_name, tclass_name);
+		avc_dump_av(ab, tclass, masked);
+		audit_log_end(ab);
+	}
+}
+
+/*
  * Compute access vectors based on a context structure pair for
  * the permissions in a particular class.
  */
@@ -404,6 +503,14 @@ static int context_struct_compute_av(struct context *scontext,
 							PROCESS__DYNTRANSITION);
 	}
 
+	/*
+	 * If the given source and target types have boundary
+	 * constraint, lazy checks have to mask any violated
+	 * permission and notice it to userspace via audit.
+	 */
+	type_attribute_bounds_av(scontext, tcontext,
+				 tclass, requested, avd);
+
 	return 0;
 
 inval_class:
@@ -549,6 +656,69 @@ out:
 	return rc;
 }
 
+/*
+ * security_bounded_transition - check whether the given
+ * transition is directed to bounded, or not.
+ * It returns 0, if @newsid is bounded by @oldsid.
+ * Otherwise, it returns error code.
+ *
+ * @oldsid : current security identifier
+ * @newsid : destinated security identifier
+ */
+int security_bounded_transition(u32 old_sid, u32 new_sid)
+{
+	struct context *old_context, *new_context;
+	struct type_datum *type;
+	int index;
+	int rc = -EINVAL;
+
+	read_lock(&policy_rwlock);
+
+	old_context = sidtab_search(&sidtab, old_sid);
+	if (!old_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, old_sid);
+		goto out;
+	}
+
+	new_context = sidtab_search(&sidtab, new_sid);
+	if (!new_context) {
+		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
+		       __func__, new_sid);
+		goto out;
+	}
+
+	/* type/domain unchaned */
+	if (old_context->type == new_context->type) {
+		rc = 0;
+		goto out;
+	}
+
+	index = new_context->type;
+	while (true) {
+		type = policydb.type_val_to_struct[index - 1];
+		BUG_ON(!type);
+
+		/* not bounded anymore */
+		if (!type->bounds) {
+			rc = -EPERM;
+			break;
+		}
+
+		/* @newsid is bounded by @oldsid */
+		if (type->bounds == old_context->type) {
+			rc = 0;
+			break;
+		}
+		index = type->bounds;
+	}
+out:
+	read_unlock(&policy_rwlock);
+
+	return rc;
+}
+
+
 /**
  * security_compute_av - Compute access vector decisions.
  * @ssid: source security identifier
@@ -794,7 +964,7 @@ static int string_to_context_struct(struct policydb *pol,
 	*p++ = 0;
 
 	typdatum = hashtab_search(pol->p_types.table, scontextp);
-	if (!typdatum)
+	if (!typdatum || typdatum->attribute)
 		goto out;
 
 	ctx->type = typdatum->value;
Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#50 lore raw

Re: [LTP][PATCH 1/2] Replacement of deprecated interfaces

In reply to Subrata Modak

Subrata,

Two patches I sent yesterday should be gone away.

The latest patch I sent today is revised, however, it is too early to apply LTP tree, because the new test checks a new kernel feature which is not included yet.

Thanks,

Quoted 73 lines · Subrata Modak

Thanks KaiGai.

Stephen/James,

Would be ACK-ing these 2 patches ?

1) [LTP][PATCH 1/2] Replacement of deprecated interfaces, &
2) [LTP][PATCH 2/2] Add a new test case for bounds types,

Regards--
Subrata

Quoted 45 lines · KaiGai Kohei
Quoted 10 lines · Stephen Smalley
Quoted 9 lines · KaiGai Kohei
Quoted 5 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

Quoted 7 lines
Quoted 5 lines

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

I don't quite follow. Did you follow the instructions in the selinux-testsuite README?

I didn't read the README file carefully, Oops.

The update_refpolicy.sh fixes some of deprecated interfaces and inject an interface to kick test script from unconfined domain. So, I can run the testsuite which includs bounds test without any problems on Rawhide.

# However, I got some warnings for deprecated interfaces/macros

# like r_dir_perms, userdom_sysadm_bin_spec_domtrans_to or
# userdom_use_sysadm_ptys.

The attached patch is a new test case of the boundary feature, which contains six tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, because write permission is boundary violated.
test05: It tries to write a bounded type, even if the domain cannot write to
its bounds type. The expected result is fail.
test06: It makes a bounded domain try to set an attribute of bounded type.

Quoted 8 lines

Thanks,

Quoted 6 lines

I can run the test scripts either using the
test_selinux.sh script or by manually loading the policy and then individually running them as described in the README. Watch out that your patch doesn't disturb the existing misc/sbin_deprecated.patch that gets applied by test_selinux.sh. Keep in mind that this testsuite gets run on everything from RHEL4 to F9.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#51 lore raw

Re: [LTP][PATCH 1/2] Replacement of deprecated interfaces

Quoted 7 lines · KaiGai Kohei

Subrata,

Two patches I sent yesterday should be gone away.

The latest patch I sent today is revised, however, it is too early to apply LTP tree, because the new test checks a new kernel feature which is not included yet.

Oops. Please send those to the ltp-list whenever the respective features are in, and you feel it is the right time to go in ;-)

Regards--
Subrata

Quoted 79 lines

Thanks,

Quoted 73 lines · Subrata Modak

Thanks KaiGai.

Stephen/James,

Would be ACK-ing these 2 patches ?

1) [LTP][PATCH 1/2] Replacement of deprecated interfaces, &
2) [LTP][PATCH 2/2] Add a new test case for bounds types,

Regards--
Subrata

Quoted 45 lines · KaiGai Kohei
Quoted 10 lines · Stephen Smalley
Quoted 9 lines · KaiGai Kohei
Quoted 5 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

Quoted 7 lines
Quoted 5 lines

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

I don't quite follow. Did you follow the instructions in the selinux-testsuite README?

I didn't read the README file carefully, Oops.

The update_refpolicy.sh fixes some of deprecated interfaces and inject an interface to kick test script from unconfined domain. So, I can run the testsuite which includs bounds test without any problems on Rawhide.

# However, I got some warnings for deprecated interfaces/macros

# like r_dir_perms, userdom_sysadm_bin_spec_domtrans_to or
# userdom_use_sysadm_ptys.

The attached patch is a new test case of the boundary feature, which contains six tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, because write permission is boundary violated.
test05: It tries to write a bounded type, even if the domain cannot write to
its bounds type. The expected result is fail.
test06: It makes a bounded domain try to set an attribute of bounded type.

Quoted 8 lines

Thanks,

Quoted 6 lines

I can run the test scripts either using the
test_selinux.sh script or by manually loading the policy and then individually running them as described in the README. Watch out that your patch doesn't disturb the existing misc/sbin_deprecated.patch that gets applied by test_selinux.sh. Keep in mind that this testsuite gets run on everything from RHEL4 to F9.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#60 lore raw

Re: [PATCH] SELinux: add boundary support and thread context assignment

In reply to KaiGai Kohei
Quoted 5 lines · KaiGai Kohei

This feature requires a new policy version.
The 24th version (POLICYDB_VERSION_BOUNDARY) enables to ship them into kernel space, and the following patch enables to handle it.

Applied to:
git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/security-testing-2.6#next

This should appear in linux-next within 24 hrs and be tested there.

- James

Signature · 7 lines
James Morris
<[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#69 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.4)

In reply to KaiGai Kohei
Quoted 9 lines · KaiGai Kohei

The following patch is revised one for libsepol.

Updates:
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
The first bit (TYPEDATUM_PROPERTY_PRIMARY) means the entry is a primary type, and the second bit (TYPEDATUM_PROPERTY_ATTRIBUTE) means the entry is an attribute.

I didn't see an answer in the current threads, and this looks like the latest userland patch series so I'll ask here: What is the purpose of the properties? We can infer what it knows from the other fields in the datum, right?

One thing that bothers me is that we read prop out of the binary but it is nowhere in the type datum, I can see this leading to errors in the reader where a developer can't figure out where the extra data is coming from.

I will echo Steve's request to remove the old hierarchy stuff from here and add in the implementation necessary to do validation of the bounds in libsepol.

The rest of the patchset looks good, after reading through it (I haven't applied and tested it yet).

Quoted 610 lines

Thanks,

--

 include/sepol/policydb/policydb.h |   26 ++++++-
 src/expand.c                      |  132 ++++++++++++++++++++++++++++++--------
 src/link.c                        |  108 ++++++++++++++++++++++++++++++-
 src/policydb.c                    |   89 +++++++++++++++++++------
 src/write.c                       |   28 +++++++-
 5 files changed, 329 insertions(+), 54 deletions(-)

Index: libsepol/include/sepol/policydb/policydb.h
===================================================================

include/sepol/policydb/policydb.h +24 -2
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,8 +146,16 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/*
+ * type_datum properties
+ * available at the kernel policy version >= POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY      0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
+
 /* User attributes */
 typedef struct user_datum {
 	symtab_datum_t s;
@@ -156,6 +165,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +605,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +619,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN

Index: libsepol/src/policydb.c
===================================================================

src/policydb.c +69 -20
@@ -110,6 +110,12 @@
 	 .sym_num = SYM_NUM,
 	 .ocon_num = OCON_NODE6 + 1,
 	 },
+        {
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	},
 	{
 	 .type = POLICY_BASE,
 	 .version = MOD_POLICYDB_VERSION_BASE,
@@ -141,6 +147,12 @@
 	 .ocon_num = OCON_NODE6 + 1,
 	 },
 	{
+	 .type = POLICY_BASE,
+	 .version = MOD_POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_NODE6 + 1,
+	},
+	{
 	 .type = POLICY_MOD,
 	 .version = MOD_POLICYDB_VERSION_BASE,
 	 .sym_num = SYM_NUM,
@@ -170,6 +182,12 @@
 	 .sym_num = SYM_NUM,
 	 .ocon_num = 0
 	 },
+	{
+	 .type = POLICY_MOD,
+	 .version = MOD_POLICYDB_VERSION_BOUNDARY,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = 0
+	},
 };
 
 #if 0
@@ -1855,20 +1873,25 @@
 {
 	char *key = 0;
 	role_datum_t *role;
-	uint32_t buf[2];
+	uint32_t buf[3];
 	size_t len;
-	int rc;
+	int rc, to_read = 2;
 
 	role = calloc(1, sizeof(role_datum_t));
 	if (!role)
 		return -1;
 
-	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (policydb_has_boundary_feature(p))
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	role->s.value = le32_to_cpu(buf[1]);
+	if (policydb_has_boundary_feature(p))
+		role->bounds = le32_to_cpu(buf[2]);
 
 	key = malloc(len + 1);
 	if (!key)
@@ -1916,32 +1939,53 @@
 {
 	char *key = 0;
 	type_datum_t *typdatum;
-	uint32_t buf[5];
+	uint32_t buf[6];
 	size_t len;
-	int rc, to_read;
+	int rc, to_read, items = 0;
 
 	typdatum = calloc(1, sizeof(type_datum_t));
 	if (!typdatum)
 		return -1;
 
-	if (p->policy_type == POLICY_KERN)
-		to_read = 3;
-	else if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
-		to_read = 5;
-	else
-		to_read = 4;
+	if (p->policy_type == POLICY_KERN) {
+		if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
+			to_read = 4;
+		else
+			to_read = 3;
+	} else {
+		if (p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)
+			to_read = 6;
+		else if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
+			to_read = 5;
+		else
+			to_read = 4;
+	}
 
 	rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
 	if (rc < 0)
 		goto bad;
+	len = le32_to_cpu(buf[items++]);
+	typdatum->s.value = le32_to_cpu(buf[items++]);
+	if (p->policy_type == POLICY_KERN) {
+		if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+			uint32_t prop = le32_to_cpu(buf[items++]);
 
-	len = le32_to_cpu(buf[0]);
-	typdatum->s.value = le32_to_cpu(buf[1]);
-	typdatum->primary = le32_to_cpu(buf[2]);
-	if (p->policy_type != POLICY_KERN) {
-		typdatum->flavor = le32_to_cpu(buf[3]);
+			if (prop & TYPEDATUM_PROPERTY_PRIMARY)
+				typdatum->primary = 1;
+			if (prop & TYPEDATUM_PROPERTY_ATTRIBUTE)
+				typdatum->flavor = TYPE_ATTRIB;
+
+			typdatum->bounds = le32_to_cpu(buf[items++]);
+		} else {
+			typdatum->primary = le32_to_cpu(buf[items++]);
+		}
+	} else {
+		typdatum->primary = le32_to_cpu(buf[items++]);
+		if (p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)
+			typdatum->bounds = le32_to_cpu(buf[items++]);
+		typdatum->flavor = le32_to_cpu(buf[items++]);
 		if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
-			typdatum->flags = le32_to_cpu(buf[4]);
+			typdatum->flags = le32_to_cpu(buf[items++]);
 		if (ebitmap_read(&typdatum->types, fp))
 			goto bad;
 	}
@@ -2293,20 +2337,25 @@
 {
 	char *key = 0;
 	user_datum_t *usrdatum;
-	uint32_t buf[2];
+	uint32_t buf[3];
 	size_t len;
-	int rc;
+	int rc, to_read = 2;
 
 	usrdatum = calloc(1, sizeof(user_datum_t));
 	if (!usrdatum)
 		return -1;
 
-	rc = next_entry(buf, fp, sizeof(uint32_t) * 2);
+	if (policydb_has_boundary_feature(p))
+		to_read = 3;
+
+	rc = next_entry(buf, fp, sizeof(uint32_t) * to_read);
 	if (rc < 0)
 		goto bad;
 
 	len = le32_to_cpu(buf[0]);
 	usrdatum->s.value = le32_to_cpu(buf[1]);
+	if (policydb_has_boundary_feature(p))
+		usrdatum->bounds = le32_to_cpu(buf[2]);
 
 	key = malloc(len + 1);
 	if (!key)

Index: libsepol/src/expand.c
===================================================================

src/expand.c +105 -27
@@ -466,6 +466,100 @@
 	return 0;
 }
 
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	type_datum_t *type = (type_datum_t *) datum;
+	type_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!type->bounds)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_TYPES))
+		return 0;
+
+	bounds_val = state->typemap[type->bounds - 1];
+
+	dest = hashtab_search(state->out->p_types.table, (char *)key);
+	if (!dest) {
+		ERR(state->handle, "Type lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	role_datum_t *role = (role_datum_t *) datum;
+	role_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!role->bounds)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_ROLES))
+		return 0;
+
+	bounds_val = state->rolemap[role->bounds - 1];
+
+	dest = hashtab_search(state->out->p_roles.table, (char *)key);
+	if (!dest) {
+		ERR(state->handle, "Role lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	expand_state_t *state = (expand_state_t *) data;
+	user_datum_t *user = (user_datum_t *) datum;
+	user_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!user->bounds)
+		return 0;
+
+	if (!is_id_enabled((char *)key, state->base, SYM_USERS))
+		return 0;
+
+	bounds_val = state->usermap[user->bounds - 1];
+
+	dest = hashtab_search(state->out->p_users.table, (char *)key);
+	if (!dest) {
+		ERR(state->handle, "User lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle, "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
 /* The aliases have to be copied after the types and attributes to be certain that
  * the out symbol table will have the type that the alias refers. Otherwise, we
  * won't be able to find the type value for the alias. We can't depend on the
@@ -1865,31 +1959,6 @@
 	return 0;
 }
 
-static void type_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p
-			 __attribute__ ((unused)))
-{
-	free(key);
-	type_datum_destroy((type_datum_t *) datum);
-	free(datum);
-}
-
-static int type_attr_remove(hashtab_key_t key
-			    __attribute__ ((unused)), hashtab_datum_t datum,
-			    void *args)
-{
-	type_datum_t *typdatum;
-	policydb_t *p;
-
-	typdatum = (type_datum_t *) datum;
-	p = (policydb_t *) args;
-	if (typdatum->flavor == TYPE_ATTRIB) {
-		p->type_val_to_struct[typdatum->s.value - 1] = NULL;
-		p->p_type_val_to_name[typdatum->s.value - 1] = NULL;
-		return 1;
-	}
-	return 0;
-}
-
 /* converts typeset using typemap and expands into ebitmap_t types using the attributes in the passed in policy.
  * this should not be called until after all the blocks have been processed and the attributes in target policy
  * are complete. */
@@ -2393,6 +2462,11 @@
 		goto cleanup;
 	}
 
+	/* copy type bounds */
+	if (hashtab_map(state.base->p_types.table,
+			type_bounds_copy_callback, &state))
+		goto cleanup;
+
 	/* copy aliases */
 	if (hashtab_map(state.base->p_types.table, alias_copy_callback, &state))
 		goto cleanup;
@@ -2406,6 +2480,9 @@
 	/* copy roles */
 	if (hashtab_map(state.base->p_roles.table, role_copy_callback, &state))
 		goto cleanup;
+	if (hashtab_map(state.base->p_roles.table,
+			role_bounds_copy_callback, &state))
+		goto cleanup;
 
 	/* copy MLS's sensitivity level and categories - this needs to be done
 	 * before expanding users (they need to be indexed too) */
@@ -2421,6 +2498,9 @@
 	/* copy users */
 	if (hashtab_map(state.base->p_users.table, user_copy_callback, &state))
 		goto cleanup;
+	if (hashtab_map(state.base->p_users.table,
+			user_bounds_copy_callback, &state))
+		goto cleanup;
 
 	/* copy bools */
 	if (hashtab_map(state.base->p_bools.table, bool_copy_callback, &state))
@@ -2510,8 +2590,6 @@
 	}
 	if (hashtab_map(state.out->p_types.table, type_attr_map, &state))
 		goto cleanup;
-	hashtab_map_remove_on_error(state.out->p_types.table,
-				    type_attr_remove, type_destroy, state.out);
 	if (check) {
 		if (hierarchy_check_constraints(handle, state.out))
 			goto cleanup;

Index: libsepol/src/write.c
===================================================================

src/write.c +26 -2
@@ -920,6 +920,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(role->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(role->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;
@@ -952,12 +954,32 @@
 
 	typdatum = (type_datum_t *) datum;
 
+	if (p->policy_type == POLICY_KERN
+	    && p->policyvers < POLICYDB_VERSION_BOUNDARY
+	    && typdatum->flavor == TYPE_ATTRIB)
+		return POLICYDB_SUCCESS;
+
 	len = strlen(key);
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(typdatum->s.value);
-	buf[items++] = cpu_to_le32(typdatum->primary);
-	if (p->policy_type != POLICY_KERN) {
+	if (p->policy_type == POLICY_KERN) {
+		if (p->policyvers >= POLICYDB_VERSION_BOUNDARY) {
+			uint32_t prop = 0;
+
+			if (typdatum->primary)
+				prop |= TYPEDATUM_PROPERTY_PRIMARY;
+			if (typdatum->flavor == TYPE_ATTRIB)
+				prop |= TYPEDATUM_PROPERTY_ATTRIBUTE;
+			buf[items++] = cpu_to_le32(prop);
+			buf[items++] = cpu_to_le32(typdatum->bounds);
+		} else {
+			buf[items++] = cpu_to_le32(typdatum->primary);
+		}
+	} else {
+		buf[items++] = cpu_to_le32(typdatum->primary);
+		if (p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY)
+			buf[items++] = cpu_to_le32(typdatum->bounds);
 		buf[items++] = cpu_to_le32(typdatum->flavor);
 		if (p->policyvers >= MOD_POLICYDB_VERSION_PERMISSIVE)
 			buf[items++] = cpu_to_le32(typdatum->flags);
@@ -997,6 +1019,8 @@
 	items = 0;
 	buf[items++] = cpu_to_le32(len);
 	buf[items++] = cpu_to_le32(usrdatum->s.value);
+	if (policydb_has_boundary_feature(p))
+		buf[items++] = cpu_to_le32(usrdatum->bounds);
 	items2 = put_entry(buf, sizeof(uint32_t), items, fp);
 	if (items != items2)
 		return POLICYDB_ERROR;

Index: libsepol/src/link.c
===================================================================

src/link.c +98 -3
@@ -660,6 +660,97 @@
 	    user_copy_callback, bool_copy_callback, sens_copy_callback,
 	    cat_copy_callback};
 
+/*
+ * The boundaries have to be copied after the types/roles/users are copied,
+ * because it refers hashtab to lookup destinated objects.
+ */
+static int type_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	type_datum_t *type = (type_datum_t *) datum;
+	type_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!type->bounds)
+		return 0;
+
+	bounds_val = state->cur->map[SYM_TYPES][type->bounds - 1];
+
+	dest = hashtab_search(state->base->p_types.table, key);
+	if (!dest) {
+		ERR(state->handle,
+		    "Type lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle,
+		    "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int role_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	role_datum_t *role = (role_datum_t *) datum;
+	role_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!role->bounds)
+		return 0;
+
+	bounds_val = state->cur->map[SYM_ROLES][role->bounds - 1];
+
+	dest = hashtab_search(state->base->p_roles.table, key);
+	if (!dest) {
+		ERR(state->handle,
+		    "Role lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle,
+		    "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
+static int user_bounds_copy_callback(hashtab_key_t key,
+				     hashtab_datum_t datum, void *data)
+{
+	link_state_t *state = (link_state_t *) data;
+	user_datum_t *user = (user_datum_t *) datum;
+	user_datum_t *dest;
+	uint32_t bounds_val;
+
+	if (!user->bounds)
+		return 0;
+
+	bounds_val = state->cur->map[SYM_USERS][user->bounds - 1];
+
+	dest = hashtab_search(state->base->p_users.table, key);
+	if (!dest) {
+		ERR(state->handle,
+		    "User lookup failed for %s", (char *)key);
+		return -1;
+	}
+	if (dest->bounds != 0 && dest->bounds != bounds_val) {
+		ERR(state->handle,
+		    "Inconsistent boundary for %s", (char *)key);
+		return -1;
+	}
+	dest->bounds = bounds_val;
+
+	return 0;
+}
+
 /* The aliases have to be copied after the types and attributes to be
  * certain that the base symbol table will have the type that the
  * alias refers. Otherwise, we won't be able to find the type value
@@ -1362,11 +1453,22 @@
 		}
 	}
 
-	if (hashtab_map
-	    (src_symtab[SYM_TYPES].table, alias_copy_callback, state)) {
+	if (hashtab_map(src_symtab[SYM_TYPES].table,
+			type_bounds_copy_callback, state))
 		return -1;
-	}
 
+	if (hashtab_map(src_symtab[SYM_TYPES].table,
+			alias_copy_callback, state))
+		return -1;
+
+	if (hashtab_map(src_symtab[SYM_ROLES].table,

src/link.c line 1474

Quoted 10 lines
src/link.c +7 -0
+			role_bounds_copy_callback, state))
+		return -1;
+
+	if (hashtab_map(src_symtab[SYM_USERS].table,
+			user_bounds_copy_callback, state))
+		return -1;
+
 	/* then fix bitmaps associated with those newly copied identifiers */
 	for (i = 0; i < SYM_NUM; i++) {
 		if (fix_callback_f[i] != NULL &&

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#70 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.4)

Quoted 11 lines · Joshua Brindle
Quoted 9 lines · KaiGai Kohei

The following patch is revised one for libsepol.

Updates:
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
The first bit (TYPEDATUM_PROPERTY_PRIMARY) means the entry is a primary type, and the second bit (TYPEDATUM_PROPERTY_ATTRIBUTE) means the entry is an attribute.

Quoted 4 lines

I didn't see an answer in the current threads, and this looks like the latest userland patch series so I'll ask here: What is the purpose of the properties? We can infer what it knows from the other fields in the datum, right?

Stephen said as follows:
http://marc.info/?l=selinux&m=121882413424973&w=2

| Keeping the type attribute names in the types symtab in the kernel
| policy allows tools like audit2why and apol to extract the original
| attribute names and display them.  I originally shed them because the
| kernel didn't need to use that information and we don't want attribute
| names to be used in security contexts, but it costs us little to save
| them and check for them, and it benefits the tools.

The purpose of property bits is to identify the sort of type_datum. The kernel policy version >= 24 allows to load attribute entries, so we have to distinguish them from existing type entries.

Any type_datum entries of attributes were removed at the tail of expand_module in the older version, so we can assume any entries loaded to kernel space are primary or alias type.
Because existing format of type_datum does not have any information to identify it to be an attribute, we had to add a flag bit to mark.

Quoted 4 lines

One thing that bothers me is that we read prop out of the binary but it is nowhere in the type datum, I can see this leading to errors in the reader where a developer can't figure out where the extra data is coming from.

(?_?) I'm not sure about your concern.

The type_datum has the following format in the newer kernel policy:

+0 +-------------------------+
| length of name |
+4 +-------------------------+
| type identifier value |
+8 +-------------------------+

    | property bits           | <--- TYPEDATUM_PROPERTY_PRIMARY
+12 +-------------------------+      TYPEDATUM_PROPERTY_ATTRIBUTE
    | bounds type identifier  |
+16 +-------------------------+
    | text representation of  |
    | name (variable length)  |
    +-------------------------+

Any property bits are packed within the third field.

Quoted 3 lines

I will echo Steve's request to remove the old hierarchy stuff from here and add in the implementation necessary to do validation of the bounds in libsepol.

OK, please wait for a few days.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#71 lore raw

RE: [PATCH 3/3] Thread/Child-Domain Assignment (rev.4)

Quoted 12 lines · KaiGai Kohei
Quoted 11 lines · Joshua Brindle
Quoted 9 lines · KaiGai Kohei

The following patch is revised one for libsepol.

Updates:
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
The first bit (TYPEDATUM_PROPERTY_PRIMARY) means the entry is a primary type, and the second bit (TYPEDATUM_PROPERTY_ATTRIBUTE) means the entry is an attribute.

Quoted 16 lines
Quoted 2 lines

I didn't see an answer in the current threads, and this looks like the latest userland patch series so I'll ask here: What is

the purpose > of the properties? We can infer what it knows from the other fields

Quoted 1 line

in the datum, right?

Stephen said as follows:
http://marc.info/?l=selinux&m=121882413424973&w=2

Quoted 6 lines

Keeping the type attribute names in the types symtab in the kernel policy allows tools like audit2why and apol to extract the original attribute names and display them. I originally shed them because the kernel didn't need to use that information and we don't want attribute names to be used in security contexts, but it costs us little to save them and check for them, and it benefits the tools.

No, I got that part. What I was missing was that we identified attributes differently in modules and kernel policy now, kind of confusing.

Quoted 33 lines

The purpose of property bits is to identify the sort of type_datum. The kernel policy version >= 24 allows to load attribute entries, so we have to distinguish them from existing type entries.

Any type_datum entries of attributes were removed at the tail of expand_module in the older version, so we can assume any entries loaded to kernel space are primary or alias type. Because existing format of type_datum does not have any information to identify it to be an attribute, we had to add a flag bit to mark.

Quoted 2 lines

One thing that bothers me is that we read prop out of the binary but it is nowhere in the type datum, I can see this leading to

errors in > the reader where a developer can't figure out where the extra data is > coming from.

(?_?) I'm not sure about your concern.

The type_datum has the following format in the newer kernel policy:

+0 +-------------------------+
| length of name |
+4 +-------------------------+
| type identifier value |
+8 +-------------------------+

     | property bits           | <--- TYPEDATUM_PROPERTY_PRIMARY
+12 +-------------------------+      TYPEDATUM_PROPERTY_ATTRIBUTE
     | bounds type identifier  |
+16 +-------------------------+
     | text representation of  |
     | name (variable length)  |
     +-------------------------+
Quoted 2 lines

Any property bits are packed within the third field.

I don't see that in the libsepol patch:

@@ -145,8 +146,16 @@
ebitmap_t types; /* types with this attribute */
#define TYPE_FLAGS_PERMISSIVE 0x01
uint32_t flags;
+ uint32_t bounds; /* bounds type, if exist */
} type_datum_t;

Quoted 9 lines
Quoted 4 lines

I will echo Steve's request to remove the old hierarchy stuff from here
and add in the implementation necessary to do validation

of the bounds > in libsepol.

OK, please wait for a few days.

Thanks,

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#72 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.4)

Quoted 27 lines · Joshua Brindle
Quoted 11 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 9 lines · KaiGai Kohei

The following patch is revised one for libsepol.

Updates:
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
The first bit (TYPEDATUM_PROPERTY_PRIMARY) means the entry is a primary type, and the second bit (TYPEDATUM_PROPERTY_ATTRIBUTE) means the entry is an attribute.

Quoted 14 lines
Quoted 2 lines

I didn't see an answer in the current threads, and this looks like the latest userland patch series so I'll ask here: What is

the purpose > of the properties? We can infer what it knows from the other fields

Quoted 1 line

in the datum, right?

Stephen said as follows:
http://marc.info/?l=selinux&m=121882413424973&w=2

Quoted 6 lines

Keeping the type attribute names in the types symtab in the kernel policy allows tools like audit2why and apol to extract the original attribute names and display them. I originally shed them because the kernel didn't need to use that information and we don't want attribute names to be used in security contexts, but it costs us little to save them and check for them, and it benefits the tools.

Quoted 3 lines

No, I got that part. What I was missing was that we identified attributes differently in modules and kernel policy now, kind of confusing.

I see, modular policy format now has "primary", "flavor" and "flags" members to identify its properties. It is different from newer kernel policy format.

Quoted 21 lines
Quoted 15 lines

The type_datum has the following format in the newer kernel policy:

+0 +-------------------------+
| length of name |
+4 +-------------------------+
| type identifier value |
+8 +-------------------------+

     | property bits           | <--- TYPEDATUM_PROPERTY_PRIMARY
+12 +-------------------------+      TYPEDATUM_PROPERTY_ATTRIBUTE
     | bounds type identifier  |
+16 +-------------------------+
     | text representation of  |
     | name (variable length)  |
     +-------------------------+
Quoted 2 lines

Any property bits are packed within the third field.

I don't see that in the libsepol patch:

include/sepol/policydb/policydb.h line 150

Quoted 5 lines
include/sepol/policydb/policydb.h +1 -0
@@ -145,8 +146,16 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;

Are you saying members within type_datum_t should have one-to-one mapping with its disk format? If so, it is the most straightforward approach to add a "flavor" member for the disk format of kernel policy.

I guess your opinion is that smaller differences between kernel and modular policy format is better. If so, what do you think about an idea which packs all properties of a type into a property bits members. We need 1 bit for "primary" property, 2 bits for "flavor" and 1 bit for "permissive", so it is enough to store them into a 32bits variable.

In this case, the format of type_datum is changed as follows:

+ 0 : length of name (unchanged)
+ 4 : type identifier value (unchanged)
+ 8 : property bits which can have following bits +12 : bounds type identifier (newly added) +16 : ebitmap of attributes (modular only/unchanged) +XX : text representation of type name
(*) flavor in modular policy format is deprecated.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#73 lore raw

PATCH 1/1 libsepol : Add support for a new policy version (POLICYDB_VERSION_BOUNDARY)

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.

This version contains the following features.
- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

TODO:
- Replace implementation of existing name based hierarchy checkings by the newer boundary feature.

---
 include/sepol/policydb/policydb.h |   28 +++++++-
 src/expand.c                      |  132 ++++++++++++++++++++++++++++++--------
 src/link.c                        |  108 ++++++++++++++++++++++++++++++-
 src/policydb.c                    |   72 +++++++++++++++++---
 src/write.c                       |   54 ++++++++++++---
 5 files changed, 342 insertions(+), 52 deletions(-)

---

include/sepol/policydb/policydb.h +26 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,8 +146,18 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+#define TYPEDATUM_PROPERTY_ALIAS	0x0004	/* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE	0x0008	/* userspace only */
+
 /* User attributes */
 typedef struct user_datum {
 	symtab_datum_t s;
@@ -156,6 +167,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +607,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +621,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +61 -11

137 lines not on this page · raw message

src/expand.c +105 -27

168 lines not on this page · raw message

src/write.c +45 -9

76 lines not on this page · raw message

src/link.c +105 -3

122 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#74 lore raw

RE: [PATCH 3/3] Thread/Child-Domain Assignment (rev.4)

In reply to KaiGai Kohei
Quoted 56 lines · KaiGai Kohei
Quoted 27 lines · Joshua Brindle
Quoted 11 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 9 lines · KaiGai Kohei

The following patch is revised one for libsepol.

Updates:
- The properties of type_datum are packed within the third word of type entries in the kernel policy.
The first bit (TYPEDATUM_PROPERTY_PRIMARY) means the entry is a primary type, and the second bit (TYPEDATUM_PROPERTY_ATTRIBUTE) means the entry is an attribute.

Quoted 14 lines
Quoted 2 lines

I didn't see an answer in the current threads, and this looks like the latest userland patch series so I'll ask here: What is the

purpose > of the properties? We can infer what it knows from the other fields

Quoted 1 line

in the datum, right?

Stephen said as follows:
http://marc.info/?l=selinux&m=121882413424973&w=2

Quoted 6 lines

Keeping the type attribute names in the types symtab in the kernel policy allows tools like audit2why and apol to extract the original attribute names and display them. I originally shed them because the kernel didn't need to use that information and we don't want attribute names to be used in security contexts, but it costs us little to save them and check for them, and it benefits the tools.

Quoted 3 lines

No, I got that part. What I was missing was that we identified attributes differently in modules and kernel policy now, kind of confusing.

I see, modular policy format now has "primary", "flavor" and "flags" members to identify its properties. It is different from newer kernel policy format.

Quoted 20 lines
Quoted 15 lines

The type_datum has the following format in the newer kernel policy:

+0 +-------------------------+
| length of name |
+4 +-------------------------+
| type identifier value |
+8 +-------------------------+

     | property bits           | <--- TYPEDATUM_PROPERTY_PRIMARY
+12 +-------------------------+      TYPEDATUM_PROPERTY_ATTRIBUTE
     | bounds type identifier  |
+16 +-------------------------+
     | text representation of  |
     | name (variable length)  |
     +-------------------------+
Quoted 2 lines

Any property bits are packed within the third field.

I don't see that in the libsepol patch:

Quoted 12 lines

include/sepol/policydb/policydb.h line 150

Quoted 6 lines
include/sepol/policydb/policydb.h +1 -0
@@ -145,8 +146,16 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;

Are you saying members within type_datum_t should have one-to-one mapping with its disk format? If so, it is the most straightforward approach to add a "flavor" member for the disk format of kernel policy.

No, don't add flavor to the kernel format. Add the property to the libsepol type_datum

Quoted 2 lines

I guess your opinion is that smaller differences between kernel and modular policy format is better. If so, what do

No, I'm fine with differences in those 2 formats. I just don't want to get confused later when the on-disk format has extra fields that the structs in libsepol don't have.

Quoted 16 lines

you think about an idea which packs all properties of a type into a property bits members.
We need 1 bit for "primary" property, 2 bits for "flavor" and 1 bit for "permissive", so it is enough to store them into a 32bits variable.

In this case, the format of type_datum is changed as follows:

+ 0 : length of name (unchanged)
+ 4 : type identifier value (unchanged)
+ 8 : property bits which can have following bits +12 : bounds type identifier (newly added) +16 : ebitmap of attributes (modular only/unchanged) +XX : text representation of type name
(*) flavor in modular policy format is deprecated.

Quoted 1 line

Thanks,

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#75 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.4)

Quoted 6 lines
Quoted 2 lines

I guess your opinion is that smaller differences between kernel and modular policy format is better. If so, what do

No, I'm fine with differences in those 2 formats. I just don't want to get confused later when the on-disk format has extra fields that the structs in libsepol don't have.

How do you think the approach on the latest libsepol patch?

It integrates all fields to represent its properties ("flavor", "primary" and "flags") into a single field deployed on the third word of type_datum entry. These are encoded/decoded by type_read/type_write.

I think an extra field like a new "properties" is unavoidable, because existing fields of properties are external specification of libsepol. So we cannot re-organize them arbitrarily.

Thanks,

Signature · 6 lines
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#76 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

FEATURES:

- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

- Hierarchy checks are reworked
The existing userspace hierarchy checks are reworked for the upcoming boundary feature. It can handle parent one based on both newer bounds relationship and existing name-based hierarchy.

In addition, I put a trick to evaluate conditional rules correctly. The following example shows a confusable case. A_t is the bounds of B_t, so B_t can never has wider permission than A_t.

Example)
allow B_t X_t : file { read_file_perms };

   if (A_can_write_X) {
       allow A_t X_t : file { write_file_perms };
   } else {
       allow A_t X_t : file { read_file_perms };

}

A_t's permissions on X_t is depend on the 'A_can_write_X', however, a part of them, like 'read', are unconditionally allowed. If we can find common permission on both of true/false lists, these are pulled up to unconditional rules.
Thus, B_t's read permission on X_t is not hierarchy violated in the above example. It also matches the upcoming kernel behavior no need to say.

Thanks,

---
 include/sepol/policydb/policydb.h |   28 ++
 src/expand.c                      |  132 +++++++++--
 src/hierarchy.c                   |  436 +++++++++++++++++++++-----------------
 src/link.c                        |  108 +++++++++
 src/policydb.c                    |   72 +++++-
 src/write.c                       |   54 +++-
 6 files changed, 585 insertions(+), 245 deletions(-)

---

include/sepol/policydb/policydb.h +26 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,8 +146,18 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+#define TYPEDATUM_PROPERTY_ALIAS	0x0004	/* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE	0x0008	/* userspace only */
+
 /* User attributes */
 typedef struct user_datum {
 	symtab_datum_t s;
@@ -156,6 +167,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +607,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +621,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +61 -11

137 lines not on this page · raw message

src/hierarchy.c +243 -193

590 lines not on this page · raw message

src/expand.c +105 -27

168 lines not on this page · raw message

src/write.c +45 -9

76 lines not on this page · raw message

src/link.c +105 -3

122 lines not on this page · raw message

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#77 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 48 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

FEATURES:

- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

- Hierarchy checks are reworked
The existing userspace hierarchy checks are reworked for the upcoming boundary feature. It can handle parent one based on both newer bounds relationship and existing name-based hierarchy.

In addition, I put a trick to evaluate conditional rules correctly. The following example shows a confusable case. A_t is the bounds of B_t, so B_t can never has wider permission than A_t.

Example)

   allow B_t X_t : file { read_file_perms };
   if (A_can_write_X) {
       allow A_t X_t : file { write_file_perms };
   } else {
       allow A_t X_t : file { read_file_perms };
   }
Quoted 8 lines

A_t's permissions on X_t is depend on the 'A_can_write_X', however, a part of them, like 'read', are unconditionally allowed. If we can find common permission on both of true/false lists, these are pulled up to unconditional rules.
Thus, B_t's read permission on X_t is not hierarchy violated in the above example. It also matches the upcoming kernel behavior no need to say.

Was this the latest patch? I can't seem to apply it either to the latest git HEAD or to the last svn revision:

[root@misterfreeze trunk]# patch -p0 --dry-run -F5< /root/selinux/patch
patching file libsepol/include/sepol/policydb/policydb.h
Hunk #1 succeeded at 119 with fuzz 3.
Hunk #2 FAILED at 146.
Hunk #3 succeeded at 167 with fuzz 3.
Hunk #4 FAILED at 607.
Hunk #5 FAILED at 621.
3 out of 5 hunks FAILED -- saving rejects to file libsepol/include/sepol/policydb/policydb.h.rej patching file libsepol/src/policydb.c
Hunk #1 succeeded at 110 with fuzz 3.
Hunk #2 succeeded at 147 with fuzz 3.
Hunk #3 succeeded at 182 with fuzz 3.
Hunk #4 FAILED at 1873.
Hunk #5 succeeded at 1947 with fuzz 3.
Hunk #6 FAILED at 1962.
Hunk #7 FAILED at 2338.
3 out of 7 hunks FAILED -- saving rejects to file libsepol/src/policydb.c.rej patching file libsepol/src/hierarchy.c
Hunk #1 FAILED at 1.
Hunk #2 FAILED at 46.
Hunk #3 FAILED at 125.
Hunk #4 FAILED at 157.
Hunk #5 FAILED at 335.
Hunk #6 FAILED at 402.
Hunk #7 FAILED at 428.
Hunk #8 succeeded at 467 with fuzz 3.
7 out of 8 hunks FAILED -- saving rejects to file libsepol/src/hierarchy.c.rej patching file libsepol/src/expand.c
Hunk #1 succeeded at 466 with fuzz 3.
Hunk #2 succeeded at 1959 with fuzz 3.
Hunk #3 succeeded at 2462 with fuzz 3.
Hunk #4 succeeded at 2480 with fuzz 3.
Hunk #5 succeeded at 2498 with fuzz 3.
Hunk #6 succeeded at 2590 with fuzz 3.
patching file libsepol/src/write.c
Hunk #1 succeeded at 920 with fuzz 3.
Hunk #2 FAILED at 954.
Hunk #3 succeeded at 1031 with fuzz 3.
1 out of 3 hunks FAILED -- saving rejects to file libsepol/src/write.c.rej patching file libsepol/src/link.c
Hunk #1 succeeded at 660 with fuzz 3.
Hunk #2 FAILED at 1453.
1 out of 2 hunks FAILED -- saving rejects to file libsepol/src/link.c.rej

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#78 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 58 lines · Joshua Brindle
Quoted 48 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

FEATURES:

- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

- Hierarchy checks are reworked
The existing userspace hierarchy checks are reworked for the upcoming boundary feature. It can handle parent one based on both newer bounds relationship and existing name-based hierarchy.

In addition, I put a trick to evaluate conditional rules correctly. The following example shows a confusable case. A_t is the bounds of B_t, so B_t can never has wider permission than A_t.

Example)

   allow B_t X_t : file { read_file_perms };
   if (A_can_write_X) {
       allow A_t X_t : file { write_file_perms };
   } else {
       allow A_t X_t : file { read_file_perms };
   }
Quoted 8 lines

A_t's permissions on X_t is depend on the 'A_can_write_X', however, a part of them, like 'read', are unconditionally allowed. If we can find common permission on both of true/false lists, these are pulled up to unconditional rules.
Thus, B_t's read permission on X_t is not hierarchy violated in the above example. It also matches the upcoming kernel behavior no need to say.

Quoted 2 lines

Was this the latest patch? I can't seem to apply it either to the latest git HEAD or to the last svn revision:

Sorry, my Thunderbird translated any tabs into spaces. The patch is made based on the latest subversion repository. Can you apply the attached one correctly?

Thanks,

Quoted 44 lines

[root@misterfreeze trunk]# patch -p0 --dry-run -F5< /root/selinux/patch
patching file libsepol/include/sepol/policydb/policydb.h
Hunk #1 succeeded at 119 with fuzz 3.
Hunk #2 FAILED at 146.
Hunk #3 succeeded at 167 with fuzz 3.
Hunk #4 FAILED at 607.
Hunk #5 FAILED at 621.
3 out of 5 hunks FAILED -- saving rejects to file libsepol/include/sepol/policydb/policydb.h.rej patching file libsepol/src/policydb.c
Hunk #1 succeeded at 110 with fuzz 3.
Hunk #2 succeeded at 147 with fuzz 3.
Hunk #3 succeeded at 182 with fuzz 3.
Hunk #4 FAILED at 1873.
Hunk #5 succeeded at 1947 with fuzz 3.
Hunk #6 FAILED at 1962.
Hunk #7 FAILED at 2338.
3 out of 7 hunks FAILED -- saving rejects to file libsepol/src/policydb.c.rej patching file libsepol/src/hierarchy.c
Hunk #1 FAILED at 1.
Hunk #2 FAILED at 46.
Hunk #3 FAILED at 125.
Hunk #4 FAILED at 157.
Hunk #5 FAILED at 335.
Hunk #6 FAILED at 402.
Hunk #7 FAILED at 428.
Hunk #8 succeeded at 467 with fuzz 3.
7 out of 8 hunks FAILED -- saving rejects to file libsepol/src/hierarchy.c.rej patching file libsepol/src/expand.c
Hunk #1 succeeded at 466 with fuzz 3.
Hunk #2 succeeded at 1959 with fuzz 3.
Hunk #3 succeeded at 2462 with fuzz 3.
Hunk #4 succeeded at 2480 with fuzz 3.
Hunk #5 succeeded at 2498 with fuzz 3.
Hunk #6 succeeded at 2590 with fuzz 3.
patching file libsepol/src/write.c
Hunk #1 succeeded at 920 with fuzz 3.
Hunk #2 FAILED at 954.
Hunk #3 succeeded at 1031 with fuzz 3.
1 out of 3 hunks FAILED -- saving rejects to file libsepol/src/write.c.rej patching file libsepol/src/link.c
Hunk #1 succeeded at 660 with fuzz 3.
Hunk #2 FAILED at 1453.
1 out of 2 hunks FAILED -- saving rejects to file libsepol/src/link.c.rej

Signature · 1 line
KaiGai Kohei <[email protected]>
include/sepol/policydb/policydb.h +26 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,8 +146,18 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+#define TYPEDATUM_PROPERTY_ALIAS	0x0004	/* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE	0x0008	/* userspace only */
+
 /* User attributes */
 typedef struct user_datum {
 	symtab_datum_t s;
@@ -156,6 +167,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +607,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +621,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +61 -11

137 lines not on this page · raw message

src/hierarchy.c +243 -193

590 lines not on this page · raw message

src/expand.c +105 -27

168 lines not on this page · raw message

src/write.c +45 -9

76 lines not on this page · raw message

src/link.c +105 -3

122 lines not on this page · raw message

#79 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 58 lines · KaiGai Kohei
Quoted 57 lines · Joshua Brindle
Quoted 56 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

FEATURES:

- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

- Hierarchy checks are reworked
The existing userspace hierarchy checks are reworked for the upcoming boundary feature. It can handle parent one based on both newer bounds relationship and existing name-based hierarchy.

In addition, I put a trick to evaluate conditional rules correctly. The following example shows a confusable case. A_t is the bounds of B_t, so B_t can never has wider permission than A_t.

Example)

   allow B_t X_t : file { read_file_perms };
   if (A_can_write_X) {
       allow A_t X_t : file { write_file_perms };
   } else {
       allow A_t X_t : file { read_file_perms };
   }

A_t's permissions on X_t is depend on the 'A_can_write_X', however, a part of them, like 'read', are unconditionally allowed. If we can find common permission on both of true/false lists, these are pulled up to unconditional rules.
Thus, B_t's read permission on X_t is not hierarchy violated in the above example. It also matches the upcoming kernel behavior no need to say.

Quoted 7 lines
Quoted 2 lines

Was this the latest patch? I can't seem to apply it either to the latest git HEAD or to the last svn revision:

Sorry, my Thunderbird translated any tabs into spaces. The patch is made based on the latest subversion repository. Can you apply the attached one correctly?

Yes it applies. I'm going to have to track down that bug you reported before merging this because it prevents policy compilation.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#80 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 61 lines · Joshua Brindle
Quoted 60 lines · KaiGai Kohei
Quoted 59 lines · Joshua Brindle
Quoted 48 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

FEATURES:

- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

- Hierarchy checks are reworked
The existing userspace hierarchy checks are reworked for the upcoming boundary feature. It can handle parent one based on both newer bounds relationship and existing name-based hierarchy.

In addition, I put a trick to evaluate conditional rules correctly. The following example shows a confusable case. A_t is the bounds of B_t, so B_t can never has wider permission than A_t.

Example)

   allow B_t X_t : file { read_file_perms };
   if (A_can_write_X) {
       allow A_t X_t : file { write_file_perms };
   } else {
       allow A_t X_t : file { read_file_perms };
   }
Quoted 8 lines

A_t's permissions on X_t is depend on the 'A_can_write_X', however, a part of them, like 'read', are unconditionally allowed. If we can find common permission on both of true/false lists, these are pulled up to unconditional rules.
Thus, B_t's read permission on X_t is not hierarchy violated in the above example. It also matches the upcoming kernel behavior no need to say.

Was this the latest patch? I can't seem to apply it either to the latest git HEAD or to the last svn revision:

Quoted 7 lines
Quoted 4 lines

Sorry, my Thunderbird translated any tabs into spaces. The patch is made based on the latest subversion repository. Can you apply the attached one correctly?

Yes it applies. I'm going to have to track down that bug you reported before merging this because it prevents policy compilation.

Note that the patch does not contain fixes for a bug I reported.

IMO, alias types of invisible primay should be simply filtered at the expand_module(), or should generate an error.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#81 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24. Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

Quoted 52 lines
Quoted 52 lines
Quoted 52 lines

FEATURES:

- Boundary feature support:
The upcoming kernel has a feature to define boundary relationship between two users, roles and types. It enables to restrict a bounded one can never have wider permissions than its bounds one. Any XXXX_datum_t structure have "u32 bounds" member to indicate its bounds, and we can handle it with the latest version of policy format provided by this patch.

- Loading attributes into kernel space:
The upcoming kernel also allows to load entries of attribute. The attached patch turn off to drop them, when it tries to write kernel policy with its version is equal or greater than POLICYDB_VERSION_BOUNDARY.
Any entries of attribute has a property of TYPEDATUM_PROPERTY_ATTRIBUTE.

- Improvement of type_datum format on kernel/modular policy. The type_datum entry has several its attribute fields like "primary", "flavor" and "flags", and these are stored within separated fields on-disk format. This patch enables to pack them into a single field. Currently four bits are defined, and rest of them are reserved.

   #define TYPEDATUM_PROPERTY_PRIMARY      0x0001
   #define TYPEDATUM_PROPERTY_ATTRIBUTE    0x0002
   #define TYPEDATUM_PROPERTY_ALIAS        0x0004  /* userspace only */
   #define TYPEDATUM_PROPERTY_PERMISSIVE   0x0008  /* userspace only */

- Hierarchy checks are reworked
The existing userspace hierarchy checks are reworked for the upcoming boundary feature. It can handle parent one based on both newer bounds relationship and existing name-based hierarchy.

In addition, I put a trick to evaluate conditional rules correctly. The following example shows a confusable case. A_t is the bounds of B_t, so B_t can never has wider permission than A_t.

Example)

   allow B_t X_t : file { read_file_perms };
   if (A_can_write_X) {
       allow A_t X_t : file { write_file_perms };
   } else {
       allow A_t X_t : file { read_file_perms };
   }

A_t's permissions on X_t is depend on the 'A_can_write_X', however, a part of them, like 'read', are unconditionally allowed. If we can find common permission on both of true/false lists, these are pulled up to unconditional rules.
Thus, B_t's read permission on X_t is not hierarchy violated in the above example. It also matches the upcoming kernel behavior no need to say.

Quoted 55 lines
Quoted 2 lines

Was this the latest patch? I can't seem to apply it either to the latest git HEAD or to the last svn revision:

Sorry, my Thunderbird translated any tabs into spaces. The patch is made based on the latest subversion repository. Can you apply the attached one correctly?

Thanks,

Quoted 44 lines

[root@misterfreeze trunk]# patch -p0 --dry-run -F5< /root/selinux/patch
patching file libsepol/include/sepol/policydb/policydb.h
Hunk #1 succeeded at 119 with fuzz 3.
Hunk #2 FAILED at 146.
Hunk #3 succeeded at 167 with fuzz 3.
Hunk #4 FAILED at 607.
Hunk #5 FAILED at 621.
3 out of 5 hunks FAILED -- saving rejects to file libsepol/include/sepol/policydb/policydb.h.rej patching file libsepol/src/policydb.c
Hunk #1 succeeded at 110 with fuzz 3.
Hunk #2 succeeded at 147 with fuzz 3.
Hunk #3 succeeded at 182 with fuzz 3.
Hunk #4 FAILED at 1873.
Hunk #5 succeeded at 1947 with fuzz 3.
Hunk #6 FAILED at 1962.
Hunk #7 FAILED at 2338.
3 out of 7 hunks FAILED -- saving rejects to file libsepol/src/policydb.c.rej patching file libsepol/src/hierarchy.c
Hunk #1 FAILED at 1.
Hunk #2 FAILED at 46.
Hunk #3 FAILED at 125.
Hunk #4 FAILED at 157.
Hunk #5 FAILED at 335.
Hunk #6 FAILED at 402.
Hunk #7 FAILED at 428.
Hunk #8 succeeded at 467 with fuzz 3.
7 out of 8 hunks FAILED -- saving rejects to file libsepol/src/hierarchy.c.rej patching file libsepol/src/expand.c
Hunk #1 succeeded at 466 with fuzz 3.
Hunk #2 succeeded at 1959 with fuzz 3.
Hunk #3 succeeded at 2462 with fuzz 3.
Hunk #4 succeeded at 2480 with fuzz 3.
Hunk #5 succeeded at 2498 with fuzz 3.
Hunk #6 succeeded at 2590 with fuzz 3.
patching file libsepol/src/write.c
Hunk #1 succeeded at 920 with fuzz 3.
Hunk #2 FAILED at 954.
Hunk #3 succeeded at 1031 with fuzz 3.
1 out of 3 hunks FAILED -- saving rejects to file libsepol/src/write.c.rej patching file libsepol/src/link.c
Hunk #1 succeeded at 660 with fuzz 3.
Hunk #2 FAILED at 1453.
1 out of 2 hunks FAILED -- saving rejects to file libsepol/src/link.c.rej

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#82 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 11 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

Also, please tell me the steps.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#83 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 12 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Quoted 9 lines

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

Err, ok. I'm getting inconsistent results now:

[root@misterfreeze policy]# semodule -B
SELinux: Could not load policy file /etc/selinux/targeted/policy/policy.23: Invalid argument /usr/sbin/load_policy: Can't load policy: Invalid argument libsemanage.semanage_reload_policy: load_policy returned error code 2.

I'm not sure what is causing it but it is a different problem than I had before, I'll investigate and see what is going on.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#84 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei
Quoted 12 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Quoted 9 lines

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

I'm not sure why this wasn't happening to you but from what I can tell the new patch was returning from type_write when an attribute was passed in, however the length of the table was not updated. This caused policydb_read to read over the edge of the type symbol table, resulting in badness.

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Do you have a problem with this Stephen?

index 6f1f655..d2c2c32 100644

libsepol/src/write.c +0 -9
@@ -954,15 +954,6 @@ static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
 
        typdatum = (type_datum_t *) datum;
 
-       /*
-        * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
-        * does not support to load entries of attribute, so we skip to write it.
-        */
-       if (p->policy_type == POLICY_KERN
-           && p->policyvers < POLICYDB_VERSION_BOUNDARY
-           && typdatum->flavor == TYPE_ATTRIB)
-               return POLICYDB_SUCCESS;
-
        len = strlen(key);
        items = 0;
        buf[items++] = cpu_to_le32(len);

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#85 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 19 lines · Joshua Brindle
Quoted 18 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 6 lines
Quoted 1 line
Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

I'm not sure why this wasn't happening to you but from what I can tell the new patch was returning from type_write when an attribute was passed in, however the length of the table was not updated. This caused policydb_read to read over the edge of the type symbol table, resulting in badness.

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 3 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

Thanks,

Quoted 23 lines

Do you have a problem with this Stephen?

index 6f1f655..d2c2c32 100644

libsepol/src/write.c +0 -9
@@ -954,15 +954,6 @@ static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
 
        typdatum = (type_datum_t *) datum;
 
-       /*
-        * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
-        * does not support to load entries of attribute, so we skip to write it.
-        */
-       if (p->policy_type == POLICY_KERN
-           && p->policyvers < POLICYDB_VERSION_BOUNDARY
-           && typdatum->flavor == TYPE_ATTRIB)
-               return POLICYDB_SUCCESS;
-
        len = strlen(key);
        items = 0;
        buf[items++] = cpu_to_le32(len);
Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#92 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to Joshua Brindle
Quoted 20 lines · Joshua Brindle
Quoted 19 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 8 lines
Quoted 2 lines
Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

I'm not sure why this wasn't happening to you but from what I can tell the new patch was returning from type_write when an attribute was passed in, however the length of the table was not updated. This caused policydb_read to read over the edge of the type symbol table, resulting in badness.

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Do you have a problem with this Stephen?

The problem with writing attributes to older policy versions is that older kernels will then treat the attribute like any other type and allow its use in a security context.

Quoted 20 lines

index 6f1f655..d2c2c32 100644

libsepol/src/write.c +0 -9
@@ -954,15 +954,6 @@ static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr)
 
        typdatum = (type_datum_t *) datum;
 
-       /*
-        * The kernel policy version less than 24 (= POLICYDB_VERSION_BOUNDARY)
-        * does not support to load entries of attribute, so we skip to write it.
-        */
-       if (p->policy_type == POLICY_KERN
-           && p->policyvers < POLICYDB_VERSION_BOUNDARY
-           && typdatum->flavor == TYPE_ATTRIB)
-               return POLICYDB_SUCCESS;
-
        len = strlen(key);
        items = 0;
        buf[items++] = cpu_to_le32(len);
Signature · 8 lines
Stephen Smalley
National Security Agency


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#86 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei
Quoted 32 lines · KaiGai Kohei
Quoted 16 lines · Joshua Brindle
Quoted 15 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

Quoted 8 lines
Quoted 4 lines

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

I'm not sure why this wasn't happening to you but from what I can tell the new patch was returning from type_write when an attribute was passed in, however the length of the table was not updated. This caused policydb_read to read over the edge of the type symbol table, resulting in badness.

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 8 lines
Quoted 3 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

It isn't impossible. You are going to have to make it walk to type symbol table to calculate the length without attributes, then write that length instead of the total symtab length.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#93 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to Stephen Smalley
Quoted 23 lines · Stephen Smalley
Quoted 22 lines · Joshua Brindle
Quoted 11 lines · KaiGai Kohei
Quoted 10 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei
Quoted 5 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

The attached patch for libsepol add suport for a new policy version named as (MOD_)POLICYDB_VERSION_BOUNDARY.
Userspace hierarchy checks are reworked in this revision.

I'm seeing a couple problems. First when writing out the policy it doesn't seem to respect policyvers, I told it to generate a version 23 and it still made a 24.

Quoted 8 lines

Are you saying a configuration of "policy-version = 23" at semanage.conf is ignored? I could not reproduce it in my environment. Could you tell me the steps to reproduce it?

I injected several printf()'s, but it shows a proper policyvers which reflects semanage.conf correctly.

Quoted 1 line

Second it is failing to downgrade the 24 to 23 since my kernel doesn't support 24.

I'm not sure why this wasn't happening to you but from what I can tell the new patch was returning from type_write when an attribute was passed in, however the length of the table was not updated. This caused policydb_read to read over the edge of the type symbol table, resulting in badness.

Quoted 7 lines
Quoted 3 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Do you have a problem with this Stephen?

The problem with writing attributes to older policy versions is that older kernels will then treat the attribute like any other type and allow its use in a security context.

Yes, I remembered that after I sent the first email.. doh

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#87 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to Joshua Brindle
Quoted 9 lines
Quoted 9 lines

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 3 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Quoted 8 lines
Quoted 4 lines

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

It isn't impossible. You are going to have to make it walk to type symbol table to calculate the length without attributes, then write that length instead of the total symtab length.

The attached patch enables to fixup the number of type/attribute entries to be written. The type_attr_uncount() decrements the number of attribute entries skipped at type_write().

At first, I had a plan to invoke type_attr_remove() with hashtab_map_remove_on_error(), but it means the given policydb structure is modified at policydb_write() and implicit changes to external interface.

Differences from the previous version are here:

$ diff -NU3 thread-context-libsepol.6.patch thread-context-libsepol.7.patch
--- thread-context-libsepol.6.patch     2008-09-09 10:24:41.000000000 +0900
+++ thread-context-libsepol.7.patch     2008-10-07 14:50:32.000000000 +0900
@@ -1086,6 +1086,45 @@
        items2 = put_entry(buf, sizeof(uint32_t), items, fp);
        if (items != items2)
                return POLICYDB_ERROR;
+@@ -1515,6 +1551,19 @@
+       return POLICYDB_SUCCESS;
+ }
+
++static int type_attr_uncount(hashtab_key_t key __attribute__ ((unused)),
++                           hashtab_datum_t datum, void *args)
++{
++      type_datum_t *typdatum = datum;
++      uint32_t *p_nel = args;
++
++      if (typdatum->flavor == TYPE_ATTRIB) {
++              /* uncount attribute from total number of types */
++              (*p_nel)--;
++      }
++      return 0;
++}
++
+ /*
+  * Write the configuration data in a policy database
+  * structure to a policy database binary representation
+@@ -1646,6 +1695,18 @@
+       for (i = 0; i < num_syms; i++) {
+               buf[0] = cpu_to_le32(p->symtab[i].nprim);
+               buf[1] = cpu_to_le32(p->symtab[i].table->nel);
++
++              /*
++               * A special case when writing type/attribute symbol table.
++               * The kernel policy version less than 24 does not support
++               * to load entries of attribute, so we have to re-calculate
++               * the actual number of types except for attributes.
++               */
++              if (i == SYM_TYPES &&
++                  p->policyvers < POLICYDB_VERSION_BOUNDARY &&
++                  p->policy_type == POLICY_KERN) {
++                      hashtab_map(p->symtab[i].table, type_attr_uncount, &buf[1]);
++              }
+               items = put_entry(buf, sizeof(uint32_t), 2, fp);
+               if (items != 2)
+                       return POLICYDB_ERROR;
 Index: libsepol/src/link.c
 ===================================================================
 --- libsepol/src/link.c        (revision 2950)
Signature · 2 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>
include/sepol/policydb/policydb.h +26 -2
Index: libsepol/include/sepol/policydb/policydb.h
===================================================================
@@ -119,6 +119,7 @@
 	ebitmap_t dominates;	/* set of roles dominated by this role */
 	type_set_t types;	/* set of authorized types for role */
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
+	uint32_t bounds;	/* bounds role, if exist */
 } role_datum_t;
 
 typedef struct role_trans {
@@ -145,8 +146,18 @@
 	ebitmap_t types;	/* types with this attribute */
 #define TYPE_FLAGS_PERMISSIVE	0x01
 	uint32_t flags;
+	uint32_t bounds;	/* bounds type, if exist */
 } type_datum_t;
 
+/*
+ * Properties of type_datum
+ * available on the policy version >= (MOD_)POLICYDB_VERSION_BOUNDARY
+ */
+#define TYPEDATUM_PROPERTY_PRIMARY	0x0001
+#define TYPEDATUM_PROPERTY_ATTRIBUTE	0x0002
+#define TYPEDATUM_PROPERTY_ALIAS	0x0004	/* userspace only */
+#define TYPEDATUM_PROPERTY_PERMISSIVE	0x0008	/* userspace only */
+
 /* User attributes */
 typedef struct user_datum {
 	symtab_datum_t s;
@@ -156,6 +167,7 @@
 	ebitmap_t cache;	/* This is an expanded set used for context validation during parsing */
 	mls_range_t exp_range;     /* expanded range used for validation */
 	mls_level_t exp_dfltlevel; /* expanded range used for validation */
+	uint32_t bounds;	/* bounds user, if exist */
 } user_datum_t;
 
 /* Sensitivity attributes */
@@ -595,10 +607,11 @@
 #define POLICYDB_VERSION_RANGETRANS	21
 #define POLICYDB_VERSION_POLCAP		22
 #define POLICYDB_VERSION_PERMISSIVE	23
+#define POLICYDB_VERSION_BOUNDARY	24
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_PERMISSIVE
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_BOUNDARY
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE	   4
@@ -608,12 +621,23 @@
 #define MOD_POLICYDB_VERSION_MLS_USERS	   6
 #define MOD_POLICYDB_VERSION_POLCAP	   7
 #define MOD_POLICYDB_VERSION_PERMISSIVE	   8
+#define MOD_POLICYDB_VERSION_BOUNDARY      9
 
 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE
-#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PERMISSIVE
+#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_BOUNDARY
 
 #define POLICYDB_CONFIG_MLS    1
 
+/* macros to check policy feature */
+
+/* TODO: add other features here */
+
+#define policydb_has_boundary_feature(p)			\
+	(((p)->policy_type == POLICY_KERN			\
+	  && p->policyvers >= POLICYDB_VERSION_BOUNDARY) ||	\
+	 ((p)->policy_type != POLICY_KERN			\
+	  && p->policyvers >= MOD_POLICYDB_VERSION_BOUNDARY))
+
 /* the config flags related to unknown classes/perms are bits 2 and 3 */
 #define DENY_UNKNOWN	SEPOL_DENY_UNKNOWN
 #define REJECT_UNKNOWN	SEPOL_REJECT_UNKNOWN
src/policydb.c +61 -11

137 lines not on this page · raw message

src/hierarchy.c +243 -193

590 lines not on this page · raw message

src/expand.c +105 -27

168 lines not on this page · raw message

src/write.c +70 -9

113 lines not on this page · raw message

src/link.c +105 -3

122 lines not on this page · raw message

#88 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 21 lines · KaiGai Kohei
Quoted 11 lines
Quoted 11 lines

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 4 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Quoted 9 lines
Quoted 5 lines

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

It isn't impossible. You are going to have to make it walk to type symbol table to calculate the length without attributes, then write that length instead of the total symtab length.

Quoted 9 lines

The attached patch enables to fixup the number of type/attribute entries to be written. The type_attr_uncount() decrements the number of attribute entries skipped at type_write().

At first, I had a plan to invoke type_attr_remove() with hashtab_map_remove_on_error(), but it means the given policydb structure is modified at policydb_write() and implicit changes to external interface.

This does not cause a hierarchy error, is this an expected limitation?

typebounds goodbye_world_t hello_world_t;

allow hello_world_t self: file ~{read };

allow goodbye_world_t self: file *;

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#89 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

Quoted 37 lines · Joshua Brindle
Quoted 24 lines · KaiGai Kohei
Quoted 19 lines
Quoted 13 lines

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 5 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Quoted 6 lines

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

Quoted 5 lines

It isn't impossible. You are going to have to make it walk to type symbol table to calculate the length without attributes, then write that length instead of the total symtab length.

Quoted 10 lines

The attached patch enables to fixup the number of type/attribute entries to be written. The type_attr_uncount() decrements the number of attribute entries skipped at type_write().

At first, I had a plan to invoke type_attr_remove() with hashtab_map_remove_on_error(), but it means the given policydb structure is modified at policydb_write() and implicit changes to external interface.

Quoted 7 lines

This does not cause a hierarchy error, is this an expected limitation?

typebounds goodbye_world_t hello_world_t;

allow hello_world_t self: file ~{read };

allow goodbye_world_t self: file *;

I'm going to go ahead and merge this with the expectation that the above will get fixed.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#63 lore raw

Re: [PATCH 2/3] Thread/Child-Domain Assignment (rev.2)

In reply to KaiGai Kohei
Quoted 6 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.2.patch
It enables to support TYPEBOUNDS statement and to expand existing hierarchies implicitly.

Merged into checkpolicy-2.0.17

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#91 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to KaiGai Kohei
Quoted 21 lines · KaiGai Kohei
Quoted 11 lines
Quoted 11 lines

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 4 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Quoted 9 lines
Quoted 5 lines

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

It isn't impossible. You are going to have to make it walk to type symbol table to calculate the length without attributes, then write that length instead of the total symtab length.

Quoted 9 lines

The attached patch enables to fixup the number of type/attribute entries to be written. The type_attr_uncount() decrements the number of attribute entries skipped at type_write().

At first, I had a plan to invoke type_attr_remove() with hashtab_map_remove_on_error(), but it means the given policydb structure is modified at policydb_write() and implicit changes to external interface.

Merged in to libsepol-2.0.34

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#90 lore raw

Re: [PATCH 3/3] Thread/Child-Domain Assignment (rev.6)

In reply to Joshua Brindle
Quoted 31 lines · Joshua Brindle
Quoted 20 lines · KaiGai Kohei
Quoted 11 lines
Quoted 11 lines

Hmm....
It seems to me what you pointed out is a bug of my patch. It prevents to deliver actual number of type/attribute symbols to policy file, but it is unclear why does it makes libsepol ignore the policyvers.
(I guess it may be a separated matter.)

Quoted 4 lines

Rather than trying to calculate the length without attributes I just removed the attribute check. This causes attributes to be written for all versions, but this should not cause any problems at all.

Quoted 9 lines
Quoted 5 lines

The reason why I injected such an ad-hoc code is that we cannot decide the policy version written when type_attr_remove() is invoked.
Is it impossible to move it to policydb_write()?
It is invoked after the policyvers is fixed by caller.

It isn't impossible. You are going to have to make it walk to type symbol table to calculate the length without attributes, then write that length instead of the total symtab length.

Quoted 9 lines

The attached patch enables to fixup the number of type/attribute entries to be written. The type_attr_uncount() decrements the number of attribute entries skipped at type_write().

At first, I had a plan to invoke type_attr_remove() with hashtab_map_remove_on_error(), but it means the given policydb structure is modified at policydb_write() and implicit changes to external interface.

Quoted 7 lines

This does not cause a hierarchy error, is this an expected limitation?

typebounds goodbye_world_t hello_world_t;

allow hello_world_t self: file ~{read };

allow goodbye_world_t self: file *;

This case should not cause a hierarchy error.

Please assume a domain "S" is a bounds of "S.sub" and a type "T" is a bounds of "T.sub", and P(x,y) means permissions between "x" and "y".

As you know, the hierarchy constraint has the following rules.
1. P(S.sub, T) is equal or smaller than P(S, T)
2. P(S, T.sub) is equal or smaller than P(S, T)
3. P(S.sub, T.sub) is equal or smaller than P(S, T)
4. rest of permissions are violated.

Your case matches the third rule which should be allowed.

P(hello_world_t, hello_world_t) = file : ~{ read }

is equal or smaller than

P(goodbye_world_t, goodbye_world_t) = file : *

It is an expected behavior, not a limitation.

Thanks,

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#64 lore raw

Re: [PATCH 2/3] Thread/Child-Domain Assignment (rev.2)

In reply to Joshua Brindle
Quoted 9 lines · Joshua Brindle
Quoted 6 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.2.patch
It enables to support TYPEBOUNDS statement and to expand existing hierarchies implicitly.

Merged into checkpolicy-2.0.17

Has the repository completely moved to git now?

If so, is it possible to provide "git://..." connection?

Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#65 lore raw

Re: [PATCH 2/3] Thread/Child-Domain Assignment (rev.2)

Quoted 8 lines · KaiGai Kohei
Quoted 6 lines · Joshua Brindle
Quoted 4 lines · KaiGai Kohei

[2/3] thread-context-checkpolicy.2.patch
It enables to support TYPEBOUNDS statement and to expand existing hierarchies implicitly.

Quoted 9 lines
Quoted 5 lines
Quoted 3 lines

Merged into checkpolicy-2.0.17

Has the repository completely moved to git now?

Yes

Quoted 2 lines

If so, is it possible to provide "git://..." connection?

git clone http://oss.tresys.com/git/selinux.git

http://userspace.selinuxproject.org/trac/wiki/Contributing
<http://userspace.selinuxproject.org/trac/wiki/Contributing>

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#54 lore raw

Re: [LTP][PATCH 2/2] Add a new test case for bounds types

In reply to KaiGai Kohei

Kaigai,

Are these tests ready to be added to LTP ?

Regards--
Subrata

Quoted 457 lines · KaiGai Kohei
Quoted 1 line · James Morris

Could you also please add tests for this (at least one which should

fail

Quoted 4 lines

and one which should succeed) to the Linux Test Project?

- James

The attached patch adds a new test case to check correctness of boundary
feature. It contains four sub tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, even if
the bounded
domain is allowed to write the file.

---- The result of execution
[root@saba tests]# ./runtest.sh bounds /home/kaigai/develop/ltp/testcases/kernel/security/selinux-testsuite/tests Running with security context=unconfined_u:unconfined_r:unconfined_t:SystemLow-SystemHigh 1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 8.6321e-05 s, 11.9 MB/s
All systems go
test01 PASS : thread dyntrans passed.
setcon() on multithread process failed: Operation not permitted All systems go
test02 PASS : thread dyntrans to unbound domain failed.
2+0 records in
2+0 records out
1024 bytes (1.0 kB) copied, 4.2932e-05 s, 23.9 MB/s
test03 PASS : unbounded action to be allowed.
dd: opening `/tmp/selinux/test_file': Permission denied
test04 PASS : bounded action to be denied.
Done.
[root@saba tests]#

(*) I added a bit ad-hoc policy to invoke the script from the shell.

Signature · 20 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>







differences
between files
attachment
(ltp-selinux-bounds-tests.patch)

Index: ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile      (revision 2)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile      (revision 3)
(quoted diff) +0 -0
@@ -3,7 +3,7 @@
 ifeq (redhat-release-4, $(findstring redhat-release-4,
 $(REDHAT_RELEASE)))
     SUBDIRS=domain_trans entrypoint execshare exectrace

execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys
else
- SUBDIRS=domain_trans entrypoint execshare exectrace
execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans
+ SUBDIRS=domain_trans entrypoint execshare exectrace
execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans bounds
endif

all:
Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +4 -0
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008 NEC Corporation
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +38 -0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static int thread_status = 0;
+
+static void *worker(void *datap)
+{
+       security_context_t security_context = datap;
+       int rc;
+
+       rc = setcon(security_context);
+       if (rc < 0) {
+               perror("setcon() on multithread process failed");
+               thread_status = 1;
+       }
+
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       security_context_t security_context;
+       context_t context;
+       pthread_t thread;
+       int rc;
+
+       if (argc != 2) {
+               fprintf(stderr, "usage: %s <new domain>\n", argv[0]);
+               return 1;
+       }
+
+       rc = getcon(&security_context);
+       if (rc < 0) {
+               fprintf(stderr, "%s: unable to get my context\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       context = context_new(security_context);
+       if (!context) {
+               fprintf(stderr, "%s: unable to create context

structure\n", argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +5 -0
+               return 1;
+       }
+
+       if (context_type_set(context, argv[1])) {
+               fprintf(stderr, "%s: unable to set new type\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +7 -0
+               return 1;
+        }
+
+       freecon(security_context);
+       security_context = context_str(context);
+       if (!security_context) {
+               fprintf(stderr, "%s: unable to obtain new context

string\n", argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       rc = pthread_create(&thread, NULL, worker, security_context);
+       if (rc) {
+               fprintf(stderr, "%s: unable to kick a new thread\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       rc = pthread_join(thread, NULL);
+       if (rc) {
+               fprintf(stderr, "%s: unable to join its thread\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       printf("All systems go\n");
+       return thread_status;
+}

Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +5 -0
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 NEC Corporation
+#
+# This program is free software; you can redistribute it and/or

modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +47 -0
+# any later version.
+#
+
+setup()
+{
+       export TCID="setup"
+       export TST_COUNT=0
+       export TST_TOTAL=4
+
+       # Remove any leftover test directories from prior failed runs.
+       rm -rf $SELINUXTMPDIR/test_file
+
+       # Create a test files
+       dd if=/dev/zero of=$SELINUXTMPDIR/test_file count=1 bs=1024
+       chcon -t test_bounds_file_t $SELINUXTMPDIR/test_file
+}
+
+test01()
+{
+       TCID="test01"
+       TST_COUNT=1
+       RC=0
+
+       runcon -t test_bounds_parent_t \
+              -- selinux_bounds_thread test_bounds_child_t 2>&1
+       RC=$?
+       if [ $RC -eq 0 ];
+       then
+               echo "$TCID   PASS : thread dyntrans passed."
+       else
+               echo "$TCID   FAIL : thread dynstrans failed."
+       fi
+       return $RC
+}
+
+test02()
+{
+       TCID="test02"
+       TST_COUND=2
+       RC=0
+
+       runcon -t test_bounds_parent_t \
+              -- selinux_bounds_thread test_bounds_unbound_t 2>&1
+       RC=$?
+       if [ $RC -ne 0 ];       # we expect this to fail
+       then
+               echo "$TCID   PASS : thread dyntrans to unbound domain

failed."

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +3 -0
+               RC=0
+       else
+               echo "$TCID   FAIL : thread dyntrans to unbound domain

succeeded."

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +31 -0
+               RC=1
+       fi
+       return $RC
+}
+
+test03()
+{
+       TCID="test03"
+       TST_COUND=3
+       RC=0
+
+       runcon -t test_bounds_child_t \
+              -- dd if=$SELINUXTMPDIR/test_file of=/dev/null
+       RC=$?
+       if [ $RC -eq 0 ];
+       then
+               echo "$TCID   PASS : unbounded action to be allowed."
+       else
+               echo "$TCID   FAIL : unbounded action to be allowed."
+       fi
+       return $RC
+}
+
+test04()
+{
+       TCID="test04"
+       TST_COUNT=4
+       RC=0
+
+       runcon -t test_bounds_child_t \
+               -- dd if=/dev/zero of=$SELINUXTMPDIR/test_file count=1

bs=1024

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +35 -0
+       RC=$?
+       if [ $RC -ne 0 ];       # we expect this to fail
+       then
+               echo "$TCID   PASS : bounded action to be denied."
+               RC=0
+       else
+               echo "$TCID   FAIL : bounded action to be denied."
+               RC=1
+       fi
+       return $RC
+}
+
+cleanup()
+{
+       # Cleanup
+       rm -rf $SELINUXTMPDIR/test_file
+}
+
+# Function:    main
+#
+# Description: - Execute all tests, exit with test status.
+#
+# Exit:                - zero on success
+#              - non-zero on failure.
+#
+RC=0   # Return value from setup, and test functions.
+EXIT_VAL=0
+
+setup
+test01 || EXIT_VAL=$RC
+test02 || EXIT_VAL=$RC
+test03 || EXIT_VAL=$RC
+test04 || EXIT_VAL=$RC
+cleanup
+exit $EXIT_VAL

Property changes on:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
___________________________________________________________________
Added: svn:executable
+ *

Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +7 -0
@@ -0,0 +1,11 @@
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+LDLIBS += -lselinux -lpthread
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f

$$i ../../../../../bin/$$i; done

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +4 -0
+       ln -f selinux_bounds.sh ../../../../../bin/
+
+clean:
+       rm -f $(TARGETS)
\ No newline at end of file

Index:
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile (revision 2)
+++
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile (revision 3)

testcases/kernel/security/selinux-testsuite/refpolicy/Makefile +1 -1
@@ -1,7 +1,7 @@
 POLICYDEVEL = /usr/share/selinux/devel
 SEMODULE = /usr/sbin/semodule
 
-TARGETS=test_global.te test_capable_file.te test_capable_net.te \
+TARGETS=test_global.te test_bounds.te test_capable_file.te
 test_capable_net.te \
 test_capable_sys.te test_dyntrace.te test_dyntrans.te
 test_entrypoint.te \

test_execshare.te test_exectrace.te test_execute_no_trans.te \
test_fdreceive.te test_file.te test_inherit.te test_ioctl.te
test_ipc.te \
Index:
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te (revision 3)

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +34 -0
@@ -0,0 +1,65 @@
+#################################
+#
+# Policy for testing boundary features
+#
+
+attribute test_bounds_domain;
+
+# Domain for process that allows to other domains
+type test_bounds_parent_t;
+domain_type(test_bounds_parent_t)
+typeattribute test_bounds_parent_t test_bounds_domain;
+typeattribute test_bounds_parent_t testdomain;
+
+# Domain for process that has a bounds type
+type test_bounds_child_t;
+domain_type(test_bounds_child_t)
+typeattribute test_bounds_child_t test_bounds_domain;
+typeattribute test_bounds_child_t testdomain;
+
+# Domain for process that does not have any bounds type
+type test_bounds_unbound_t;
+domain_type(test_bounds_unbound_t)
+typeattribute test_bounds_unbound_t test_bounds_domain;
+typeattribute test_bounds_unbound_t testdomain;
+
+# Types for test files
+type test_bounds_file_t;
+files_type(test_bounds_file_t)
+
+# Definition of boundary relationship
+typebounds test_bounds_parent_t test_bounds_child_t;
+
+# Allow the test_bounds_parent_t to dyntrans
+allow test_bounds_parent_t test_bounds_child_t   : process

{ dyntransition };
+allow test_bounds_parent_t test_bounds_unbound_t : process { dyntransition };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +3 -0
+
+# Allow domains to access test_bounds_file_t
+allow test_bounds_parent_t  test_bounds_file_t : file

{ read_file_perms };
+allow test_bounds_child_t test_bounds_file_t : file
{ rw_file_perms };
+allow test_bounds_unbound_t test_bounds_file_t : file { rw_file_perms };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +22 -0
+
+# Allow execution of helper programs.
+corecmd_exec_bin(test_bounds_domain)
+allow test_bounds_domain bin_t : file { entrypoint };
+libs_use_ld_so(test_bounds_domain)
+libs_use_shared_libs(test_bounds_domain)
+libs_exec_ld_so(test_bounds_domain)
+libs_exec_lib_files(test_bounds_domain)
+
+# Allow all of these domains to be entered from sysadm domain
+miscfiles_domain_entry_test_files(test_bounds_domain)
+sysadm_entry_spec_domtrans(test_bounds_domain)
+
+# Allow to invoke script on targeted policy
+optional_policy(`
+       gen_require(`
+               role unconfined_r;
+               type unconfined_t;
+       ')
+
+       role unconfined_r types test_bounds_domain;
+       allow unconfined_t test_bounds_domain : process

{ transition };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te line 65

Quoted 3 lines
testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +3 -0
+
+       userdom_use_user_terminals(unconfined, test_bounds_domain)
+')

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#55 lore raw

Re: [LTP][PATCH 2/2] Add a new test case for bounds types

Quoted 3 lines · Subrata Modak

Kaigai,

Are these tests ready to be added to LTP ?

I agree to the patch to be added to LTP, if it is acceptable. :)

Please note that the type bounds feature now got merged into Linus's tree, but it is not released officially.
(I guess the v2.6.28 will be released about three months later.)

I'm not good at the policy in LTP' community, so I will support their decision.

Thanks,

Quoted 466 lines

Regards--
Subrata

Quoted 459 lines · KaiGai Kohei
Quoted 1 line · James Morris

Could you also please add tests for this (at least one which should

fail

Quoted 4 lines

and one which should succeed) to the Linux Test Project?

- James

The attached patch adds a new test case to check correctness of boundary
feature. It contains four sub tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, even if
the bounded
domain is allowed to write the file.

---- The result of execution
[root@saba tests]# ./runtest.sh bounds /home/kaigai/develop/ltp/testcases/kernel/security/selinux-testsuite/tests Running with security context=unconfined_u:unconfined_r:unconfined_t:SystemLow-SystemHigh 1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 8.6321e-05 s, 11.9 MB/s
All systems go
test01 PASS : thread dyntrans passed.
setcon() on multithread process failed: Operation not permitted All systems go
test02 PASS : thread dyntrans to unbound domain failed.
2+0 records in
2+0 records out
1024 bytes (1.0 kB) copied, 4.2932e-05 s, 23.9 MB/s
test03 PASS : unbounded action to be allowed.
dd: opening `/tmp/selinux/test_file': Permission denied
test04 PASS : bounded action to be denied.
Done.
[root@saba tests]#

(*) I added a bit ad-hoc policy to invoke the script from the shell.

Signature · 20 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>







differences
between files
attachment
(ltp-selinux-bounds-tests.patch)

Index: ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile      (revision 2)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile      (revision 3)
(quoted diff) +0 -0
@@ -3,7 +3,7 @@
 ifeq (redhat-release-4, $(findstring redhat-release-4,
 $(REDHAT_RELEASE)))
     SUBDIRS=domain_trans entrypoint execshare exectrace

execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys
else
- SUBDIRS=domain_trans entrypoint execshare exectrace
execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans
+ SUBDIRS=domain_trans entrypoint execshare exectrace
execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans bounds
endif

all:
Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +4 -0
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008 NEC Corporation
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +38 -0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static int thread_status = 0;
+
+static void *worker(void *datap)
+{
+       security_context_t security_context = datap;
+       int rc;
+
+       rc = setcon(security_context);
+       if (rc < 0) {
+               perror("setcon() on multithread process failed");
+               thread_status = 1;
+       }
+
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       security_context_t security_context;
+       context_t context;
+       pthread_t thread;
+       int rc;
+
+       if (argc != 2) {
+               fprintf(stderr, "usage: %s <new domain>\n", argv[0]);
+               return 1;
+       }
+
+       rc = getcon(&security_context);
+       if (rc < 0) {
+               fprintf(stderr, "%s: unable to get my context\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       context = context_new(security_context);
+       if (!context) {
+               fprintf(stderr, "%s: unable to create context

structure\n", argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +5 -0
+               return 1;
+       }
+
+       if (context_type_set(context, argv[1])) {
+               fprintf(stderr, "%s: unable to set new type\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +7 -0
+               return 1;
+        }
+
+       freecon(security_context);
+       security_context = context_str(context);
+       if (!security_context) {
+               fprintf(stderr, "%s: unable to obtain new context

string\n", argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       rc = pthread_create(&thread, NULL, worker, security_context);
+       if (rc) {
+               fprintf(stderr, "%s: unable to kick a new thread\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       rc = pthread_join(thread, NULL);
+       if (rc) {
+               fprintf(stderr, "%s: unable to join its thread\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       printf("All systems go\n");
+       return thread_status;
+}

Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +5 -0
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 NEC Corporation
+#
+# This program is free software; you can redistribute it and/or

modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +47 -0
+# any later version.
+#
+
+setup()
+{
+       export TCID="setup"
+       export TST_COUNT=0
+       export TST_TOTAL=4
+
+       # Remove any leftover test directories from prior failed runs.
+       rm -rf $SELINUXTMPDIR/test_file
+
+       # Create a test files
+       dd if=/dev/zero of=$SELINUXTMPDIR/test_file count=1 bs=1024
+       chcon -t test_bounds_file_t $SELINUXTMPDIR/test_file
+}
+
+test01()
+{
+       TCID="test01"
+       TST_COUNT=1
+       RC=0
+
+       runcon -t test_bounds_parent_t \
+              -- selinux_bounds_thread test_bounds_child_t 2>&1
+       RC=$?
+       if [ $RC -eq 0 ];
+       then
+               echo "$TCID   PASS : thread dyntrans passed."
+       else
+               echo "$TCID   FAIL : thread dynstrans failed."
+       fi
+       return $RC
+}
+
+test02()
+{
+       TCID="test02"
+       TST_COUND=2
+       RC=0
+
+       runcon -t test_bounds_parent_t \
+              -- selinux_bounds_thread test_bounds_unbound_t 2>&1
+       RC=$?
+       if [ $RC -ne 0 ];       # we expect this to fail
+       then
+               echo "$TCID   PASS : thread dyntrans to unbound domain

failed."

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +3 -0
+               RC=0
+       else
+               echo "$TCID   FAIL : thread dyntrans to unbound domain

succeeded."

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +31 -0
+               RC=1
+       fi
+       return $RC
+}
+
+test03()
+{
+       TCID="test03"
+       TST_COUND=3
+       RC=0
+
+       runcon -t test_bounds_child_t \
+              -- dd if=$SELINUXTMPDIR/test_file of=/dev/null
+       RC=$?
+       if [ $RC -eq 0 ];
+       then
+               echo "$TCID   PASS : unbounded action to be allowed."
+       else
+               echo "$TCID   FAIL : unbounded action to be allowed."
+       fi
+       return $RC
+}
+
+test04()
+{
+       TCID="test04"
+       TST_COUNT=4
+       RC=0
+
+       runcon -t test_bounds_child_t \
+               -- dd if=/dev/zero of=$SELINUXTMPDIR/test_file count=1

bs=1024

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +35 -0
+       RC=$?
+       if [ $RC -ne 0 ];       # we expect this to fail
+       then
+               echo "$TCID   PASS : bounded action to be denied."
+               RC=0
+       else
+               echo "$TCID   FAIL : bounded action to be denied."
+               RC=1
+       fi
+       return $RC
+}
+
+cleanup()
+{
+       # Cleanup
+       rm -rf $SELINUXTMPDIR/test_file
+}
+
+# Function:    main
+#
+# Description: - Execute all tests, exit with test status.
+#
+# Exit:                - zero on success
+#              - non-zero on failure.
+#
+RC=0   # Return value from setup, and test functions.
+EXIT_VAL=0
+
+setup
+test01 || EXIT_VAL=$RC
+test02 || EXIT_VAL=$RC
+test03 || EXIT_VAL=$RC
+test04 || EXIT_VAL=$RC
+cleanup
+exit $EXIT_VAL

Property changes on:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
___________________________________________________________________
Added: svn:executable
+ *

Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +7 -0
@@ -0,0 +1,11 @@
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+LDLIBS += -lselinux -lpthread
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f

$$i ../../../../../bin/$$i; done

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +4 -0
+       ln -f selinux_bounds.sh ../../../../../bin/
+
+clean:
+       rm -f $(TARGETS)
\ No newline at end of file

Index:
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile (revision 2)
+++
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile (revision 3)

testcases/kernel/security/selinux-testsuite/refpolicy/Makefile +1 -1
@@ -1,7 +1,7 @@
 POLICYDEVEL = /usr/share/selinux/devel
 SEMODULE = /usr/sbin/semodule
 
-TARGETS=test_global.te test_capable_file.te test_capable_net.te \
+TARGETS=test_global.te test_bounds.te test_capable_file.te
 test_capable_net.te \
 test_capable_sys.te test_dyntrace.te test_dyntrans.te
 test_entrypoint.te \

test_execshare.te test_exectrace.te test_execute_no_trans.te \
test_fdreceive.te test_file.te test_inherit.te test_ioctl.te
test_ipc.te \
Index:
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te (revision 3)

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +34 -0
@@ -0,0 +1,65 @@
+#################################
+#
+# Policy for testing boundary features
+#
+
+attribute test_bounds_domain;
+
+# Domain for process that allows to other domains
+type test_bounds_parent_t;
+domain_type(test_bounds_parent_t)
+typeattribute test_bounds_parent_t test_bounds_domain;
+typeattribute test_bounds_parent_t testdomain;
+
+# Domain for process that has a bounds type
+type test_bounds_child_t;
+domain_type(test_bounds_child_t)
+typeattribute test_bounds_child_t test_bounds_domain;
+typeattribute test_bounds_child_t testdomain;
+
+# Domain for process that does not have any bounds type
+type test_bounds_unbound_t;
+domain_type(test_bounds_unbound_t)
+typeattribute test_bounds_unbound_t test_bounds_domain;
+typeattribute test_bounds_unbound_t testdomain;
+
+# Types for test files
+type test_bounds_file_t;
+files_type(test_bounds_file_t)
+
+# Definition of boundary relationship
+typebounds test_bounds_parent_t test_bounds_child_t;
+
+# Allow the test_bounds_parent_t to dyntrans
+allow test_bounds_parent_t test_bounds_child_t   : process

{ dyntransition };
+allow test_bounds_parent_t test_bounds_unbound_t : process { dyntransition };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +3 -0
+
+# Allow domains to access test_bounds_file_t
+allow test_bounds_parent_t  test_bounds_file_t : file

{ read_file_perms };
+allow test_bounds_child_t test_bounds_file_t : file
{ rw_file_perms };
+allow test_bounds_unbound_t test_bounds_file_t : file { rw_file_perms };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +22 -0
+
+# Allow execution of helper programs.
+corecmd_exec_bin(test_bounds_domain)
+allow test_bounds_domain bin_t : file { entrypoint };
+libs_use_ld_so(test_bounds_domain)
+libs_use_shared_libs(test_bounds_domain)
+libs_exec_ld_so(test_bounds_domain)
+libs_exec_lib_files(test_bounds_domain)
+
+# Allow all of these domains to be entered from sysadm domain
+miscfiles_domain_entry_test_files(test_bounds_domain)
+sysadm_entry_spec_domtrans(test_bounds_domain)
+
+# Allow to invoke script on targeted policy
+optional_policy(`
+       gen_require(`
+               role unconfined_r;
+               type unconfined_t;
+       ')
+
+       role unconfined_r types test_bounds_domain;
+       allow unconfined_t test_bounds_domain : process

{ transition };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +3 -0
+
+       userdom_use_user_terminals(unconfined, test_bounds_domain)
+')
Signature · 7 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>

--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.
#56 lore raw

Re: [LTP][PATCH 2/2] Add a new test case for bounds types

Thanks Kaigai.

Quoted 5 lines · KaiGai Kohei
Quoted 3 lines · Subrata Modak

Kaigai,

Are these tests ready to be added to LTP ?

Quoted 7 lines

I agree to the patch to be added to LTP, if it is acceptable. :)

Please note that the type bounds feature now got merged into Linus's tree, but it is not released officially.
(I guess the v2.6.28 will be released about three months later.)

I'm not good at the policy in LTP' community, so I will support their decision.

Well, we started to induct test cases into LTP for which they are still to make it to the Mainline Kernel - something we call as LTP-mm. Since, it is inside Linus´s tree, then it will become part of Mainline soon. So, we can go ahead and add the tests. People can start using it immediately on release of the corresponding feature. Thanks once again.

Regards--
Subrata

Quoted 471 lines

Thanks,

Quoted 466 lines

Regards--
Subrata

Quoted 459 lines · KaiGai Kohei
Quoted 1 line · James Morris

Could you also please add tests for this (at least one which should

fail

Quoted 4 lines

and one which should succeed) to the Linux Test Project?

- James

The attached patch adds a new test case to check correctness of boundary
feature. It contains four sub tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, even if
the bounded
domain is allowed to write the file.

---- The result of execution
[root@saba tests]# ./runtest.sh bounds /home/kaigai/develop/ltp/testcases/kernel/security/selinux-testsuite/tests Running with security context=unconfined_u:unconfined_r:unconfined_t:SystemLow-SystemHigh 1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 8.6321e-05 s, 11.9 MB/s
All systems go
test01 PASS : thread dyntrans passed.
setcon() on multithread process failed: Operation not permitted All systems go
test02 PASS : thread dyntrans to unbound domain failed.
2+0 records in
2+0 records out
1024 bytes (1.0 kB) copied, 4.2932e-05 s, 23.9 MB/s
test03 PASS : unbounded action to be allowed.
dd: opening `/tmp/selinux/test_file': Permission denied
test04 PASS : bounded action to be denied.
Done.
[root@saba tests]#

(*) I added a bit ad-hoc policy to invoke the script from the shell.

Signature · 20 lines
OSS Platform Development Division, NEC
KaiGai Kohei <[email protected]>







differences
between files
attachment
(ltp-selinux-bounds-tests.patch)

Index: ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile      (revision 2)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/Makefile      (revision 3)
(quoted diff) +0 -0
@@ -3,7 +3,7 @@
 ifeq (redhat-release-4, $(findstring redhat-release-4,
 $(REDHAT_RELEASE)))
     SUBDIRS=domain_trans entrypoint execshare exectrace

execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys
else
- SUBDIRS=domain_trans entrypoint execshare exectrace
execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans
+ SUBDIRS=domain_trans entrypoint execshare exectrace
execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys dyntrace dyntrans bounds
endif

all:
Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +4 -0
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008 NEC Corporation
+ *
+ * This program is free software; you can redistribute it and/or

modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +38 -0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static int thread_status = 0;
+
+static void *worker(void *datap)
+{
+       security_context_t security_context = datap;
+       int rc;
+
+       rc = setcon(security_context);
+       if (rc < 0) {
+               perror("setcon() on multithread process failed");
+               thread_status = 1;
+       }
+
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       security_context_t security_context;
+       context_t context;
+       pthread_t thread;
+       int rc;
+
+       if (argc != 2) {
+               fprintf(stderr, "usage: %s <new domain>\n", argv[0]);
+               return 1;
+       }
+
+       rc = getcon(&security_context);
+       if (rc < 0) {
+               fprintf(stderr, "%s: unable to get my context\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       context = context_new(security_context);
+       if (!context) {
+               fprintf(stderr, "%s: unable to create context

structure\n", argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +5 -0
+               return 1;
+       }
+
+       if (context_type_set(context, argv[1])) {
+               fprintf(stderr, "%s: unable to set new type\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +7 -0
+               return 1;
+        }
+
+       freecon(security_context);
+       security_context = context_str(context);
+       if (!security_context) {
+               fprintf(stderr, "%s: unable to obtain new context

string\n", argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       rc = pthread_create(&thread, NULL, worker, security_context);
+       if (rc) {
+               fprintf(stderr, "%s: unable to kick a new thread\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       rc = pthread_join(thread, NULL);
+       if (rc) {
+               fprintf(stderr, "%s: unable to join its thread\n",

argv[0]);

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds_thread.c +6 -0
+               return 1;
+       }
+
+       printf("All systems go\n");
+       return thread_status;
+}

Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +5 -0
@@ -0,0 +1,123 @@
+#!/bin/sh
+#
+# Copyright (c) 2008 NEC Corporation
+#
+# This program is free software; you can redistribute it and/or

modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +47 -0
+# any later version.
+#
+
+setup()
+{
+       export TCID="setup"
+       export TST_COUNT=0
+       export TST_TOTAL=4
+
+       # Remove any leftover test directories from prior failed runs.
+       rm -rf $SELINUXTMPDIR/test_file
+
+       # Create a test files
+       dd if=/dev/zero of=$SELINUXTMPDIR/test_file count=1 bs=1024
+       chcon -t test_bounds_file_t $SELINUXTMPDIR/test_file
+}
+
+test01()
+{
+       TCID="test01"
+       TST_COUNT=1
+       RC=0
+
+       runcon -t test_bounds_parent_t \
+              -- selinux_bounds_thread test_bounds_child_t 2>&1
+       RC=$?
+       if [ $RC -eq 0 ];
+       then
+               echo "$TCID   PASS : thread dyntrans passed."
+       else
+               echo "$TCID   FAIL : thread dynstrans failed."
+       fi
+       return $RC
+}
+
+test02()
+{
+       TCID="test02"
+       TST_COUND=2
+       RC=0
+
+       runcon -t test_bounds_parent_t \
+              -- selinux_bounds_thread test_bounds_unbound_t 2>&1
+       RC=$?
+       if [ $RC -ne 0 ];       # we expect this to fail
+       then
+               echo "$TCID   PASS : thread dyntrans to unbound domain

failed."

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +3 -0
+               RC=0
+       else
+               echo "$TCID   FAIL : thread dyntrans to unbound domain

succeeded."

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +31 -0
+               RC=1
+       fi
+       return $RC
+}
+
+test03()
+{
+       TCID="test03"
+       TST_COUND=3
+       RC=0
+
+       runcon -t test_bounds_child_t \
+              -- dd if=$SELINUXTMPDIR/test_file of=/dev/null
+       RC=$?
+       if [ $RC -eq 0 ];
+       then
+               echo "$TCID   PASS : unbounded action to be allowed."
+       else
+               echo "$TCID   FAIL : unbounded action to be allowed."
+       fi
+       return $RC
+}
+
+test04()
+{
+       TCID="test04"
+       TST_COUNT=4
+       RC=0
+
+       runcon -t test_bounds_child_t \
+               -- dd if=/dev/zero of=$SELINUXTMPDIR/test_file count=1

bs=1024

testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh +35 -0
+       RC=$?
+       if [ $RC -ne 0 ];       # we expect this to fail
+       then
+               echo "$TCID   PASS : bounded action to be denied."
+               RC=0
+       else
+               echo "$TCID   FAIL : bounded action to be denied."
+               RC=1
+       fi
+       return $RC
+}
+
+cleanup()
+{
+       # Cleanup
+       rm -rf $SELINUXTMPDIR/test_file
+}
+
+# Function:    main
+#
+# Description: - Execute all tests, exit with test status.
+#
+# Exit:                - zero on success
+#              - non-zero on failure.
+#
+RC=0   # Return value from setup, and test functions.
+EXIT_VAL=0
+
+setup
+test01 || EXIT_VAL=$RC
+test02 || EXIT_VAL=$RC
+test03 || EXIT_VAL=$RC
+test04 || EXIT_VAL=$RC
+cleanup
+exit $EXIT_VAL

Property changes on:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/selinux_bounds.sh
___________________________________________________________________
Added: svn:executable
+ *

Index:
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile (revision 3)

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +7 -0
@@ -0,0 +1,11 @@
+TARGETS=$(patsubst %.c,%,$(wildcard *.c))
+LDLIBS += -lselinux -lpthread
+
+all: $(TARGETS)
+
+install:
+       @set -e; for i in $(TARGETS); do ln -f

$$i ../../../../../bin/$$i; done

testcases/kernel/security/selinux-testsuite/tests/bounds/Makefile +4 -0
+       ln -f selinux_bounds.sh ../../../../../bin/
+
+clean:
+       rm -f $(TARGETS)
\ No newline at end of file

Index:
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile (revision 2)
+++
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/Makefile (revision 3)

testcases/kernel/security/selinux-testsuite/refpolicy/Makefile +1 -1
@@ -1,7 +1,7 @@
 POLICYDEVEL = /usr/share/selinux/devel
 SEMODULE = /usr/sbin/semodule
 
-TARGETS=test_global.te test_capable_file.te test_capable_net.te \
+TARGETS=test_global.te test_bounds.te test_capable_file.te
 test_capable_net.te \
 test_capable_sys.te test_dyntrace.te test_dyntrans.te
 test_entrypoint.te \

test_execshare.te test_exectrace.te test_execute_no_trans.te \
test_fdreceive.te test_file.te test_inherit.te test_ioctl.te
test_ipc.te \
Index:
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te
===================================================================
---
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te (revision 0)
+++
ltp/testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te (revision 3)

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +34 -0
@@ -0,0 +1,65 @@
+#################################
+#
+# Policy for testing boundary features
+#
+
+attribute test_bounds_domain;
+
+# Domain for process that allows to other domains
+type test_bounds_parent_t;
+domain_type(test_bounds_parent_t)
+typeattribute test_bounds_parent_t test_bounds_domain;
+typeattribute test_bounds_parent_t testdomain;
+
+# Domain for process that has a bounds type
+type test_bounds_child_t;
+domain_type(test_bounds_child_t)
+typeattribute test_bounds_child_t test_bounds_domain;
+typeattribute test_bounds_child_t testdomain;
+
+# Domain for process that does not have any bounds type
+type test_bounds_unbound_t;
+domain_type(test_bounds_unbound_t)
+typeattribute test_bounds_unbound_t test_bounds_domain;
+typeattribute test_bounds_unbound_t testdomain;
+
+# Types for test files
+type test_bounds_file_t;
+files_type(test_bounds_file_t)
+
+# Definition of boundary relationship
+typebounds test_bounds_parent_t test_bounds_child_t;
+
+# Allow the test_bounds_parent_t to dyntrans
+allow test_bounds_parent_t test_bounds_child_t   : process

{ dyntransition };
+allow test_bounds_parent_t test_bounds_unbound_t : process { dyntransition };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +3 -0
+
+# Allow domains to access test_bounds_file_t
+allow test_bounds_parent_t  test_bounds_file_t : file

{ read_file_perms };
+allow test_bounds_child_t test_bounds_file_t : file
{ rw_file_perms };
+allow test_bounds_unbound_t test_bounds_file_t : file { rw_file_perms };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +22 -0
+
+# Allow execution of helper programs.
+corecmd_exec_bin(test_bounds_domain)
+allow test_bounds_domain bin_t : file { entrypoint };
+libs_use_ld_so(test_bounds_domain)
+libs_use_shared_libs(test_bounds_domain)
+libs_exec_ld_so(test_bounds_domain)
+libs_exec_lib_files(test_bounds_domain)
+
+# Allow all of these domains to be entered from sysadm domain
+miscfiles_domain_entry_test_files(test_bounds_domain)
+sysadm_entry_spec_domtrans(test_bounds_domain)
+
+# Allow to invoke script on targeted policy
+optional_policy(`
+       gen_require(`
+               role unconfined_r;
+               type unconfined_t;
+       ')
+
+       role unconfined_r types test_bounds_domain;
+       allow unconfined_t test_bounds_domain : process

{ transition };

testcases/kernel/security/selinux-testsuite/refpolicy/test_bounds.te +3 -0
+
+       userdom_use_user_terminals(unconfined, test_bounds_domain)
+')

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.

#52 lore raw

Re: [LTP][PATCH 1/2] Replacement of deprecated interfaces

In reply to KaiGai Kohei
Quoted 47 lines · KaiGai Kohei
Quoted 10 lines · Stephen Smalley
Quoted 9 lines · KaiGai Kohei
Quoted 5 lines · James Morris

Could you also please add tests for this (at least one which should fail and one which should succeed) to the Linux Test Project?

- James

Policies stored in ltp/testcases/kernel/security/selinux-testsuite/refpolicy/ invokes massive deprecated interfaces on selinux-policy-3.5.4.

Quoted 8 lines
Quoted 5 lines

This patch fixes them according to the warning messages which encourage to replace older ones.

BTW, I'm not happy with the test_policy.pp does not allow to invoke test scripts from unconfined_t domain. Is it to be fixed?

I don't quite follow. Did you follow the instructions in the selinux-testsuite README?

I didn't read the README file carefully, Oops.

The update_refpolicy.sh fixes some of deprecated interfaces and inject an interface to kick test script from unconfined domain. So, I can run the testsuite which includs bounds test without any problems on Rawhide.

# However, I got some warnings for deprecated interfaces/macros

# like r_dir_perms, userdom_sysadm_bin_spec_domtrans_to or
# userdom_use_sysadm_ptys.

The attached patch is a new test case of the boundary feature, which contains six tests, as follows:

test01: It tries to invoke setcon() with bounded domain in a multi-threaded
process. The expected result is success.
test02: It tries to invoke setcon() with unrelated domain in a multi-threaded
process. The expected result is fail.
test03: It makes a bounded domain try to read a file, when its bounds domain
can read the file. The expected result is success.
test04: It makes a bounded domain try to write a file, when its bounds domain
cannot write the file. The expected result is fail, because write permission is boundary violated.
test05: It tries to write a bounded type, even if the domain cannot write to
its bounds type. The expected result is fail.
test06: It makes a bounded domain try to set an attribute of bounded type.

Quoted 2 lines

Thanks,

Thanks too. Added.

Regards--
Subrata

Quoted 7 lines
Quoted 6 lines

I can run the test scripts either using the
test_selinux.sh script or by manually loading the policy and then individually running them as described in the README. Watch out that your patch doesn't disturb the existing misc/sbin_deprecated.patch that gets applied by test_selinux.sh. Keep in mind that this testsuite gets run on everything from RHEL4 to F9.

--
This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to [email protected] with the words "unsubscribe selinux" without quotes as the message.