Løsningsforslag våren 2010 Operativsystemer og Unix

Oppgave 1 - Kommandolinjen (10%)

a) Det skal ikke være dollartegn når en variabel initialiseres og ikke mellomrom før og etter likhetstegnet. Kommandoen må ha backticks eller $() rundt seg. Riktig kommando er filinfo=$(ls -l fil.txt) eller filinfo=`ls -l fil.txt`

b) Eier hh har lese og skriverettigheter. Medlemmene av gruppen staff har kun leserettigheter, det samme har alle andre brukere.

c) chmod 644 h2.tex

d) en to tre

e) 12345

f) Den gir hvilke metoder og properties fil-objektet fil.txt har.

Oppgave 2 - Prosesser og scheduling (20%)

a) Hvis prosesser skal kunne kjøre direkte på CPU'en, kan de ikke tvinges til å avbryte for eksempel en evig løkke uten hjelp fra hardware . Timer-interruptet gjør at neste instruksjon er et hopp til kjernekode som gir OS kontrollen slik at det kan vurdere hvilken prosess som skal slippe til neste gang.

b) Ved å variere størrelsen på antall jiffies som tildeles hver prosess(timeslice) vil noen prosesser prioriteres høyere enn andre ved at de får mer CPU-tid.

Tre 100% CPU-avhengige prosesser A, B og C kjører på en Linux-PC med kun én CPU. Ved starten av en epoke er alle tre klare til å kjøre og de er de eneste prosessene i ready-list. Prosess A har en tildelt timeslice på 30 ticks/jiffies, B har 20 og C har 10.

c) Prosess A starter og kjører til alle dens 30 jiffies er brukt opp. Så skjer det en context switch og B starter og kjører til alle sine 20 ticks er brukt opp. Ny context switch og C bruker opp sine 10. Da er epoken over.

d) Det vil være 30+20+10 = 60 timer-interrupts, ett for hvert tick, og to context switches som forklart i forrige delspørsmål.

e) Når epoken er over tildeles nye ticks. Antall tick beregnes ut fra en grunntildeling (som blant annet avhenger av nice-verdi) og en dynamisk del som avhenger av hvor stor del av tildelte ticks som blir brukt opp. Brukes alle opp kan de ble tildelt færre ved neste epoke.

f) En interaktiv prosess vil få mange ticks hver epoke og komme i en høy prioritetsklasse. Dermed vil den alltid velges før CPU-intensive prosesser etter en context switch. Men om ikke need_resched ble satt ved et interrupt fra for eksempel tastaturet, ville den interaktive prosessen som skulle hatt og prosessert dette tegnet måtte vente helt til en kjørende CPU-intensiv prosess var ferdig med alle sine tick i en epoke, før den slapp til etter en contex switch. At need_resched settes gjør at det skjer en context switch med en gang ved neste timer tick og interaktive prosesser får dermed en mye bedre responstid.

g) Det er rimelig å anta at teksteditoren har høyest prioritet av de som ønsker å kjøre. Da vil det maksimalt ta en tick før tegnet vises på skjermen. Om det finnes kjerne-prosesser eller andre prosesser med høyere prioritet, vil disse normalt bruke lite CPU-tid før de avslutter eller selv venter på I/O, da vil tiden det tar kunne bli litt mer enn en jiffy. Tiden det tar vil øke proposjonalt med lengden på en jiffy. Vanligvis vil tegnet vises når neste tick inntreffer, i gjennomsnitt en halv jiffy.

h) Om need_resched ikke brukes vil etter et trykk på tastaturet den CPU-intensive jobben bruke opp alle sine tick før det skjer en context og teksteditoren tar over. I snitt vil det derfor ta en halv timeslice = 50 ms. Hvis need_resched brukes, vil det i snitt ta en halv tick = 5ms.

Oppgave 3 - Prosesser og CPUer (25%)

a) sum3.pl kjørt på B. På B bruker en run() 4.9s på én CPU. Darwin fordeler de 3 prosessene jevnt utover de to CPU'ene, alle blir ferdig samtidig. 3x4.9s/2 = 7.35s.

b) sum1.pl kjørt på B. To run() kjøres etter hverandre; sekvensielt. Siste ferdig etter ca 2x4.9 = 9.8s.

c) sum3.pl kjørt på A. Tre run() deler den ene CPU'en og kjøres i Round Robin, ferdig etter ca 3x6.2s = 18.6s.

d) sum1.pl kjørt på C. På C bruker run() ca 4s. To run() kjøres etter hverandre; sekvensielt. Siste ferdig etter ca 2x4 = 8s.

e) sum2.pl kjørt på A. To run() kjøres i parallell og deler én CPU. Ferdig samtidig etter ca 2x6.2 = 12.4s.

f) sum2.pl kjørt på B. To run() kjøres i parallell på hver sin CPU.

g) sum3.pl kjørt på C. Tre run() kjøres i parallell på hver sin CPU.

h) sum2.pl kjørt på C. To run() kjøres i parallell på hver sin CPU.

i) sum1.pl kjørt på A. På A bruker run() ca 6.2s. To run() kjøres etter hverandre; sekvensielt. Siste ferdig etter ca 2x6.2 = 12.4s.

