3 |
* |
* |
4 |
* Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO. |
* Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO. |
5 |
* |
* |
6 |
* Copyright (C) 2005-2007 NTT DATA CORPORATION |
* Copyright (C) 2005-2008 NTT DATA CORPORATION |
7 |
* |
* |
8 |
* Version: 1.3.2 2007/02/14 |
* Version: 1.6.0-pre 2008/03/04 |
9 |
* |
* |
10 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
11 |
* See README.ccs for ChangeLog. |
* See README.ccs for ChangeLog. |
32 |
#include <linux/proc_fs.h> |
#include <linux/proc_fs.h> |
33 |
#include <linux/ccs_common.h> |
#include <linux/ccs_common.h> |
34 |
|
|
|
extern int sbin_init_started; |
|
|
|
|
35 |
/***** realpath handler *****/ |
/***** realpath handler *****/ |
36 |
|
|
37 |
/* |
/* |
52 |
{ |
{ |
53 |
char *start = buffer; |
char *start = buffer; |
54 |
char *end = buffer + buflen; |
char *end = buffer + buflen; |
55 |
int is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)); |
bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)); |
56 |
|
|
57 |
if (buflen < 256) goto out; |
if (buflen < 256) goto out; |
58 |
|
|
165 |
struct dentry *d_dentry; |
struct dentry *d_dentry; |
166 |
struct vfsmount *d_mnt; |
struct vfsmount *d_mnt; |
167 |
if (!dentry || !mnt || !newname || newname_len <= 0) return -EINVAL; |
if (!dentry || !mnt || !newname || newname_len <= 0) return -EINVAL; |
|
if (!current->fs) { |
|
|
printk("%s: current->fs == NULL for pid=%d\n", __FUNCTION__, current->pid); |
|
|
return -ENOENT; |
|
|
} |
|
168 |
d_dentry = dget(dentry); |
d_dentry = dget(dentry); |
169 |
d_mnt = mntget(mnt); |
d_mnt = mntget(mnt); |
170 |
/***** CRITICAL SECTION START *****/ |
/***** CRITICAL SECTION START *****/ |
191 |
{ |
{ |
192 |
struct nameidata nd; |
struct nameidata nd; |
193 |
if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) { |
if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) { |
194 |
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) |
195 |
|
char *buf = realpath_from_dentry(nd.path.dentry, nd.path.mnt); |
196 |
|
path_put(&nd.path); |
197 |
|
#else |
198 |
char *buf = realpath_from_dentry(nd.dentry, nd.mnt); |
char *buf = realpath_from_dentry(nd.dentry, nd.mnt); |
199 |
path_release(&nd); |
path_release(&nd); |
200 |
|
#endif |
201 |
return buf; |
return buf; |
202 |
} |
} |
203 |
return NULL; |
return NULL; |
207 |
{ |
{ |
208 |
struct nameidata nd; |
struct nameidata nd; |
209 |
if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW, &nd) == 0) { |
if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW, &nd) == 0) { |
210 |
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) |
211 |
|
char *buf = realpath_from_dentry(nd.path.dentry, nd.path.mnt); |
212 |
|
path_put(&nd.path); |
213 |
|
#else |
214 |
char *buf = realpath_from_dentry(nd.dentry, nd.mnt); |
char *buf = realpath_from_dentry(nd.dentry, nd.mnt); |
215 |
path_release(&nd); |
path_release(&nd); |
216 |
|
#endif |
217 |
return buf; |
return buf; |
218 |
} |
} |
219 |
return NULL; |
return NULL; |
241 |
} |
} |
242 |
|
|
243 |
/* Allocate memory for structures. The RAM is chunked, so NEVER try to kfree() the returned pointer. */ |
/* Allocate memory for structures. The RAM is chunked, so NEVER try to kfree() the returned pointer. */ |
244 |
char *alloc_element(const unsigned int size) |
void *alloc_element(const unsigned int size) |
245 |
{ |
{ |
246 |
static DECLARE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
247 |
static char *buf = NULL; |
static char *buf = NULL; |
248 |
static unsigned int buf_used_len = PAGE_SIZE; |
static unsigned int buf_used_len = PAGE_SIZE; |
249 |
char *ptr = NULL; |
char *ptr = NULL; |
250 |
const unsigned int word_aligned_size = ROUNDUP(size); |
const unsigned int word_aligned_size = ROUNDUP(size); |
251 |
if (word_aligned_size > PAGE_SIZE) return NULL; |
if (word_aligned_size > PAGE_SIZE) return NULL; |
252 |
down(&lock); |
mutex_lock(&lock); |
253 |
if (buf_used_len + word_aligned_size > PAGE_SIZE) { |
if (buf_used_len + word_aligned_size > PAGE_SIZE) { |
254 |
if ((ptr = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) { |
if ((ptr = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) { |
255 |
printk("ERROR: Out of memory for alloc_element().\n"); |
printk("ERROR: Out of memory for alloc_element().\n"); |
272 |
} |
} |
273 |
} |
} |
274 |
} |
} |
275 |
up(&lock); |
mutex_unlock(&lock); |
276 |
return ptr; |
return ptr; |
277 |
} |
} |
278 |
|
|
287 |
|
|
288 |
#define MAX_HASH 256 |
#define MAX_HASH 256 |
289 |
|
|
290 |
typedef struct name_entry { |
struct name_entry { |
291 |
struct name_entry *next; /* Pointer to next record. NULL if none. */ |
struct list1_head list; |
292 |
struct path_info entry; |
struct path_info entry; |
293 |
} NAME_ENTRY; |
}; |
294 |
|
|
295 |
typedef struct free_memory_block_list { |
struct free_memory_block_list { |
296 |
struct free_memory_block_list *next; /* Pointer to next record. NULL if none. */ |
struct list_head list; |
297 |
char *ptr; /* Pointer to a free area. */ |
char *ptr; /* Pointer to a free area. */ |
298 |
int len; /* Length of the area. */ |
int len; /* Length of the area. */ |
299 |
} FREE_MEMORY_BLOCK_LIST; |
}; |
300 |
|
|
301 |
|
static struct list1_head name_list[MAX_HASH]; /* The list of names. */ |
302 |
|
|
303 |
/* Keep the given name on the RAM. The RAM is shared, so NEVER try to modify or kfree() the returned name. */ |
/* Keep the given name on the RAM. The RAM is shared, so NEVER try to modify or kfree() the returned name. */ |
304 |
const struct path_info *SaveName(const char *name) |
const struct path_info *SaveName(const char *name) |
305 |
{ |
{ |
306 |
static FREE_MEMORY_BLOCK_LIST fmb_list = { NULL, NULL, 0 }; |
static LIST_HEAD(fmb_list); |
307 |
static NAME_ENTRY name_list[MAX_HASH]; /* The list of names. */ |
static DEFINE_MUTEX(lock); |
308 |
static DECLARE_MUTEX(lock); |
struct name_entry *ptr; |
|
NAME_ENTRY *ptr, *prev = NULL; |
|
309 |
unsigned int hash; |
unsigned int hash; |
310 |
FREE_MEMORY_BLOCK_LIST *fmb = &fmb_list; |
struct free_memory_block_list *fmb; |
311 |
int len; |
int len; |
312 |
static int first_call = 1; |
char *cp; |
313 |
if (!name) return NULL; |
if (!name) return NULL; |
314 |
len = strlen(name) + 1; |
len = strlen(name) + 1; |
315 |
if (len > CCS_MAX_PATHNAME_LEN) { |
if (len > CCS_MAX_PATHNAME_LEN) { |
317 |
return NULL; |
return NULL; |
318 |
} |
} |
319 |
hash = full_name_hash((const unsigned char *) name, len - 1); |
hash = full_name_hash((const unsigned char *) name, len - 1); |
320 |
down(&lock); |
mutex_lock(&lock); |
321 |
if (first_call) { |
list1_for_each_entry(ptr, &name_list[hash % MAX_HASH], list) { |
|
int i; |
|
|
first_call = 0; |
|
|
memset(&name_list, 0, sizeof(name_list)); |
|
|
for (i = 0; i < MAX_HASH; i++) { |
|
|
name_list[i].entry.name = "/"; |
|
|
fill_path_info(&name_list[i].entry); |
|
|
} |
|
|
if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE) panic("Bad size."); |
|
|
} |
|
|
ptr = &name_list[hash % MAX_HASH]; |
|
|
while (ptr) { |
|
322 |
if (hash == ptr->entry.hash && strcmp(name, ptr->entry.name) == 0) goto out; |
if (hash == ptr->entry.hash && strcmp(name, ptr->entry.name) == 0) goto out; |
|
prev = ptr; ptr = ptr->next; |
|
323 |
} |
} |
324 |
while (len > fmb->len) { |
list_for_each_entry(fmb, &fmb_list, list) { |
325 |
if (fmb->next) { |
if (len <= fmb->len) goto ready; |
|
fmb = fmb->next; |
|
|
} else { |
|
|
char *cp; |
|
|
if ((cp = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL || (fmb->next = (FREE_MEMORY_BLOCK_LIST *) alloc_element(sizeof(FREE_MEMORY_BLOCK_LIST))) == NULL) { |
|
|
kfree(cp); |
|
|
printk("ERROR: Out of memory for SaveName().\n"); |
|
|
if (!sbin_init_started) panic("MAC Initialization failed.\n"); |
|
|
goto out; /* ptr == NULL */ |
|
|
} |
|
|
memset(cp, 0, PAGE_SIZE); |
|
|
allocated_memory_for_savename += PAGE_SIZE; |
|
|
fmb = fmb->next; |
|
|
fmb->ptr = cp; |
|
|
fmb->len = PAGE_SIZE; |
|
|
} |
|
326 |
} |
} |
327 |
if ((ptr = (NAME_ENTRY *) alloc_element(sizeof(NAME_ENTRY))) == NULL) goto out; |
cp = kmalloc(PAGE_SIZE, GFP_KERNEL); |
328 |
|
fmb = kmalloc(sizeof(*fmb), GFP_KERNEL); |
329 |
|
if (!cp || !fmb) { |
330 |
|
kfree(cp); |
331 |
|
kfree(fmb); |
332 |
|
printk("ERROR: Out of memory for SaveName().\n"); |
333 |
|
if (!sbin_init_started) panic("MAC Initialization failed.\n"); |
334 |
|
ptr = NULL; |
335 |
|
goto out; |
336 |
|
} |
337 |
|
memset(cp, 0, PAGE_SIZE); |
338 |
|
allocated_memory_for_savename += PAGE_SIZE; |
339 |
|
list_add(&fmb->list, &fmb_list); |
340 |
|
fmb->ptr = cp; |
341 |
|
fmb->len = PAGE_SIZE; |
342 |
|
ready: |
343 |
|
ptr = alloc_element(sizeof(*ptr)); |
344 |
|
if (!ptr) goto out; |
345 |
ptr->entry.name = fmb->ptr; |
ptr->entry.name = fmb->ptr; |
346 |
memmove(fmb->ptr, name, len); |
memmove(fmb->ptr, name, len); |
347 |
fill_path_info(&ptr->entry); |
fill_path_info(&ptr->entry); |
348 |
fmb->ptr += len; |
fmb->ptr += len; |
349 |
fmb->len -= len; |
fmb->len -= len; |
350 |
prev->next = ptr; /* prev != NULL because name_list is not empty. */ |
list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]); |
351 |
if (fmb->len == 0) { |
if (fmb->len == 0) { |
352 |
FREE_MEMORY_BLOCK_LIST *ptr = &fmb_list; |
list_del(&fmb->list); |
353 |
while (ptr->next != fmb) ptr = ptr->next; ptr->next = fmb->next; |
kfree(fmb); |
354 |
} |
} |
355 |
out: |
out: |
356 |
up(&lock); |
mutex_unlock(&lock); |
357 |
return ptr ? &ptr->entry : NULL; |
return ptr ? &ptr->entry : NULL; |
358 |
} |
} |
359 |
|
|
360 |
/***** Dynamic memory allocator. *****/ |
/***** Dynamic memory allocator. *****/ |
361 |
|
|
362 |
typedef struct cache_entry { |
struct cache_entry { |
363 |
struct list_head list; |
struct list_head list; |
364 |
void *ptr; |
void *ptr; |
365 |
int size; |
int size; |
366 |
} CACHE_ENTRY; |
}; |
367 |
|
|
368 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) |
369 |
static struct kmem_cache *ccs_cachep = NULL; |
static struct kmem_cache *ccs_cachep = NULL; |
373 |
|
|
374 |
void __init realpath_Init(void) |
void __init realpath_Init(void) |
375 |
{ |
{ |
376 |
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(CACHE_ENTRY), 0, 0, NULL, NULL); |
int i; |
377 |
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) |
378 |
|
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL); |
379 |
|
#else |
380 |
|
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL, NULL); |
381 |
|
#endif |
382 |
if (!ccs_cachep) panic("Can't create cache.\n"); |
if (!ccs_cachep) panic("Can't create cache.\n"); |
383 |
|
for (i = 0; i < MAX_HASH; i++) { |
384 |
|
INIT_LIST1_HEAD(&name_list[i]); |
385 |
|
} |
386 |
|
if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE) panic("Bad size."); |
387 |
|
INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list); |
388 |
|
KERNEL_DOMAIN.domainname = SaveName(ROOT_NAME); |
389 |
|
list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list); |
390 |
|
if (FindDomain(ROOT_NAME) != &KERNEL_DOMAIN) panic("Can't register KERNEL_DOMAIN"); |
391 |
} |
} |
392 |
|
|
393 |
static LIST_HEAD(cache_list); |
static LIST_HEAD(cache_list); |
399 |
return dynamic_memory_size; |
return dynamic_memory_size; |
400 |
} |
} |
401 |
|
|
402 |
char *ccs_alloc(const size_t size) |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) |
403 |
|
static int round2(size_t size) |
404 |
|
{ |
405 |
|
#if PAGE_SIZE == 4096 |
406 |
|
size_t bsize = 32; |
407 |
|
#else |
408 |
|
size_t bsize = 64; |
409 |
|
#endif |
410 |
|
while (size > bsize) bsize <<= 1; |
411 |
|
return bsize; |
412 |
|
} |
413 |
|
#endif |
414 |
|
|
415 |
|
void *ccs_alloc(const size_t size) |
416 |
{ |
{ |
417 |
void *ret = kmalloc(size, GFP_KERNEL); |
void *ret = kmalloc(size, GFP_KERNEL); |
418 |
if (ret) { |
if (ret) { |
419 |
CACHE_ENTRY *new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL); |
struct cache_entry *new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL); |
420 |
if (!new_entry) { |
if (!new_entry) { |
421 |
kfree(ret); ret = NULL; |
kfree(ret); ret = NULL; |
422 |
} else { |
} else { |
423 |
INIT_LIST_HEAD(&new_entry->list); |
INIT_LIST_HEAD(&new_entry->list); |
424 |
new_entry->ptr = ret; |
new_entry->ptr = ret; |
425 |
new_entry->size = size; |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) |
426 |
|
new_entry->size = ksize(ret); |
427 |
|
#else |
428 |
|
new_entry->size = round2(size); |
429 |
|
#endif |
430 |
spin_lock(&cache_list_lock); |
spin_lock(&cache_list_lock); |
431 |
list_add_tail(&new_entry->list, &cache_list); |
list_add_tail(&new_entry->list, &cache_list); |
432 |
dynamic_memory_size += size; |
dynamic_memory_size += new_entry->size; |
433 |
spin_unlock(&cache_list_lock); |
spin_unlock(&cache_list_lock); |
434 |
memset(ret, 0, size); |
memset(ret, 0, size); |
435 |
} |
} |
436 |
} |
} |
437 |
return (char *) ret; |
return ret; |
438 |
} |
} |
439 |
|
|
440 |
void ccs_free(const void *p) |
void ccs_free(const void *p) |
441 |
{ |
{ |
442 |
struct list_head *v; |
struct list_head *v; |
443 |
CACHE_ENTRY *entry = NULL; |
struct cache_entry *entry = NULL; |
444 |
if (!p) return; |
if (!p) return; |
445 |
spin_lock(&cache_list_lock); |
spin_lock(&cache_list_lock); |
446 |
list_for_each(v, &cache_list) { |
list_for_each(v, &cache_list) { |
447 |
entry = list_entry(v, CACHE_ENTRY, list); |
entry = list_entry(v, struct cache_entry, list); |
448 |
if (entry->ptr != p) { |
if (entry->ptr != p) { |
449 |
entry = NULL; continue; |
entry = NULL; continue; |
450 |
} |
} |