리눅스 커널(Linux Kernel) 관련 일을 하다 보니 가끔씩 보안 패치를 보내기도 하는데요, 메일링 리스트에 패치를 보낼 때마다 리뷰어(Reviewer)며 메인테이너(Maintainer)며 기타 구경꾼들까지 달려들어서 코드를 검토해주는 바람에 거절되는 경우도 많이 있습니다. 특히 최근에는 AMD사의 펌웨어 TPM(fTPM) 관련 패치가 수십 번의 핑퐁 끝에 거절당해서 트라우마까지 생겼거든요. ㅠㅠ 그런데 그런 일보다 더 황당한 일이 있었네요. @0@a..

미네소타 대학에서 논문(On the Feasibility of Stealthily Introducing Vulnerabilities in Open-Source Software via Hypocrite Commits)을 쓰기 위해 보안 취약점이 들어있는 패치를 여러 번에 걸쳐서 메일링 리스트에 보냈고, 그중에 일부는 이미 안정 버전(Stable)에까지 반영이 되어서 급히 제거했다고 합니다. 리눅스 커널은 이미 IoT 장비부터 서버, 우주선에까지 사용되고 있기 때문에 파급효과가 엄청난데... 아무리 논문 욕심이 있었다고 해도 선을 넘은 것 같네요. 메일링 리스트를 보면 너무 길고 양이 많기 때문에, 전체 이야기에 관심이 있다면 ZDNet 기사(Greg Kroah-Hartman bans University of Minnesota from Linux development for deliberately buggy patches)를 보시는 것이 좋을 것 같습니다. ^^;;;

미네소타 대학의 불순한 커널 패치에 대한 ZDNet 기사

과연 얼마나 정교하게 패치를 보냈길래 제대로 검증이 되지 않았나 몇 개를 살펴봤는데요, 꽤나 별 것 아닌 것처럼 보냈습니다. 성공적으로 병합(Merge)된 패치(https://lore.kernel.org/lkml/20210407000913.2207831-1-pakki001@umn.edu/)를 하나 보면 아래와 같습니다.

From: Aditya Pakki <pakki001@umn.edu>
To: pakki001@umn.edu
Cc: Santosh Shilimkar <santosh.shilimkar@oracle.com>,
	"David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	netdev@vger.kernel.org, linux-rdma@vger.kernel.org,
	rds-devel@oss.oracle.com, linux-kernel@vger.kernel.org
Subject: [PATCH] net/rds: Avoid potential use after free in rds_send_remove_from_sock
Date: Tue,  6 Apr 2021 19:09:12 -0500
Message-ID: <20210407000913.2207831-1-pakki001@umn.edu> (raw)

In case of rs failure in rds_send_remove_from_sock(), the 'rm' resource
is freed and later under spinlock, causing potential use-after-free.
Set the free pointer to NULL to avoid undefined behavior.

Signed-off-by: Aditya Pakki <pakki001@umn.edu>
---
 net/rds/message.c | 1 +
 net/rds/send.c    | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/rds/message.c b/net/rds/message.c
index 071a261fdaab..90ebcfe5fe3b 100644
--- a/net/rds/message.c
+++ b/net/rds/message.c
@@ -180,6 +180,7 @@ void rds_message_put(struct rds_message *rm)
 		rds_message_purge(rm);
 
 		kfree(rm);
+		rm = NULL;
 	}
 }
 EXPORT_SYMBOL_GPL(rds_message_put);
diff --git a/net/rds/send.c b/net/rds/send.c
index 985d0b7713ac..fe5264b9d4b3 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -665,7 +665,7 @@ static void rds_send_remove_from_sock(struct list_head *messages, int status)
 unlock_and_drop:
 		spin_unlock_irqrestore(&rm->m_rs_lock, flags);
 		rds_message_put(rm);
-		if (was_on_sock)
+		if (was_on_sock && rm)
 			rds_message_put(rm);
 	}
 
-- 
2.25.1

위의 내용을 보면 기존 소스가 메모리 해제 후 재사용(Use After Free, UAF) 문제가 있어서 이를 수정한다는 내용입니다. 그런데 실제 패치에 추가된 내용을 보시면, rds_message_put() 함수에서 rm = NULL;을 추가해서 rm이라는 변수에 NULL을 넣고 난 다음, rds_send_remove_from_sock() 함수에서 if 문에 rm 변수가 NULL이 아닌 것을 검사하게 만들었습니다. 사실 rm이라는 변수는 rds_send_remove_from_sock() 함수에 있는 지역변수인데요, 이 지역변수를 다른 함수에서 넘겨받아 값을 NULL로 바꿨지만 사실 눈속임에 불과합니다. 즉 쓸모없는 수정이라는 말입니다.

