µ¿Àû Ä¿³Î ¸µÄ¿(KLD) ÇÁ·Î±×·¡¹Ö Æ©Å丮¾ó

Andrew Reiter <arr@watson.org> Àú.
http://www.daemonnews.org/200010/blueprints.html
2000³â 10¿ù

ÃÖÁøÈñ <jhchoi@os.korea.ac.kr> ¿ª.
2001³â 4¿ù 20ÀÏ

Overview

 ÀÌ ¹®¼­ÀÇ ¸ñÀûÀº  FreeBSD ȯ°æ¿¡¼­ KLD¸¦ °³¹ßÇϰí À̸¦ ÀÌ¿ëÇÑ ÇÁ·Î±×·¡¹ÖÀÇ ±âº» Áö½ÄÀ» ¼Ò°³ÇÏ
´Â µ¥ ÀÖ½À´Ï´Ù. µû¶ó¼­ ¿¹Á¦¸¦ Áß½ÉÀ¸·Î(learn by example) Â÷±ÙÂ÷±Ù ÁøÇàÇØ ³ª°¡¸é¼­ µ¶ÀÚ°¡ ÃÖ´ëÇÑ 
½±°Ô KLD Äڵ带 ÀÛ¼ºÇÒ ¼ö ÀÖµµ·Ï ÀÏÁ¾ÀÇ »À´ë ÄÚµå(skeleton code)µµ Á¦°øÇÏ´Â ½ÄÀ¸·Î ±ÛÀ» Àü°³ÇØ 
³ª°¥ °ÍÀÔ´Ï´Ù.

