All of lore.kernel.org
 help / color / mirror / Atom feed
From: Andy Lutomirski <luto@stanford.edu>
To: Stephen Smalley <sds@epoch.ncsc.mil>
Cc: Chris Wright <chrisw@osdl.org>,
	Andy Lutomirski <luto@myrealbox.com>,
	Andrew Morton <akpm@osdl.org>, Linus Torvalds <torvalds@osdl.org>,
	James Morris <jmorris@redhat.com>,
	lkml <linux-kernel@vger.kernel.org>
Subject: Re: compute_creds fixup in -mm
Date: Wed, 21 Apr 2004 12:37:30 -0700	[thread overview]
Message-ID: <4086CD7A.8060303@stanford.edu> (raw)
In-Reply-To: <1082572971.9213.75.camel@moss-spartans.epoch.ncsc.mil>

Stephen Smalley wrote:

> On Wed, 2004-04-21 at 14:28, Chris Wright wrote:
> 
>>* Stephen Smalley (sds@epoch.ncsc.mil) wrote:
>>
>>>I didn't see Chris' patch.  I assume that the worst case is unexpected
>>>program failure due to lack of capability, right?  The SELinux security
>>
>>The opposite.  You'd get a program with non-root euid, but full
>>capability set, and AT_SECURE set false.  My patch is below.
> 
> 
> Sorry, I wasn't clear.  I meant the worst case due to the share/ptrace
> state check being duplicated in SELinux and in commoncap, as opposed to
> being performed once as in Andy's patch.
> 

I was worried about sid changing but uid and caps staying the same if
a ptrace_detach or _exit happens between the cap_bprm_apply_creds call
and the rest of selinux_bprm_apply_creds.  Remember the sendmail bug --
program failure due to lack of capabilities can cause privilege leaks
(in this case selinux sid leaks).

If this isn't a concern, then Chris' patch should be fine.  On the other
hand, some other LSM may prefer my version.  Here's my corrected patch
(thanks, Chris):

--- linux-2.6.5-mm5/include/linux/security.h.ptlock	2004-04-21 08:52:49.904877920 -0700
+++ linux-2.6.5-mm5/include/linux/security.h	2004-04-21 09:12:46.540961584 -0700
@@ -44,7 +44,7 @@
  extern int cap_capset_check (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
  extern void cap_capset_set (struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
  extern int cap_bprm_set_security (struct linux_binprm *bprm);
-extern void cap_bprm_apply_creds (struct linux_binprm *bprm);
+extern void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe);
  extern int cap_bprm_secureexec(struct linux_binprm *bprm);
  extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags);
  extern int cap_inode_removexattr(struct dentry *dentry, char *name);
@@ -86,6 +86,11 @@
  struct sched_param;
  struct swap_info_struct;

