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.5.2-pre 2007/10/19 |
* Version: 1.6.0-pre 2008/03/11 |
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 |
/* |
/* |
81 |
continue; |
continue; |
82 |
} |
} |
83 |
if (is_dir) { |
if (is_dir) { |
84 |
is_dir = 0; *--end = '/'; buflen--; |
is_dir = false; *--end = '/'; buflen--; |
85 |
} |
} |
86 |
parent = dentry->d_parent; |
parent = dentry->d_parent; |
87 |
{ |
{ |
181 |
/* These functions use ccs_alloc(), so caller must ccs_free() if these functions didn't return NULL. */ |
/* These functions use ccs_alloc(), so caller must ccs_free() if these functions didn't return NULL. */ |
182 |
char *realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt) |
char *realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt) |
183 |
{ |
{ |
184 |
char *buf = ccs_alloc(CCS_MAX_PATHNAME_LEN); |
char *buf = ccs_alloc(sizeof(struct ccs_page_buffer)); |
185 |
if (buf && realpath_from_dentry2(dentry, mnt, buf, CCS_MAX_PATHNAME_LEN - 1) == 0) return buf; |
if (buf && realpath_from_dentry2(dentry, mnt, buf, CCS_MAX_PATHNAME_LEN - 1) == 0) return buf; |
186 |
ccs_free(buf); |
ccs_free(buf); |
187 |
return NULL; |
return NULL; |
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; |
251 |
if (word_aligned_size > PAGE_SIZE) return NULL; |
if (word_aligned_size > PAGE_SIZE) return NULL; |
252 |
mutex_lock(&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 = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) { |
255 |
printk("ERROR: Out of memory for alloc_element().\n"); |
printk("ERROR: Out of memory for alloc_element().\n"); |
256 |
if (!sbin_init_started) panic("MAC Initialization failed.\n"); |
if (!sbin_init_started) panic("MAC Initialization failed.\n"); |
257 |
} else { |
} else { |
|
memset(ptr, 0, PAGE_SIZE); |
|
258 |
buf = ptr; |
buf = ptr; |
259 |
allocated_memory_for_elements += PAGE_SIZE; |
allocated_memory_for_elements += PAGE_SIZE; |
260 |
buf_used_len = word_aligned_size; |
buf_used_len = word_aligned_size; |
278 |
/***** Shared memory allocator. *****/ |
/***** Shared memory allocator. *****/ |
279 |
|
|
280 |
static unsigned int allocated_memory_for_savename = 0; |
static unsigned int allocated_memory_for_savename = 0; |
281 |
|
static unsigned int allocated_memory_for_pool = 0; |
282 |
|
|
283 |
unsigned int GetMemoryUsedForSaveName(void) |
unsigned int GetMemoryUsedForSaveName(void) |
284 |
{ |
{ |
285 |
return allocated_memory_for_savename; |
return allocated_memory_for_savename + allocated_memory_for_pool; |
286 |
} |
} |
287 |
|
|
288 |
#define MAX_HASH 256 |
#define MAX_HASH 256 |
289 |
|
|
290 |
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 |
}; |
}; |
294 |
|
|
295 |
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 |
}; |
}; |
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 struct free_memory_block_list fmb_list = { NULL, NULL, 0 }; |
static LIST_HEAD(fmb_list); |
|
static struct name_entry name_list[MAX_HASH]; /* The list of names. */ |
|
307 |
static DEFINE_MUTEX(lock); |
static DEFINE_MUTEX(lock); |
308 |
struct name_entry *ptr, *prev = NULL; |
struct name_entry *ptr; |
309 |
unsigned int hash; |
unsigned int hash; |
310 |
struct 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) { |
318 |
} |
} |
319 |
hash = full_name_hash((const unsigned char *) name, len - 1); |
hash = full_name_hash((const unsigned char *) name, len - 1); |
320 |
mutex_lock(&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 = alloc_element(sizeof(*fmb))) == 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 = alloc_element(sizeof(*ptr))) == NULL) goto out; |
cp = kzalloc(PAGE_SIZE, GFP_KERNEL); |
328 |
|
fmb = kzalloc(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 |
|
allocated_memory_for_savename += PAGE_SIZE; |
338 |
|
list_add(&fmb->list, &fmb_list); |
339 |
|
fmb->ptr = cp; |
340 |
|
fmb->len = PAGE_SIZE; |
341 |
|
ready: |
342 |
|
ptr = alloc_element(sizeof(*ptr)); |
343 |
|
if (!ptr) goto out; |
344 |
ptr->entry.name = fmb->ptr; |
ptr->entry.name = fmb->ptr; |
345 |
memmove(fmb->ptr, name, len); |
memmove(fmb->ptr, name, len); |
346 |
fill_path_info(&ptr->entry); |
fill_path_info(&ptr->entry); |
347 |
fmb->ptr += len; |
fmb->ptr += len; |
348 |
fmb->len -= len; |
fmb->len -= len; |
349 |
prev->next = ptr; /* prev != NULL because name_list is not empty. */ |
list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]); |
350 |
if (fmb->len == 0) { |
if (fmb->len == 0) { |
351 |
struct free_memory_block_list *ptr = &fmb_list; |
list_del(&fmb->list); |
352 |
while (ptr->next != fmb) ptr = ptr->next; ptr->next = fmb->next; |
kfree(fmb); |
353 |
} |
} |
354 |
out: |
out: |
355 |
mutex_unlock(&lock); |
mutex_unlock(&lock); |
370 |
static kmem_cache_t *ccs_cachep = NULL; |
static kmem_cache_t *ccs_cachep = NULL; |
371 |
#endif |
#endif |
372 |
|
|
373 |
|
#ifdef CCS_MAX_RESERVED_PAGES |
374 |
|
#define MAX_CCS_PAGE_BUFFER_POOL (CCS_MAX_RESERVED_PAGES) |
375 |
|
#else |
376 |
|
#define MAX_CCS_PAGE_BUFFER_POOL 10 |
377 |
|
#endif |
378 |
|
|
379 |
|
static struct ccs_page_buffer *ccs_page_buffer_pool[MAX_CCS_PAGE_BUFFER_POOL]; |
380 |
|
static bool ccs_page_buffer_pool_in_use[MAX_CCS_PAGE_BUFFER_POOL]; |
381 |
|
|
382 |
void __init realpath_Init(void) |
void __init realpath_Init(void) |
383 |
{ |
{ |
384 |
|
int i; |
385 |
|
if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE) panic("Bad size."); |
386 |
|
if (sizeof(struct path_info_with_data) > sizeof(struct ccs_page_buffer)) panic("Bad size."); |
387 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) |
388 |
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL); |
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL); |
389 |
#else |
#else |
390 |
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL, NULL); |
ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL, NULL); |
391 |
#endif |
#endif |
392 |
if (!ccs_cachep) panic("Can't create cache.\n"); |
if (!ccs_cachep) panic("Can't create cache.\n"); |
393 |
|
for (i = 0; i < MAX_HASH; i++) { |
394 |
|
INIT_LIST1_HEAD(&name_list[i]); |
395 |
|
} |
396 |
|
INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list); |
397 |
|
KERNEL_DOMAIN.domainname = SaveName(ROOT_NAME); |
398 |
|
list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list); |
399 |
|
if (FindDomain(ROOT_NAME) != &KERNEL_DOMAIN) panic("Can't register KERNEL_DOMAIN"); |
400 |
|
memset(ccs_page_buffer_pool, 0, sizeof(ccs_page_buffer_pool)); |
401 |
|
for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) ccs_page_buffer_pool_in_use[i] = false; |
402 |
} |
} |
403 |
|
|
404 |
static LIST_HEAD(cache_list); |
static LIST_HEAD(cache_list); |
423 |
} |
} |
424 |
#endif |
#endif |
425 |
|
|
426 |
|
static spinlock_t ccs_page_buffer_pool_lock = SPIN_LOCK_UNLOCKED; |
427 |
|
|
428 |
void *ccs_alloc(const size_t size) |
void *ccs_alloc(const size_t size) |
429 |
{ |
{ |
430 |
void *ret = kmalloc(size, GFP_KERNEL); |
int i; |
431 |
if (ret) { |
void *ret; |
432 |
struct cache_entry *new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL); |
struct cache_entry *new_entry; |
433 |
if (!new_entry) { |
if (size != sizeof(struct ccs_page_buffer)) goto normal; |
434 |
kfree(ret); ret = NULL; |
for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) { |
435 |
} else { |
struct ccs_page_buffer *ptr; |
436 |
INIT_LIST_HEAD(&new_entry->list); |
if (ccs_page_buffer_pool_in_use[i]) continue; |
437 |
new_entry->ptr = ret; |
spin_lock(&ccs_page_buffer_pool_lock); |
438 |
|
if (ccs_page_buffer_pool_in_use[i]) { |
439 |
|
spin_unlock(&ccs_page_buffer_pool_lock); |
440 |
|
continue; |
441 |
|
} |
442 |
|
ccs_page_buffer_pool_in_use[i] = true; |
443 |
|
spin_unlock(&ccs_page_buffer_pool_lock); |
444 |
|
ptr = ccs_page_buffer_pool[i]; |
445 |
|
if (!ptr) { |
446 |
|
ptr = kmalloc(sizeof(struct ccs_page_buffer), GFP_KERNEL); |
447 |
|
spin_lock(&ccs_page_buffer_pool_lock); |
448 |
|
if (ptr) { |
449 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) |
450 |
new_entry->size = ksize(ret); |
allocated_memory_for_pool += ksize(ptr); |
451 |
#else |
#else |
452 |
new_entry->size = round2(size); |
allocated_memory_for_pool += round2(sizeof(struct ccs_page_buffer)); |
453 |
#endif |
#endif |
454 |
spin_lock(&cache_list_lock); |
} else { |
455 |
list_add_tail(&new_entry->list, &cache_list); |
ccs_page_buffer_pool_in_use[i] = false; |
456 |
dynamic_memory_size += new_entry->size; |
} |
457 |
spin_unlock(&cache_list_lock); |
spin_unlock(&ccs_page_buffer_pool_lock); |
458 |
memset(ret, 0, size); |
if (!ptr) goto normal; |
459 |
|
ccs_page_buffer_pool[i] = ptr; |
460 |
|
printk(KERN_DEBUG "Allocated permanent buffer %d/%d\n", i, MAX_CCS_PAGE_BUFFER_POOL); |
461 |
} |
} |
462 |
|
memset(ptr, 0, sizeof(struct ccs_page_buffer)); |
463 |
|
return ptr; |
464 |
} |
} |
465 |
|
normal: |
466 |
|
ret = kzalloc(size, GFP_KERNEL); |
467 |
|
if (!ret) goto out; |
468 |
|
new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL); |
469 |
|
if (!new_entry) { |
470 |
|
kfree(ret); ret = NULL; |
471 |
|
goto out; |
472 |
|
} |
473 |
|
INIT_LIST_HEAD(&new_entry->list); |
474 |
|
new_entry->ptr = ret; |
475 |
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) |
476 |
|
new_entry->size = ksize(ret); |
477 |
|
#else |
478 |
|
new_entry->size = round2(size); |
479 |
|
#endif |
480 |
|
spin_lock(&cache_list_lock); |
481 |
|
list_add_tail(&new_entry->list, &cache_list); |
482 |
|
dynamic_memory_size += new_entry->size; |
483 |
|
spin_unlock(&cache_list_lock); |
484 |
|
out: |
485 |
return ret; |
return ret; |
486 |
} |
} |
487 |
|
|
488 |
void ccs_free(const void *p) |
void ccs_free(const void *p) |
489 |
{ |
{ |
490 |
|
int i; |
491 |
struct list_head *v; |
struct list_head *v; |
492 |
struct cache_entry *entry = NULL; |
struct cache_entry *entry = NULL; |
493 |
if (!p) return; |
if (!p) return; |
494 |
|
for (i = 0; i < MAX_CCS_PAGE_BUFFER_POOL; i++) { |
495 |
|
bool done; |
496 |
|
if (p != ccs_page_buffer_pool[i]) continue; |
497 |
|
spin_lock(&ccs_page_buffer_pool_lock); |
498 |
|
done = ccs_page_buffer_pool_in_use[i]; |
499 |
|
if (done) ccs_page_buffer_pool_in_use[i] = false; |
500 |
|
spin_unlock(&ccs_page_buffer_pool_lock); |
501 |
|
if (done) return; |
502 |
|
} |
503 |
spin_lock(&cache_list_lock); |
spin_lock(&cache_list_lock); |
504 |
list_for_each(v, &cache_list) { |
list_for_each(v, &cache_list) { |
505 |
entry = list_entry(v, struct cache_entry, list); |
entry = list_entry(v, struct cache_entry, list); |