[µ¿Àû Ä¿³Î ¸µÄ¿(dynamic kernel linker)¿¡ Àͼ÷Ä¡ ¾ÊÀº µ¶ÀÚµéÀ» À§ÇØ Àá±ñ ¼³¸íÇÏÀÚ¸é KLD´Â 
FreeBSD 3.1¿¡ ÀÖ¾ú´ø LKM(Loadable Kernel Modules)À» ´ëüÇÑ ÀÎÅÍÆäÀ̽º·Î, µÑÀº ¸ðµÎ ½Ã½ºÅÛ °ü
¸®ÀÚ°¡ ¼öÇà ÁßÀÎ ½Ã½ºÅÛ¿¡ µ¿ÀûÀ¸·Î ¾î¶² ±â´ÉÀ» Ãß°¡/»èÁ¦ÇÒ ¼ö ÀÖ´Â ±â´ÉÀ» Á¦°øÇÕ´Ï´Ù. 
ÀÌ·¯ÇÑ Æ¯Â¡À» ÀÌ¿ëÇÏ¸é ¼ÒÇÁÆ®¿þ¾î °³¹ßÀÚµéÀº ÀÛ¼ºÇÑ Ä¿³Î ÄÚµåÀÇ Å×½ºÆ®Çϱâ À§ÇØ ½Ã½ºÅÛÀ» ÀçºÎÆÃ 
ÇÒ Çʿ䰡 ¾ø°Ô µË´Ï´Ù[ref. 1]. ´ëÇ¥ÀûÀÎ ¿¹·Î µð¹ÙÀ̽º µå¶óÀ̹ö, ƯÈ÷ ³×Æ®¿öÅ© Ä«µå¸¦ À§ÇÑ µå¶óÀ̹ö
¸¦ °³¹ßÇÏ´Â »óȲÀ» µé ¼ö ÀÖ½À´Ï´Ù. ÇÑ °¡Áö ¾Ë¾ÆµÎ¾î¾ß ÇÒ Á¡Àº KLD°¡ LKMÀÇ ºÎºÐ ÁýÇÕÀ̶ó´Â °ÍÀÔ
´Ï´Ù.
Áï, KLD¶ó´Â ¿ë¾î´Â Ä¿³Î ¸ðµâ ½Ã½ºÅÛÀÌ ±âÁ¸°ú ´Þ¶óÁ³´Ù´Â »ç½ÇÀ» ºÎ°¢½Ã۱â À§ÇØ ¼±ÅÃµÈ ¿ë¾î¶ó´Â 
¶æÀÌÁÒ.

Á» ´õ ÀÌÇØ¸¦ µ½±â À§ÇØ ¿©±â¼­ Peter WemmÀÇ ±ÛÀ» ÀοëÇϰڽÀ´Ï´Ù. (IRC¿¡¼­ ÀÖ¾ú´ø "FreeBSD KLD 
vs LKM"À̶ó´Â ²Ï ½Éµµ ±í¾ú´ø ³íÀÇ¿¡¼­ ¹ßÃéÇÕ´Ï´Ù.)

 LKM ½Ã½ºÅÛÀº Àç¹èÄ¡µÈ ¹ÙÀ̳ʸ® µ¥ÀÌÅ͸¦ »ç¿ëÀÚ ·¹º§ÀÇ ¸µÄ¿¸¦ »ç¿ëÇÏ¿© Ä¿³Î°ú °áÇÕ½Ãŵ´Ï´Ù.
- KLD ½Ã½ºÅÛÀº Ä¿³Î ³»ºÎ¿¡¼­ Àç¹èÄ¡°¡ ÀÌ·ç¾î Áý´Ï´Ù. ¹Ý¸é, LKMÀº Ä¿³Î°ú LKM ÇÁ·Î±×·¥À» ¿¬°áÇØ 
ÁÖ´Â ¾î¶² Ưº°ÇÑ ÀÚ·á ±¸Á¶°¡ ÇÊ¿äÇϸç, lkm µå¶óÀ̹ö°¡ ÀÌ ÀÚ·á ±¸Á¶ÀÇ ³»¿ëÀ» ¾Ë°í ÀÖ¾î¾ß ÇÕ´Ï´Ù. 
°¡·É, VFS lkmÀ̶ó¸é vfs Å×À̺íÀ» °¡¸®Å°´Â ÀÚ·á ±¸Á¶¸¦ À¯ÁöÇϰí ÀÖ¾î¾ß ÇÑ´Ù´Â ¸»ÀÔ´Ï´Ù.
- LKMÀº ÇϳªÀÇ ¿ëµµ¿¡ »ç¿ëÇϱâ À§ÇØ ¼³°èµÇ¾úÀ¸¸ç, LKM Äڵ带 ½ÇÁ¦ Ä¿³Î ÄÚµå·Î º¯È­½ÃŰ´Â °Íµµ 
¸Å¿ì ¾î·Á¿î ÀÛ¾÷ÀÔ´Ï´Ù.
- KLD´Â ¿©·¯ ¿ëµµ¸¦ ¸¸Á·½Ãų ¼ö ÀÖ´Â º¸´Ù º¸ÆíÀûÀÎ ±¸Á¶¸¦ ÁöÇâÇÕ´Ï´Ù. ÀÌ·± ÀÌÀ¯·Î ÇϳªÀÇ ÆÄÀÏÀÌ 
0°³ ÀÌ»óÀÇ ¸ðµâÀ» Æ÷ÇÔÇÒ ¼ö ÀÖ½À´Ï´Ù.
- °¢ ¸ðµâ ³»ºÎ¿¡´Â ÀÚ½ÅÀ» ÃʱâÈ­ÇÏ°í µî·Ï½ÃŰ´Â ¸ÅÄ¿´ÏÁòÀÌ Æ÷ÇԵǾî ÀÖ½À´Ï´Ù.
- KLD¿Í Ä¿³Î ÄÚµå´Â °°Àº ½Ã±â¿¡ ÄÄÆÄÀϵ˴ϴÙ.
- Ä¿³Î ÄÚµåÀÇ ÀϺθ¦ ½±°Ô KLD·Î ¹Ù²Ü ¼ö ÀÖ½À´Ï´Ù.
- °¢ ¸ðµâ »çÀÌÀÇ ÀÇÁ¸¼º°ú ¹öÁ¯ °ü¸®´Â ¸ðµâ ·¹º§¿¡¼­ ÀÌ·ç¾î Áý´Ï´Ù.

ÀÌ Æ©Å丮¾óÀÌ KLD ÄÚµå ÀÛ¼º¹ýÀÇ ±âÃʸ¦ ¹è¿ì°í ½ÍÀº »ç¶÷µéÀ» ´ë»óÀ¸·Î ÀÛ¼ºµÇ¾ú´Ù´Â »ç½Ç¿¡ ´Ù½Ã 
Çѹø ÁÖ¸ñÇØ ÁֽʽÿÀ. µû¶ó¼­ ÀÌ ¹®¼­¸¦ Á¦´ë·Î ÀÌÇØÇÏ·Á¸é FreeBSD Ä¿³Î¿¡ ´ëÇÑ Áö½ÄÀÌ ¾î´À Á¤µµ´Â 
ÀÖ¾î¾ß Çϸç, C ÇÁ·Î±×·¥µµ ¾î´À Á¤µµ´Â ÀÛ¼ºÇÒ ¼ö ÀÖ¾î¾ß ÇÕ´Ï´Ù. ¸¶Áö¸·À¸·Î ÀÌ ¹®¼­ÀÇ ¸ðµç ¿¹Á¦°¡ 
FreeBSD 4.0¿¡¼­ ÀÛ¼ºµÇ¾ú´Ù´Â »ç½Ç¿¡ À¯ÀÇÇϽʽÿÀ.

ÀÌ ¹®¼­¿¡¼­´Â ´ÙÀ½°ú °°Àº ÁÖÁ¦¸¦ ´Ù·ì´Ï´Ù.
- ¸ðµç KLD ÇÁ·Î±×·¥ÀÇ ÀϹÝÀû Ư¼º
- KLD ½Ã½ºÅÛ ÄÝÀÇ »À´ë ÄÚµå
- KLD ij¸¯ÅÍ µð¹ÙÀ̽º µå¶óÀ̹ö(character device driver)ÀÇ »À´ë ÄÚµå

ÀÌ ¹®¼­ÀÇ Ã¹¹øÂ° ¸ñÀûÀº KLD¿¡ Àͼ÷ÇÑ »ç¶÷µéÀÌ °£´ÜÇÑ KLD ÇÁ·Î±×·¥À» ÀÛ¼ºÇÒ ¼ö ÀÖµµ·Ï µµ¿Í ÁÖ´Â 
°ÍÀ̸ç, KLD ÀÛ¼ºÀ» ÅëÇØ KLD¿¡ ´ëÇØ º¸´Ù ±íÀº ÀÌÇØ¸¦ ÇÏ¿© À̸¦ °í±Þ ¼öÁØÀÇ ÀÛ¾÷¿¡ Ȱ¿ëÇϵµ·Ï ÇÏ
´Â °ÍÀÌ µÎ¹øÂ° ¸ñÀûÀÔ´Ï´Ù.


 

Characteristics common to all KLDs

 ¸ðµç KLD ÇÁ·Î±×·¥¿¡ ¹Ýµå½Ã Æ÷ÇԵǾî¾ß ÇÏ´Â µÎ°³ÀÇ ÁÖ¿ä ÇÔ¼ö/¸ÅÅ©·Î°¡ Àִµ¥, ¹Ù·Î ´ÙÀ½°ú °°½À´Ï
´Ù.
- ·Îµå Çڵ鷯 ÇÔ¼ö(Load Handler Function)
- DECLARE_MODULE ¸ÅÅ©·Î (Macro)
- MakefileÀ» ÀÌ¿ëÇÑ ¼Õ½¬¿î ÄÄÆÄÀÏ

±âº»ÀûÀ¸·Î ·Îµå Çڵ鷯 ÇÔ¼ö´Â ¾î¶² KLD ÇÁ·Î±×·¥À» ·ÎµåÇÏ°í ¾ð·Îµå(unload)ÇÏ´Â ¿ªÇÒÀ» ´ã´çÇϰí 
ÀÖ½À´Ï´Ù. °£´ÜÇÑ ·Îµå Çڵ鷯 Äڵ带 º¸¸é¼­ À̾߱⸦ ÁøÇàÇϰڽÀ´Ï´Ù.

static int
load_handler(module_t mod, int what, void* arg)
{
	int err = 0;

	switch(what){
	case MOD_LOAD:
		uprintf("KLD loaded successfully!\n");
		break;
	case MOD_UNLOAD:
		uprintf("KLD unloaded successfully!\n");
		break;
	default:
		err = EINVAL;
		break;
	}
	return (err);
}
 
 ÀÌ ·Îµå Çڵ鷯(load handler)´Â /usr/include/sys/module.h¿¡ Á¤ÀÇµÈ ÇÔ¼ö Æ÷ÀÎÅÍ¿¡ ´ëÀÀµË´Ï´Ù.
typedef int (*modeventhand_t)(module_t mod, int what, void* arg);

'module_t mod' ±¸Á¶Ã¼´Â ¸ðµâ ±¸Á¶Ã¼¿¡ ´ëÇÑ Æ÷ÀÎÅÍÀÔ´Ï´Ù. ÀÌ ±¸Á¶Ã¼´Â ÇöÀç ·ÎµåµÈ ¸ðµâµéÀÇ ¿¬°á ¸®
½ºÆ®ÀÇ ÀϺÎÀÔ´Ï´Ù. µû¶ó¼­ ·ÎµåµÈ ´Ù¸¥ ¸ðµâµé°ú ¿¬°áµÇ¸ç, KLD Id ¹øÈ£ µîÀÇ À¯¿ëÇÑ ´Ù¸¥ Á¤º¸µéµµ Æ÷
ÇÔÇϰí ÀÖ½À´Ï´Ù.

'int what'Àº modeventtype_t¿¡ µû¶ó °¢°¢ ´ÙÀ½°ú °°Àº °ªµé Áß Çϳª°¡ µË´Ï´Ù.
MOD_LOAD      : ¸ðµâÀÌ ·ÎµåµÉ ¶§ ¼³Á¤ÇÕ´Ï´Ù. (kldload)
MOD_UNLOAD    : ¸ðµâÀÌ ¾ð·Îµå(unload)µÉ ¶§ ¼³Á¤µË´Ï´Ù. (kldunload)
MOD_SHUTDOWN  : ¸ðµâÀÌ ¿ÏÀüÈ÷ Á¦°ÅµÉ ¶§ ¼³Á¤µË´Ï´Ù.

DECLARE_MODULE ¸ÅÅ©·Î ¿ª½Ã ¸ðµç KLD¿¡¼­ »ç¿ëµÇ´Â ±âº» ¿ä¼ÒÀÔ´Ï´Ù. ÇÏÁö¸¸ ÀÌ ¸ÅÅ©·Î°¡ Ç×»ó 
DECLARE_MODULEÀ̶õ À̸§À¸·Î ³ªÅ¸³ª´Â °ÍÀº ¾Æ´Õ´Ï´Ù. ƯÁ¤ ŸÀÔÀ¸·Î ¸ðµâÀ» ´õ ½±°Ô Á¤ÀÇÇϱâ 
À§ÇØ ´Ù¸¥ À̸§À» °®±âµµ ÇÑ´Ù´Â °ÍÀÌÁÒ. ÇÏÁö¸¸ º»ÁúÀûÀ¸·Î °°Àº ÀÏÀ» ¼öÇàÇÕ´Ï´Ù. 
DECLARE_MODULEÀº ÀÌ¹Ì ¾ð±ÞÇßµíÀÌ ´ÙÀ½°ú °°Àº ¸ÅÅ©·ÎÀÏ »ÓÀÔ´Ï´Ù.

#define DECLARE_MODULE(name, data, sub, order) \
  SYSINIT(name##module, sub, order, module_register_init, &data) \
  struct __hack

À̰ÍÀº /usr/include/sys/module.h¿¡ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. ÀÌÁ¦ °¢°¢ÀÇ ¸Å°³ º¯¼öÀÇ Àǹ̸¦ »ìÆì º¾½Ã´Ù.

name : ÀϹÝÀûÀÎ ¸ðµâÀÇ À̸§À¸·Î SYSINIT È£Ãâ¿¡¼­ »ç¿ëµË´Ï´Ù.

data : module_data ±¸Á¶Ã¼¿¡ ´ëÇÑ Æ÷ÀÎÅÍ·Î ÀÌ ±¸Á¶Ã¼´Â ´ÙÀ½°ú °°Àº µÎ °¡Áö ÁÖ¿ä ¾ÆÀÌÅÛÀ» Æ÷ÇÔÇϰí 
ÀÖ½À´Ï´Ù.
	* char* name;
	 °ø½ÄÀûÀÎ ¸ðµâÀÇ À̸§À¸·Î module ±¸Á¶Ã¼¿¡¼­ »ç¿ëµË´Ï´Ù.
	* modeventhand_t evhand;
	 À̰ÍÀÌ ·Îµå Çڵ鷯 ÇÔ¼öÀÇ Æ÷ÀÎÅÍÀÔ´Ï´Ù. µû¶ó¼­ ÀÌ Çʵå´Â ÀÛ¼ºÇÏ´Â ¸ðµâÀÇ ·Îµå Çڵ鷯 ÇÔ
¼ö À̸§ÀÌ µÇ°ÚÁÒ.

sub : À̰͵µ SYSINIT ¸ÅÅ©·Î¿¡°Ô ¹Ù·Î Àü´ÞµÇ´Â ¸Å°³ º¯¼öÀε¥, ÀÌ °ªÀº /usr/include/sys/kernel.h¿¡ 
ÀÖ´Â system_sub_id ³ª¿­ ¸®½ºÆ®ÀÇ °ª Áß Çϳª°¡ µË´Ï´Ù. ³ª¿­ ¸®½ºÆ®ÀÇ °ªµéÀº ½Ã½ºÅÛ ÃʱâÈ­ ÀÎÅÍÆä
À̽º(system startup interface)¿¡°Ô ¾Ë·ÁÁø °ªµéÀÔ´Ï´Ù. °¡·É, µð¹ÙÀ̽º·Î »ç¿ëµÇ´Â KLD¸¦ °³¹ßÇÒ ¶§´Â 
SI_SUB_DRIVERS ŸÀÔÀÌ ÁöÁ¤µÉ ¼ö ÀÖ½À´Ï´Ù.

order : ÀÌ ¸Å°³ º¯¼ö´Â SYSINITÀÇ È£Ãâ ÈÄ¿¡ »ç¿ëµÇ´Âµ¥, ÀÌ °ªÀº ¼­ºê ½Ã½ºÅÛ¿¡¼­ÀÇ KLSµéÀÇ ÃʱâÈ­ 
¼ø¼­¸¦ ³ªÅ¸³À´Ï´Ù. ÀÌ ÇʵåÀÇ À¯È¿ °ªµéÀº /usr/include/sys/kernel.h¿¡ ÀÖ´Â sysinit_elem_order ³ª¿­ 
¸®½ºÆ®ÀÇ °ªµé Áß ÇϳªÀÔ´Ï´Ù.

±×·¸Áö¸¸ »ó´çÈ÷ À¯¿ëÇÑ µÎ°³ÀÇ ´Ù¸¥ *_MODULE ¸ÅÅ©·Î°¡ Àִµ¥, SYSCALL_MODULE°ú 
DEV_MODULEÀÌ ±×°ÍÀÔ´Ï´Ù. ÀÌ ¸ÅÅ©·ÎµéÀº DECLARE_MODULE ¸ÅÅ©·Î¸¦ ·¦ÇÎ(wapping)ÇÑ °ÍÀÌÁÒ.
ÀÌ ¸ÅÅ©·ÎµéÀº 1) ½Ã½ºÅÛ ÄÝÀ̳ª µð¹ÙÀ̽º µå¶óÀ̹ö ¸ðµâÀ» ÀÛ¼ºÇϱ⠽±µµ·Ï ¼³°èµÇ¾úÀ» »Ó ¾Æ´Ï¶ó 2) 
¸ðµâ Äڵ带 ´õ Àб⠽¬¿î ¹æ½ÄÀ¸·Î ±â¼úÇÒ ¼ö ÀÖ°Ô ÇØ ÁÝ´Ï´Ù. ¸¸¾à SYSCALL_MODULE ¸ÅÅ©·Î°¡ »ç
¿ëµÈ Äڵ带 Àд´ٸé ÀÌ Äڵ尡 ½Ã½ºÅÛ ÄÝÀ» ÀÛ¼ºÇϱâ À§ÇÑ °ÍÀ̶ó´Â »ç½ÇÀ» ±×¸¸Å­ ½±°Ô ¾Ë¾Æ Â÷¸± 
¼ö ÀÖ°ÚÁÒ. 

SYSCALL_MODULE ¸ÅÅ©·Î´Â /usr/include/sys/sysent.h¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç, ´ÙÀ½°ú °°Àº ¸Å°³ º¯¼ö°¡ 
ÇÊ¿äÇÕ´Ï´Ù.

name : DECLARE_MODULE¿¡¼­ÀÇ name°ú °°Àº Àǹ̷Π»ç¿ëµË´Ï´Ù.

offset : ½Ã½ºÅÛ ÄÝÀÇ ¹øÈ£¸¦ ³Ñ±â´Âµ¥ »ç¿ëµË´Ï´Ù. KLD¸¦ »ç¿ëÇÏ¿© ½Ã½ºÅÛ ÄÝÀ» ÀÛ¼ºÇÑ´Ù¸é º¸Åë ±× ½Ã
½ºÅÛ ÄÝÀº ¿¹¾àµÈ ¹øÈ£°¡ ¾øÀ» °æ¿ì°¡ ¸¹½À´Ï´Ù. ÀÌ·¯ÇÑ °æ¿ì, ÀÌ ¸Å°³ º¯¼ö¿¡ ÀûÇÕÇÑ °ªÀº 
NO_SYSCALLÀÔ´Ï´Ù. ÀÌ °ªÀÇ Àǹ̴ ¼­ºê ½Ã½ºÅÛ¿¡°Ô ±âÁ¸ ½Ã½ºÅÛ ÄÝÀÌ »ç¿ëÇÏÁö ¾Ê´Â ÀûÀýÇÑ °ªÀ» 
ã¾Æ ³Ö¾î ´Þ¶ó´Â ÀǹÌÀÔ´Ï´Ù.
 
new_sysent : »õ·Î¿î ½Ã½ºÅÛ ÄÝÀ» À§ÇØ Á¤ÀÇµÈ sysent ±¸Á¶Ã¼¸¦ ÀǹÌÇÕ´Ï´Ù.

evh : modeventhand_t ·Îµå Çڵ鷯ÀÇ ÇÔ¼ö Æ÷ÀÎÅÍÀÔ´Ï´Ù.(À§ÀÇ module_data ±¸Á¶Ã¼¿¡¼­ÀÇ evhand¿Í 
°°½À´Ï´Ù.)

arg : syscall_module_data ±¸Á¶Ã¼¿¡¼­ »ç¿ëµÇ´Â °ªÀÔ´Ï´Ù. ÀÌ ¸Å°³ º¯¼ö´Â º¸Åë NULL·Î ¼³Á¤µË´Ï´Ù.


DEV_MODULE ¸ÅÅ©·Î´Â /usr/include/sys/conf.h¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç, ´ÙÀ½°ú °°Àº ¸Å°³ º¯¼ö°¡ ÇÊ¿äÇÕ
´Ï´Ù.

name : À§ÀÇ µÎ *_MODULE ¸ÅÅ©·Î¿¡¼­¿Í °°Àº Àǹ̷Π»ç¿ëµË´Ï´Ù.

evh : modeventhand_t ·Îµå Çڵ鷯ÀÇ ÇÔ¼ö Æ÷ÀÎÅÍÀÔ´Ï´Ù.

arg : module_data ±¸Á¶Ã¼¿¡¼­ »ç¿ëµË´Ï´Ù¸é º¸ÅëÀº NULL·Î ¼³Á¤ÇÕ´Ï´Ù.


¿©·¯ºÐÀÇ ¸ðµâÀÌ ¾î¶»°Ô °³¹ßµÇ´À¾ß¿¡ µû¶ó ´Ù¸£°ÚÁö¸¸ Àû¾îµµ ÇϳªÀÇ ·Îµå Çڵ鷯¿Í *_MODULE ¸ÅÅ©
·Î¸¦ °®°Ô µË´Ï´Ù. ÀÌ Æ©Å丮¾ó¿¡¼­´Â Çϳª ÀÌ»óÀÇ ·Îµå Çڵ鷯¿Í ¸ÅÅ©·Î°¡ ÇÊ¿äÇÑ »óȲÀº °í·ÁÇÏÁö ¾Ê
½À´Ï´Ù. 
´ë½Å ÀÌ·¯ÇÑ »óȲÀ» ¼³¸íÇÑ [ref.2]¸¦ ¿¬°áÇØ ³õ°Ú½À´Ï´Ù. ÂüÁ¶ ¹®¼­´Â ¸ðµâ¿¡ ´ëÇÑ º¸´Ù ½Éµµ ±íÀº ³í
ÀǸ¦ Çϰí ÀÖÀ¸¸ç, ´Ù¼öÀÇ ÈǸ¢ÇÑ ¿¹Á¦ Äڵ带 Æ÷ÇÔÇϰí ÀÖÀ¸¹Ç·Î º¸´Ù ¼öÁØ ³ôÀº ¿¹Á¦¸¦ ¿øÇÏ´Â µ¶ÀÚ¿¡
°Ô ÃßõÇÕ´Ï´Ù.

ÀϹÝÀûÀ¸·Î »ç¿ëÇØ¿Â Makefile¿¡´Â ¹Ì¸® Á¤ÀÇµÈ º¯¼öÀÇ ÁýÇÕÀÌ ÀÖ½À´Ï´Ù. ÀÌÁ¦ ÀÌ º¯¼öµéÀ» ¼³Á¤Çϰí 
MakefileÀ» È£ÃâÇϱ⸸ ÇÏ¸é ¸ðµç ÀÏÀº ³¡³³´Ï´Ù. ÀÌ·¯ÇÑ °úÁ¤ ¶§¹®¿¡ KLD¸¦ ÄÄÆÄÀÏÇϱâ À§ÇÑ 
Makefile ÀÛ¼º ¶§¹®¿¡ °ñ¸Ó¸® ¾ÎÀ» Çʿ䰡 ¾ø½À´Ï´Ù. 
".include" ¸¦ »ç¿ëÇÒ ¼ö ÀÖ´Â  MakefileÀº /usr/share/mk¿¡ ÀÖ½À´Ï´Ù.

ÇÏÁö¸¸ ¿ì¸®°¡ °ü½ÉÀÖ´Â ".include"´Â [ref.3]¿¡ ÀÖ½À´Ï´Ù. ¿©·¯ºÐ ½º½º·Î MakefileÀ» ÀÛ¼ºÇϱâ Àü¿¡ 
[ref.3]ÀÇ Makefile »ó´Ü¿¡ ÀÖ´Â ÁÖ¼®À» ÀÐ¾î º¸½Ã±â ¹Ù¶ø´Ï´Ù. 
¿©·¯ºÐÀÌ ¼³Á¤ÇØ¾ß ÇÏ´Â ÇÙ½É º¯¼öµéÀº ¸î °³ µÇÁö ¾Ê½À´Ï´Ù.

SRCS : ¼Ò½ºµéÀÇ ¸ñ·Ï
KMOD : ºôµåÇØ¾ß ÇÏ´Â ¸ðµâÀÇ À̸§

ÀÌ ¿Ü¿¡µµ À¯¿ëÇÑ º¯¼öµéÀº ¸¹ÀÌ ÀÖ½À´Ï´Ù.  ".include" ¿Í ÇÔ²² MakefileÀ» »ç¿ëÇÏ´Â ¿¹Á¦´Â ´ÙÀ½ ÆäÀÌ
ÁöºÎÅÍ ³ª¿À´Â »À´ë ÄÚµå¿Í ÇÔ²² ¼Ò°³µË´Ï´Ù. ¾Ö½á Áߺ¹ ÅõÀÚÇÒ ÇÊ¿ä´Â ¾ø½À´Ï´Ù. ƯÈ÷ Makefile°ú °°ÀÌ 
»ç¼ÒÇÑ °Í¿¡´Â ´õ¿í ±×·¸ÁÒ.


 

KLD Syscall Implementation Skeleton

 ÀÌ Àý¿¡¼­´Â µ¿Àû Ä¿³Î ¸µÄ¿ ÀÎÅÍÆäÀ̽º(dynamic kernel linker interface)¸¦ ÀÌ¿ëÇÏ¿© ½Ã½ºÅÛ ÄÝÀ» Ãß
°¡ÇÏ´Â ¾ÆÁÖ ÀϹÝÀûÀÎ ¿¹Á¦°¡ ¼Ò°³µË´Ï´Ù.

¼Ò°³µÉ ÄÚµå´Â ¾çÀÌ ¸¹Áø ¾ÊÁö¸¸ Áß¿äÇÑ Äڵ尡 Æ÷ÇԵǾî ÀÖ½À´Ï´Ù. °Ô´Ù°¡ ÀÌ ÄÚµåµéÀº ½Ã½ºÅÛ ÄÝÀ» Ãß
°¡ÇÏ´Â ¸ðµç ¸ðµâ¿¡ °øÅëÀûÀ¸·Î Æ÷ÇԵ˴ϴÙ. ÄÚµå´Â Å©°Ô ³× °³ÀÇ ÁÖ¿ä ºÎºÐÀ¸·Î ³ª´¯´Ï´Ù. ¹°·Ð ·Îµå 
Çڵ鷯¿Í DECALRE_MODULE ¸ÅÅ©·Î´Â Á¦¿ÜÇÏ°í ³ª´« °ÍÀÔ´Ï´Ù.

- syscallname_args ±¸Á¶Ã¼¸¦ Á¤ÀÇÇÕ´Ï´Ù.
- ½Ã½ºÅÛ ÄÝÀÌ µÉ ÇÔ¼ö´Â int ÇüÀ» ¸®ÅÏ °ªÀ¸·Î °®À¸¸ç, Á¤Àû ÇÔ¼ö(static function)À¸·Î ¼±¾ðµÇ¾î¾ß 
ÇÕ´Ï´Ù.
- sysent ±¸Á¶Ã¼ÀÇ ¸â¹ö º¯¼öµéÀ» ±¸ÇöÇÏ·Á´Â ½Ã½ºÅÛ ÄÝ¿¡ ¸Â°Ô ¼³Á¤ÇÕ´Ï´Ù.
- offset º¯¼ö¸¦ NO_SYSCALL·Î ¼³Á¤ÇÕ´Ï´Ù.   

Ä¿³Î Äڵ忡¼­ ¹ß°ßÇÒ ¼ö ÀÖ´Â ¸ðµç ½Ã½ºÅÛ ÄݵéÀÇ ¸Å°³ º¯¼ö ¸ñ·ÏÀº ´ÙÀ½°ú °°½À´Ï´Ù.

-struct proc*
-struct syscallname_args*

»ç¿ëÀÚ ¿µ¿ª¿¡¼­ ½Ã½ºÅÛ ÄÝ·Î Àü´ÞµÇ¾î¾ß ÇÏ´Â ¸Å°³ º¯¼öµéÀº syscallname_args ±¸Á¶Ã¼¿¡ Á¤ÀǵǾî ÀÖ
½À´Ï´Ù. ¿ì¸®°¡ proc ±¸Á¶Ã¼¿Í arguments ±¸Á¶Ã¼¿¡ ´ëÇÑ Æ÷ÀÎÅ͸¦ ³Ñ±âÁö ¾Ê°íµµ ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÒ 
¼ö ÀÖ´Â ÀÌÀ¯´Â ÀÌ ÀÛ¾÷À» libc°¡ ´ë½ÅÇØ Áֱ⠶§¹®ÀÔ´Ï´Ù.
¿ì¸®´Â µ¿ÀûÀ¸·Î ½Ã½ºÅÛ ÄÝÀ» Ãß°¡½ÃŰ´Â °ÍÀ̰í, libc¿¡°Ô ¿ì¸®ÀÇ ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇØ ÁÙ ¼ö ÀÖ´Â ±â´É
À» Ãß°¡ÇÏÁö ¾Ê±â ¶§¹®¿¡ »õ·Î ÀÛ¼ºÇÑ ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÏ·Á¸é syscall(2)À» »ç¿ëÇØ¾ß ÇÕ´Ï´Ù. 
ÀÌ·¯ÇÑ ³»¿ëÀº ¿¹Á¦¸¦ ¼Ò°³Çϸ鼭 Á¶±Ý ´õ ¼³¸íÇÏ°Ô µÉ °ÍÀÔ´Ï´Ù.

ÀÌ ¿¹Á¦¿¡¼­ ¿ì¸®´Â ´ÙÀ½°ú °°Àº ½Ã½ºÅÛ ÄÝ ¸Å°³ º¯¼ö¸¦ »ç¿ëÇÕ´Ï´Ù.
struct sc_example_args {
  	char *str;
		int val;
};

¸Å°³ º¯¼ö¿¡  ¹®ÀÚ¿­ Æ÷ÀÎÅÍ(character string pointer)¿Í Á¤¼ö(integer)¸¦ Æ÷ÇÔ½ÃŲ ÀÌÀ¯´Â ÀÌ µÎ ŸÀÔÀÇ 
ÀÚ·áÇüÀ» ½Ã½ºÅÛ ÄÝ·Î ³Ñ±â´Â ¹æ¹ýÀ» º¸¿©ÁÖ±â À§ÇÔÀÔ´Ï´Ù.(»ç¿ëÀÚ ¿µ¿ª¿¡¼­ Ä¿³Î ¿µ¿ªÀ¸·Î µ¥ÀÌÅ͸¦ ³Ñ
±â´Â °ÍÀÌ ´ëÇ¥ÀûÀÎ ¿¹°ÚÁÒ.)

´ÙÀ½ÀÌ ¹Ù·Î ¿¹Á¦ ½Ã½ºÅÛ ÄÝÀÇ ÄÚµåÀÔ´Ï´Ù.
static int
sc_example(struct proc *p, struct sc_example_args *uap)
{
	char kstr[1024+1];  	/* Holds kernel land copy of uap->str */
  	int err = 0;		/* Generic return(err) */
  	int size = 0;
  
	/*
	 * _IMPORTANT_:
	 *
	 * When one has a contiguous set of data and wish to copy this from
	 * userland to kernel land (or vice versa) the copy(9) functions 
	 * are recommended for doing this.
 	 */

	/*
	 * Copy the string located at the user land address uap->str to
	 * the kernel land address of &kstr.
	 */

	err = copyinstr(uap->str, &kstr, 1024, &size);
  	if (err == EFAULT) 
  		return(err);

  	/*
   	 * Print out the values we have gathered.
   	 *
   	 * uprintf() is a kernel land function that acts like printf().
   	 * When using the printf() in kernel land, it uses the dmesg
   	 * facility.. uprintf() on the other hand will output directly to 
   	 * the currently used tty.
   	 */
 
  	uprintf("The string passed was: %s\n", kstr); 
  	uprintf("The value passed was: %d\n", uap->val);
  	return(0);
}

ÀÌ ÇÔ¼ö´Â Àü´ÞµÇ´Â ¸Å°³ º¯¼ö(ÇϳªÀÇ ¹®ÀÚ¿­°ú Á¤¼ö)¸¸À» ³Ñ°Ü ¹ÞÀº ÈÄ, ±× °ªÀ» ÇöÀç ÀÛ¾÷Çϰí ÀÖ´Â 
tty(½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÑ ÇÁ·Î±×·¥ÀÌ ¼öÇàµÇ°í ÀÖ´Â Å͹̳Î)¿¡ Ãâ·ÂÇÕ´Ï´Ù.

´ÙÀ½¿¡ ÇØ¾ß ÇÒ ÀÏÀº ½Ã½ºÅÛ ÄÝÀ» À§ÇØ sysent ±¸Á¶Ã¼ÀÇ ³»¿ëÀ» ä¿ö³Ö´Â ÀÏÀÔ´Ï´Ù. Sysent ±¸ÃÊÁ¦´Â 
/usr/include/sys/sysent.h¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç, ´ÙÀ½°ú °°½À´Ï´Ù.

	struct sysent {
              int sy_narg;
  	      sy_call_t *sy_call;
	};

°¢ ½Ã½ºÅÛ Äݸ¶´Ù Á¤ÀÇµÈ sysent ±¸Á¶Ã¼¸¦ °®°í ÀÖ½À´Ï´Ù. 'int sy_narg'´Â Á¤ÀÇµÉ ½Ã½ºÅÛ ÄÝ¿¡°Ô ¾ó¸¶³ª 
¸¹Àº ¸Å°³ º¯¼ö°¡ ³Ñ¾î¿Ã °ÍÀÎÁö¸¦ °áÁ¤ÇÏ´Â º¯¼öÀÔ´Ï´Ù.  ¿ì¸®ÀÇ »À´ë Äڵ忡¼­´Â 2°³ÀÇ ¸Å°³ º¯¼ö¸¸ÀÌ 
³Ñ¾î¿É´Ï´Ù.(char* str°ú int val) µû¶ó¼­ sy_narg´Â 2·Î ¼³Á¤ÇÕ´Ï´Ù. 'sy_call_t* sy_call'Àº static int 
syscall¿¡ ´ëÇÑ ÇÔ¼ö Æ÷ÀÎÅÍÀÔ´Ï´Ù. Sy_call_t´Â /usr/include/sys/sysent.h¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç ´ÙÀ½°ú °°
½À´Ï´Ù.

typedef int sy_call_t __P((struct proc *, void *));

µû¶ó¼­ ¿ì¸® Äڵ忡¼­´Â ´ÙÀ½°ú °°ÀÌ ¼³Á¤µÉ °ÍÀÔ´Ï´Ù.

static struct sysent sc_example_sysent = { 2, /* Number of parameters for our system call. */ 
sc_example /* A function pointer to our new system call. */ };

ÀÌÀüÀÇ ¼³¸íÀ» ±â¾ïÇÑ´Ù¸é SYSCALL_MODULE ¸ÅÅ©·Î¿¡°Ô ³Ñ¾î¿Â offsetÀ̶ó´Â ¸Å°³ º¯¼ö°¡ ÀÖ¾ú´Ù´Â 
»ç½ÇÀ» ¾Ë°í ÀÖÀ» °ÍÀÔ´Ï´Ù. ÀÌ ¸Å°³ º¯¼ö´Â ¼±¾ðÇϰí ÀÖ´Â ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇϴµ¥ »ç¿ëµÉ °ªÀ» ´ã°í 
ÀÖ½À´Ï´Ù. ÇÏÁö¸¸ º¸Åë KLD °°Àº °ÍÀ» ÀÌ¿ëÇÏ¿© µ¿ÀûÀ¸·Î ½Ã½ºÅÛ ÄÝÀ» »ý¼ºÇÒ ¶§¿¡´Â ƯÁ¤ÇÑ °ªÀ» Á¤ÇÏ
¿© ³Ñ±âÁö ¾Ê´Â °ÍÀÌ ÁÁ½À´Ï´Ù. º¸Åë ÀÌ °ªÀ» NO_SYSCALL·Î ¼³Á¤ÇÏ´Â °ÍÀÌ ÁÁÀºµ¥, ÀÌ °ªÀÇ Àǹ̴ 
"ÇÒ´ç °¡´ÉÇÑ ´ÙÀ½ ½Ã½ºÅÛ ÄÝ °ªÀ» ã¾Æ´Þ¶ó"´Â °ÍÀÔ´Ï´Ù.(ÀÌ ³»¿ëµµ ÀÌ¹Ì ¼³¸íÇß¾ú½À´Ï´Ù.) µû¶ó¼­ ¸ÅÅ©
·Î¿¡°Ô offset °ªÀ¸·Î NO_SYSCALL¸¸À» ³Ñ±â¸é ½Ã½ºÅÛ ÄÝ ¹øÈ£ÀÇ ¹®Á¦´Â ÇØ°áµÉ °ÍÀÔ´Ï´Ù. ÇÏÁö¸¸ ¾î
¶² Á¤Àû º¯¼ö °ªÀ» NO_SYSCALL·Î ¼³Á¤ÇÑ ÈÄ ±× º¯¼ö¸¦ ³Ñ±â´Â ¹æ½ÄÀÌ ´õ ÃßõµÇ´Âµ¥, ÀÌ·¸°Ô Çϸé 
¸ðµâÀ» ·ÎµåÇÒ ¶§ ÀÌ º¯¼öÀÇ °ªÀÌ ¹«¾ùÀ¸·Î ¼³Á¤µÇ¾î ÀÖ´ÂÁö¸¦ ¾Ë ¼ö Àֱ⠶§¹®ÀÔ´Ï´Ù. ÀÌ ¸ÅÅ©·Î´Â 
NO_SYSCALLÀ» ´ã°í ÀÖ´ø º¯¼ö¸¦ ½Ã½ºÅÛÀÌ ÇÒ´çÇØ ÁØ ¹øÈ£·Î º¯°æ½Ãŵ´Ï´Ù. ½Ã½ºÅÛ¿¡ ÀÌ¹Ì Á¤ÀǵǾî 
ÀÖ´Â ½Ã½ºÅÛ Äݰú ±× È£Ãâ ¹øÈ£´Â /usr/include/sys/syscall.h¿¡ Á¤ÀǵǾî ÀÖ½À´Ï´Ù. 
ÀÌ·± ÀÌÀ¯·Î ¿ì¸®´Â ÄÚµåÀÇ ´ÙÀ½ ¶óÀÎÀ» ´ÙÀ½°ú °°ÀÌ ÀÛ¼ºÇÒ °ÍÀÔ´Ï´Ù.

static int syscall_num = NO_SYSCALL;

NO_SYSCALLÀº /usr/include/sys/sysent.h¿¡ Á¤ÀǵǾî Àִµ¥, (-1)·Î ¼³Á¤µÇ¾î ÀÖ½À´Ï´Ù.

¿ì¸®´Â ÀÌ¹Ì ÇϳªÀÇ ½Ã½ºÅÛ ÄÝÀ» ±¸ÇöÇϴµ¥ ÇÊ¿äÇÑ ¸ðµç ºÎºÐÀ» ¿Ï¼ºÇß½À´Ï´Ù. µû¶ó¼­ ³²Àº ºÎºÐÀº ·Î
µå Çڵ鷯¸¦ ÀÛ¼ºÇϰí SYSCALL_MODULE ¸ÅÅ©·Î È£ÃâÇÏ´Â °Í »ÓÀÔ´Ï´Ù.

static int
  load_handler(struct module *m, int what, void *arg)
  {
          int err = 0;
    
          switch (what) {
          case MOD_LOAD:
                     /* Print out syscall_num so we know the value to call */
                  printf("System call loaded at slot: %d\n", syscall_num);
                  break;
          case MOD_UNLOAD:
	          printf("System call unloaded from slot: %d\n", syscall_num);
                  break;
          default:
	          err = EINVAL;
                  break;
    	  }
          return(err);
  }

  SYSCALL_MODULE(sc_example, 
		  &syscall_num, 
		  &sc_example_sysent, 
                  load_handler,
		  NULL);
ÀÌÁ¦ ¿ì¸®ÀÇ »À´ë Äڵ尡 ¿Ï¼ºµÇ¾ú½À´Ï´Ù. (ÁÖ¼®¾ø´Â ÄÚµå´Â [ref. 4]¿¡¼­ ¾òÀ» ¼ö ÀÖ½À´Ï´Ù.) ÀÌÁ¦ ÄÄÆÄ
ÀÏÇÒ Áغñ°¡ ´Ù µÇ¾ú±º¿ä. ±×·¸´Ù¸é ´ÙÀ½°ú °°ÀÌ °£´ÜÇÑ MakefileÀ» ÀÛ¼ºÇսôÙ.
SRCS=sc_example.c 
KMOD=sc_example 
 
.include <bsd.kmod.mk> 
±×¸®°í make¶ó°í ŸÀÌÇÎÇϽʽÿÀ. ÀÌÁ¦ ÄÄÆÄÀÏÀÌ ³¡³µ´Ù¸é ·çÆ® ±ÇÇÑÀ¸·Î ´ÙÀ½°ú °°ÀÌ ÀÔ·ÂÇϼ¼¿ä. 
'kldload ./sc_example.ko'
Áö±Ý±îÁöÀÇ °úÁ¤¿¡ ¾î¶² ¿¡·¯°¡ ¾ø¾ú´Ù¸é ´ÙÀ½°ú °°Àº Ãâ·Â¹°À» º¼ ¼ö ÀÖÀ» °ÍÀÔ´Ï´Ù.

System call loaded at slot: 210

¿©±â¿¡¼­ ³íÀǵÇÁö ¾ÊÀº Á¡Àº ½Ã½ºÅÛ ÄÝÀÌ ·ÎµåµÈ ÈÄ, ¾î¶»°Ô ÀÌ ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇϴ°¡ ÇÏ´Â °ÍÀÔ´Ï´Ù. 
ÇÏÁö¸¸ [ref.4]¿¡¼­ Á¦°øµÇ´Â Äڵ带 ÂüÁ¶Çϸé ÀÌ ½Ã½ºÅÛ ÄÝÀ» È£ÃâÇÏ´Â ¸î °¡Áö ´Ù¸¥ ¹æ¹ýÀÇ ¿¹¸¦ º¼ 
¼ö ÀÖÀ» °ÍÀÔ´Ï´Ù. ¶ÇÇÑ syscall(2)ÀÇ man pageµµ ÀÐ¾î º¸½Ã±â ¹Ù¶ø´Ï´Ù.

 

Character Device KLD Implementation Skeleton

´ëºÎºÐÀÇ À¯´Ð½º ½Ã½ºÅÛ¿¡¼­ °¡Àå À¯¿ëÇÏ°Ô »ç¿ëµÇ´Â µð¹ÙÀ̽ºÀÇ ÇüÅ´ ij¸¯ÅÍ(character) µð¹ÙÀ̽ºÀÔ
´Ï´Ù. ÀÌ·¯ÇÑ ÇüÅÂÀÇ µð¹ÙÀ̽º´Â ¹°¸® µð¹ÙÀ̽º(physical device)¸¦ ³ªÅ¸³»´Âµ¥ »ç¿ëµÇ´Â °Í »Ó ¾Æ´Ï¶ó 
Ä¿³ÎÀÇ Æ¯Á¤ ºÎºÐÀ» Àаí, ¾²°í, Ç÷¡±×¸¦ ¼³Á¤Çϱâ À§ÇÑ ÀÎÅÍÆäÀ̽º·Î »ç¿ëµÇ±âµµ ÇÕ´Ï´Ù. °¡·É, ij¸¯ÅÍ 
µð¹ÙÀ̽º¸¦ ¼³Á¤ÇÏ¿© ³×Æ®¿öÅ© Æ®·¡ÇÈ(network traffic)°ú °ü·ÃµÈ µð¹ÙÀ̽º·ÎºÎÅÍ µ¥ÀÌÅ͸¦ ÀÐ¾î ¿À´Â °Í
µµ °¡´ÉÇÕ´Ï´Ù. 
½Ã½ºÅÛ ÄÝ ±¸Çö°ú °°ÀÌ Ä³¸¯ÅÍ µð¹ÙÀ̽ºÀÇ Á¦ÀÛµµ ¿¹Á¦ Áß½ÉÀ¸·Î ÁøÇàµÉ °ÍÀÔ´Ï´Ù. ÀÌ µð¹ÙÀ̽º°¡ °¡Áø 
±â´ÉÀº ½Ç·Î ¹Ì¾àÇÏÁö¸¸ ¸ðµç ij¸¯ÅÍ µð¹ÙÀ̽ºÀÇ ÀϹÝÀûÀΠƯ¼ºÀ» ÆÄ¾ÇÇÏ´Â µ¥´Â ¹«¸®°¡ ¾ø´Â ¿¹ÀÏ °Í
ÀÔ´Ï´Ù. ¾ÕÀ¸·Î ÁøÇàµÉ ¼³¸íÀ» ÅëÇØ ¿©·¯ºÐÀÌ Ä³¸¯ÅÍ µð¹ÙÀ̽ºÀÇ Á¦ÀÛÀÌ ±×·¸°Ô ¾î·Á¿î °ÍÀº ¾Æ´Ï¸ç, ÀÌ 
µð¹ÙÀ̽º¸¦ Á¦ÀÛÇÏ¿© »ç¿ëÇÏ´Â °ÍÀÌ »ó´çÈ÷ À¯¿ëÇÏ´Ù´Â »ç½ÇÀ» ±ú´ÞÀ» ¼ö ÀÖÀ¸¸é ÇÕ´Ï´Ù.

´ÙÀ½°ú °°Àº Á¡µéÀº ¸ðµç ij¸¯ÅÍ µð¹ÙÀ̽ºÀÇ ±¸Çö¿¡ °øÅëÀûÀÎ ºÎºÐÀÔ´Ï´Ù.
- ¿øÇü µð¹ÙÀ̽º ÇÔ¼öµé(prototype device functions)
- cdevsw ±¸Á¶Ã¼ ¼±¾ð
- ¼±¾ðµÈ cdevsw ±¸Á¶¿¡ µû¸¥ ÇÔ¼öµé
- ·Îµå Çڵ鷯¿Í DEV_MODULE ¸ÅÅ©·Î

À§¿Í °°Àº °ÍµéÀÌ ¾ÕÀ¸·Î ¸¸µé¾î ³ª°¥ »À´ë Äڵ忡 Æ÷Ç﵃ ³»¿ëµéÀÔ´Ï´Ù. ½Ã½ºÅÛ ÄÝ ¿¹Á¦ ÄÚµå¿Í ¸¶Âù°¡
Áö·Î ÁÖ¼® ¾ø´Â Äڵ带 ¿øÇÑ´Ù¸é [ref.4]¸¦ ÂüÁ¶ÇϽñ⠹ٶø´Ï´Ù. ÄÄÆÄÀÏÇÏ°í ½ÇÇà½ÃÄÑ º¸´Â °ÍÀÌ ÄÚµå
¸¦ ºÐ¼®Çϴµ¥ »ó´çÈ÷ Å« µµ¿òÀÌ µÈ´Ù´Â »ç½ÇÀ» ±â¾ïÇϽʽÿÀ.

¿©±â¿¡¼­ ÇÁ·ÎÅäŸÀÔ(prototype)À» ¸¸µé ÇÔ¼ö´Â ´ÜÁö »õ·Î¿î µð¹ÙÀ̽º¿¡ ¹Ù·Î Á¢±ÙÇϱâ À§ÇØ È£ÃâµÇ´Â 
ÇÔ¼öµéÀ̸ç, cdevsw ±¸Á¶Ã¼¿¡ Æ÷ÇԵ˴ϴÙ. ÀÌ·¯ÇÑ ÇÔ¼ö·Î´Â µð¹ÙÀ̽º¸¦ ¿­°í, ´Ý°í, ¾²°í, Àд ÇÔ¼ö¸¦ 
µé ¼ö ÀÖ½À´Ï´Ù.

  d_open_t 	example_open;
  d_close_t		example_close;
  d_read_t		example_read;
  d_write_t		example_write;

cdevsw ±¸Á¶Ã¼¿¡´Â ¿ì¸®°¡ ±¸ÇöÇϰí Àִ ij¸¯ÅÍ µð¹ÙÀ̽º¿Í °ü·Ã ÀÖ´Â ¸¹Àº °ÍµéÀÌ Á¤Àǵ˴ϴÙ. ÀÌ ±¸
Á¶Ã¼´Â /usr/include/sys/conf.h¿¡ Á¤ÀǵǾî ÀÖÀ¸¸ç, ´ÙÀ½°ú °°½À´Ï´Ù.

  struct cdevsw {
          d_open_t *d_open;	     /* Func. pointer to dev open function */
          d_close_t *d_close; 	     /* Func. pointer to dev close function */ 
          d_read_t *d_read;	     /* Func. pointer to dev read function */
          d_write_t *d_write; 	     /* Func. pointer to dev write function */ 
          d_ioctl_t *d_ioctl;	     /* Func. pointer to dev ioctl function */
          d_poll_t *d_poll;	     /* Func. pointer to dev poll function */
          d_mmap_t *d_mmap;	     /* Func. pointer to dev mmap function 
*/
          d_strategy_t *d_strategy;  /* Func. pointer to dev strategy func. */
          const char *d_name;	     /* Device name in /dev */
          int d_maj;		     /* Device major value */
          d_dump_t *d_dump;	     /* Func. pointer to dev dump function */
          d_psize_t *d_psize;	     /* Func. pointer to dev psize function */
          u_int d_flags;	     /* D_TAPE, D_DISK, D_TTY, D_MEM */
          int d_bmaj;	      /* Block Device major value (used by D_DISK) */
  };

 ±¸Á¶Ã¼ ³»ÀÇ ¸ðµç ÇÔ¼ö Æ÷ÀÎÅͰ¡ Á¤ÀǵǾî¾ß ÇÏ´Â °ÍÀº ¾Æ´Õ´Ï´Ù. ÀÌÀ¯°¡ ¹»±î¿ä? ¿©·¯ºÐÀÌ ¾²±â¸¸ °¡
´ÉÇÑ µð¹ÙÀ̽º¸¦ ¿øÇÑ´Ù°í °¡Á¤ÇØ º¾½Ã´Ù. ÀÌ °æ¿ì, ´ÜÁö ÆÄÀÏ Çã°¡±Ç(permission)À» ¼³Á¤ÇÏ´Â °Í ¿Ü¿¡ 
cdevsw ±¸Á¶Ã¼¸¦ ¼±¾ðÇÒ ¶§ d_read Æ÷ÀÎÅ͸¦ noread·Î ¼³Á¤ÇÒ ¼ö ÀÖÀ» °ÍÀÔ´Ï´Ù.(½ÇÁ¦·Ð ºñ¿ö³õ´Â °Í
ÀÌÁÒ.) ¿ì¸®ÀÇ ¿¹Á¦ Äڵ忡¼­´Â ´ÜÁö d_open, d_close, d_write ÇÔ¼ö¸¸À» ¼³Á¤ÇÏ¿© ÃßÈÄÀÇ ³íÀǸ¦ ´Ü¼øÈ­
ÇϰڽÀ´Ï´Ù. ±×·¸´Ù¸é ¿ì¸®ÀÇ cdevsw ±¸Á¶Ã¼´Â ´ÙÀ½°ú °°Àº ¸ð½ÀÀ» ÇÏ°Ô µÇ°ÚÁÒ.

  static struct cdevsw example_cdevsw = {
          example_open,
          example_close,
          example_read,
          example_write,
          noioctl,
          nopoll,
          nommap,
          nostrategy,
          "example",
          33,			/* /usr/src/sys/conf/majors */		
          nodump,
          nopsize,
          D_TTY,
          -1
  };

°á±¹ "no*"·Î ½ÃÀ۵Ǵ ¼±¾ðÀ» Á¦¿ÜÇÑ´Ù¸é d_open_t, d_close_t, d_read_t, d_write_t¸¦ À§ÇÑ ÇÔ¼ö¸¸ÀÌ 
¼±¾ðµÇ¾î ÀÖ´Â ¼ÀÀÔ´Ï´Ù. ´Ù¸¥ ij¸¯ÅÍ µð¹ÙÀ̽ºÀÇ Äڵ带 ¿øÇÑ´Ù¸é [ref. 5]¸¦ ÂüÁ¶ÇϽʽÿÀ. ÀÌ ¿¹Á¦¿¡
¼­´Â d_open_t, d_close_t, d_read_t, d_write_t¸¦ À§ÇÑ °£´ÜÇÑ ¿¹Á¦ ÇÔ¼ö¸¸ÀÌ Á¤Àǵ˴ϴÙ. ¶Ç Çϳª, ÁÖ 
¹øÈ£(major value)°¡ 33ÀÎÁö È®ÀÎÇØ º¸½Ã±â ¹Ù¶ø´Ï´Ù. 33Àº ¿¹Á¦ ¸ñÀûÀ¸·Î ¿¹¾àµÈ ÁÖ ¹øÈ£ Áß ÇϳªÀÔ´Ï
´Ù. ÀÌ ¿Ü¿¡ ´Ù¸¥ ¿¹Á¦ ¹øÈ£¸¦ È®ÀÎÇÏ°í ½Í°Å³ª ½ÇÁ¦ »ç¿ëµÉ µð¹ÙÀ̽º¸¦ À§ÇØ ÇÒ´çµÈ ÁÖ ¹øÈ£ °ªÀ» È®ÀÎ
ÇÏ°í ½Í´Ù¸é /usr/src/sys/conf/majors ÆÄÀÏÀ» »ìÆì º¸½Ã±â ¹Ù¶ø´Ï´Ù. 

ÀÌ ¿¹Á¦ÀÇ ±âº» Àǵµ´Â µð¹ÙÀ̽º µå¶óÀ̹ö¿ÍÀÇ »óÈ£ ÀÛ¿ëÀÌ ¾î¶»°Ô ÀÌ·ç¾î Áö´Â°¡¸¦ º¸¿© ÁÖ´Â °ÍÀÔ´Ï
´Ù. ÀÌ·¯ÇÑ ÀÌÀ¯·Î ÀÌ µå¶óÀ̹ö¿¡¼­ÀÇ ÄÚµå È帧Àº ´ÙÀ½°ú °°Àº ¼ø¼­·Î ¼³Á¤Çß½À´Ï´Ù.

	open(2) -> write(2) -> read(2) -> close(2).

¿ì¸®´Â ¸ÕÀú /dev/ µð·ºÅ丮¿¡ ÀÖ´Â µð¹ÙÀ̽º¸¦ ¿­ °ÍÀÔ´Ï´Ù. ±× ÈÄ, write(2) ½Ã½ºÅÛ ÄÝÀ» »ç¿ëÇÏ¿© ª
Àº ¹®ÀÚ¿­À» ¾¹´Ï´Ù. ¿ì¸®°¡ µð¹ÙÀ̽º¿¡ ¾´ ¹®ÀÚ¿­Àº ¾î¶² Á¤Àû ¹öÆÛ(static buffer)¿¡ ÀúÀåµÉ °ÍÀ̰í, ÀÌ 
°ªÀº read(2) ½Ã½ºÅÛ ÄÝÀ» °ÅÃÄ Á¢±ÙµÉ °ÍÀÔ´Ï´Ù. ÀÌÁ¦ ÀÌ µð¹ÙÀ̽º¸¦ ´Ý¾Æ ´õ ÀÌ»ó Àаųª ¾µ ¼ö ¾øµµ
·Ï ¸¸µì´Ï´Ù. 

  /* Stores string recv'd by _write() */
  static char buf[512+1];
  static int len;

  /* 
   * Used as the variable that is the reference to our device
   * in devfs... we must keep this variable sane until we 
   * call kldunload.
   */
  
  static dev_t sdev;

  /*
   * This open function solely checks for open(2) flags.  We are only 
   * allowing for the flags to be O_RDWR for the purpose of showing
   * how one could only allow a read-only device, for example.
   */

  int 
  example_open(dev_t dev, int oflags, int devtype, struct proc *p)
  {
          int err = 0;

          memset(&buf, '\0', 513);
          len = 0;
          uprintf("Opened device \"example\" successfully.\n");
          return(err);
  }

  /*
   * Simply "closes" our device that was opened with example_open.
   */

  int 
  example_close(dev_t dev, int fflag, int devtype, struct proc *p)
  {
          memset(&buf, '\0', 513);
          len = 0;
          uprintf("Closing device \"example.\"\n"); 
          return(0);
  } 

  /*
   * The read function just takes the buf that was saved 
   * via example_write() and returns it to userland for
   * accessing.
   */

  int
  example_read(dev_t dev, struct uio *uio, int ioflag)
  {
          int err = 0;
    
          if (len <= 0) {
      	        err = -1; 
          } else {		/* copy buf to userland */
                err = copystr(&buf, uio->uio_iov->iov_base, 513, &len);
          }
          return(err);
  }

  /*
   * example_write takes in a character string and saves it
   * to buf for later accessing.
   */
  
  int
  example_write(dev_t dev, struct uio *uio, int ioflag)
  {
          int err = 0;
  
          err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len);
          if (err != 0) {
                uprintf("Write to \"example\" failed.\n");
          }
          return(err);
  }