조금 어려운 이야기인데... 다른 함수에서 rm에 NULL을 넣으려면 rm 자체가 일단 싱글 포인터(Single Pointer)이기 때문에 더블 포인터(Double Pointer)로 rm 변수의 주소 값을 넘겨야 하거든요(포인터는 항상 어렵습니다 ㅠㅠ). 리눅스 커널 개발자들은 위에서 보시는 것처럼 패치 형태로 전달하는데요, 패치는 수정된 코드의 위아래 일부분만 보여주기 때문에 자칫 잘못하면 실수를 할 수 있습니다. 이런 부분을 노리고 리뷰가 얼마나 잘되는지를 판단하려고 저런 패치를 보냈다고 생각하니, 의도가 얼마나 불순했는지를 알 수 있습니다. 그래도 이런 패치는 양반입니다. 아무런 영향을 미치지 않으니까요.

그럼 이제 문제의 패치를 보겠습니다. 실제로 보안 문제를 일으키는 패치인데요, 심지어 가명으로 만든 계정으로 보낸 걸로 추측됩니다. 왜냐하면 제임스 본드(James Bond)거든요. ^^;;; 쿨럭..;;; 다행히도 이 패치(https://lore.kernel.org/lkml/20200821070537.30317-1-jameslouisebond@gmail.com/)는 거절되었습니다.

From: James Bond <jameslouisebond@gmail.com>
To: jameslouisebond@gmail.com
Cc: Miquel Raynal <miquel.raynal@bootlin.com>,
	Richard Weinberger <richard@nod.at>,
	Vignesh Raghavendra <vigneshr@ti.com>,
	Arnd Bergmann <arnd@arndb.de>, Ryan Jackson <rjackson@lnxi.com>,
	David Woodhouse <dwmw2@infradead.org>,
	linux-mtd@lists.infradead.org, linux-kernel@vger.kernel.org
Subject: [PATCH] mtd: ck804xrom: fix missing pci device put in error paths
Date: Fri, 21 Aug 2020 02:05:36 -0500
Message-ID: <20200821070537.30317-1-jameslouisebond@gmail.com> (raw)

pci_dev_get increases the refcount of "pdev".
In the error paths, pci_dev_put should be called
to handle the "pdev" and decrease the corresponding refcount.

Fixes: 90afffc8bd79 ("[MTD] [MAPS] Support for BIOS flash chips on the nvidia ck804 southbridge")
Signed-off-by: James Bond <jameslouisebond@gmail.com>
---
 drivers/mtd/maps/ck804xrom.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c
index 460494212f6a..16af8b5ee653 100644
--- a/drivers/mtd/maps/ck804xrom.c
+++ b/drivers/mtd/maps/ck804xrom.c
@@ -195,6 +195,7 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
 	if (!window->virt) {
 		printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
 			window->phys, window->size);
+		pci_dev_put(pdev);
 		goto out;
 	}
 
@@ -222,6 +223,7 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
 
 		if (!map) {
 			printk(KERN_ERR MOD_NAME ": kmalloc failed");
+			pci_dev_put(pdev);
 			goto out;
 		}
 		memset(map, 0, sizeof(*map));
@@ -295,6 +297,7 @@ static int __init ck804xrom_init_one(struct pci_dev *pdev,
 		if (mtd_device_register(map->mtd, NULL, 0)) {
 			map_destroy(map->mtd);
 			map->mtd = NULL;
+			pci_dev_put(pdev);
 			goto out;
 		}
 
-- 
2.17.1

위의 패치를 보시면 매번 goto out 예외 처리 루틴으로 넘어가기 전에 pci_dev_put(pdev)를 호출하는 부분을 추가했습니다. 위의 패치 코드만 보면 추가된 부분이 필요할 것같은 느낌이 듭니다. 하지만, 실제로 goto out 부분을 보면 아래처럼 ck804xrom_cleanup(window)를 부르고 그 내부에서 pci_dev_put(pdev)를 다시 호출합니다. 따라서, 제임스 본드(ㅡ_ㅡ;;;)가 보낸 패치를 넣게 되면 pci_dev_put(pdev)를 두 번 호출하게 되고, 보안 취약점 중에 하나인 중복 해제(Double Free) 버그가 생깁니다. 쉽게 말씀드리면, 같은 메모리를 두 번이나 해제해서 malloc/free에 사용하는 힙(Heap) 영역이 꼬이고, 악의적인 사용자가 이를 이용하면 다양한 문제가 발생합니다.

 out:
	/* Free any left over map structures */
	kfree(map);

	/* See if I have any map structures */
	if (list_empty(&window->maps)) {
		ck804xrom_cleanup(window);
		return -ENODEV;
	}
	return 0;
}