+/* brpm_apply_creds unsafe reasons */
+#define LSM_UNSAFE_SHARE	1
+#define LSM_UNSAFE_PTRACE	2
+#define LSM_UNSAFE_PTRACE_CAP	4
+
  #ifdef CONFIG_SECURITY

  /**
@@ -112,6 +117,8 @@
   *	also perform other state changes on the process (e.g.  closing open
   *	file descriptors to which access is no longer granted if the attributes
   *	were changed).
+ *	bprm_apply_creds is called under task_lock.  @unsafe indicates various
+ *	reasons why it may be unsafe to change security state.
   *	@bprm contains the linux_binprm structure.
   * @bprm_set_security:
   *	Save security information in the bprm->security field, typically based
@@ -1026,7 +1033,7 @@

  	int (*bprm_alloc_security) (struct linux_binprm * bprm);
  	void (*bprm_free_security) (struct linux_binprm * bprm);
-	void (*bprm_apply_creds) (struct linux_binprm * bprm);
+	void (*bprm_apply_creds) (struct linux_binprm * bprm, int unsafe);
  	int (*bprm_set_security) (struct linux_binprm * bprm);
  	int (*bprm_check_security) (struct linux_binprm * bprm);
  	int (*bprm_secureexec) (struct linux_binprm * bprm);
@@ -1290,9 +1297,9 @@
  {
  	security_ops->bprm_free_security (bprm);
  }
-static inline void security_bprm_apply_creds (struct linux_binprm *bprm)
+static inline void security_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
  {
-	security_ops->bprm_apply_creds (bprm);
+	security_ops->bprm_apply_creds (bprm, unsafe);
  }
  static inline int security_bprm_set (struct linux_binprm *bprm)
  {
@@ -1962,9 +1969,9 @@
  static inline void security_bprm_free (struct linux_binprm *bprm)
  { }

-static inline void security_bprm_apply_creds (struct linux_binprm *bprm)
+static inline void security_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
  {
-	cap_bprm_apply_creds (bprm);
+	cap_bprm_apply_creds (bprm, unsafe);
  }

  static inline int security_bprm_set (struct linux_binprm *bprm)
--- linux-2.6.5-mm5/fs/exec.c.ptlock	2004-04-21 08:50:37.767965784 -0700
+++ linux-2.6.5-mm5/fs/exec.c	2004-04-21 12:23:01.915761696 -0700
@@ -919,24 +919,28 @@

  EXPORT_SYMBOL(prepare_binprm);

-/*
- * This function is used to produce the new IDs and capabilities
- * from the old ones and the file's capabilities.
- *
- * The formula used for evolving capabilities is:
- *
- *       pI' = pI
- * (***) pP' = (fP & X) | (fI & pI)
- *       pE' = pP' & fE          [NB. fE is 0 or ~0]
- *
- * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
- * ' indicates post-exec(), and X is the global 'cap_bset'.
- *
- */
+static inline int must_not_trace_exec (struct task_struct *p)
+{
+	int unsafe = 0;
+	if (p->ptrace & PT_PTRACED) {
+		if(p->ptrace & PT_PTRACE_CAP)
+			unsafe |= LSM_UNSAFE_PTRACE_CAP;
+		else
+			unsafe |= LSM_UNSAFE_PTRACE;
+	}
+	if (atomic_read(&p->fs->count) > 1 ||
+	    atomic_read(&p->files->count) > 1 ||
+	    atomic_read(&p->sighand->count) > 1)
+		unsafe |= LSM_UNSAFE_SHARE;
+
+	return unsafe;
+}

  void compute_creds(struct linux_binprm *bprm)
  {
-	security_bprm_apply_creds(bprm);
+	task_lock(current);
+	security_bprm_apply_creds(bprm, must_not_trace_exec(current));
+	task_unlock(current);
  }

  EXPORT_SYMBOL(compute_creds);
--- linux-2.6.5-mm5/security/selinux/hooks.c.ptlock	2004-04-21 08:57:16.947281304 -0700
+++ linux-2.6.5-mm5/security/selinux/hooks.c	2004-04-21 12:23:58.245198320 -0700
@@ -1746,7 +1746,7 @@
  	spin_unlock(&files->file_lock);
  }

-static void selinux_bprm_apply_creds(struct linux_binprm *bprm)
+static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe)
  {
  	struct task_security_struct *tsec, *psec;
  	struct bprm_security_struct *bsec;
@@ -1756,7 +1756,7 @@
  	struct rlimit *rlim, *initrlim;
  	int rc, i;

-	secondary_ops->bprm_apply_creds(bprm);
+	secondary_ops->bprm_apply_creds(bprm, unsafe);

  	tsec = current->security;

@@ -1767,9 +1767,7 @@
  	if (tsec->sid != sid) {
  		/* Check for shared state.  If not ok, leave SID
  		   unchanged and kill. */
-		if ((atomic_read(&current->fs->count) > 1 ||
-		     atomic_read(&current->files->count) > 1 ||
-		     atomic_read(&current->sighand->count) > 1)) {
+		if (unsafe & LSM_UNSAFE_SHARE) {
  			rc = avc_has_perm(tsec->sid, sid,
  					  SECCLASS_PROCESS, PROCESS__SHARE,
  					  NULL, NULL);
@@ -1781,15 +1779,13 @@

  		/* Check for ptracing, and update the task SID if ok.
  		   Otherwise, leave SID unchanged and kill. */
-		task_lock(current);
-		if (current->ptrace & PT_PTRACED) {
+		if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) {
  			psec = current->parent->security;
  			rc = avc_has_perm_noaudit(psec->sid, sid,
  					  SECCLASS_PROCESS, PROCESS__PTRACE,
  					  NULL, &avd);
  			if (!rc)
  				tsec->sid = sid;
-			task_unlock(current);
  			avc_audit(psec->sid, sid, SECCLASS_PROCESS,
  				  PROCESS__PTRACE, &avd, rc, NULL);
  			if (rc) {
@@ -1798,7 +1794,6 @@
  			}
  		} else {
  			tsec->sid = sid;
-			task_unlock(current);
  		}

  		/* Close files for which the new task SID is not authorized. */
--- linux-2.6.5-mm5/security/commoncap.c.ptlock	2004-04-21 08:54:16.824664104 -0700
+++ linux-2.6.5-mm5/security/commoncap.c	2004-04-21 09:24:01.468357024 -0700
@@ -115,15 +115,7 @@
  	return 0;
  }

-static inline int must_not_trace_exec (struct task_struct *p)
-{
-	return ((p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP))
-		|| atomic_read(&p->fs->count) > 1
-		|| atomic_read(&p->files->count) > 1
-		|| atomic_read(&p->sighand->count) > 1;
-}
-
-void cap_bprm_apply_creds (struct linux_binprm *bprm)
+void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
  {
  	/* Derived from fs/exec.c:compute_creds. */
  	kernel_cap_t new_permitted, working;
@@ -133,30 +125,25 @@
  				 current->cap_inheritable);
  	new_permitted = cap_combine (new_permitted, working);

-	task_lock(current);
-
-	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
+	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid ||
+	    !cap_issubset (new_permitted, current->cap_permitted)) {
  		current->mm->dumpable = 0;

-		if (must_not_trace_exec(current) && !capable(CAP_SETUID)) {
-			bprm->e_uid = current->uid;
-			bprm->e_gid = current->gid;
+		if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) {
+			if (!capable(CAP_SETUID)) {
+				bprm->e_uid = current->uid;
+				bprm->e_gid = current->gid;
+			}
+			if (!capable (CAP_SETPCAP)) {
+				new_permitted = cap_intersect (new_permitted,
+							current->cap_permitted);
+			}
  		}
  	}

  	current->suid = current->euid = current->fsuid = bprm->e_uid;
  	current->sgid = current->egid = current->fsgid = bprm->e_gid;

-	if (!cap_issubset (new_permitted, current->cap_permitted)) {
-		current->mm->dumpable = 0;
-
-		if (must_not_trace_exec (current) && !capable (CAP_SETPCAP)) {
-			new_permitted = cap_intersect (new_permitted,
-						       current->
-						       cap_permitted);
-		}
-	}
-
  	/* For init, we want to retain the capabilities set
  	 * in the init_task struct. Thus we skip the usual
  	 * capability rules */
@@ -167,7 +154,6 @@
  	}

  	/* AUD: Audit candidate if current->cap_effective is set */
-	task_unlock(current);

  	current->keep_capabilities = 0;
  }
