Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 94058
b: refs/heads/master
c: 3898b1b
h: refs/heads/master
v: v3
  • Loading branch information
Andrew G. Morgan authored and Linus Torvalds committed Apr 28, 2008
1 parent 12af452 commit 5cefd36
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 61 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4016a1390d07f15b267eecb20e76a48fd5c524ef
refs/heads/master: 3898b1b4ebff8dcfbcf1807e0661585e06c9a91c
3 changes: 1 addition & 2 deletions trunk/include/linux/capability.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ typedef struct kernel_cap_struct {
* Add any capability from current's capability bounding set
* to the current process' inheritable set
* Allow taking bits out of capability bounding set
* Allow modification of the securebits for a process
*/

#define CAP_SETPCAP 8
Expand Down Expand Up @@ -490,8 +491,6 @@ extern const kernel_cap_t __cap_init_eff_set;
int capable(int cap);
int __capable(struct task_struct *t, int cap);

extern long cap_prctl_drop(unsigned long cap);

#endif /* __KERNEL__ */

#endif /* !_LINUX_CAPABILITY_H */
3 changes: 2 additions & 1 deletion trunk/include/linux/init_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <linux/ipc.h>
#include <linux/pid_namespace.h>
#include <linux/user_namespace.h>
#include <linux/securebits.h>
#include <net/net_namespace.h>

#define INIT_FDTABLE \
Expand Down Expand Up @@ -172,7 +173,7 @@ extern struct group_info init_groups;
.cap_inheritable = CAP_INIT_INH_SET, \
.cap_permitted = CAP_FULL_SET, \
.cap_bset = CAP_INIT_BSET, \
.keep_capabilities = 0, \
.securebits = SECUREBITS_DEFAULT, \
.user = INIT_USER, \
.comm = "swapper", \
.thread = INIT_THREAD, \
Expand Down
9 changes: 7 additions & 2 deletions trunk/include/linux/prctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */
# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */

/* Get/set whether or not to drop capabilities on setuid() away from uid 0 */
/* Get/set whether or not to drop capabilities on setuid() away from
* uid 0 (as per security/commoncap.c) */
#define PR_GET_KEEPCAPS 7
#define PR_SET_KEEPCAPS 8

Expand Down Expand Up @@ -63,7 +64,7 @@
#define PR_GET_SECCOMP 21
#define PR_SET_SECCOMP 22

/* Get/set the capability bounding set */
/* Get/set the capability bounding set (as per security/commoncap.c) */
#define PR_CAPBSET_READ 23
#define PR_CAPBSET_DROP 24

Expand All @@ -73,4 +74,8 @@
# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */

/* Get/set securebits (as per security/commoncap.c) */
#define PR_GET_SECUREBITS 27
#define PR_SET_SECUREBITS 28

#endif /* _LINUX_PRCTL_H */
3 changes: 1 addition & 2 deletions trunk/include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ struct sched_param {
#include <linux/smp.h>
#include <linux/sem.h>
#include <linux/signal.h>
#include <linux/securebits.h>
#include <linux/fs_struct.h>
#include <linux/compiler.h>
#include <linux/completion.h>
Expand Down Expand Up @@ -1133,7 +1132,7 @@ struct task_struct {
gid_t gid,egid,sgid,fsgid;
struct group_info *group_info;
kernel_cap_t cap_effective, cap_inheritable, cap_permitted, cap_bset;
unsigned keep_capabilities:1;
unsigned securebits;
struct user_struct *user;
#ifdef CONFIG_KEYS
struct key *request_key_auth; /* assumed request_key authority */
Expand Down
25 changes: 18 additions & 7 deletions trunk/include/linux/securebits.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,39 @@

#define SECUREBITS_DEFAULT 0x00000000

extern unsigned securebits;

/* When set UID 0 has no special privileges. When unset, we support
inheritance of root-permissions and suid-root executable under
compatibility mode. We raise the effective and inheritable bitmasks
*of the executable file* if the effective uid of the new process is
0. If the real uid is 0, we raise the inheritable bitmask of the
executable file. */
#define SECURE_NOROOT 0
#define SECURE_NOROOT 0
#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */

/* When set, setuid to/from uid 0 does not trigger capability-"fixes"
to be compatible with old programs relying on set*uid to loose
privileges. When unset, setuid doesn't change privileges. */
#define SECURE_NO_SETUID_FIXUP 2
#define SECURE_NO_SETUID_FIXUP 2
#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */

/* When set, a process can retain its capabilities even after
transitioning to a non-root user (the set-uid fixup suppressed by
bit 2). Bit-4 is cleared when a process calls exec(); setting both
bit 4 and 5 will create a barrier through exec that no exec()'d
child can use this feature again. */
#define SECURE_KEEP_CAPS 4
#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */

/* Each securesetting is implemented using two bits. One bit specify
whether the setting is on or off. The other bit specify whether the
setting is fixed or not. A setting which is fixed cannot be changed
from user-level. */
#define issecure_mask(X) (1 << (X))
#define issecure(X) (issecure_mask(X) & current->securebits)

#define issecure(X) ( (1 << (X+1)) & SECUREBITS_DEFAULT ? \
(1 << (X)) & SECUREBITS_DEFAULT : \
(1 << (X)) & securebits )
#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
issecure_mask(SECURE_NO_SETUID_FIXUP) | \
issecure_mask(SECURE_KEEP_CAPS))
#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)

#endif /* !_LINUX_SECUREBITS_H */
16 changes: 9 additions & 7 deletions trunk/include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
#include <linux/xfrm.h>
#include <net/flow.h>

extern unsigned securebits;

/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10

Expand All @@ -61,6 +59,8 @@ extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
extern int cap_task_post_setuid (uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
extern void cap_task_reparent_to_init (struct task_struct *p);
extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5, long *rc_p);
extern int cap_task_setscheduler (struct task_struct *p, int policy, struct sched_param *lp);
extern int cap_task_setioprio (struct task_struct *p, int ioprio);
extern int cap_task_setnice (struct task_struct *p, int nice);
Expand Down Expand Up @@ -720,7 +720,9 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @arg3 contains a argument.
* @arg4 contains a argument.
* @arg5 contains a argument.
* Return 0 if permission is granted.
* @rc_p contains a pointer to communicate back the forced return code
* Return 0 if permission is granted, and non-zero if the security module
* has taken responsibility (setting *rc_p) for the prctl call.
* @task_reparent_to_init:
* Set the security attributes in @p->security for a kernel thread that
* is being reparented to the init task.
Expand Down Expand Up @@ -1420,7 +1422,7 @@ struct security_operations {
int (*task_wait) (struct task_struct * p);
int (*task_prctl) (int option, unsigned long arg2,
unsigned long arg3, unsigned long arg4,
unsigned long arg5);
unsigned long arg5, long *rc_p);
void (*task_reparent_to_init) (struct task_struct * p);
void (*task_to_inode)(struct task_struct *p, struct inode *inode);

Expand Down Expand Up @@ -1684,7 +1686,7 @@ int security_task_kill(struct task_struct *p, struct siginfo *info,
int sig, u32 secid);
int security_task_wait(struct task_struct *p);
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
unsigned long arg4, unsigned long arg5, long *rc_p);
void security_task_reparent_to_init(struct task_struct *p);
void security_task_to_inode(struct task_struct *p, struct inode *inode);
int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
Expand Down Expand Up @@ -2271,9 +2273,9 @@ static inline int security_task_wait (struct task_struct *p)
static inline int security_task_prctl (int option, unsigned long arg2,
unsigned long arg3,
unsigned long arg4,
unsigned long arg5)
unsigned long arg5, long *rc_p)
{
return 0;
return cap_task_prctl(option, arg2, arg3, arg3, arg5, rc_p);
}