이런 류의 패치 시도가 다양하게 있었던 것 같은데... 정말 대단한 집념인 것 같습니다. 그 와중에 해명(https://lore.kernel.org/linux-nfs/YH%2FfM%2FTsbmcZzwnX@kroah.com/)을 하기는 했는데, 자기는 정적 분석 도구(Static Analysis Tool)가 알려주는 대로 수정해서 패치를 보냈다고 하더라구요. 이미 아시는 분도 계시겠지만, 정적 분석 도구가 저런 리포트를 만들어냈다고 보기는 좀 어려울 것 같고, 다분히 사람이 악의적인 의도를 가지고 만들었다고 판단하는 게 옳을 것 같네요. ^^;;;

정말 세상에 별일이 다 있네요. 제가 쓰는 소프트웨어에 더 주의를 기울여야겠습니다.

그럼 즐거운 밤 되세요 >ㅁ<)/~

데비안(Debian)이나 우분투(Ubuntu)가 엄청 발전해서 쓰기가 많이 좋아진 것은 사실이지만, 조금만 깊게 들어가면 여전히 손볼 대가 많습니다. ^^;;; 이번에는 커널을 직접 컴파일했을 때 흔히 발생하는 블랙 스크린, 즉 데스크탑 화면이 표시되지 않고 검은색 바탕에 화면 좌측 상단에 커서만 깜빡이는 현상 처리 방법입니다.

이런 상황은 보통 Nvidia나 ATI에서 제공하는 3rd party 드라이버를 사용하는 경우에 발생합니다. 저는 오래된 Nvidia 그래픽카드를 쓰고 있는데요, 아래처럼 패키지를 다시 설치하는 방법으로 해결하고 있습니다. 새로운 커널에서 로딩할 Nvidia 드라이버가 없어서 발생하는 문제거든요. 

# Nvidia의 커널 모듈을 다시 컴파일해주는 패키지입니다.
$> sudo apt reinstall nvidia-kernel-dkms

커널 컴파일 후 비슷한 문제가 생길 때마다 스택 오버플로우(Stack Overflow) 사이트에서 찾아 쓰다가, 생각난 김에 정리해둡니다.

그럼 즐거운 밤 되세요 >ㅁ<)/~

언제부터인지 데비안(Debian)이나 우분투(Ubuntu) 커널을 빌드하고 모듈을 인스톨하면 디버그 심볼이나 기타 정보가 엄청 생성돼서 파일이 너무 커지는 일이 발생했습니다. 사실 모듈이 커지는 것쯤은 별일이 아닐 수 있지만, 문제는 램디스크, 즉 initrd를 생성할 때 발생합니다. 모듈이 너무 커서 initrd 사이즈가 500MB까지 증가하거든요. ^^;;;

저는 커널 보안기능을 주로 개발하기 때문에 수시로 커널을 빌드하는데요, 그러다 보면 커널 모듈 크기 때문에 initrd 빌드 시간이 길어져서 빌드 완료까지 대기하는 전체 시간(이라고 쓰고 노는 시간이라고 읽는... 쿨럭..;;)도 길어지더라구요. 그래서 방법을 찾다 보니 아래처럼 하면 된다는 걸 발견했습니다.

# 먼저 커널과 커널 모듈을 빌드합니다.
$> make -j <cpu 갯수>
$> make modules -j <cpu 갯수>

# 불필요한 정보를 제거한 후 모듈을 설치하고 커널을 설치합니다.
$> make INSTALL_MOD_STRIP=1 modules_install -j <cpu 갯수>
$> make install

이제 시간을 효율적(?!)으로 쓸 수 있겠네요!

그럼 즐거운 저녁 되세요 ㅠㅠ)/

