contributed by <raygoah
>
假設每個出生日期的機率,在一年 365 天中是平均分布的
計算
機率大於
閱讀 生日攻擊 介紹
從 hash function 中的 collision, 藉由枚舉找到能產生相同 hash value 的訊息,即可用來偽造傳遞的訊息或是合約
若是 hash function 中使用的 hash value 其值域不夠大,bits 數不夠多,便可以藉由生日攻擊,找到一個 y ,使得 y 和原本的 x 在 hash funcion 中會得到相同的值,h(x)=h(y)
網路上搜尋到的資料中,大多以簽署電子合約時,利用修改合約中不容易被發現有更動過的地方,且更改後合約經過 hash function 產生出的 hash value 會相同,進而欺騙或是造成傷害
而關於生日攻擊的防禦辦法,可藉由將產生出的 hash value bits 數增加,減少 collision 的發生,讓經由生日攻擊找到 collision 的困難增加,需要更多更久的計算才能找到一個 collision,來達到防禦的作用
在 Frequently-Asked Questions 中有提到:
Q: How "random" is Stat Trek's Random Number Generator?
A: Although no computer algorithm can produce numbers that are truly random, Stat Trek's Random Number Generator produces numbers that are nearly random. Stat Trek's Random Number Generator can be used for most statistical applications (like randomly assigning subjects to treatments in a statistical experiment). However, it should not be used to generate numbers for cryptography.
大部分的電腦產生亂數都不是真正完全隨機的亂數,而是很接近隨機的一種偽隨機性的偽亂數
首先先輸入 seed 值 800,觀察得到的 Random Number Table,接著輸入其他 seed 值多次後,再回來輸入一開始的 seed 值 800,可以發現到 Random Number Table 中所有數字是相同的且順序也是一樣的
可以知道利用偽亂數所製作的亂數產生器,在 seed 值輸入相同的情況下,產生出來的『亂數』順序和值都會是一樣的,因此亂數產生器並不是真的完全隨機產生亂數,但是在 seed 值總是輸入不同的情況下,會造成產生的亂數永遠會是不同的錯覺
參考:
Manages the free list, the system allocates free pages here.
list_add_tail
將 page 加到 linked list 的最後一個,最後回傳新 pages 在 linked list 上被分配的編號,程式碼如下:
/*
* Obtain a specified number of elements from the buddy allocator, all under
* a single hold of the lock, for efficiency. Add them to the supplied list.
* Returns the number of new pages which were placed at *list.
*/
static int rmqueue_bulk(struct zone *zone, unsigned int order,
unsigned long count, struct list_head *list,
int migratetype)
{
int i, alloced = 0;
spin_lock(&zone->lock);
for (i = 0; i < count; ++i) {
struct page *page = __rmqueue(zone, order, migratetype);
if (unlikely(page == NULL))
break;
if (unlikely(check_pcp_refill(page)))
continue;
/*
* Split buddy pages returned by expand() are received here in
* physical page order. The page is added to the tail of
* caller's list. From the callers perspective, the linked list
* is ordered by page number under some conditions. This is
* useful for IO devices that can forward direction from the
* head, thus also in the physical page order. This is useful
* for IO devices that can merge IO requests if the physical
* pages are ordered properly.
*/
list_add_tail(&page->lru, list);
alloced++;
if (is_migrate_cma(get_pcppage_migratetype(page)))
__mod_zone_page_state(zone, NR_FREE_CMA_PAGES,
-(1 << order));
}
/*
* i pages were removed from the buddy list even if some leak due
* to check_pcp_refill failing so adjust NR_FREE_PAGES based
* on i. Do not confuse with 'alloced' which is the number of
* pages added to the pcp list.
*/
__mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order));
spin_unlock(&zone->lock);
return alloced;
}
/*
* This is the priority-queue data structure of the RT scheduling class:
*/
struct rt_prio_array {
DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */
struct list_head queue[MAX_RT_PRIO];
};
int x; /* Plain old int variable. */
typeof(x) y; /* Same type as x. Plain old int variable. */
#define container_of(ptr, type, member) \
__extension__({ \
const __typeof__(((type *) 0)->member) *__pmember = (ptr); \
(type *) ((char *) __pmember - offsetof(type, member)); \
})
/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/
/**
* list_del() - Remove a list node from the list
* @node: pointer to the node
*
* The node is only removed from the list. Neither the memory of the removed
* node nor the memory of the entry containing the node is free'd. The node
* has to be handled like an uninitialized node. Accessing the next or prev
* pointer of the node is not safe.
*
* Unlinked, initialized nodes are also uninitialized after list_del.
*
* LIST_POISONING can be enabled during build-time to provoke an invalid memory
* access when the memory behind the next/prev pointer is used after a list_del.
* This only works on systems which prohibit access to the predefined memory
* addresses.
*/
static __inline__ void list_del(struct list_head *node)
{
struct list_head *next = node->next;
struct list_head *prev = node->prev;
next->prev = prev;
prev->next = next;
#ifdef LIST_POISONING
node->prev = (struct list_head *)(0x00100100);
node->next = (struct list_head *)(0x00200200);
#endif
}
註解部份有提到,使用 list_del() 所刪除的 node,只是先從 linked list 中被移除,但其 node 所在的記憶體區段仍未被釋放,因此不該操作此 node 的 prev 或是 next pointer ,因為此 node 已經從 linked list 中被刪除,該被視為 uninitialized
而 LIST_POISONING 便是針對這個問題而產生的,將被 list_del() 所刪除的 node 其 prev/next pointer 指向 LIST_POISONING 所給定的記憶體位置,若是操作了已經被 list_del() 所刪除的 node 中的 prev/next pointer,就會變成存取到 LIST_POISONING 的記憶體地址,防止存取到非法的記憶體地址
list_for_each
:#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
list_for_each_safe
:#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)