Áö±Ý±îÁö »ìÆì º» ¹Ù¿Í °°ÀÌ °£´ÜÇÑ Ä³¸¯ÅÍ µð¹ÙÀ̽º µå¶óÀ̹ö¸¦ ÀÛ¼ºÇÏ´Â °ÍÀº ¸Å¿ì ½¬¿î ÀÏÀÌ´Ù. ƯÈ÷, 
sysctl·Î °¡´ÉÇÑ ¾ç ÀÌ»óÀ¸·Î ¸¹Àº µ¥ÀÌÅ͸¦ Ä¿³Î°ú ±³È¯ÇÏ°í ½Í´Ù¸é ÀÌ ¹æ¹ýÀº ¸ÚÁø ÇØ°áÃ¥ÀÌ µÉ °ÍÀÔ
´Ï´Ù.

´ÙÀ½¿¡ ³ª¿Ã ÄÚµå´Â ½ÇÁ¦ KLD¸¦ ·ÎµåÇÏ°í ¾ð·ÎµåÇÒ ¶§ »ç¿ëµÇ´Â ÇÔ¼öÀÔ´Ï´Ù. µð¹ÙÀ̽º µå¶óÀ̹öÀÇ °æ¿ì, 
·ÎµåÇÏ°í ¾ð·ÎµåÇÒ ¶§ ½Ã½ºÅÛ ÄÝ¿¡¼­´Â ÇÏÁö ¾Ê¾Ò´ø Ưº°ÇÑ ÀÛ¾÷À» ¼öÇàÇØ¾ß ÇÕ´Ï´Ù. Áï, MOD_LOAD 
½Ã make_dev¸¦ »ç¿ëÇÏ¿© devfs¿¡ ¿ì¸®ÀÇ µð¹ÙÀ̽º¸¦ µî·ÏÇØ¾ß ÇÕ´Ï´Ù. devfs´Â Device File SystemÀÇ 
¾à¾î·Î¼­ FreeBSD Ä¿³Î ³»ºÎ¿¡ ÀÖ´Â µð¹ÙÀ̽º °ø°£¿¡ Á¢±ÙÇÒ ¼ö ÀÖµµ·Ï ÇØ ÁÝ´Ï´Ù. ¶ÇÇÑ 
MOD_UNLOAD ½Ã¿¡´Â destroy_dev¸¦ È£ÃâÇØ¾ß Çϴµ¥, ¸Å°³ º¯¼ö·Î´Â make_dev°¡ ¸®ÅÏÇØ ÁØ dev_t 
º¯¼ö°¡ »ç¿ëµÇ¾î¾ß ÇÕ´Ï´Ù.

  /*
   * chardev_example_load()
   *
   * This is used as the function that handles what is to occur
   * when the KLD binary is loaded and unloaded via the kldload
   * and kldunload programs.
   */
 
  static int
  chardev_example_load(struct module *m, int what, void *arg)
  {
          int err = 0;
    
          switch (what) {
          case MOD_LOAD:		/* kldload */
                  sdev = make_dev(&example_cdevsw,	  /* explained below */
		  			0,
					UID_ROOT,
					GID_WHEEL,
					0600,
					"example");
                  printf("Example device loaded.\n");
                  break;
          case MOD_UNLOAD:
                  destroy_dev(sdev);		/* explained below */
	          printf("Example device unloaded.\n");
                  break;
          default:
                  err = EINVAL;
	          break;
          }
          return(err);
  }

 ´Ù¸¥ Á¾·ùÀÇ KLD¸¦ ¸¸µé ¶§Ã³·³ ±âº»ÀûÀ¸·Î *_MODULE ¸ÅÅ©·Î¸¦ »ç¿ëÇÏ¿© ¾î´À ÇÔ¼ö°¡ ·Îµå Çڵ鷯