요즘 진행 중인 프로젝트가 있는데, 어찌하다 보니 디버깅을 위해서 버추어박스의 소스코드를 빌드할 일이 생겼습니다. 전체적인 빌드 과정은 https://www.virtualbox.org/wiki/Linux%20build%20instructions에 잘 정리되어 있긴 한데요... 아시겠지만 실제로 빌드를 해보면 다양한 문제에 봉착하게 되죠... 쿨럭..;;; 오라클 버추어박스의 소스코드를 빌드를 하다 보면 아래와 같은 오류가 발생합니다.

/home/user/project/VirtualBox-6.1.16/doc/manual/en_US/user_KnownIssues.xml:6: warning: failed to load external entity "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
]>
  ^
/home/userproject/VirtualBox-6.1.16/doc/manual/en_US/user_ChangeLog.xml:6: warning: failed to load external entity "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
]>
  ^
/home/user/project/VirtualBox-6.1.16/doc/manual/en_US/user_ThirdParty.xml:6: warning: failed to load external entity "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
]>
  ^
/home/user/project/VirtualBox-6.1.16/doc/manual/en_US/user_PrivacyPolicy.xml:6: warning: failed to load external entity "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
]>
  ^
/home/user/project/VirtualBox-6.1.16/doc/manual/en_US/user_Glossary.xml:6: warning: failed to load external entity "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
]>
  ^
warning: failed to load external entity "/usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd"
Could not parse DTD /usr/share/xml/docbook/schema/dtd/4.5/docbookx.dtd
kBuild: Validating /home/user/project/VirtualBox-6.1.16/doc/manual/en_US/UserManual.xml

실제로 docbookx.dtd 파일에 문제가 있는 건 아닌 것 같고, 소스코드 tarball에서 파일이 한 개 없어서 발생한 오류였습니다. 아래와 같이 입력해서 빈 파일을 만들어주면 실제로 빌드가 잘 됩니다.

user@user:~/project/VirtualBox-6.1.16$ touch out/linux.amd64/release/obj/manual/en_US/validatemanual.run
user@user:~/project/VirtualBox-6.1.16$ chmod +x out/linux.amd64/release/obj/manual/en_US/validatemanual.run

뭔가 일부러 빠뜨렸을 것 같지는 않은데... 그리고 벌써 몇년이나 지난 버그인데, 아직도 고쳐지지 않았더라고요. 여하튼 빌드가 잘 되어 천만다행입니다. ^^;;;

그럼 좋은 밤 되세요.

pip로 재미있는(?) 툴을 설치할 일이 있었습니다. 그런데 이게 웬일? 데비안(Debian)에는 pip가 기본적으로 설치되어 있지 않더라고요. 사실 pip는 파이썬으로 만든 툴을 설치하는 용도로 많이 사용했던지라 좀 당황했습니다. 허나, 찾으려고 하면 또 찾아지는 법이더라고요. ^^;; 데비안 계열에서 설치하려면 아래와 같이 입력하면 됩니다.

$> sudo apt install python-pip python-setuptools python3-pip python3-setuptools

$> sudo apt install python-pip python-setuptools python3-pip python3-setuptools

그럼 즐거운 리눅스 생활되세요 >ㅁ<)/

i3 윈도우 매니저는 불친절하기 그지없는데요, 배경 이미지를 설정하는 것조차 커맨드로 처리해야 합니다. ㅠㅠ feh라는 도구를 활용해서 말이죠. 아래는 ~/.config/i3/config 파일을 수정해서 매번 로그인할 때마다 배경을 로딩하도록 해주는 코드입니다.

# 절대 경로와 함께 아래 라인을 추가해줘야 함
exec --no-startup-id feh --bg-scale /home/user/사진/background.jpg

아아... 정말 불친절하기 그지없네요. 뭔가 한 방에 다 깔끔하게 처리해주는 패키지가 있으면 좋을텐데 말이죠. ^^;;;
그럼 좋은 하루 되세요 >ㅁ<)/

i3 윈도우 매니저(Window Manager)를 사용하다 보니 이것저것 아쉬운 부분이 있는데요, 이번에는 볼륨 컨트롤입니다. XFCE나 GNOME, KDE 같은 윈도우 매니저들은 웬만한 기능들을 다 가지고 있지만 i3 윈도우 매니저는 대부분 다른 것들을 빌려서 사용해야 합니다. ^^;;; 쿨럭...;;;