static inline void security_task_reparent_to_init (struct task_struct *p)
Expand Down
27 changes: 2 additions & 25 deletions trunk/kernel/sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -1632,10 +1632,9 @@ asmlinkage long sys_umask(int mask)
asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5)
{
long error;
long uninitialized_var(error);

error = security_task_prctl(option, arg2, arg3, arg4, arg5);
if (error)
if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error))
return error;

switch (option) {
Expand Down Expand Up @@ -1688,17 +1687,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
error = -EINVAL;
break;

case PR_GET_KEEPCAPS:
if (current->keep_capabilities)
error = 1;
break;
case PR_SET_KEEPCAPS:
if (arg2 != 0 && arg2 != 1) {
error = -EINVAL;
break;
}
current->keep_capabilities = arg2;
break;
case PR_SET_NAME: {
struct task_struct *me = current;
unsigned char ncomm[sizeof(me->comm)];
Expand Down Expand Up @@ -1732,17 +1720,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
case PR_SET_SECCOMP:
error = prctl_set_seccomp(arg2);
break;

case PR_CAPBSET_READ:
if (!cap_valid(arg2))
return -EINVAL;
return !!cap_raised(current->cap_bset, arg2);
case PR_CAPBSET_DROP:
#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
return cap_prctl_drop(arg2);
#else
return -EINVAL;
#endif
case PR_GET_TSC:
error = GET_TSC_CTL(arg2);
break;
Expand Down
1 change: 1 addition & 0 deletions trunk/security/capability.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static struct security_operations capability_ops = {
.task_setioprio = cap_task_setioprio,
.task_setnice = cap_task_setnice,
.task_post_setuid = cap_task_post_setuid,
.task_prctl = cap_task_prctl,
.task_reparent_to_init = cap_task_reparent_to_init,

.syslog = cap_syslog,
Expand Down
103 changes: 94 additions & 9 deletions trunk/security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,8 @@
#include <linux/hugetlb.h>
#include <linux/mount.h>
#include <linux/sched.h>

/* Global security state */

unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
EXPORT_SYMBOL(securebits);
#include <linux/prctl.h>
#include <linux/securebits.h>

int cap_netlink_send(struct sock *sk, struct sk_buff *skb)
{
Expand Down Expand Up @@ -368,7 +365,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)

/* AUD: Audit candidate if current->cap_effective is set */

current->keep_capabilities = 0;
current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS);
}

int cap_bprm_secureexec (struct linux_binprm *bprm)
Expand Down Expand Up @@ -448,7 +445,7 @@ static inline void cap_emulate_setxuid (int old_ruid, int old_euid,
{
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
(current->uid != 0 && current->euid != 0 && current->suid != 0) &&
!current->keep_capabilities) {
!issecure(SECURE_KEEP_CAPS)) {
cap_clear (current->cap_permitted);
cap_clear (current->cap_effective);
}
Expand Down Expand Up @@ -547,7 +544,7 @@ int cap_task_setnice (struct task_struct *p, int nice)
* this task could get inconsistent info. There can be no
* racing writer bc a task can only change its own caps.
*/
long cap_prctl_drop(unsigned long cap)
static long cap_prctl_drop(unsigned long cap)
{
if (!capable(CAP_SETPCAP))
return -EPERM;
Expand All @@ -556,6 +553,7 @@ long cap_prctl_drop(unsigned long cap)
cap_lower(current->cap_bset, cap);
return 0;
}

#else
int cap_task_setscheduler (struct task_struct *p, int policy,
struct sched_param *lp)
Expand All @@ -572,12 +570,99 @@ int cap_task_setnice (struct task_struct *p, int nice)
}
#endif

int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5, long *rc_p)
{
long error = 0;

switch (option) {
case PR_CAPBSET_READ:
if (!cap_valid(arg2))
error = -EINVAL;
else
error = !!cap_raised(current->cap_bset, arg2);
break;
#ifdef CONFIG_SECURITY_FILE_CAPABILITIES
case PR_CAPBSET_DROP:
error = cap_prctl_drop(arg2);
break;

/*
* The next four prctl's remain to assist with transitioning a
* system from legacy UID=0 based privilege (when filesystem
* capabilities are not in use) to a system using filesystem
* capabilities only - as the POSIX.1e draft intended.
*
* Note:
*
* PR_SET_SECUREBITS =
* issecure_mask(SECURE_KEEP_CAPS_LOCKED)
* | issecure_mask(SECURE_NOROOT)
* | issecure_mask(SECURE_NOROOT_LOCKED)
* | issecure_mask(SECURE_NO_SETUID_FIXUP)
* | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)
*
* will ensure that the current process and all of its
* children will be locked into a pure
* capability-based-privilege environment.
*/
case PR_SET_SECUREBITS:
if ((((current->securebits & SECURE_ALL_LOCKS) >> 1)
& (current->securebits ^ arg2)) /*[1]*/
|| ((current->securebits & SECURE_ALL_LOCKS
& ~arg2)) /*[2]*/
|| (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/
|| (cap_capable(current, CAP_SETPCAP) != 0)) { /*[4]*/
/*
* [1] no changing of bits that are locked
* [2] no unlocking of locks
* [3] no setting of unsupported bits
* [4] doing anything requires privilege (go read about
* the "sendmail capabilities bug")
*/
error = -EPERM; /* cannot change a locked bit */
} else {
current->securebits = arg2;
}
break;
case PR_GET_SECUREBITS:
error = current->securebits;
break;

#endif /* def CONFIG_SECURITY_FILE_CAPABILITIES */

case PR_GET_KEEPCAPS:
if (issecure(SECURE_KEEP_CAPS))
error = 1;
break;
case PR_SET_KEEPCAPS:
if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */
error = -EINVAL;
else if (issecure(SECURE_KEEP_CAPS_LOCKED))
error = -EPERM;
else if (arg2)
current->securebits |= issecure_mask(SECURE_KEEP_CAPS);
else
current->securebits &=
~issecure_mask(SECURE_KEEP_CAPS);
break;

default:
/* No functionality available - continue with default */
return 0;
}

/* Functionality provided */
*rc_p = error;
return 1;
}

void cap_task_reparent_to_init (struct task_struct *p)
{
cap_set_init_eff(p->cap_effective);
cap_clear(p->cap_inheritable);
cap_set_full(p->cap_permitted);
p->keep_capabilities = 0;
p->securebits = SECUREBITS_DEFAULT;
return;
}

Expand Down
Loading

0 comments on commit 5cefd36

Please sign in to comment.