ÀÎÁö¿Í ÀÌ ¸ðµâ¿¡ Á¢±ÙÇÒ ¶§ »ç¿ëÇÒ À̸§À» ¾Ë·Á ÁÖ¾î¾ß ÇÕ´Ï´Ù.

DEV_MODULE(chardev_example, chardev_example_load, NULL);

ÀÌÁ¦ ¸Å¿ì °£´ÜÇÑ Ä³¸¯ÅÍ µð¹ÙÀ̽ºÀÇ »À´ë Äڵ尡 ¿Ï¼ºµÇ¾ú½À´Ï´Ù. ÀÌÁ¦ ³²Àº ÀÏÀº MakefileÀ» ¸¸µé°í 
/dev µð·ºÅ丮¿¡ µð¹ÙÀ̽º¸¦ ½ÇÁ¦·Î »ý¼ºÇÏ´Â ÀÏ »ÓÀÔ´Ï´Ù. ÀÌ ÀÛ¾÷ ¿ª½Ã °áÄÚ ¾î·Á¿î ÀÛ¾÷ÀÌ ¾Æ´Õ´Ï´Ù.

 # cd /dev
 # mknod example c 33 0 
 # ls -al  | grep example
 crw-r--r--  1 root  wheel   33,   0 Aug 14 04:40 example
 #