볼륨 컨트롤 같은 경우는 GTK로 된 Pulseaudio Volume Control을 설치하니 사용하는데 큰 불편함이 없더라구요. 데비안 계열에서는 아래와 같이 설치하고 사용할 수 있습니다.

# 설치
$> sudo apt install pavucontrol

# 실행
$> pavucontrol

그럼 즐거운 하루 되세요. ^^)/

요즘 제가 메인으로 사용하고 있는 i3 윈도우 매니저(Window Manager, wm)는 틸팅(Tilting)이라는 멋진 기능이 있어서 많은 유저를 확보하고 있는데요, 반면에 GUI로 제공되는 그놈 컨트롤 센터(Gnome Control Center) 같은 툴이 없어서 불편한 점도 있습니다. 그래서 모니터 설정이나 밝기 같은 부분은 xrandr 같은 툴을 활용해야 하죠. ^^;;;

먼저 모니터의 위치를 변경하는 방법입니다. 아래처럼 xrandr --listmonitors를 하면 현재 연결된 모니터를 확인할 수 있는데요, i3 윈도우 매니저는 연결된 모니터를 순서대로 오른쪽에 배치를 해줍니다. 노트북 같은 경우는 내장 모니터와 외장 모니터로 구분되고, 내장 모니터가 왼쪽에, 외장 모니터가 오른쪽에 자동으로 배치됩니다.

$> xrandr --listmonitors
 0: +*eDP-1 1920/344x1080/194+2560+0  eDP-1     <== 내장 모니터
 1: +DP-1 2560/698x1440/392+0+0  DP-1                  <== 외장 모니터

이러한 순서를 바꾸려면 아래와 같이 입력하면 됩니다. --left-of 나 --right-of를 이용해서 말이죠. :)

# 내장 모니터의 왼쪽에 외장 모니터를 위치시킴
$> xrandr --output DP-1 --auto --left-of eDP-1

xrandr는 소프트웨어적으로 밝기도 조절할 수 있는데요, 아래처럼 --brightness를 이용하면 됩니다.

$> xrandr --output eDP-1 --brightness 0.7

그럼 즐거운 하루 되세요. ^^)/

가벼운 윈도우 매니저를 찾다가 올해부터 본격적으로 i3wm을 사용하기 시작했습니다. ^^;;; i3wm의 가장 큰 매력은 틸팅(Tilting) 기능인데요, 창이 뜰 때마다 화면의 절반을 갈라서 자동으로 분할 및 배치를 해준다는 점입니다. 저처럼 개발을 주로 하고 화면을 양분할 해서 코딩 윈도우와 검색 윈도우를 배치하는 사람한테는 멋진 기능이 아닐 수 없죠. 특히 키보드로 창 이동과 배치 등등이 가능한 부분은 마치 VIM을 윈도우 매니저로 사용하는 것 같은 착각을 불러일으키기도 하죠. ^^a...

i3wm의 윈도우 배치 화면

이런 편리한 기능도 가끔은 당황스러울 때가 있는데요, 바로 파일 다이얼로그처럼 기존의 창 위에 표시되는 다이얼로그도 강제로 틸팅되어 배치되기 때문입니다. 그래서 매번 파일 다이얼로그가 뜰 때마다 어색한 정적이 흐르는데요... i3wm의 설정파일을 아래와 같이 수정하면 파일 다이얼로그가 뜰 때 다른 창 위에 자연스럽게 표시됩니다.

# 설정 파일은 ~/.config/i3/config에 있습니다.

bindsym $mod+n exec nautilus --class floatingWM
for_window [class="^floatingWM$"] floating enable

# 위의 파일을 저장하고 아래와 같이 입력하면 바로 적용됩니다.
$> i3 reload
$> i3 restart

다른 윈도우 매니저도 좋지만 VIM처럼 쓸 수 있는 i3wm이 제일 손에 맞는 것 같네요.

그럼 즐거운 하루 보내세요 ^^)/

최근에 서버에 세팅하고 쓰던 오라클 버추어 박스(Oracle Virtual Box)가 갑자기 죽는 바람에 정상적으로 가상 머신이 구동되지 않는 문제가 발생했습니다. 아무래도 오래된 가상 머신이다 보니 저장된 데이터도 많고 특히 스냅샷이 많아서 데이터가 하드디스크의 차분 데이터(Difference)가 많이 쌓여 있었거든요. 그런데 부팅을 했더니 지난주의 스냅샷으로 돌아가버리는 겁니다. ㅠㅠ)/ 정말 돌아버릴 것 같더라구요.