--- linux-2.6.5-mm5/security/dummy.c.ptlock	2004-04-21 08:56:00.608886504 -0700
+++ linux-2.6.5-mm5/security/dummy.c	2004-04-21 09:14:57.345076336 -0700
@@ -171,21 +171,12 @@
  	return;
  }

-static inline int must_not_trace_exec (struct task_struct *p)
+static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
  {
-	return ((p->ptrace & PT_PTRACED) && !(p->ptrace & PT_PTRACE_CAP))
-		|| atomic_read(&p->fs->count) > 1
-		|| atomic_read(&p->files->count) > 1
-		|| atomic_read(&p->sighand->count) > 1;
-}
-
-static void dummy_bprm_apply_creds (struct linux_binprm *bprm)
-{
-	task_lock(current);
  	if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) {
  		current->mm->dumpable = 0;

-		if (must_not_trace_exec(current) && !capable(CAP_SETUID)) {
+		if (unsafe && !capable(CAP_SETUID)) {
  			bprm->e_uid = current->uid;
  			bprm->e_gid = current->gid;
  		}
@@ -193,8 +184,6 @@

  	current->suid = current->euid = current->fsuid = bprm->e_uid;
  	current->sgid = current->egid = current->fsgid = bprm->e_gid;
-
-	task_unlock(current);
  }

  static int dummy_bprm_set_security (struct linux_binprm *bprm)


  parent reply	other threads:[~2004-04-21 19:38 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20040421010621.L22989@build.pdx.osdl.net>
2004-04-21 17:27 ` compute_creds fixup in -mm Andy Lutomirski
2004-04-21 18:13   ` Stephen Smalley
2004-04-21 18:28     ` Chris Wright
2004-04-21 18:42       ` Stephen Smalley
2004-04-21 18:54         ` Chris Wright
2004-04-21 19:37         ` Andy Lutomirski [this message]
2004-04-21 20:10           ` Stephen Smalley
2004-04-21 19:07   ` Chris Wright
     [not found] <fa.n7n31hd.1k7ce37@ifi.uio.no>
     [not found] ` <fa.f9m11dm.206fg4@ifi.uio.no>
2004-04-21 20:36   ` Andy Lutomirski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4086CD7A.8060303@stanford.edu \
    --to=luto@stanford.edu \
    --cc=akpm@osdl.org \
    --cc=chrisw@osdl.org \
    --cc=jmorris@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luto@myrealbox.com \
    --cc=sds@epoch.ncsc.mil \
    --cc=torvalds@osdl.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.