* problem with capabilities inheritance and auditing in python
@ 2009-02-05 17:08 Xavier Toth
2009-02-05 18:10 ` Stephen Smalley
0 siblings, 1 reply; 21+ messages in thread
From: Xavier Toth @ 2009-02-05 17:08 UTC (permalink / raw)
To: SELinux List
I've set the capabilities on a script that runs some python code with
auditing calls in it but I'm not getting audit records written to the
audit log. From what I've read I thought the +i would all the
capability to be inherited across execve but this doesn't appear to be
the case. Can anyone help me understand what's going wrong here? Is
there a way in the python code to get the capabilities to see if
indeed cap_audit_write was inherited?
sudo /usr/sbin/setcap cap_audit_write+pei audit_test
-------------------------------------------------------- audit_test
-----------------------------------------------------------------------
#!/bin/sh
/usr/bin/python2 audit_test.py
--------------------------------------------------------
audit_test.py -------------------------------------------------------------------
import audit
import traceback
import errno
import sys, os
def test():
msg = "foo"
try:
audit_fd = audit.audit_open()
if audit_fd < 0:
print("Error connecting to audit daemon")
sys.exit(1)
except:
print("Failed to connecting to audit daemon: %s : %s" % (
sys.exc_info()[0], traceback.format_exc()))
sys.exit(1)
hostname = 'unknown'
hostaddr = 'unknown'
ttyname = 'unknown'
try:
hostname = socket.gethostname()
try:
hostaddr = socket.gethostbyname(hostname)
except:
hostaddr = 'unknown'
except:
hostname = 'unknown'
try:
ttyname = os.readlink('/proc/self/fd/0')
if ttyname.find('/dev') != 0:
ttyname = 'notatty'
except:
ttyname = 'unknown'
try:
print "call audit_log_user_message"
rc = audit.audit_log_user_message(audit_fd,
audit.AUDIT_LABEL_LEVEL_CHANGE, msg, hostname, hostaddr, ttyname, 0);
rc = audit.audit_log_user_message(audit_fd,
audit.AUDIT_TRUSTED_APP, msg, hostname, hostaddr, ttyname, 0);
if rc < 0:
print("Error writing to audit")
sys.exit(1)
except:
print("Failed to write audit: %s : %s" % ( sys.exc_info()[0],
traceback.format_exc()))
sys.exit(1)
if __name__ == '__main__':
test()
--------------------------------------------------------------------------------------------------------------------------------------------------------
Ted
--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with
the words "unsubscribe selinux" without quotes as the message.
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: problem with capabilities inheritance and auditing in python 2009-02-05 17:08 problem with capabilities inheritance and auditing in python Xavier Toth @ 2009-02-05 18:10 ` Stephen Smalley 2009-02-06 21:56 ` Xavier Toth 0 siblings, 1 reply; 21+ messages in thread From: Stephen Smalley @ 2009-02-05 18:10 UTC (permalink / raw) To: Xavier Toth; +Cc: SELinux List On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: > I've set the capabilities on a script that runs some python code with > auditing calls in it but I'm not getting audit records written to the > audit log. From what I've read I thought the +i would all the > capability to be inherited across execve but this doesn't appear to be > the case. Can anyone help me understand what's going wrong here? Is > there a way in the python code to get the capabilities to see if > indeed cap_audit_write was inherited? Linux doesn't honor setuid on scripts, and file capabilities are supposed to have the same behavior (they didn't for a while due to an oversight, but that was corrected). You need an executable wrapper program that invokes the script, like: http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-05 18:10 ` Stephen Smalley @ 2009-02-06 21:56 ` Xavier Toth 2009-02-09 14:02 ` Stephen Smalley 0 siblings, 1 reply; 21+ messages in thread From: Xavier Toth @ 2009-02-06 21:56 UTC (permalink / raw) To: Stephen Smalley; +Cc: SELinux List On Thu, Feb 5, 2009 at 12:10 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: >> I've set the capabilities on a script that runs some python code with >> auditing calls in it but I'm not getting audit records written to the >> audit log. From what I've read I thought the +i would all the >> capability to be inherited across execve but this doesn't appear to be >> the case. Can anyone help me understand what's going wrong here? Is >> there a way in the python code to get the capabilities to see if >> indeed cap_audit_write was inherited? > > Linux doesn't honor setuid on scripts, and file capabilities are > supposed to have the same behavior (they didn't for a while due to an > oversight, but that was corrected). You need an executable wrapper > program that invokes the script, like: > http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c > > -- > Stephen Smalley > National Security Agency > > Having used this wrapper code pretty much as is I'm now seeing self:capability dac_override and dac_read_search AVCs. Do I need to do something similar to what newrole does to drop capabilities that I don't need my python script to have after all I'm only trying to give it the ability to audit? Ted -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-06 21:56 ` Xavier Toth @ 2009-02-09 14:02 ` Stephen Smalley 2009-02-09 16:42 ` Xavier Toth 0 siblings, 1 reply; 21+ messages in thread From: Stephen Smalley @ 2009-02-09 14:02 UTC (permalink / raw) To: Xavier Toth; +Cc: SELinux List On Fri, 2009-02-06 at 15:56 -0600, Xavier Toth wrote: > On Thu, Feb 5, 2009 at 12:10 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: > >> I've set the capabilities on a script that runs some python code with > >> auditing calls in it but I'm not getting audit records written to the > >> audit log. From what I've read I thought the +i would all the > >> capability to be inherited across execve but this doesn't appear to be > >> the case. Can anyone help me understand what's going wrong here? Is > >> there a way in the python code to get the capabilities to see if > >> indeed cap_audit_write was inherited? > > > > Linux doesn't honor setuid on scripts, and file capabilities are > > supposed to have the same behavior (they didn't for a while due to an > > oversight, but that was corrected). You need an executable wrapper > > program that invokes the script, like: > > http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c > > > > -- > > Stephen Smalley > > National Security Agency > > > > > > Having used this wrapper code pretty much as is I'm now seeing > self:capability dac_override and dac_read_search AVCs. Do I need to do > something similar to what newrole does to drop capabilities that I > don't need my python script to have after all I'm only trying to give > it the ability to audit? You can just dontaudit those denials if you don't need those capabilities. -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-09 14:02 ` Stephen Smalley @ 2009-02-09 16:42 ` Xavier Toth 2009-02-09 20:17 ` Stephen Smalley 0 siblings, 1 reply; 21+ messages in thread From: Xavier Toth @ 2009-02-09 16:42 UTC (permalink / raw) To: Stephen Smalley; +Cc: SELinux List On Mon, Feb 9, 2009 at 8:02 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > On Fri, 2009-02-06 at 15:56 -0600, Xavier Toth wrote: >> On Thu, Feb 5, 2009 at 12:10 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: >> > On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: >> >> I've set the capabilities on a script that runs some python code with >> >> auditing calls in it but I'm not getting audit records written to the >> >> audit log. From what I've read I thought the +i would all the >> >> capability to be inherited across execve but this doesn't appear to be >> >> the case. Can anyone help me understand what's going wrong here? Is >> >> there a way in the python code to get the capabilities to see if >> >> indeed cap_audit_write was inherited? >> > >> > Linux doesn't honor setuid on scripts, and file capabilities are >> > supposed to have the same behavior (they didn't for a while due to an >> > oversight, but that was corrected). You need an executable wrapper >> > program that invokes the script, like: >> > http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c >> > >> > -- >> > Stephen Smalley >> > National Security Agency >> > >> > >> >> Having used this wrapper code pretty much as is I'm now seeing >> self:capability dac_override and dac_read_search AVCs. Do I need to do >> something similar to what newrole does to drop capabilities that I >> don't need my python script to have after all I'm only trying to give >> it the ability to audit? > > You can just dontaudit those denials if you don't need those > capabilities. > > -- > Stephen Smalley > National Security Agency > > Unfortunately python doesn't survive the dac_read_search AVC. I also tried removing the setreuid/setregid calls, doing a setcap cap_audit_write=ep on the wrapper and not running the wrapper as setuid but that doesn't work. Ted -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-09 16:42 ` Xavier Toth @ 2009-02-09 20:17 ` Stephen Smalley 2009-02-09 20:42 ` Serge E. Hallyn 0 siblings, 1 reply; 21+ messages in thread From: Stephen Smalley @ 2009-02-09 20:17 UTC (permalink / raw) To: Xavier Toth; +Cc: SELinux List, Serge E. Hallyn On Mon, 2009-02-09 at 10:42 -0600, Xavier Toth wrote: > On Mon, Feb 9, 2009 at 8:02 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > On Fri, 2009-02-06 at 15:56 -0600, Xavier Toth wrote: > >> On Thu, Feb 5, 2009 at 12:10 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > >> > On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: > >> >> I've set the capabilities on a script that runs some python code with > >> >> auditing calls in it but I'm not getting audit records written to the > >> >> audit log. From what I've read I thought the +i would all the > >> >> capability to be inherited across execve but this doesn't appear to be > >> >> the case. Can anyone help me understand what's going wrong here? Is > >> >> there a way in the python code to get the capabilities to see if > >> >> indeed cap_audit_write was inherited? > >> > > >> > Linux doesn't honor setuid on scripts, and file capabilities are > >> > supposed to have the same behavior (they didn't for a while due to an > >> > oversight, but that was corrected). You need an executable wrapper > >> > program that invokes the script, like: > >> > http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c > >> > > >> > -- > >> > Stephen Smalley > >> > National Security Agency > >> > > >> > > >> > >> Having used this wrapper code pretty much as is I'm now seeing > >> self:capability dac_override and dac_read_search AVCs. Do I need to do > >> something similar to what newrole does to drop capabilities that I > >> don't need my python script to have after all I'm only trying to give > >> it the ability to audit? > > > > You can just dontaudit those denials if you don't need those > > capabilities. > > > > -- > > Stephen Smalley > > National Security Agency > > > > > > Unfortunately python doesn't survive the dac_read_search AVC. I also > tried removing the setreuid/setregid calls, doing a setcap > cap_audit_write=ep on the wrapper and not running the wrapper as > setuid but that doesn't work. So what is it trying to access (enable syscall auditing with at least one audit syscall filter defined so the kernel will collect PATH records for you and emit them after any AVC denials)? On the separate question of capability inheritance on exec of a script from a wrapper with file capabilities, I'll defer to Serge. -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-09 20:17 ` Stephen Smalley @ 2009-02-09 20:42 ` Serge E. Hallyn 2009-02-10 17:00 ` Xavier Toth 0 siblings, 1 reply; 21+ messages in thread From: Serge E. Hallyn @ 2009-02-09 20:42 UTC (permalink / raw) To: Stephen Smalley; +Cc: Xavier Toth, SELinux List Quoting Stephen Smalley (sds@tycho.nsa.gov): > On Mon, 2009-02-09 at 10:42 -0600, Xavier Toth wrote: > > On Mon, Feb 9, 2009 at 8:02 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > > On Fri, 2009-02-06 at 15:56 -0600, Xavier Toth wrote: > > >> On Thu, Feb 5, 2009 at 12:10 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > >> > On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: > > >> >> I've set the capabilities on a script that runs some python code with > > >> >> auditing calls in it but I'm not getting audit records written to the > > >> >> audit log. From what I've read I thought the +i would all the > > >> >> capability to be inherited across execve but this doesn't appear to be > > >> >> the case. Can anyone help me understand what's going wrong here? Is > > >> >> there a way in the python code to get the capabilities to see if > > >> >> indeed cap_audit_write was inherited? > > >> > > > >> > Linux doesn't honor setuid on scripts, and file capabilities are > > >> > supposed to have the same behavior (they didn't for a while due to an > > >> > oversight, but that was corrected). You need an executable wrapper > > >> > program that invokes the script, like: > > >> > http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c > > >> > > > >> > -- > > >> > Stephen Smalley > > >> > National Security Agency > > >> > > > >> > > > >> > > >> Having used this wrapper code pretty much as is I'm now seeing > > >> self:capability dac_override and dac_read_search AVCs. Do I need to do > > >> something similar to what newrole does to drop capabilities that I > > >> don't need my python script to have after all I'm only trying to give > > >> it the ability to audit? > > > > > > You can just dontaudit those denials if you don't need those > > > capabilities. > > > > > > -- > > > Stephen Smalley > > > National Security Agency > > > > > > > > > > Unfortunately python doesn't survive the dac_read_search AVC. I also > > tried removing the setreuid/setregid calls, doing a setcap > > cap_audit_write=ep on the wrapper and not running the wrapper as > > setuid but that doesn't work. > > So what is it trying to access (enable syscall auditing with at least > one audit syscall filter defined so the kernel will collect PATH records > for you and emit them after any AVC denials)? > > On the separate question of capability inheritance on exec of a script > from a wrapper with file capabilities, I'll defer to Serge. Right, file capabilities on scripts are disregarded. So things to do would include: 1. set capabilities on the interpreter (in which case you'll likely want to make sure the interpreter can't be called by anyone else) 2. keep capabilities in pI, and place capabilities in fI (and if you must fE) on all of the compiled programs called by the script. 3. Make the whole thing a compiled program... -serge -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-09 20:42 ` Serge E. Hallyn @ 2009-02-10 17:00 ` Xavier Toth 2009-02-10 18:34 ` Serge E. Hallyn 0 siblings, 1 reply; 21+ messages in thread From: Xavier Toth @ 2009-02-10 17:00 UTC (permalink / raw) To: Serge E. Hallyn; +Cc: Stephen Smalley, SELinux List On Mon, Feb 9, 2009 at 2:42 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > Quoting Stephen Smalley (sds@tycho.nsa.gov): >> On Mon, 2009-02-09 at 10:42 -0600, Xavier Toth wrote: >> > On Mon, Feb 9, 2009 at 8:02 AM, Stephen Smalley <sds@tycho.nsa.gov> wrote: >> > > On Fri, 2009-02-06 at 15:56 -0600, Xavier Toth wrote: >> > >> On Thu, Feb 5, 2009 at 12:10 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: >> > >> > On Thu, 2009-02-05 at 11:08 -0600, Xavier Toth wrote: >> > >> >> I've set the capabilities on a script that runs some python code with >> > >> >> auditing calls in it but I'm not getting audit records written to the >> > >> >> audit log. From what I've read I thought the +i would all the >> > >> >> capability to be inherited across execve but this doesn't appear to be >> > >> >> the case. Can anyone help me understand what's going wrong here? Is >> > >> >> there a way in the python code to get the capabilities to see if >> > >> >> indeed cap_audit_write was inherited? >> > >> > >> > >> > Linux doesn't honor setuid on scripts, and file capabilities are >> > >> > supposed to have the same behavior (they didn't for a while due to an >> > >> > oversight, but that was corrected). You need an executable wrapper >> > >> > program that invokes the script, like: >> > >> > http://oss.tresys.com/projects/clip/browser/trunk/RHEL5.2/scripts/wrappers/wrapper.c >> > >> > >> > >> > -- >> > >> > Stephen Smalley >> > >> > National Security Agency >> > >> > >> > >> > >> > >> >> > >> Having used this wrapper code pretty much as is I'm now seeing >> > >> self:capability dac_override and dac_read_search AVCs. Do I need to do >> > >> something similar to what newrole does to drop capabilities that I >> > >> don't need my python script to have after all I'm only trying to give >> > >> it the ability to audit? >> > > >> > > You can just dontaudit those denials if you don't need those >> > > capabilities. >> > > >> > > -- >> > > Stephen Smalley >> > > National Security Agency >> > > >> > > >> > >> > Unfortunately python doesn't survive the dac_read_search AVC. I also >> > tried removing the setreuid/setregid calls, doing a setcap >> > cap_audit_write=ep on the wrapper and not running the wrapper as >> > setuid but that doesn't work. >> >> So what is it trying to access (enable syscall auditing with at least >> one audit syscall filter defined so the kernel will collect PATH records >> for you and emit them after any AVC denials)? >> >> On the separate question of capability inheritance on exec of a script >> from a wrapper with file capabilities, I'll defer to Serge. > > Right, file capabilities on scripts are disregarded. So things to do > would include: > > 1. set capabilities on the interpreter (in which case you'll likely > want to make sure the interpreter can't be called by anyone else) > > 2. keep capabilities in pI, and place capabilities in fI (and if you > must fE) on all of the compiled programs called by the script. > > 3. Make the whole thing a compiled program... > > -serge > I was not putting capabilities on the script but rather on a compiled wrapper which execs a python script in which I need to do auditing. Will this not work? Ted -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 17:00 ` Xavier Toth @ 2009-02-10 18:34 ` Serge E. Hallyn 2009-02-10 20:20 ` Xavier Toth 0 siblings, 1 reply; 21+ messages in thread From: Serge E. Hallyn @ 2009-02-10 18:34 UTC (permalink / raw) To: Xavier Toth; +Cc: Stephen Smalley, SELinux List Quoting Xavier Toth (txtoth@gmail.com): > I was not putting capabilities on the script but rather on a compiled > wrapper which execs a python script in which I need to do auditing. > Will this not work? No, because of the way capabilities are re-calculated on exec(). pI' = pI pP' = (X&fP) | (pI & fI) pE' = fE ? pP' : 0 So since the interpreter has fI=fP=fE=0 and is not setuid root (which would fill in fP and/or fE to emulate privileged root), pP' and pE' will be empty after exec(). Now you could use a wrapper as follows: Have the wrapper fill pI, and then fill fI on the python interpreter. Any user who has an empty pI (which generally is all users) will execute python scripts with no privilege, but when the wrapper execs the script, pP' will be filled with (pI&fI) = full. -serge -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 18:34 ` Serge E. Hallyn @ 2009-02-10 20:20 ` Xavier Toth 2009-02-10 20:33 ` Stephen Smalley 2009-02-10 21:25 ` Stephen Smalley 0 siblings, 2 replies; 21+ messages in thread From: Xavier Toth @ 2009-02-10 20:20 UTC (permalink / raw) To: Serge E. Hallyn; +Cc: Stephen Smalley, SELinux List On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > Quoting Xavier Toth (txtoth@gmail.com): >> I was not putting capabilities on the script but rather on a compiled >> wrapper which execs a python script in which I need to do auditing. >> Will this not work? > > No, because of the way capabilities are re-calculated on exec(). > > pI' = pI > pP' = (X&fP) | (pI & fI) > pE' = fE ? pP' : 0 > > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > be empty after exec(). > > Now you could use a wrapper as follows: Have the wrapper fill pI, > and then fill fI on the python interpreter. Any user who has an > empty pI (which generally is all users) will execute python scripts > with no privilege, but when the wrapper execs the script, pP' will > be filled with (pI&fI) = full. > > -serge > Thanks for the clarification. For anyone one that is interested I've included some test code. The wrapper is a modified version of a wrapper Stephen sent me a link to. Basic steps to test are: 1) edit the wrapper to set the path to the audit_test.py script 2) compiler the wrapper gcc -o audit-wrapper audit-wrapper.c -lcap 3) set the capabilities on the wrapper and python setcap cap_audit_write,cap_setfcap=epi audit-wrapper setcap cap_audit_write=ei /usr/bin/python 4) run audit-wrapper 5) check audit log for audit records. I also ran audit_test.py without the wrapper to verify that no audit would occur. Ted ------------------------------------------------------------------------------ audit-wrapper.c ------------------------------------------------------------------------ /* ------------------------------------------------------------------------- Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, The Netherlands. All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the names of Stichting Mathematisch Centrum or CWI or Corporation for National Research Initiatives or CNRI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. While CWI is the initial source for this software, a modified version is made available by the Corporation for National Research Initiatives (CNRI) at the Internet address ftp://ftp.python.org. STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ------------------------------------------------------------------------- Template for a setuid program that calls a script. The script should be in an unwritable directory and should itself be unwritable. In fact all parent directories up to the root should be unwritable. The script must not be setuid, that's what this program is for. This is a template program. You need to fill in the name of the script that must be executed. This is done by changing the definition of FULL_PATH below. There are also some rules that should be adhered to when writing the script itself. The first and most important rule is to never, ever trust that the user of the program will behave properly. Program defensively. Check your arguments for reasonableness. If the user is allowed to create files, check the names of the files. If the program depends on argv[0] for the action it should perform, check it. Assuming the script is a Bourne shell script, the first line of the script should be #!/bin/sh - The - is important, don't omit it. If you're using esh, the first line should be #!/usr/local/bin/esh -f and for ksh, the first line should be #!/usr/local/bin/ksh -p The script should then set the variable IFS to the string consisting of <space>, <tab>, and <newline>. After this (*not* before!), the PATH variable should be set to a reasonable value and exported. Do not expect the PATH to have a reasonable value, so do not trust the old value of PATH. You should then set the umask of the program by calling umask 077 # or 022 if you want the files to be readable If you plan to change directories, you should either unset CDPATH or set it to a good value. Setting CDPATH to just ``.'' (dot) is a good idea. If, for some reason, you want to use csh, the first line should be #!/bin/csh -fb You should then set the path variable to something reasonable, without trusting the inherited path. Here too, you should set the umask using the command umask 077 # or 022 if you want the files to be readable */ #define _GNU_SOURCE #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <sys/capability.h> /* CONFIGURATION SECTION */ #ifndef FULL_PATH /* so that this can be specified from the Makefile */ /* Uncomment the following line: */ #define FULL_PATH "<your path to>/audit_test.py" /* Then comment out the #error line. #error "You must define FULL_PATH somewhere" */ #endif #ifndef UMASK #define UMASK 077 #endif /* END OF CONFIGURATION SECTION */ #if defined(__STDC__) && defined(__sgi) #define environ _environ #endif /* don't change def_IFS */ char def_IFS[] = "IFS= \t\n"; /* you may want to change def_PATH, but you should really change it in */ /* your script */ #ifdef __sgi char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin"; #else char def_PATH[] = "PATH=/usr/bin:/bin:/usr/local/bin"; #endif /* don't change def_CDPATH */ char def_CDPATH[] = "CDPATH=."; /* don't change def_ENV */ char def_ENV[] = "ENV=:"; /* This function changes all environment variables that start with LD_ into variables that start with XD_. This is important since we don't want the script that is executed to use any funny shared libraries. The other changes to the environment are, strictly speaking, not needed here. They can safely be done in the script. They are done here because we don't trust the script writer (just like the script writer shouldn't trust the user of the script). If IFS is set in the environment, set it to space,tab,newline. If CDPATH is set in the environment, set it to ``.''. Set PATH to a reasonable default. */ void clean_environ(void) { char **p; extern char **environ; for (p = environ; *p; p++) { if (strncmp(*p, "LD_", 3) == 0) **p = 'X'; else if (strncmp(*p, "_RLD", 4) == 0) **p = 'X'; else if (strncmp(*p, "PYTHON", 6) == 0) **p = 'X'; else if (strncmp(*p, "PERL", 4) == 0) **p = 'X'; else if (strncmp(*p, "IFS=", 4) == 0) *p = def_IFS; else if (strncmp(*p, "CDPATH=", 7) == 0) *p = def_CDPATH; else if (strncmp(*p, "ENV=", 4) == 0) *p = def_ENV; } putenv(def_PATH); } int main(int argc, char **argv) { argc = argc; struct stat statb; uid_t euid = geteuid(); /* Sanity check #1. This check should be made compile-time, but that's not possible. If you're sure that you specified a full path name for FULL_PATH, you can omit this check. */ if (FULL_PATH[0] != '/') { fprintf(stderr, "%s: %s is not a full path name\n", argv[0], FULL_PATH); fprintf(stderr, "You can only use this wrapper if you\n"); fprintf(stderr, "compile it with an absolute path.\n"); exit(-1); } /* Sanity check #2. Check that the owner of the script is equal to either the effective uid or the super user. */ if (stat(FULL_PATH, &statb) < 0) { perror("stat"); exit(-1); } if (statb.st_uid != 0 && statb.st_uid != euid) { fprintf(stderr, "%s: %s has the wrong owner\n", argv[0], FULL_PATH); fprintf(stderr, "The script should be owned by root,\n"); fprintf(stderr, "and shouldn't be writeable by anyone.\n"); exit(-1); } cap_t cur = cap_from_text("cap_audit_write+i"); int ret = cap_set_proc(cur); if (ret) { perror("cap_set_proc"); return 1; } cap_free(cur); clean_environ(); umask(UMASK); while (**argv == '-') /* don't let argv[0] start with '-' */ (*argv)++; execv(FULL_PATH, argv); perror("execv"); fprintf(stderr, "%s: could not execute the script %s\n", argv[0], FULL_PATH); exit(-1); } -------------------------------------------------------------------------- audit_test.py ----------------------------------------------------------------------------- #!/usr/bin/env python import audit import traceback import errno import sys def test(): msg = "foo" try: audit_fd = audit.audit_open() if audit_fd < 0: print("Error connecting to audit daemon") sys.exit(1) except: print("Failed to connecting to audit daemon: %s : %s" % ( sys.exc_info()[0], traceback.format_exc())) sys.exit(1) try: print "call audit_log_user_message" rc = audit.audit_log_user_message(audit_fd, audit.AUDIT_LABEL_LEVEL_CHANGE, str(msg), "", "", "", 0); rc = audit.audit_log_user_message(audit_fd, audit.AUDIT_TRUSTED_APP, str(msg), "", "", "", 0); if rc < 0: print("Error writing to audit") sys.exit(1) except: print("Failed to write audit: %s : %s" % ( sys.exc_info()[0], traceback.format_exc())) sys.exit(1) if __name__ == '__main__': test() -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 20:20 ` Xavier Toth @ 2009-02-10 20:33 ` Stephen Smalley 2009-02-10 20:59 ` Xavier Toth 2009-02-10 21:25 ` Stephen Smalley 1 sibling, 1 reply; 21+ messages in thread From: Stephen Smalley @ 2009-02-10 20:33 UTC (permalink / raw) To: Xavier Toth; +Cc: Serge E. Hallyn, SELinux List On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > > Quoting Xavier Toth (txtoth@gmail.com): > >> I was not putting capabilities on the script but rather on a compiled > >> wrapper which execs a python script in which I need to do auditing. > >> Will this not work? > > > > No, because of the way capabilities are re-calculated on exec(). > > > > pI' = pI > > pP' = (X&fP) | (pI & fI) > > pE' = fE ? pP' : 0 > > > > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > > be empty after exec(). > > > > Now you could use a wrapper as follows: Have the wrapper fill pI, > > and then fill fI on the python interpreter. Any user who has an > > empty pI (which generally is all users) will execute python scripts > > with no privilege, but when the wrapper execs the script, pP' will > > be filled with (pI&fI) = full. > > > > -serge > > > > Thanks for the clarification. > For anyone one that is interested I've included some test code. The > wrapper is a modified version of a wrapper Stephen sent me a link to. > Basic steps to test are: > 1) edit the wrapper to set the path to the audit_test.py script > 2) compiler the wrapper > gcc -o audit-wrapper audit-wrapper.c -lcap > 3) set the capabilities on the wrapper and python > setcap cap_audit_write,cap_setfcap=epi audit-wrapper Why cap_setfcap (set file capability)? And do you need to set fI on the wrapper at all, given that it isn't inheriting anything from its caller? > setcap cap_audit_write=ei /usr/bin/python Is setting fE required on the interpreter? > 4) run audit-wrapper > 5) check audit log for audit records. > > I also ran audit_test.py without the wrapper to verify that no audit > would occur. So this approach suffices for your need? The alternative would be to use the setuid-root wrapper approach, using SELinux to limit the capabilities that can be used by the domain in which the wrapper and the script run (no need to touch the interpreter in that case). Did you ever track down what files the script was trying to access that caused a problem with DAC denials? -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 20:33 ` Stephen Smalley @ 2009-02-10 20:59 ` Xavier Toth 2009-02-10 21:08 ` Stephen Smalley 2009-02-10 21:38 ` Serge E. Hallyn 0 siblings, 2 replies; 21+ messages in thread From: Xavier Toth @ 2009-02-10 20:59 UTC (permalink / raw) To: Stephen Smalley; +Cc: Serge E. Hallyn, SELinux List On Tue, Feb 10, 2009 at 2:33 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: >> > Quoting Xavier Toth (txtoth@gmail.com): >> >> I was not putting capabilities on the script but rather on a compiled >> >> wrapper which execs a python script in which I need to do auditing. >> >> Will this not work? >> > >> > No, because of the way capabilities are re-calculated on exec(). >> > >> > pI' = pI >> > pP' = (X&fP) | (pI & fI) >> > pE' = fE ? pP' : 0 >> > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will >> > be empty after exec(). >> > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, >> > and then fill fI on the python interpreter. Any user who has an >> > empty pI (which generally is all users) will execute python scripts >> > with no privilege, but when the wrapper execs the script, pP' will >> > be filled with (pI&fI) = full. >> > >> > -serge >> > >> >> Thanks for the clarification. >> For anyone one that is interested I've included some test code. The >> wrapper is a modified version of a wrapper Stephen sent me a link to. >> Basic steps to test are: >> 1) edit the wrapper to set the path to the audit_test.py script >> 2) compiler the wrapper >> gcc -o audit-wrapper audit-wrapper.c -lcap >> 3) set the capabilities on the wrapper and python >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper > > Why cap_setfcap (set file capability)? The wrapper adds the 'i' back to cap_audit_write as it goes away when audit-wrapper runs. I was printing the capabilities in the wrapper for debug purposes when I noticed that it capabilities were "= cap_audit_write,cap_setfcap+ep". I think without the i cap_audit_write can't be inherited by the child process. > And do you need to set fI on the wrapper at all, given that it isn't > inheriting anything from its caller? Without cap_setfcap cap_set_proc fails, without cap_audit_write cap_set_proc fails (see cap_set_proc man page). > >> setcap cap_audit_write=ei /usr/bin/python > > Is setting fE required on the interpreter? I tried 'i' only it wouldn't work without 'e'. > >> 4) run audit-wrapper >> 5) check audit log for audit records. >> >> I also ran audit_test.py without the wrapper to verify that no audit >> would occur. > > So this approach suffices for your need? Yes > > The alternative would be to use the setuid-root wrapper approach, using > SELinux to limit the capabilities that can be used by the domain in > which the wrapper and the script run (no need to touch the interpreter > in that case). Did you ever track down what files the script was trying > to access that caused a problem with DAC denials? > We are trying to avoid setuid-root programs and there were some other complicating factor with using this approach for this particular application. As for the DAC denials they were a red herring sorry to have bothered you with those. :( > -- > Stephen Smalley > National Security Agency > > Ted -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 20:59 ` Xavier Toth @ 2009-02-10 21:08 ` Stephen Smalley 2009-02-10 21:30 ` Serge E. Hallyn 2009-02-10 21:38 ` Serge E. Hallyn 1 sibling, 1 reply; 21+ messages in thread From: Stephen Smalley @ 2009-02-10 21:08 UTC (permalink / raw) To: Xavier Toth; +Cc: Serge E. Hallyn, SELinux List On Tue, 2009-02-10 at 14:59 -0600, Xavier Toth wrote: > On Tue, Feb 10, 2009 at 2:33 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > >> > Quoting Xavier Toth (txtoth@gmail.com): > >> >> I was not putting capabilities on the script but rather on a compiled > >> >> wrapper which execs a python script in which I need to do auditing. > >> >> Will this not work? > >> > > >> > No, because of the way capabilities are re-calculated on exec(). > >> > > >> > pI' = pI > >> > pP' = (X&fP) | (pI & fI) > >> > pE' = fE ? pP' : 0 > >> > > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > >> > be empty after exec(). > >> > > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, > >> > and then fill fI on the python interpreter. Any user who has an > >> > empty pI (which generally is all users) will execute python scripts > >> > with no privilege, but when the wrapper execs the script, pP' will > >> > be filled with (pI&fI) = full. > >> > > >> > -serge > >> > > >> > >> Thanks for the clarification. > >> For anyone one that is interested I've included some test code. The > >> wrapper is a modified version of a wrapper Stephen sent me a link to. > >> Basic steps to test are: > >> 1) edit the wrapper to set the path to the audit_test.py script > >> 2) compiler the wrapper > >> gcc -o audit-wrapper audit-wrapper.c -lcap > >> 3) set the capabilities on the wrapper and python > >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper > > > > Why cap_setfcap (set file capability)? > > The wrapper adds the 'i' back to cap_audit_write as it goes away when > audit-wrapper runs. I was printing the capabilities in the wrapper for > debug purposes when I noticed that it capabilities were "= > cap_audit_write,cap_setfcap+ep". I think without the i cap_audit_write > can't be inherited by the child process. cap_setfcap controls setting of file capabilities via setxattr(2). cap_setpcap may have an effect on setting of process capabilities, but I don't think it is required if you are just setting inheritable to something in your permitted set. > We are trying to avoid setuid-root programs and there were some other > complicating factor with using this approach for this particular > application. As for the DAC denials they were a red herring sorry to > have bothered you with those. :( Ok. -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 21:08 ` Stephen Smalley @ 2009-02-10 21:30 ` Serge E. Hallyn 0 siblings, 0 replies; 21+ messages in thread From: Serge E. Hallyn @ 2009-02-10 21:30 UTC (permalink / raw) To: Stephen Smalley; +Cc: Xavier Toth, SELinux List Quoting Stephen Smalley (sds@tycho.nsa.gov): > On Tue, 2009-02-10 at 14:59 -0600, Xavier Toth wrote: > > On Tue, Feb 10, 2009 at 2:33 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > > >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > > >> > Quoting Xavier Toth (txtoth@gmail.com): > > >> >> I was not putting capabilities on the script but rather on a compiled > > >> >> wrapper which execs a python script in which I need to do auditing. > > >> >> Will this not work? > > >> > > > >> > No, because of the way capabilities are re-calculated on exec(). > > >> > > > >> > pI' = pI > > >> > pP' = (X&fP) | (pI & fI) > > >> > pE' = fE ? pP' : 0 > > >> > > > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > > >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > > >> > be empty after exec(). > > >> > > > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, > > >> > and then fill fI on the python interpreter. Any user who has an > > >> > empty pI (which generally is all users) will execute python scripts > > >> > with no privilege, but when the wrapper execs the script, pP' will > > >> > be filled with (pI&fI) = full. > > >> > > > >> > -serge > > >> > > > >> > > >> Thanks for the clarification. > > >> For anyone one that is interested I've included some test code. The > > >> wrapper is a modified version of a wrapper Stephen sent me a link to. > > >> Basic steps to test are: > > >> 1) edit the wrapper to set the path to the audit_test.py script > > >> 2) compiler the wrapper > > >> gcc -o audit-wrapper audit-wrapper.c -lcap > > >> 3) set the capabilities on the wrapper and python > > >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper > > > > > > Why cap_setfcap (set file capability)? > > > > The wrapper adds the 'i' back to cap_audit_write as it goes away when > > audit-wrapper runs. I was printing the capabilities in the wrapper for > > debug purposes when I noticed that it capabilities were "= > > cap_audit_write,cap_setfcap+ep". I think without the i cap_audit_write > > can't be inherited by the child process. > > cap_setfcap controls setting of file capabilities via setxattr(2). > cap_setpcap may have an effect on setting of process capabilities, but I > don't think it is required if you are just setting inheritable to > something in your permitted set. Right, to be able to put cap_audit_write in pI, you either need to have cap_audit_write in pP, or to have cap_setpcap in pP. -serge -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 20:59 ` Xavier Toth 2009-02-10 21:08 ` Stephen Smalley @ 2009-02-10 21:38 ` Serge E. Hallyn 2009-02-10 21:45 ` Xavier Toth 1 sibling, 1 reply; 21+ messages in thread From: Serge E. Hallyn @ 2009-02-10 21:38 UTC (permalink / raw) To: Xavier Toth; +Cc: Stephen Smalley, SELinux List Quoting Xavier Toth (txtoth@gmail.com): > On Tue, Feb 10, 2009 at 2:33 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > >> > Quoting Xavier Toth (txtoth@gmail.com): > >> >> I was not putting capabilities on the script but rather on a compiled > >> >> wrapper which execs a python script in which I need to do auditing. > >> >> Will this not work? > >> > > >> > No, because of the way capabilities are re-calculated on exec(). > >> > > >> > pI' = pI > >> > pP' = (X&fP) | (pI & fI) > >> > pE' = fE ? pP' : 0 > >> > > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > >> > be empty after exec(). > >> > > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, > >> > and then fill fI on the python interpreter. Any user who has an > >> > empty pI (which generally is all users) will execute python scripts > >> > with no privilege, but when the wrapper execs the script, pP' will > >> > be filled with (pI&fI) = full. > >> > > >> > -serge > >> > > >> > >> Thanks for the clarification. > >> For anyone one that is interested I've included some test code. The > >> wrapper is a modified version of a wrapper Stephen sent me a link to. > >> Basic steps to test are: > >> 1) edit the wrapper to set the path to the audit_test.py script > >> 2) compiler the wrapper > >> gcc -o audit-wrapper audit-wrapper.c -lcap > >> 3) set the capabilities on the wrapper and python > >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper > > > > Why cap_setfcap (set file capability)? > > The wrapper adds the 'i' back to cap_audit_write as it goes away when > audit-wrapper runs. > I was printing the capabilities in the wrapper for > debug purposes when I noticed that it capabilities were "= > cap_audit_write,cap_setfcap+ep". I think without the i cap_audit_write > can't be inherited by the child process. > > > And do you need to set fI on the wrapper at all, given that it isn't > > inheriting anything from its caller? > > Without cap_setfcap cap_set_proc fails, without cap_audit_write > cap_set_proc fails (see cap_set_proc man page). > > > > >> setcap cap_audit_write=ei /usr/bin/python > > > > Is setting fE required on the interpreter? > > I tried 'i' only it wouldn't work without 'e'. Right, without 'e' the final exec() will end up with cap_audit_write in pP' but not pE', so you won't be able to actually exercise the privilege (without using cap_set_proc() which I assume python doesn't support). It's no big deal, but your use of fI still is more liberal than it needs to be. The following should suffice: setcap cap_audit_write=p audit-wrapper setcap cap_audit_write=ei /usr/bin/python Now anyone running audit-wrapper will get cap_audit_write in pP', but not be able to exercise it (it's not in pE'). Audit-wrapper can put cap_audit_write into pI because it's in pP. Finally, when audit-wrapper execs the python script, that will run with pP'=pI'=pP'=cap_audit_write. -serge -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 21:38 ` Serge E. Hallyn @ 2009-02-10 21:45 ` Xavier Toth 0 siblings, 0 replies; 21+ messages in thread From: Xavier Toth @ 2009-02-10 21:45 UTC (permalink / raw) To: Serge E. Hallyn; +Cc: Stephen Smalley, SELinux List On Tue, Feb 10, 2009 at 3:38 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > Quoting Xavier Toth (txtoth@gmail.com): >> On Tue, Feb 10, 2009 at 2:33 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: >> > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: >> >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: >> >> > Quoting Xavier Toth (txtoth@gmail.com): >> >> >> I was not putting capabilities on the script but rather on a compiled >> >> >> wrapper which execs a python script in which I need to do auditing. >> >> >> Will this not work? >> >> > >> >> > No, because of the way capabilities are re-calculated on exec(). >> >> > >> >> > pI' = pI >> >> > pP' = (X&fP) | (pI & fI) >> >> > pE' = fE ? pP' : 0 >> >> > >> >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which >> >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will >> >> > be empty after exec(). >> >> > >> >> > Now you could use a wrapper as follows: Have the wrapper fill pI, >> >> > and then fill fI on the python interpreter. Any user who has an >> >> > empty pI (which generally is all users) will execute python scripts >> >> > with no privilege, but when the wrapper execs the script, pP' will >> >> > be filled with (pI&fI) = full. >> >> > >> >> > -serge >> >> > >> >> >> >> Thanks for the clarification. >> >> For anyone one that is interested I've included some test code. The >> >> wrapper is a modified version of a wrapper Stephen sent me a link to. >> >> Basic steps to test are: >> >> 1) edit the wrapper to set the path to the audit_test.py script >> >> 2) compiler the wrapper >> >> gcc -o audit-wrapper audit-wrapper.c -lcap >> >> 3) set the capabilities on the wrapper and python >> >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper >> > >> > Why cap_setfcap (set file capability)? >> >> The wrapper adds the 'i' back to cap_audit_write as it goes away when >> audit-wrapper runs. > >> I was printing the capabilities in the wrapper for >> debug purposes when I noticed that it capabilities were "= >> cap_audit_write,cap_setfcap+ep". I think without the i cap_audit_write >> can't be inherited by the child process. >> >> > And do you need to set fI on the wrapper at all, given that it isn't >> > inheriting anything from its caller? >> >> Without cap_setfcap cap_set_proc fails, without cap_audit_write >> cap_set_proc fails (see cap_set_proc man page). >> >> > >> >> setcap cap_audit_write=ei /usr/bin/python >> > >> > Is setting fE required on the interpreter? >> >> I tried 'i' only it wouldn't work without 'e'. > > Right, without 'e' the final exec() will end up with > cap_audit_write in pP' but not pE', so you won't be > able to actually exercise the privilege (without using > cap_set_proc() which I assume python doesn't support). > > It's no big deal, but your use of fI still is more liberal > than it needs to be. The following should suffice: > > setcap cap_audit_write=p audit-wrapper > setcap cap_audit_write=ei /usr/bin/python > > Now anyone running audit-wrapper will get cap_audit_write > in pP', but not be able to exercise it (it's not in pE'). > Audit-wrapper can put cap_audit_write into pI because it's > in pP. Finally, when audit-wrapper execs the python script, > that will run with pP'=pI'=pP'=cap_audit_write. > > -serge > You're right 'setcap cap_audit_write=p audit-wrapper' is sufficient. Ted -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 20:20 ` Xavier Toth 2009-02-10 20:33 ` Stephen Smalley @ 2009-02-10 21:25 ` Stephen Smalley 2009-02-10 21:37 ` Xavier Toth 2009-02-10 21:44 ` Serge E. Hallyn 1 sibling, 2 replies; 21+ messages in thread From: Stephen Smalley @ 2009-02-10 21:25 UTC (permalink / raw) To: Xavier Toth; +Cc: Serge E. Hallyn, SELinux List On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > > Quoting Xavier Toth (txtoth@gmail.com): > >> I was not putting capabilities on the script but rather on a compiled > >> wrapper which execs a python script in which I need to do auditing. > >> Will this not work? > > > > No, because of the way capabilities are re-calculated on exec(). > > > > pI' = pI > > pP' = (X&fP) | (pI & fI) > > pE' = fE ? pP' : 0 > > > > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > > be empty after exec(). > > > > Now you could use a wrapper as follows: Have the wrapper fill pI, > > and then fill fI on the python interpreter. Any user who has an > > empty pI (which generally is all users) will execute python scripts > > with no privilege, but when the wrapper execs the script, pP' will > > be filled with (pI&fI) = full. > > > > -serge > > > > Thanks for the clarification. > For anyone one that is interested I've included some test code. The > wrapper is a modified version of a wrapper Stephen sent me a link to. > Basic steps to test are: > 1) edit the wrapper to set the path to the audit_test.py script > 2) compiler the wrapper > gcc -o audit-wrapper audit-wrapper.c -lcap > 3) set the capabilities on the wrapper and python > setcap cap_audit_write,cap_setfcap=epi audit-wrapper > setcap cap_audit_write=ei /usr/bin/python > 4) run audit-wrapper > 5) check audit log for audit records. > > I also ran audit_test.py without the wrapper to verify that no audit > would occur. > > Ted > > ------------------------------------------------------------------------------ > audit-wrapper.c > ------------------------------------------------------------------------ > <snip> > cap_t cur = cap_from_text("cap_audit_write+i"); > int ret = cap_set_proc(cur); > if (ret) { > perror("cap_set_proc"); > return 1; > } > cap_free(cur); Looks like you could make your wrapper generic for any capabilities by having it copy the permitted (or effective) set to the inheritable set. Something like this: cap_t cur = cap_get_proc(); cap_value_t caps[1]; cap_flag_value_t value; int i, rc; for (i = 0; i < CAP_LAST_CAP; i++) { rc = cap_get_flag(cur, i, CAP_PERMITTED, &value); if (rc < 0) { perror("cap_get_flag"); return 1; } caps[0] = i; rc = cap_set_flag(cur, CAP_INHERITABLE, 1, caps, value); if (rc < 0) { perror("cap_set_flag"); return 1; } } rc = cap_set_proc(cur); if (rc < 0) { perror("cap_set_proc"); return 1; } cap_free(cur); Serge - is there any easier way? -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 21:25 ` Stephen Smalley @ 2009-02-10 21:37 ` Xavier Toth 2009-02-10 21:38 ` Stephen Smalley 2009-02-10 21:46 ` Serge E. Hallyn 2009-02-10 21:44 ` Serge E. Hallyn 1 sibling, 2 replies; 21+ messages in thread From: Xavier Toth @ 2009-02-10 21:37 UTC (permalink / raw) To: Stephen Smalley; +Cc: Serge E. Hallyn, SELinux List On Tue, Feb 10, 2009 at 3:25 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: >> > Quoting Xavier Toth (txtoth@gmail.com): >> >> I was not putting capabilities on the script but rather on a compiled >> >> wrapper which execs a python script in which I need to do auditing. >> >> Will this not work? >> > >> > No, because of the way capabilities are re-calculated on exec(). >> > >> > pI' = pI >> > pP' = (X&fP) | (pI & fI) >> > pE' = fE ? pP' : 0 >> > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will >> > be empty after exec(). >> > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, >> > and then fill fI on the python interpreter. Any user who has an >> > empty pI (which generally is all users) will execute python scripts >> > with no privilege, but when the wrapper execs the script, pP' will >> > be filled with (pI&fI) = full. >> > >> > -serge >> > >> >> Thanks for the clarification. >> For anyone one that is interested I've included some test code. The >> wrapper is a modified version of a wrapper Stephen sent me a link to. >> Basic steps to test are: >> 1) edit the wrapper to set the path to the audit_test.py script >> 2) compiler the wrapper >> gcc -o audit-wrapper audit-wrapper.c -lcap >> 3) set the capabilities on the wrapper and python >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper >> setcap cap_audit_write=ei /usr/bin/python >> 4) run audit-wrapper >> 5) check audit log for audit records. >> >> I also ran audit_test.py without the wrapper to verify that no audit >> would occur. >> >> Ted >> >> ------------------------------------------------------------------------------ >> audit-wrapper.c >> ------------------------------------------------------------------------ >> > <snip> >> cap_t cur = cap_from_text("cap_audit_write+i"); >> int ret = cap_set_proc(cur); >> if (ret) { >> perror("cap_set_proc"); >> return 1; >> } >> cap_free(cur); > > Looks like you could make your wrapper generic for any capabilities by > having it copy the permitted (or effective) set to the inheritable set. > Something like this: > cap_t cur = cap_get_proc(); > cap_value_t caps[1]; > cap_flag_value_t value; > int i, rc; > for (i = 0; i < CAP_LAST_CAP; i++) { > rc = cap_get_flag(cur, i, CAP_PERMITTED, &value); > if (rc < 0) { > perror("cap_get_flag"); > return 1; > } > caps[0] = i; > rc = cap_set_flag(cur, CAP_INHERITABLE, 1, caps, value); > if (rc < 0) { > perror("cap_set_flag"); > return 1; > } > } > rc = cap_set_proc(cur); > if (rc < 0) { > perror("cap_set_proc"); > return 1; > } > cap_free(cur); > > Serge - is there any easier way? > > -- > Stephen Smalley > National Security Agency > > "If any flag in cap_p is set for any capability not currently permitted for the calling process, the function will fail" Ted -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 21:37 ` Xavier Toth @ 2009-02-10 21:38 ` Stephen Smalley 2009-02-10 21:46 ` Serge E. Hallyn 1 sibling, 0 replies; 21+ messages in thread From: Stephen Smalley @ 2009-02-10 21:38 UTC (permalink / raw) To: Xavier Toth; +Cc: Serge E. Hallyn, SELinux List On Tue, 2009-02-10 at 15:37 -0600, Xavier Toth wrote: > On Tue, Feb 10, 2009 at 3:25 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > >> > Quoting Xavier Toth (txtoth@gmail.com): > >> >> I was not putting capabilities on the script but rather on a compiled > >> >> wrapper which execs a python script in which I need to do auditing. > >> >> Will this not work? > >> > > >> > No, because of the way capabilities are re-calculated on exec(). > >> > > >> > pI' = pI > >> > pP' = (X&fP) | (pI & fI) > >> > pE' = fE ? pP' : 0 > >> > > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > >> > be empty after exec(). > >> > > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, > >> > and then fill fI on the python interpreter. Any user who has an > >> > empty pI (which generally is all users) will execute python scripts > >> > with no privilege, but when the wrapper execs the script, pP' will > >> > be filled with (pI&fI) = full. > >> > > >> > -serge > >> > > >> > >> Thanks for the clarification. > >> For anyone one that is interested I've included some test code. The > >> wrapper is a modified version of a wrapper Stephen sent me a link to. > >> Basic steps to test are: > >> 1) edit the wrapper to set the path to the audit_test.py script > >> 2) compiler the wrapper > >> gcc -o audit-wrapper audit-wrapper.c -lcap > >> 3) set the capabilities on the wrapper and python > >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper > >> setcap cap_audit_write=ei /usr/bin/python > >> 4) run audit-wrapper > >> 5) check audit log for audit records. > >> > >> I also ran audit_test.py without the wrapper to verify that no audit > >> would occur. > >> > >> Ted > >> > >> ------------------------------------------------------------------------------ > >> audit-wrapper.c > >> ------------------------------------------------------------------------ > >> > > <snip> > >> cap_t cur = cap_from_text("cap_audit_write+i"); > >> int ret = cap_set_proc(cur); > >> if (ret) { > >> perror("cap_set_proc"); > >> return 1; > >> } > >> cap_free(cur); > > > > Looks like you could make your wrapper generic for any capabilities by > > having it copy the permitted (or effective) set to the inheritable set. > > Something like this: > > cap_t cur = cap_get_proc(); > > cap_value_t caps[1]; > > cap_flag_value_t value; > > int i, rc; > > for (i = 0; i < CAP_LAST_CAP; i++) { > > rc = cap_get_flag(cur, i, CAP_PERMITTED, &value); > > if (rc < 0) { > > perror("cap_get_flag"); > > return 1; > > } > > caps[0] = i; > > rc = cap_set_flag(cur, CAP_INHERITABLE, 1, caps, value); > > if (rc < 0) { > > perror("cap_set_flag"); > > return 1; > > } > > } > > rc = cap_set_proc(cur); > > if (rc < 0) { > > perror("cap_set_proc"); > > return 1; > > } > > cap_free(cur); > > > > Serge - is there any easier way? > > > > -- > > Stephen Smalley > > National Security Agency > > > > > > "If any flag in cap_p is set for any capability not currently permitted > for the calling process, the function will fail" That's ok, because you've set cap_audit_write=p on the wrapper, so cap_audit_write is in the permitted set and putting it into your inheritable set requires no further privilege. Certainly not cap_setpcap. I tried it here. -- 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 majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 21:37 ` Xavier Toth 2009-02-10 21:38 ` Stephen Smalley @ 2009-02-10 21:46 ` Serge E. Hallyn 1 sibling, 0 replies; 21+ messages in thread From: Serge E. Hallyn @ 2009-02-10 21:46 UTC (permalink / raw) To: Xavier Toth; +Cc: Stephen Smalley, SELinux List Quoting Xavier Toth (txtoth@gmail.com): > On Tue, Feb 10, 2009 at 3:25 PM, Stephen Smalley <sds@tycho.nsa.gov> wrote: > > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > >> On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > >> > Quoting Xavier Toth (txtoth@gmail.com): > >> >> I was not putting capabilities on the script but rather on a compiled > >> >> wrapper which execs a python script in which I need to do auditing. > >> >> Will this not work? > >> > > >> > No, because of the way capabilities are re-calculated on exec(). > >> > > >> > pI' = pI > >> > pP' = (X&fP) | (pI & fI) > >> > pE' = fE ? pP' : 0 > >> > > >> > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > >> > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > >> > be empty after exec(). > >> > > >> > Now you could use a wrapper as follows: Have the wrapper fill pI, > >> > and then fill fI on the python interpreter. Any user who has an > >> > empty pI (which generally is all users) will execute python scripts > >> > with no privilege, but when the wrapper execs the script, pP' will > >> > be filled with (pI&fI) = full. > >> > > >> > -serge > >> > > >> > >> Thanks for the clarification. > >> For anyone one that is interested I've included some test code. The > >> wrapper is a modified version of a wrapper Stephen sent me a link to. > >> Basic steps to test are: > >> 1) edit the wrapper to set the path to the audit_test.py script > >> 2) compiler the wrapper > >> gcc -o audit-wrapper audit-wrapper.c -lcap > >> 3) set the capabilities on the wrapper and python > >> setcap cap_audit_write,cap_setfcap=epi audit-wrapper > >> setcap cap_audit_write=ei /usr/bin/python > >> 4) run audit-wrapper > >> 5) check audit log for audit records. > >> > >> I also ran audit_test.py without the wrapper to verify that no audit > >> would occur. > >> > >> Ted > >> > >> ------------------------------------------------------------------------------ > >> audit-wrapper.c > >> ------------------------------------------------------------------------ > >> > > <snip> > >> cap_t cur = cap_from_text("cap_audit_write+i"); > >> int ret = cap_set_proc(cur); > >> if (ret) { > >> perror("cap_set_proc"); > >> return 1; > >> } > >> cap_free(cur); > > > > Looks like you could make your wrapper generic for any capabilities by > > having it copy the permitted (or effective) set to the inheritable set. > > Something like this: > > cap_t cur = cap_get_proc(); > > cap_value_t caps[1]; > > cap_flag_value_t value; > > int i, rc; > > for (i = 0; i < CAP_LAST_CAP; i++) { > > rc = cap_get_flag(cur, i, CAP_PERMITTED, &value); > > if (rc < 0) { > > perror("cap_get_flag"); > > return 1; > > } > > caps[0] = i; > > rc = cap_set_flag(cur, CAP_INHERITABLE, 1, caps, value); > > if (rc < 0) { > > perror("cap_set_flag"); > > return 1; > > } > > } > > rc = cap_set_proc(cur); > > if (rc < 0) { > > perror("cap_set_proc"); > > return 1; > > } > > cap_free(cur); > > > > Serge - is there any easier way? > > > > -- > > Stephen Smalley > > National Security Agency > > > > > > "If any flag in cap_p is set for any capability not currently permitted > for the calling process, the function will fail" He's only setting bits which are in CAP_PERMITTED, meaning they are permitted (but perhaps not effective) for the calling process. -serge -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: problem with capabilities inheritance and auditing in python 2009-02-10 21:25 ` Stephen Smalley 2009-02-10 21:37 ` Xavier Toth @ 2009-02-10 21:44 ` Serge E. Hallyn 1 sibling, 0 replies; 21+ messages in thread From: Serge E. Hallyn @ 2009-02-10 21:44 UTC (permalink / raw) To: Stephen Smalley; +Cc: Xavier Toth, SELinux List Quoting Stephen Smalley (sds@tycho.nsa.gov): > On Tue, 2009-02-10 at 14:20 -0600, Xavier Toth wrote: > > On Tue, Feb 10, 2009 at 12:34 PM, Serge E. Hallyn <serue@us.ibm.com> wrote: > > > Quoting Xavier Toth (txtoth@gmail.com): > > >> I was not putting capabilities on the script but rather on a compiled > > >> wrapper which execs a python script in which I need to do auditing. > > >> Will this not work? > > > > > > No, because of the way capabilities are re-calculated on exec(). > > > > > > pI' = pI > > > pP' = (X&fP) | (pI & fI) > > > pE' = fE ? pP' : 0 > > > > > > So since the interpreter has fI=fP=fE=0 and is not setuid root (which > > > would fill in fP and/or fE to emulate privileged root), pP' and pE' will > > > be empty after exec(). > > > > > > Now you could use a wrapper as follows: Have the wrapper fill pI, > > > and then fill fI on the python interpreter. Any user who has an > > > empty pI (which generally is all users) will execute python scripts > > > with no privilege, but when the wrapper execs the script, pP' will > > > be filled with (pI&fI) = full. > > > > > > -serge > > > > > > > Thanks for the clarification. > > For anyone one that is interested I've included some test code. The > > wrapper is a modified version of a wrapper Stephen sent me a link to. > > Basic steps to test are: > > 1) edit the wrapper to set the path to the audit_test.py script > > 2) compiler the wrapper > > gcc -o audit-wrapper audit-wrapper.c -lcap > > 3) set the capabilities on the wrapper and python > > setcap cap_audit_write,cap_setfcap=epi audit-wrapper > > setcap cap_audit_write=ei /usr/bin/python > > 4) run audit-wrapper > > 5) check audit log for audit records. > > > > I also ran audit_test.py without the wrapper to verify that no audit > > would occur. > > > > Ted > > > > ------------------------------------------------------------------------------ > > audit-wrapper.c > > ------------------------------------------------------------------------ > > > <snip> > > cap_t cur = cap_from_text("cap_audit_write+i"); > > int ret = cap_set_proc(cur); > > if (ret) { > > perror("cap_set_proc"); > > return 1; > > } > > cap_free(cur); > > Looks like you could make your wrapper generic for any capabilities by > having it copy the permitted (or effective) set to the inheritable set. > Something like this: > cap_t cur = cap_get_proc(); > cap_value_t caps[1]; > cap_flag_value_t value; > int i, rc; > for (i = 0; i < CAP_LAST_CAP; i++) { > rc = cap_get_flag(cur, i, CAP_PERMITTED, &value); > if (rc < 0) { > perror("cap_get_flag"); > return 1; > } > caps[0] = i; > rc = cap_set_flag(cur, CAP_INHERITABLE, 1, caps, value); > if (rc < 0) { > perror("cap_set_flag"); > return 1; > } > } > rc = cap_set_proc(cur); > if (rc < 0) { > perror("cap_set_proc"); > return 1; > } > cap_free(cur); Neat. > Serge - is there any easier way? Not that I can think of. -serge -- This message was distributed to subscribers of the selinux mailing list. If you no longer wish to subscribe, send mail to majordomo@tycho.nsa.gov with the words "unsubscribe selinux" without quotes as the message. ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2009-02-10 21:46 UTC | newest] Thread overview: 21+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-02-05 17:08 problem with capabilities inheritance and auditing in python Xavier Toth 2009-02-05 18:10 ` Stephen Smalley 2009-02-06 21:56 ` Xavier Toth 2009-02-09 14:02 ` Stephen Smalley 2009-02-09 16:42 ` Xavier Toth 2009-02-09 20:17 ` Stephen Smalley 2009-02-09 20:42 ` Serge E. Hallyn 2009-02-10 17:00 ` Xavier Toth 2009-02-10 18:34 ` Serge E. Hallyn 2009-02-10 20:20 ` Xavier Toth 2009-02-10 20:33 ` Stephen Smalley 2009-02-10 20:59 ` Xavier Toth 2009-02-10 21:08 ` Stephen Smalley 2009-02-10 21:30 ` Serge E. Hallyn 2009-02-10 21:38 ` Serge E. Hallyn 2009-02-10 21:45 ` Xavier Toth 2009-02-10 21:25 ` Stephen Smalley 2009-02-10 21:37 ` Xavier Toth 2009-02-10 21:38 ` Stephen Smalley 2009-02-10 21:46 ` Serge E. Hallyn 2009-02-10 21:44 ` Serge E. Hallyn
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.