그냥 날리기에는 너무 아까운 데이터들이라 vbox 관련 설정을 보기 시작했습니다. 그랬더니 규칙이 보이더라구요. 결국은 하드디스크의 차분 데이터를 순서대로 쌓고 가장 최근 차분으로 부팅을 시작하도록 vbox 설정을 수정하는 것이 핵심이었습니다. ^^;;

말로 하니 엄청 어려운데... 일단 .vbox 파일을 vi로 열어보시면 미디어 등록(MediaRegistry), 스냅샷(Snapshot), 하드웨어 설정(Hardware), 저장소 컨트롤러(Storage Controller)의 네 부분으로 나뉩니다.

<?xml version="1.0"?>
... 생략 ...
<VirtualBox xmlns="http://www.virtualbox.org/" version="1.16-linux">
  <Machine uuid="{e5321d5b-ec0b-46fb-b91b-21758d33bf65}" name="Linux 2.0" OSType="Oracle_64" currentSnapshot="{d3870e3c-14b2-46ba-9cae-95d8fe7f7cfe}" snapshotFolder="Snapshots" lastStateChange="2020-08-24T15:56:22Z">
    <-- 미디어 등록 -->
    <MediaRegistry>
      <HardDisks>
        <HardDisk uuid="{6f7655b2-370e-492c-93fc-5a965b18fdd7}" location="Linux 2.0.vdi" format="VDI" type="Normal">
          <HardDisk uuid="{5e9971c7-0b7e-4355-bb14-9f12841b2f05}" location="Snapshots/{5e9971c7-0b7e-4355-bb14-9f12841b2f05}.vdi" format="VDI"/>
        </HardDisk>
      </HardDisks>
      <DVDImages>
        <Image uuid="{84d51fa6-d6f3-48be-9cde-ecde3ddd84e1}" location="/usr/lib/virtualbox/additions/VBoxGuestAdditions.iso"/>
      </DVDImages>
    </MediaRegistry>
    
    <-- 스냅샷 관련 정보 -->
    <Snapshot uuid="{d3870e3c-14b2-46ba-9cae-95d8fe7f7cfe}" name="Snapshot 1" timeStamp="2020-08-24T15:56:22Z" stateFile="Snapshots/2020-08-24T15-56-22-357112000Z.sav">
      <Hardware>
        <CPU count="2">
          <PAE enabled="true"/>
          <LongMode enabled="true"/>
          <X2APIC enabled="true"/>
          <HardwareVirtExLargePages enabled="false"/>
        </CPU>
        <Memory RAMSize="8192"/>
        ... 생략 ...
    </Snapshot>
    
    <-- 가상머신 하드웨어 정보 -->
    <Hardware>
      <CPU count="2">
        <PAE enabled="true"/>
        <LongMode enabled="true"/>
        <X2APIC enabled="true"/>
        <HardwareVirtExLargePages enabled="false"/>
      </CPU>
      <Memory RAMSize="8192"/>
      <Paravirt provider="KVM"/>
      <Display controller="VMSVGA" VRAMSize="128"/>
      <VideoCapture screens="1" file="." fps="25"/>
      ... 생략 ...
    </Hardware>
    
    <-- 저장소 컨트롤러 정보 -->
    <StorageControllers>
      <StorageController name="IDE" type="PIIX4" PortCount="2" useHostIOCache="true" Bootable="true">
        <AttachedDevice passthrough="false" type="DVD" hotpluggable="false" port="0" device="0">
          <Image uuid="{84d51fa6-d6f3-48be-9cde-ecde3ddd84e1}"/>
        </AttachedDevice>
      </StorageController>
      <StorageController name="SATA" type="AHCI" PortCount="1" useHostIOCache="false" Bootable="true" IDE0MasterEmulationPort="0" IDE0SlaveEmulationPort="1" IDE1MasterEmulationPort="2" IDE1SlaveEmulationPort="3">
        <AttachedDevice type="HardDisk" hotpluggable="false" port="0" device="0">
          <Image uuid="{5e9971c7-0b7e-4355-bb14-9f12841b2f05}"/>
        </AttachedDevice>
      </StorageController>
    </StorageControllers>
  </Machine>