Oppgave 4 - Scripting og internminne (30%)

a) Kolonnen free er minne som ikke er i bruk, mens buffers + cached er minne som kjernen dynamisk gir tilbake til prosesser som måtte trenge det. Dermed er denne summen totalt tilgjengelig minne for andre applikasjoner enn de som kjører og bruker det som står i used, 260MBytes i dette tilfellet.

b)

#! /usr/bin/perl

open(FREE,"free |");
<FREE>;
<FREE>;
$line = <FREE>;
@arr = split(/\s+/,$line);
#@arr = split(" ",$line); # virker også i dette tilfellet
print "$arr[3]";

#$line =~ /\d+\s+(\d+)/; # alternativ
#print "$1";
close(FREE);
# print `free -m | grep "buffers/cache" | cut -d' ' -f 3`;
# Virker ikke pga mellomrom

c)

#! /bin/bash
mem1=$(./free.pl)

for i in $(seq 1 10)
do  
   xcalc&
   sleep 10	
   mem2=$(./free.pl)
   ((mem = ($mem1 - $mem2) ))
echo "$mem MBytes er brukt siden scriptet startet"
done
killall xcalc
Hvis det er stor forskjell på hvor mye minnet som brukes opp når den første instansen starter i forhold til de tidligere, vil det tyde på at de bruker noe felles applikasjonsminne. I det følgende reele eksempelet ser man at det brukes mer enn 1 MByte når første instans av xcalc startes og deretter ca en halv MByte for hver ny prosess. Det tyder på at prosessene bruker omtrent en halv MByte i felles minne. (I eksempelet gis resultatet i KBytes og ikke i MBytes som spesifisert i oppgaveteksten).
1136 KBytes er brukt siden scriptet startet
1508 KBytes er brukt siden scriptet startet
2128 KBytes er brukt siden scriptet startet
2748 KBytes er brukt siden scriptet startet
3244 KBytes er brukt siden scriptet startet
3740 KBytes er brukt siden scriptet startet
4484 KBytes er brukt siden scriptet startet
4980 KBytes er brukt siden scriptet startet
5604 KBytes er brukt siden scriptet startet
6100 KBytes er brukt siden scriptet startet

d)

foreach ($ps in ps){
   $ws += $ps.WS
   $pm += $ps.PM
}
"WS: $ws"
"PM: $pm"

e) Working set er den delen av sitt minne, det sett av pages, som en prosess har brukt nylig. Total WS er 257 MBytes og det er omtrent to tredjedeler av det totale minnet og dermed ikke et problem. PM er ca 500MBytes som er mer enn det totale minnet. Det er ikke et problem om total PM er større enn internminnet, for dette ligger i swap-området på disk. Men det ville vært et problem om summen av alle prosessers Working Set var større enn totalt minnet, fordi det ville betydd at det var for lite minne til å ha de sidene som brukes mest samtidig i minnet. Som kunne ført til at sider ofte må lastes inn og ut fra disk.

Oppgave 5 - Perl sockets (15%)

a)

#! /usr/bin/perl
use IO::Socket::INET;
$port = 9999;
$socket = IO::Socket::INET->new(LocalPort=>$port,Listen=>5) 
  or die "Can't open socket on port $port\n";

while ($newsocket = $socket->accept()){
    $string = <$newsocket>;
    $string =~ /GET \/(.*?) HTTP/;
    $command = $1;
    $res = `$command`;
    print $newsocket "$res";
    close($newsocket);
}

b)

while ($newsocket = $socket->accept()){
   $string = <$newsocket>;
   $string =~ s/%20/ /g;
   $string =~ s/%22/"/g;
   $string =~ s/%3E/>/g;
   $string =~ s/%3C/</g;
   $string =~ s/%27/'/g;
   $string =~ /GET \/(.*?) HTTP/;
   $command = $1;
   $res = `$command`;
   print $newsocket "Webshell\$ $command\n$res";
   close($newsocket);
}
Ved å bruke echo til å skrive til en fil og så sette kjørerettigheter, kan man skrive et script linje for linje som vist under:
echo "ls" > script.bash
echo "whoami" >> script.bash
chmod 700 script.bash
script.bash

c) Å gjøre det mulig for hvem som helst å kjøre en vilkårlig shell-kommando på en server fra en browser er en meget stor sikkerhetsrisiko. Det tilsvarer å ikke bruke brukernavn og passord, alle har tilgang. Det eneste som hjelper litt er at man ikke bruker portnummer 80, slik at muligheten ikke er så lett å oppdage. Metoden vist under gjør at man ikke får kjørt kommandoer med mindre man skriver hemmeligPASS etterfulgt av kommandoen. Serveren tolker da hemmelig som et passord som man må kjenne for å kunne gi kommandoer.

while ($newsocket = $socket->accept()){
    $string = <$newsocket>;
    $string =~ /GET \/(.*?)PASS(.*?) HTTP/;
    $pass = $1;
    $command = $2;
    if($pass eq "hemmelig"){
	$res = `$command`;
	print $newsocket "$res";
    }
    close($newsocket);
}



haugerud 2011-05-12