static asmlinkage void no_lcall7(struct pt_regs * regs);
/* tożsamościowe mapowanie numerów sygnałów . Inne domeny wykonywania
mogą mieć inne. */
static unsigned long ident_map[32] = {
0, 1, 2, 3, 4, 5, 6,
7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31
};
struct exec_domain default_exec_domain = {
/* nazwa - standardowa domena wykonania linuxa*/
"Linux", /* name */
/* lcall7 powoduje błąd segmentacji */
no_lcall7, /* lcall7 causes a seg fault. */
/* obsługuje pełny zakres osobowości (personalities) */
0, 0xff, /* All personalities. */
/* mapowanie ze standadowych numerów sygnałów w Linuxie
*/
/* na charakterystyczne dla domeny wykonywania */
ident_map, /* Identity map signals. */
/* i na odwrót - w przypadku domeny Linux - oba te mapowania
są identycznościowe */
ident_map, /* - both ways. */
/* licznik wykorzystania - ile procesów korzysta z tej domeny,
NULL - nie zliczamy tego */
NULL, /* No usage counter. */
/* następny element na liście domen */
NULL /* Nothing after this in the list.
*/
};
/* lista dostępnych w systemie domen wykonywania */
static struct exec_domain *exec_domains = &default_exec_domain;
static asmlinkage void no_lcall7(struct pt_regs * regs)
{
/*
* This may have been a static linked SVr4 binary,
so we would have the
* personality set incorrectly. Check to see
whether SVr4 is available,
* and use it, otherwise give the user a SEGV.
*/
/* jeśli to jest kod SVr4 zlinkowany statycznie, to mógł
zajść przypadek, */
/* że osobowość(personality) była ustawiona niepoprawnie.
*/
/* Sprawdź, czy jest dostępna domena dla SVr4 i jeśli tak
użyj jej, */
/* jeśli nie, to wywołaj błąd segmentacji */
/* zmieniamy domenę wykonywania bieżącego procesu, */
/* jeśli był licznik odwołań do struktury tej domeny jest
używany to go zmniejsz */
if (current->exec_domain && current->exec_domain->use_count)
(*current->exec_domain->use_count)--;
/* zmień osobowość na SVr4 */
current->personality = PER_SVR4;
/* spróbuj znaleźć domenę która to obsługuję */
current->exec_domain = lookup_exec_domain(current->personality);
/* jeśli trzeba zwiększ licznik odwołań do niej */
if (current->exec_domain && current->exec_domain->use_count)
(*current->exec_domain->use_count)++;
/* jeśli jest procedura obsługi różna od tej - czyli znaleziono
inną domenę */
/* niż standardowa Linuxa - to wywołaj tę procedurę
*/
if (current->exec_domain && current->exec_domain->handler
&& current->exec_domain->handler != no_lcall7) {
current->exec_domain->handler(regs);
return;
}
/* w przeciwnym razie błąd segmentacji */
send_sig(SIGSEGV, current, 1);
}
struct exec_domain *lookup_exec_domain(unsigned long personality)
{
unsigned long pers = personality & PER_MASK;
struct exec_domain *it;
/* przejrzyj listę domen i znajdź pierwszą do której zakresu
należy ta osobowość */
for (it=exec_domains; it; it=it->next)
if (pers >= it->pers_low
&& pers <= it->pers_high)
return it;
/* Tu nigdy nie dojdzie gdyż na końcu listy jest standardowa
domena Linuxa, */
/* a ona obsługuje wszystkie osobowości */
/* Should never get this far. */
printk(KERN_ERR "No execution domain for personality 0x%02lx\n",
pers);
return NULL;
}
/* zarejestruj nową domenę wykonywania */
int register_exec_domain(struct exec_domain *it)
{
struct exec_domain *tmp;
/* czy różna od NULL */
if (!it)
return -EINVAL;
/* czy nie tworzy jakiejś listy */
if (it->next)
return -EBUSY;
/* czy nie ma jej na liście domen */
for (tmp=exec_domains; tmp; tmp=tmp->next)
if (tmp == it)
return -EBUSY;
/* jeśli wszystko ok. to dodaj nową domenę na początku listy
*/
it->next = exec_domains;
exec_domains = it;
return 0;
}
/* wyrejestruj domenę wykonywania */
int unregister_exec_domain(struct exec_domain *it)
{
struct exec_domain ** tmp;
tmp = &exec_domains;
/* znajdź tę domenę na liście domen i usuń ją */
while (*tmp) {
if (it == *tmp) {
*tmp = it->next;
it->next = NULL;
return 0;
}
tmp = &(*tmp)->next;
}
return -EINVAL;
}
asmlinkage int sys_personality(unsigned long personality)
{
struct exec_domain *it;
unsigned long old_personality;
if (personality == 0xffffffff)
return current->personality;
/* znajdź domenę wykonywania rozpoznającą to osobowość */
it = lookup_exec_domain(personality);
if (!it)
return -EINVAL;
/* zapamiętaj poprzednią osobowość procesu */
old_personality = current->personality;
/* zmniejsz liczbę odwołań do domeny */
if (current->exec_domain && current->exec_domain->use_count)
(*current->exec_domain->use_count)--;
/* ustaw nową osobowość */
current->personality = personality;
/* ustaw nową domenę wykonywania */
current->exec_domain = it;
/* zwiększ licznik odwołań do niej */
if (current->exec_domain->use_count)
(*current->exec_domain->use_count)++;
/* zwróć poprzednią osobowość */
return old_personality;
}