여기서 중요한 점은 미디어 등록 부분과 마지막에 저장소 컨트롤러 부분인데요, 분석 결과 미디어 등록 부분은 가상 머신의 하드로 사용되는 vdi 파일 원본부터 스냅샷으로 인해 생성된 "Snapshot\{UUID}.vdi" 정보를 생성된 시간 순서대로 쌓아나가는 역할을 했습니다. 그리고 저장소 컨트롤러 정보는 미디어 등록 부분 중 한 위치를 가리키게 되는데요, 보통은 가장 마지막, 즉 가장 최근 차분 디스크의 UUID를 설정해서 최신 하드 정보로 부팅하도록 만듭니다.

위의 설정 파일 같은 경우는 저장소 컨트롤러가 "Snapshot\{5e9971c7-0b7e-4355-bb14-9f12841b2f05}.vdi"로 부팅을 시작하도록 되어 있고, 이는 미디어 등록 정보를 따르면 Linux 2.0.vdi의 최근 차분 정보임을 알 수 있습니다. 즉 아래처럼요.

{5e9971c7-0b7e-4355-bb14-9f12841b2f05}
  |-> {6f7655b2-370e-492c-93fc-5a965b18fdd7}
        |-> Linux 2.0.vdi

사실 어느 정도 정보가 살아 있는 경우는 미디어 등록 정보를 비교적 쉽게 구성할 수 있는데요, 아무런 정보가 없는 경우는 Snapshot 폴더로 이동해서 아래 명령어를 사용하면 부모의 차분 이미지 UUID를 찾아낼 수 있습니다. 이러한 정보를 이용해서 순서대로 나열하면 역시 미디어 등록 정보를 구성할 수도 있죠. 제가 직접 사용한 방법이기도 합니다. ㅠㅠ)/ 차분 정보를 보면 부모의 UUID가 6f7655b2-370e-492c-93fc-5a965b18fdd7 인데요, 아래쪽의 Linux 2.0.vdi를 보면 UUID가 동일한 것을 알 수 있습니다. 이를 통해 Linux 2.0.vdi의 첫 번째 차분임을 알 수 있는 거죠.

# 차분의 정보 표시
$> vboxmanage showhdinfo {5e9971c7-0b7e-4355-bb14-9f12841b2f05}.vdi
UUID:           5e9971c7-0b7e-4355-bb14-9f12841b2f05
Parent UUID:    6f7655b2-370e-492c-93fc-5a965b18fdd7
State:          locked write
Type:           normal (differencing)
Auto-Reset:     off
Location:       /home/user/VirtualBox VMs/Linux 2.0/Snapshots/{5e9971c7-0b7e-4355-bb14-9f12841b2f05}.vdi
Storage format: VDI
Format variant: dynamic default
Capacity:       102400 MBytes
Size on disk:   2 MBytes
Encryption:     disabled
Property:       AllocationBlockSize=
In use by VMs:  Linux 2.0 (UUID: e5321d5b-ec0b-46fb-b91b-21758d33bf65)

# 가상 하드디스크의 정보 표시
$> vboxmanage showhdinfo Linux\ 2.0.vdi 
UUID:           6f7655b2-370e-492c-93fc-5a965b18fdd7
Parent UUID:    base
State:          locked read
Type:           normal (base)
Location:       /home/user/VirtualBox VMs/Linux 2.0/Gooroom 2.0.vdi
Storage format: VDI
Format variant: dynamic default
Capacity:       102400 MBytes
Size on disk:   5967 MBytes
Encryption:     disabled
Property:       AllocationBlockSize=1048576
In use by VMs:  Linux 2.0 (UUID: e5321d5b-ec0b-46fb-b91b-21758d33bf65) [Snapshot 1 (UUID: d3870e3c-14b2-46ba-9cae-95d8fe7f7cfe)]
Child UUIDs:    5e9971c7-0b7e-4355-bb14-9f12841b2f05

어휴... 어쨌든 해결해서 다행이네요.

그럼 좋은 밤 되세요 ^^)/

가끔 임시 비밀번호를 만들어 써야하는 경우가 종종 있는데요, 임시 비밀번호지만 뭔가 습관대로 만드는 것이 불안해서 임의의 문자열을 뽑는 기능을 검색해봤습니다. 다양한 방법이 있었는데 스택 오버플로우(unix.stackexchange.com/questions/230673/how-to-generate-a-random-string)에 좋은 방법이 있었습니다. ^^)/~ 즉, 아래처럼 하면 된다는 이야기지요.

