aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/cred.h
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2009-09-02 04:13:40 -0400
committerJames Morris <jmorris@namei.org>2009-09-02 07:29:01 -0400
commite0e817392b9acf2c98d3be80c233dddb1b52003d (patch)
treeee680c020039313c9f9c40ab3542bb30a7363381 /include/linux/cred.h
parented6d76e4c32de0c2ad5f1d572b948ef49e465176 (diff)
CRED: Add some configurable debugging [try #6]
Add a config option (CONFIG_DEBUG_CREDENTIALS) to turn on some debug checking for credential management. The additional code keeps track of the number of pointers from task_structs to any given cred struct, and checks to see that this number never exceeds the usage count of the cred struct (which includes all references, not just those from task_structs). Furthermore, if SELinux is enabled, the code also checks that the security pointer in the cred struct is never seen to be invalid. This attempts to catch the bug whereby inode_has_perm() faults in an nfsd kernel thread on seeing cred->security be a NULL pointer (it appears that the credential struct has been previously released): http://www.kerneloops.org/oops.php?number=252883 Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'include/linux/cred.h')
-rw-r--r--include/linux/cred.h65
1 files changed, 64 insertions, 1 deletions
diff --git a/include/linux/cred.h b/include/linux/cred.h
index b3c76e815d66..85439abdbc80 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -114,6 +114,13 @@ struct thread_group_cred {
114 */ 114 */
115struct cred { 115struct cred {
116 atomic_t usage; 116 atomic_t usage;
117#ifdef CONFIG_DEBUG_CREDENTIALS
118 atomic_t subscribers; /* number of processes subscribed */
119 void *put_addr;
120 unsigned magic;
121#define CRED_MAGIC 0x43736564
122#define CRED_MAGIC_DEAD 0x44656144
123#endif
117 uid_t uid; /* real UID of the task */ 124 uid_t uid; /* real UID of the task */
118 gid_t gid; /* real GID of the task */ 125 gid_t gid; /* real GID of the task */
119 uid_t suid; /* saved UID of the task */ 126 uid_t suid; /* saved UID of the task */
@@ -143,6 +150,7 @@ struct cred {
143}; 150};
144 151
145extern void __put_cred(struct cred *); 152extern void __put_cred(struct cred *);
153extern void exit_creds(struct task_struct *);
146extern int copy_creds(struct task_struct *, unsigned long); 154extern int copy_creds(struct task_struct *, unsigned long);
147extern struct cred *prepare_creds(void); 155extern struct cred *prepare_creds(void);
148extern struct cred *prepare_exec_creds(void); 156extern struct cred *prepare_exec_creds(void);
@@ -158,6 +166,60 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
158extern int set_create_files_as(struct cred *, struct inode *); 166extern int set_create_files_as(struct cred *, struct inode *);
159extern void __init cred_init(void); 167extern void __init cred_init(void);
160 168
169/*
170 * check for validity of credentials
171 */
172#ifdef CONFIG_DEBUG_CREDENTIALS
173extern void __invalid_creds(const struct cred *, const char *, unsigned);
174extern void __validate_process_creds(struct task_struct *,
175 const char *, unsigned);
176
177static inline bool creds_are_invalid(const struct cred *cred)
178{
179 if (cred->magic != CRED_MAGIC)
180 return true;
181 if (atomic_read(&cred->usage) < atomic_read(&cred->subscribers))
182 return true;
183#ifdef CONFIG_SECURITY_SELINUX
184 if ((unsigned long) cred->security < PAGE_SIZE)
185 return true;
186 if ((*(u32*)cred->security & 0xffffff00) ==
187 (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))
188 return true;
189#endif
190 return false;
191}
192
193static inline void __validate_creds(const struct cred *cred,
194 const char *file, unsigned line)
195{
196 if (unlikely(creds_are_invalid(cred)))
197 __invalid_creds(cred, file, line);
198}
199
200#define validate_creds(cred) \
201do { \
202 __validate_creds((cred), __FILE__, __LINE__); \
203} while(0)
204
205#define validate_process_creds() \
206do { \
207 __validate_process_creds(current, __FILE__, __LINE__); \
208} while(0)
209
210extern void validate_creds_for_do_exit(struct task_struct *);
211#else
212static inline void validate_creds(const struct cred *cred)
213{
214}
215static inline void validate_creds_for_do_exit(struct task_struct *tsk)
216{
217}
218static inline void validate_process_creds(void)
219{
220}
221#endif
222
161/** 223/**
162 * get_new_cred - Get a reference on a new set of credentials 224 * get_new_cred - Get a reference on a new set of credentials
163 * @cred: The new credentials to reference 225 * @cred: The new credentials to reference
@@ -187,6 +249,7 @@ static inline struct cred *get_new_cred(struct cred *cred)
187static inline const struct cred *get_cred(const struct cred *cred) 249static inline const struct cred *get_cred(const struct cred *cred)
188{ 250{
189 struct cred *nonconst_cred = (struct cred *) cred; 251 struct cred *nonconst_cred = (struct cred *) cred;
252 validate_creds(cred);
190 return get_new_cred(nonconst_cred); 253 return get_new_cred(nonconst_cred);
191} 254}
192 255
@@ -205,7 +268,7 @@ static inline void put_cred(const struct cred *_cred)
205{ 268{
206 struct cred *cred = (struct cred *) _cred; 269 struct cred *cred = (struct cred *) _cred;
207 270
208 BUG_ON(atomic_read(&(cred)->usage) <= 0); 271 validate_creds(cred);
209 if (atomic_dec_and_test(&(cred)->usage)) 272 if (atomic_dec_and_test(&(cred)->usage))
210 __put_cred(cred); 273 __put_cred(cred);
211} 274}