À§ÀÇ °úÁ¤ÀÌ ³¡³ª¸é kldload¸¦ ¼öÇàÇÑ ÈÄ /dev/example¿¡ open(), close(), read(), write() È£ÃâÀ» ¼öÇà
ÇØ º¸½Ê½Ã¿À. Å×½ºÆ®°¡ ³¡³­ ÈÄ kldunload¸¦ ¼öÇàÇÒ ÅÙµ¥, ÀÌ Àü¿¡ ¹Ýµå½Ã close()¸¦ È£ÃâÇÏ¿© µð¹ÙÀ̽º
¸¦ ´Ý¾Æ ÁÖ¾î¾ß ÇÑ´Ù´Â »ç½ÇÀ» ±â¾ïÇϽñ⠹ٶø´Ï´Ù.

¿¹Á¦ÀÇ ÄÄÆÄÀÏ °¡´ÉÇÑ ÄÚµå´Â [ref. 4]¸¦ º¸½Ã±â ¹Ù¶ø´Ï´Ù.


 

Conclusion
À̰ÍÀ¸·Î FreeBSD KLD ÄÚµù ½Ã½ºÅÛ¿¡ ´ëÇÑ ¼Ò°³¸¦ ¸¶¹«¸® ÇØ¾ß ÇÒ °Í °°½À´Ï´Ù. ±ÛÀÇ Ãʹݺο¡ ¸»Çß
µíÀÌ ²Ï ªÀº ¼Ò°³¿´Áö¸¸ ´çÀå KLD ÇÁ·Î±×·¥À» ÀÛ¼ºÇϰíÀÚ ÇÏ´Â »ç¶÷¿¡°Ô´Â ²Ï À¯¿ëÇÑ Á¤º¸¿´À¸¸®¶ó 
»ý°¢ÇÕ´Ï´Ù. ÀÌ ±ÛÀº THC [ref. 2]¸¦ ÂüÁ¶·Î ÇÏ¿© ÀÛ¼ºµÇ¾ú´Âµ¥, THC´Â KLD¸¦ Á» ´õ ÀÚ¼¼È÷ ¹è¿ï ¼ö 
ÀÖ´Â ÈǸ¢ÇÑ ±â»çÀÔ´Ï´Ù. À̿ܿ¡ ´õ ¸¹Àº ¿¹Á¦ Äڵ带 ¿øÇÏ´Â µ¶ÀÚµéÀº [ref. 4]¸¦ ÂüÁ¶ÇϽñ⠹ٶø´Ï´Ù. 
[ref. 4]¿¡´Â ÀÌ Æ©Å丮¾ó¿¡¼­ ¼³¸íÇÑ °Í ÀÌ»óÀÇ ´Ù¾çÇÑ ¿¹Á¦ Äڵ尡 ¼Ò°³µË´Ï´Ù.

Contact

ÀÌ Æ©Å丮¾óÀÇ ¾î´À ºÎºÐÀÌ¶óµµ ÀúÀÚ¿¡°Ô ±Ã±ÝÇÑ Á¡ÀÌ ÀÖ´Ù¸é ¹®ÀÇÇØ Áֽñ⠹ٶø´Ï´Ù.

E-Mail : awr@blackops.org


References

1. kld(4) man page.
[Much help]

2. THC's FreeBSD Kernel Attack paper.
[Good place for taking your white hat and turning it black]

3. /usr/share/mk/*
[Key for any Makefile creation under FreeBSD]

4. Example code from tutorial
[Location of the examples plus more code.]

5. /usr/share/example/kld/cdev/
[Old example in FreeBSD tree]



Recognition
Peter Wemm 	- Discussion regarding LKM->KLD changes + long quote [intro]
Eivind Eklund 	- style(9) harassment.
Daniel O'Connor - Random comments.