$> head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo ''
uqpmpi0CpJOEh1NJL9tffi6mmPLe6ASk

$> head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo ''
cnxc8yYGGrZwz5noljO18yg8xNBH9kHY

$> head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo ''
YUvAlrdtyNUhrr5GSXLKLeA7EkSoZuTV

꽤나 유용하게 사용할 수 있겠군요.

그럼 좋은 하루 되세요 ^^)/

리눅스를 사용하다보면 배포판(Distribution)이 지원해주지 않는 디바이스를 써야할 때가 있습니다. 사실 그래서 저는 한 세대 전 장비를 선호하기도 한데요, 어쩔 수 없이 써야할 경우가 종종 있습니다. 예를 들면 최신 장비에서 제가 만든 소프트웨어가 잘 동작하는지를 봐야 하는 경우처럼요. ^^;;;

보통 이런 경우는 강제로 커널을 최신 버전으로 업그레이드 하면 되지만 이것 또한 쉽지 않은 경우가 있습니다. 배포판의 경우는 특정 커널 버전을 정해놓고 유지하면서 최신 버전 커널은 천천히 적용하는 게 대부분이거든요. 그렇다면 옛날 커널 버전에서 최신 디바이스의 드라이버를 지원하려면 어떻게 해야 하느냐... 리눅스 커널의 백포트(backport)를 쓰면 되는데요, 백포트는 git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/backport-iwlwifi.git에 있습니다. 다만, 이걸 직접 받아서 빌드하는 것이 쉽지 않은데, 데비안(Debian) 리눅스의 파생 버전인 우분투(Ubuntu) 리눅스는 이를 위한 패키지를 이미 준비해두었더라구요.

Canonical Hardware Enablement team이 이를 담당하고 있는데요, launchpad.net/~canonical-hwe-team/+archive/ubuntu/pc-oem-dkms에서 backport-iwlwifi-dkms_7906-0ubuntu3~18.04.1~oem~ubuntu18.04.1_all.deb를 받으면 됩니다. 그리고 아래처럼 설치하면 설치 중에 자동으로 커널 드라이버가 빌드됩니다.

$> sudo dpkg -i backport-iwlwifi-dkms_7906-0ubuntu3~18.04.1~oem~ubuntu18.04.1_all.deb

제가 확인해본 결과 데비안 10(Buster)에서도 일단 정상적으로 동작하는 것을 확인했고, 최신 WIFI 디바이스인 Killer AX1650도 잘 잡혔습니다. ㅠㅠ)-b 후우... 정말 다행이에요.... 지옥문이 열릴 뻔 했거든요. 쿨럭..;;;

그럼 해피 리눅스하세요. >ㅁ<)/

최근 데비안(Debian) 리눅스에서 그놈(Gnome) 데스크탑을 버리고 i3 윈도우 매니저를 사용하기 시작했습니다. i3는 틸팅(Tilting), 화면을 이등분 해서 창을 정렬하는 것이 특징인데요, 처음에는 좀 당황스럽지만 익숙해지면 vi를 사용하듯이 창을 옮겨다니면서 쓸 수 있습니다. 물론 이렇게까지 익숙해지려면 시간을 많이 투자해야 한다는 것이 함정이지만요... 쿨럭..;;;;

그놈을 버리고 나니 아쉬운 부분이 여럿 있는데요, 그중에 하나가 모니터 밝기 조절입니다. gnome-control-center를 실행해서 해결해 볼까도 했지만 커맨드 라인으로 처리할 수 있는 방법을 찾았습니다. 방법은 간단한데요, xrandr로 연결된 모니터를 찾고 밝기를 조절하는 겁니다. 아래처럼 말이죠. ^^;;;

# 연결된 모니터를 찾음.
$>xrandr -q | grep connected
eDP-1 connected primary 1920x1200+0+0 (normal left inverted right x axis y axis) 263mm x 164mm
DP-1 connected 2560x1440+1920+0 (normal left inverted right x axis y axis) 698mm x 392mm
HDMI-1 disconnected (normal left inverted right x axis y axis)

# 모니터의 밝기를 70%로 조절함.
xrandr --output eDP-1 --brightness 0.7

생각보다 간단하네요. 그럼 좋은 하루 되세요 ^^

+ Recent posts