리눅스 커널(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

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

만자로 리눅스(Manjaro Linux)

만자로(Manjaro) 리눅스는 아치(Arch) 리눅스를 바탕으로 만들어졌는데요, 버전을 구분하고 대규모 업데이트가 벌어지는 우분투(Ubuntu)나 페도라(Fedora)와 달리 변경 사항이 있으면 즉시 업데이트를 하는 특징이 있습니다. 아치 리눅스나 만자로 리눅스에서는 이를 롤링 업데이트(Rolling Update)라고 하는데, 업데이트를 그만큼 자주 하다 보니 속도가 빠른 미러 서버를 선택하는 것이 여러모로 좋습니다. ^^;;;

만자로를 설치하면 속도가 빠른 미러 서버를 선택하는데요, 미러 서버가 계속 추가되고 삭제되기 때문에 리스트를 갱신해 주는 것이 좋습니다. 미러 서버 정보는 /etc/pacman.d/mirrorlist에 있는데, 아래와 같은 방법으로 확인해 볼 수 있습니다.

$> cat /etc/pacman.d/mirrorlist 
##
## Manjaro Linux default mirrorlist
## Generated on 2020-02-03 00:40
##
## Please use 'pacman-mirrors -f [NUMBER] [NUMBER]' to modify mirrorlist
## (Use 0 for all mirrors)
##

## Country : Japan
Server = http://ftp.riken.jp/Linux/manjaro/stable/$repo/$arch

## Country : Denmark
Server = https://www.uex.dk/public/manjaro/stable/$repo/$arch

## Country : China
Server = https://mirrors.ustc.edu.cn/manjaro/stable/$repo/$arch

## Country : Iran
Server = https://repo.iut.ac.ir/repo/manjaro/stable/$repo/$arch

## Country : France
Server = https://mirror.oldsql.cc/manjaro/stable/$repo/$arch

이제 미러 서버 목록을 모두 다운로드한 뒤 이를 속도 순으로 정렬해보겠습니다. 미러 서버 목록을 다운받으러면 pacman-mirrors 커맨드와 country 옵션을 사용하면 됩니다.

$> sudo pacman-mirros --country all
::INFO Downloading mirrors from repo.manjaro.org
::INFO Using default mirror file
::INFO Querying mirrors - This may take some time
  ..... Australia      : http://manjaro.melbourneitmirror.net/
  ..... Australia      : http://manjaro.mirror.serversaustralia.com.au/
  1.698 Austria        : http://mirror.inode.at/manjaro/
  1.774 Austria        : http://mirror.easyname.at/manjaro/
  ..... Austria        : ftp://mirror.easyname.at/manjaro/
  1.169 Bangladesh     : http://mirror.xeonbd.com/manjaro/

... 생략 ...

::INFO Writing mirror list
::South_Korea     : https://mirror.d-tl.com/manjaro/stable
::Taiwan          : http://free.nchc.org.tw/manjaro/stable
::Japan           : http://ftp.tsukuba.wide.ad.jp/Linux/manjaro/stable
::Hong_Kong       : http://ftp.cuhk.edu.hk/pub/Linux/manjaro/stable

... 생략 ...

::INFO Mirror list generated and saved to: /etc/pacman.d/mirrorlist

위의 로그를 보면 모든 미러 서버 목록을 읽어와서 응답속도를 측정하고 빠른 순서대로 정렬하여 /etc/pacman.d/mirrorlist에 저장한 것을 확인할 수 있습니다. 예전에 제가 설치했을 때는 한국에 미러 서버가 없었는데 지금은 한국에도 있군요. 그저 감사할 따름입니다. ^^)/

미러 서버를 업데이트했으니 이제 더욱 빠른 속도로 만자로를 업데이트할 수 있습니다. 업데이트는 아래와 같은 방식으로 진행합니다.

$> sudo pacman -Syu

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

리눅스(linux) 환경에서 권한 상승이 필요할 때 많이 쓰는 방법이 sudo를 이용하는 것인데요, 다들 아시겠지만 sudo를 사용하려면 sudo 패키지가 시스템에 설치되어 있어야 합니다. 그리고 _etc_sudoers 파일에 sudo를 사용할 계정이 추가되거나 sudo 그룹에 가입되어야 하지요.

일반적인 상황은 아니지만, 간혹 자동화를 목적으로 사용자의 패스워드 입력 없이 특정 실행파일을 관리자(root) 권한으로 실행해야 할 경우가 있습니다. 이런 경우, 사용할 수 있는 방법이 _etc_sudoers 파일에 패스워드 입력을 생략하는 내용을 추가하는 건데요, 사용자 명이 user이고 관리자 권한으로 실행해야할 파일이 _usr_bin/xeyes라면 다음과 같이 마지막줄에 추가하면 됩니다.

# /etc/sudoers 파일의 내용
... 생략 ...

#includedir /etc/sudoers.d
user    ALL=(ALL)   NOPASSWD:   /usr/bin/xeyes

만약 user의 경우는 모든 파일을 패스워드 입력없이 사용하고 싶다면 아래와 같이 변경하시면 됩니다.

user ALL=(ALL)  NOPASSWD:   ALL

그럼 좋은 하루 되세요 ^^

요즘 만자로(Manjaro) 리눅스를 주로 쓰고 있는데요, 사용하는 PC의 NVIDIA 그래픽카드와 궁합이 좋지 않은지 화면이 찢어지는 문제가 발생했습니다. ㅠㅠ 눈 상태가 요즘 점점 나빠지고 있는데 화면까지 그런 문제가 생기니 어떻게든 해결해야겠다는 생각이 들더라구요. 아. 물론... 쉬는 게 가장 좋기는 한데... 요즘 발표 요청이 많이 들어와서 주말에도 바쁜 나날을 보내고 있습니다. ㅠㅠ

그렇게 찾다보니, 드라이버를 다시 한번 설치 봐야겠다고 알아보니, 최신 NVIDIA 드라이버를 다운받아서 설치하는 방법이 있었습니다. 이렇게 해보니 찢어지는 현상이 없어졌네요. ^^;;; 결국 드라이버의 문제였던 듯... ㅠㅠ

만자로에서 NVIDIA 드라이버를 설치하는 방법은 아래와 같습니다.

# 아래처럼 입력해서 만자로 하드웨어 디텍터로 설치하고 리부팅합니다.
$> sudo mhwd -a pci nonfree 0300
$> sudo reboot

# 리부팅 후 아래처럼 입력하면 NVIDIA 설정 프로그램을 실행할 수 있습니다.
$> nvidia-settings

최신 NVIDIA 드라이버를 만자로 리눅스에 설치하는 방법은 공식 사이트를 참고하세요.

만자로 공식 사이트: https://linuxconfig.org/how-to-install-the-nvidia-drivers-on-manjaro-18-linux

그럼 좋은 하루 되세요 ^^

만자로 리눅스(Manjaro Linux)는 아치(Arch) 리눅스 기반에 롤링 릴리즈를 장점으로 내세운 배포판인데요, 요즘 주 배포판으로 사용하고 있습니다. 기본 설치 후 한글 관련 설정만 해주면 쓸 수 있을 정도로 꽤나 잘 관리되어 있는데요, 한글 관련 설정 방법은 아래와 같습니다.

# iBus 한글 설치
$> sudo pacman -S ibus-hangul ibus-qt

# 설치 후 홈 디렉토리에 $HOME/.xprofile을 생성하고 아래 내용을 추가
$> vi $HOME/.xprofile
export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULE=ibus
export OOO_FORCE_DESKTOP="gnome"
ibus-daemon -drx

그리고 로그아웃 및 로그인을 하면 한글 입력기가 실행됩니다.

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

요즘 만자로 리눅스(Manjaro Linux)를 주로 사용하고 있는데요, 만자로를 쓰다보면 제일 먼저 당황하는 것이 한글 입력 설정과 마우스 클릭 시 바로 실행되는 옵션입니다. 보통은 더블클릭을 해야 실행에 옮기기 때문에 이러한 기본 설정은 상당히 당황스러운데요, $HOME/.config/kdeglobals 설정 파일을 변경함으로써 처리할 수 있습니다.

$> vim ~/.config/kdeglobals

[KDE]
# 아래 라인 추가
SingleClick=false

그리고 로그아웃 후에 다시 로그인하면 마우스 클릭이 아닌 더블클릭으로 실행할 수 있습니다.

그럼 좋은 하루 되세요 >ㅁ<)-b

응용프로그램을 디버깅하다보면 항상 고정된 위치에 응용프로그램이 로딩되어야 할 필요가 있는데요, 최신의 리눅스에는 해킹 방지를 위해 ASLR(Address Space Layout Randomization) 기능이 활성화되어 있어서 실행할 때마다 항상 다른 위치에 응용프로그램이 로딩됩니다. ㅠㅠ 좋은 기능이긴 한데... 디버깅시에는 크게 도움이 안되지요. ㅠㅠ

이 기능을 비활성화하려면 다음과 같이 파일을 추가하면 됩니다.

$> sudo vi /etc/sysctl.d/01-disable-aslr.conf

kernel.randomize_va_space = 0

아우 디버깅이 빨리 끝나야할텐데... 걱정이네요. ㅠㅠ

그럼 좋은 밤 되세요. ^^

Git에 소스코드를 커밋하기 전에 git diff로 소스를 확인하면 불필요한 공백(Whitespace)를 붉은색으로 표시해줍니다. 일일이 이 부분을 찾아서 제거하려면 불편한 점이 한 두가지가 아닌데요, VIM에서는 이를 한 번에 해결할 수 있습니다.

바로 VIM의 커맨드라인에서 아래와 같이 입력하면 됩니다. @0@)-b

:%s/\s\+$//e

아아 역시 VIM은 진리인 듯... 그럼 즐거운 하루 되세요. ^^

최근 뜨고 있는 쉘로 ZSH, Z Shell가 있는데요, 무엇보다 Git에 친화적인 인터페이스때문에 요즘 저도 쓰고 있습니다. 처음 ZSH를 설치하면 일반 bash와 크게 다를 바가 없어서 조금 실망할 수 있는데, 밋밋함을 없애고 기본적인 셋팅을 해주는 것이 Oh My Zsh 입니다.

Oh My Zsh를 설치하고 홈 디렉터리에 있는 .zshrc만 수정해주면 Git 친화적인 쉘이 탄생하는데... 써보고 싶은 분들은 아래와 같이 입력하시면 됩니다.

# Zsh 설치
$> sudo apt-get update
$> sudo apt-get install zsh

# Oh My Zsh 설치
$> curl -L https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | sh

# Git 친화적인 테마인 agnoster로 설정 변경
$> vi ~/.zshrc
...
ZSH_THEME="agnoster"

# Zsh 실행
$> zsh

그럼 좋은 하루 되세요 ^^

우분투(Ubuntu)에서 신규 커널 설치 후 USB, WIFI가 동작하지 않을 때 해결 방법

간만에 우분투(Ubuntu)에서 실험을 할 일이 있어서 여러 버전의 커널을 설치해습니다. 그런데 이상하게도... 새로 설치한 커널로 부팅하면 USB, WIFI, 터치패드 등등이 동작하지 않더라구요. ㅠㅠ... 실험할 때 동영상을 찍어야하는 지라 USB가 안되면 큰일나는데... 그래서 조금 살펴봤더니... linux-image 패키지와 함께 linux-image-extras 패키지도 설치해줘야 했습니다. 아래처럼 말이죠. ^^;;;

$> sudo apt-get update
# 신규 커널 설치
$> sudo apt-get install linux-image-4.4.0-21-generic
# 신규 커널과 관련도니 추가 패키지 설치
$> sudo apt-get install linux-image-extras-4.4.0-21-generic

예전에는 굳이 이렇게 하지 않아도 되었던 것 같은데... 오래되서 기억이 잘 안나는군요. ^^;;; 원래 이랬던 건가... ㅎㅎ

그럼 좋은 하루 되세요 ^^

Arch Linux에서 커널 소스코드 다운로드 하는 법

소싯적에는 한참 Fedora만 쓰다가 최근에는 Debian으로 작업을 많이 했는데, 갑자기 이번에는 Arch Linux에 관심이 생겨서 급하게 설치를 감행하여 살펴보고 있습니다. 배포판을 여러가지 사용하다보면 각 배포판마다 독특한 특징이나 철학을 느낄 수 있는데요, Arch Linux의 경우 이런 부분이 타 배포판에 비해 두드러지는 것 같습니다. ㅠㅠ 설치가 너무 불친절한 게 단점이지만 업데이트가 엄청 빠른 건 장점이네요. 만 하루가 지났는데, 업데이트 된 패키지만 벌써 20개라는... 쿨럭..;;

일단 패키지 빌드 시 프로세서의 코어 갯수만큼 동시에 빌드를 진행하려면 /etc/makepkg.conf 파일에 아래 라인을 추가해줘야 합니다. 안그러면 커널 빌드하는데 시간이 엄청 오래 걸리더라구요. ㅠㅠ

$> sudo vi /etc/makepkg.conf

MAKEFLAGS='-j$(nproc)'

그리고 아래와 같이 순서대로 입력해서 소스코드 다운로드 -> 빌드 -> 설치를 진행할 수 있습니다.

# 소스코드 다운로드를 위해 asp 설치
$> sudo pacman -S asp

# asp로 linux 커널 소스코드 다운로드
$> asp export linux

# 패키지 빌드에 필요한 의존 패키지를 설치하면서 패키지 빌드
$> makepkg -s

# Public Key 관련 오류가 발생하면 아래와 같이 입력해서 등록해줌
$> gpg --keyserver pgp.mit.edu --recv-keys <PUB KEY>

# 빌드가 완료되면 pacman -U <패키지명>.pkg.tar.xz로 설치
$> sudo pacman -U linux-xxx.pkg.tar.xz

항상 최신을 쓴다고 생각하니 뭔가 업데이트 중 문제가 발생할 것 같은 기분이 드는데... 좀 더 써봐야 알 것 같습니다.

그럼 좋은 밤 되세요. ^^

요 근래에 너무 바빠서 업데이트를 진행할 시간도 없었는데, 간만에 오늘 아이맥에 업데이트를 실행했습니다. 기분 좋게 다운로드가 완료되고 리부팅 뒤에 설치가 잘 진행되었는데요, 이때부터 사파리가 비정상 종료되고 앱스토어가 먹통이되는 문제가 발생했습니다. 아... 세상에... 눈 앞이 깜깜한 게 스티브 잡스가 급 그리워지더라구요. ㅠㅠ

터미널로 소프트웨어 업데이트를 찾는 명령어가 있길래 직접 실행해봤더니 아래와 같이 AMSupportURLConnectionDelegate가 중복으로 구현되었다는 오류가 보였습니다.

nonames-iMac:~ noname$ softwareupdate -l
objc[1457]: Class AMSupportURLConnectionDelegate is implemented in
both /System/Library/PrivateFrameworks/OSPersonalization.framework/Versions/A/OSPersonalization(0x1116ba498) and /System/Library/PrivateFrameworks/EmbeddedOSInstall.framework/Versions/A/EmbeddedOSInstall(0x111848748). One of the two will be used. Which one is undefined.
Software Update Tool

Finding available software
No new software available.
nonames-iMac:~ noname$

인터넷을 한참을 뒤지니 맥 OS의 업데이트가 일부만 진행되었을 때 이런 문제가 발생한다고 하길래, 모든 업데이트가 한 번에 들어있는 콤보 업데이트를 찾아서 설치하여 문제를 해결했습니다. >ㅁ<)-b 맥 OS High Sierra의 최신 콤보 업데이트는 High Sierra 10.13.2 Combo에서 찾을 수 있습니다.

이제야 다시 개발을 시작할 수 있겠군요. ^^;;; 다들 즐거운 밤 되세요. ^^

git으로 작업을 하다보면 간혹 다른 프로젝트의 폴더를 내 폴더 아래에 위치시킬 필요가 있는데요, 다른 프로젝트의 폴더 역시 git으로 관리되고 있다면 부모 프로젝트 밑에 자식 프로젝트가 위치하는 형상이 됩니다. 아래와 같이 말이죠. ^^;;;;

내 프로젝트 폴더
|----> 내 프로젝트의 폴더 및 파일들...
|----> 다른 프로젝트 폴더
        |----> 다른 프로젝트의 폴더 및 파일들...

이때 아무 생각 없이 git add로 다른 프로젝트의 폴더를 추가하면 내 프로젝트의 git과 다른 프로젝트의 git이 부모 자식 관계로 연결됩니다. 만일 부모 자식 관계가 아니라 완전하게 내 프로젝트에 포함시키고 싶어서 다른 프로젝트 폴더 내에 있는 .git 폴더를 삭제하고 나면 다른 프로젝트의 파일을 추가하거나 변경했을 때 아래와 같은 오류가 발생합니다. ㅠㅠ

$> git add "다른 프로젝트 폴더/파일.c"
Git: fatal: Pathspec is XXX in submodule

해결 방법은 아주 간단한데요, 부모 폴더로 가서 아래와 같이 cache를 삭제하고, 다시 프로젝트를 추가하면 됩니다.

$> git rm --cached "다른 프로젝트 폴더"
$> git add "다른 프로젝트 폴더"

아우, 깜짝 놀랐네요.

그럼 좋은 하루 되세요 ^^

요즘 리눅스 커널에 특별한 기능을 넣고 있는데요, 이것 때문에 성능 저하가 얼마나 나오는지를 측정해야되서 밴치마크 툴을 찾아보니 SPEC CPU 2006을 많이 사용하더라구요. ^^;;; 그래서 저도 한 번 해보기로 했는데... 2006년도에 나온 버전이라서 그런지... 페도라 21버전에서는 빌드 오류가 발생했습니다. ㅠㅠ

이게 오류가 한 두개면 어찌 고쳐보겠는데... 뭔가 산 넘어 산처럼 계속 나오더라구요. 그래서 구글신께 여쭈었더니 역시나~!! 해결법을 알려주셨습니다.

아래는 CPU 2006 빌드에서 발생하는 오류를 해결하는 링크입니다. ^^

https://wiki.linaro.org/MichaelHope/Sandbox/BuildingSPECTools

http://www-hiraki.is.s.u-tokyo.ac.jp/members/tomari/runspec.html

그리고 이건 SPEC CPU 2006에 대한 간단한 사용법을 잘 정리해놓은 사이트입니다.

http://jmanbal.tistory.com/entry/spec2006-install-%EB%B0%A9%EB%B2%95

아아... 이제 성능이 잘 나오길 비는 것만 남았네요. ^^ 그럼 좋은 하루 되세요 ^^

최근에 팀을 옮기면서 리눅스 관련 일을 하게 되었습니다. ^^;;; 리눅스는 사실 MINT64 OS를 만들 때 리눅스 커널 구조를 본 게 전부라... 제가 잘 할 수 있을 까 걱정이 많이 되었는데요, 아직까지는 별 탈 없이 잘 지내고 있습니다. ^^;;;

최근에 옮긴 팀에서는 주로 리눅스 커널 관련 일을 하고 있는데요, 그러다보니 간단한 커널 모듈을 만들 일이 많아 코드를 남겨둡니다. 아래 코드는 Loadable Kernel Module 형태로 insmod를 통해 로딩되면 /dev/hello 디바이스를 생성하고 통신하는 역할을 합니다. ^^

1. 커널 모듈 소스 코드 작성 및 Makefile 작성

터미널에서 vi hello.c를 입력한 뒤 아래 코드를 붙여넣고 저장합니다.

/**
 *  본 파일은 프레임워크 예제 파일임
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <linux/cred.h>

int in_use = 0;

// 모듈 정보
MODULE_LICENSE("HIDDEN");
MODULE_AUTHOR("root");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("Hello World");

/**
 *  /dev 밑에 등록한 파일을 누가 열었을 때 호출되는 함수
 */
static int my_open(struct inode *inode, struct file *file)
{
    // 해당 파일을 동시에 여러개를 열지 못하도록 하는 코드
    if(in_use)
    {
        return -EBUSY;
    }

    in_use++;
    printk(KERN_INFO "Hello Open\n");

    return 0;
}

/**
 *  /dev 밑에 등록한 파일을 누가 닫았을 때 호출되는 함수
 */    
static int my_release(struct inode *inode, struct file *file)
{
    in_use--;
    printk(KERN_INFO "Hello Closed\n");
    return 0;
}

/**
 *  /dev 밑에 등록한 파일을 누가 닫았을 때 호출되는 함수
 */
static int my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int retval = 0;
    printk(KERN_INFO "Hello Ioctl~!!\n");
    return retval;
}

/**
 *  /dev 밑에 등록한 파일을 누가 읽었을 때 호출되는 함수
 */
static ssize_t my_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
    printk (KERN_INFO "Hello Read~!!.\n");
    //printk (KERN_INFO "%X\n", sys_call_table);
    return 0;

    // 실제로 Read 명령을 처리하는 코드, 일단 예제로 남겨둠
    /*
    // Number of bytes actually written to the buffer
    int bytes_read = 0;

    // If we're at the end of the message, return 0 signifying end of file
    if (*msg_Ptr == 0) return 0;

    // Actually put the data into the buffer
    while (length && *msg_Ptr)  
    {
        put_user(*(msg_Ptr++), buffer++);

        length--;
        bytes_read++;
    }

    // Most read functions return the number of bytes put into the buffer
    return bytes_read;
    */
}

/**
 *  /dev 밑에 등록한 파일에 누가 썼었을 때 호출되는 함수
 */
static ssize_t my_write(struct file *filp, const char *buff, size_t len, loff_t *off)
{
    printk (KERN_INFO "Hello Write~!!.\n");
    return -EINVAL;
}

/**
 *  /dev/hello 파일 등록시 필요한 file operation 구조체
 */
static const struct file_operations my_fops = \
{
    .owner = THIS_MODULE,
    .open = &my_open,
    .read = &my_read,
    .write = &my_write,
    .release = &my_release,
    .unlocked_ioctl = (void*) &my_ioctl,
    .compat_ioctl = (void*) &my_ioctl
};

/**
 *  /dev/hello 파일 등록시 필요한 device 구조체
 */
static struct miscdevice my_device = \
{
    MISC_DYNAMIC_MINOR,
    "hello",
    &my_fops
};

/**
 *  커널 드라이버 시작 함수
 *      - 커널 드라이버가 로딩될 때 호출됨
 */
static int __init hello_init(void)
{
    printk(KERN_INFO "Hello, world\n");    

    int retval = misc_register(&my_device);
    return 0;
}

/**
 *  커널 드라이버 종료 함수
 *      - 커널 드라이버가 언로딩될 때 호출됨
 */
static void __exit hello_exit(void)
{   
    printk(KERN_INFO "Goodbye, world\n");
    misc_deregister(&my_device);
}

// 시작 함수와 종료 함수 지정 매크로
module_init(hello_init);
module_exit(hello_exit);    

코드를 다 붙여넣었으면 이제 터미널에서 vi Makefile을 입력한 뒤 아래 코드를 붙여넣고 저장합니다.

obj-m += hello.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Makefile을 생성한 후에 make를 입력하면 자동으로 빌드가 시작되고 다음과 같이 hello.ko가 생성됩니다.

[root@BuildMachine module]# ll
합계 244
-rw-r--r-- 1 root root    154  2월 24 09:39 Makefile
-rw-r--r-- 1 root root      0  2월 24 09:39 Module.symvers
-rw-r--r-- 1 root root    351  2월 24 09:42 hello.c
-rw-r--r-- 1 root root 112027  2월 24 09:41 hello.ko
-rw-r--r-- 1 root root    454  2월 24 09:39 hello.mod.c
-rw-r--r-- 1 root root  63104  2월 24 09:39 hello.mod.o
-rw-r--r-- 1 root root  50384  2월 24 09:41 hello.o
-rw-r--r-- 1 root root     29  2월 24 09:41 modules.order

3. 커널 모듈 시험 및 결과 확인

커널 모듈은 insmod를 이용하여 커널에 동적으로 올릴 수 있구요, rmmod를 이용하여 커널에서 내릴 수 있습니다. 그리고 로딩된 모듈의 목록은 lsmod를 이용하여 확인할 수 있습니다.

커널 모듈은 슈퍼유저(root) 권한으로만 로딩할 수 있으므로, 커널 모듈 시험 전에 root 계정으로 로그인하거나 sudo와 함께 insmod를 실행합니다. 다음은 커널 모듈을 로딩하고 삭제한 뒤 그 결과를 dmesg를 통해 확인한 것입니다. printk() 출력은 dmesg나 cat /proc/kmsg 를 통해 확인할 수 있습니다.

$>insmod hello.ko
$>ls /dev/hello -l
crw------- 1 root root 10, 57  2월 26 13:59 /dev/hello

$>chmod 666 /dev/hello           <== /dev/hello를 유저 권한으로 읽고 쓸 수 있게 만듬

4. 커널 모듈 테스트 프로그램 구현 및 빌드

커널 모듈이 정상적으로 로딩되었으니 이제 테스트 프로그램을 만들 차례입니다. ^^ 프레임워크 커널 모듈은 /dev/hello에 접근하면 메시지를 출력하게 되어있습니다. 커널 모듈 테스트 프로그램의 소스 코드는 다음과 같고 터미널에서 vi test.c를 입력한 뒤 저장합니다.

/**
 * 본 파일은 프레임워크 테스트 파일임
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char** argv)
{
    int fd;

    fd = open("/dev/hello", O_RDONLY);
    if (fd == -1)
    {   
        printf("Kernel Module Open Error\n");
    }   
    else
    {   
        printf("Kernel Module Open Success\n");
    }   
    close(fd);

    return 0;
}        

저장한 테스트 프로그램의 소스코드 코드는 다음과 같이 빌드할 수 있습니다.

$>gcc -o hello hello.c

5. 커널 모듈 기능 테스트

./hello를 실행하면 테스트 프로그램이 커널 모듈이 생성한 파일을 열어서 메시지를 표시합니다. 테스트 프로그램 실행 후 dmesg나 cat /dev/kmsg를 입력하여 커널 메시지를 확인하면 정상적으로 커널 모듈이 실행되었음을 알 수 있습니다. ^^

그럼 좋은 하루 되세요 ^^

판다보드용 우분투를 아래 명령으로 업그레이드를 진행한 후, Omap4-extras 패키지를 설치하면 리부팅 중 멈추는 오류가 발생합니다. ㅠㅠ 아아 정말 삽질은 끝이 없군요 ㅠㅠ

sudo update
sudo upgrade
sudo clean
sudo reboot

확인 결과 PHP5와 Omap4-extras 패키지가 같이 설치되면 커널 부팅 오류가 발생했는데요, 해결법은... 둘중에 하나를 안까는 겁니다. ㅠㅠ 사실 서버를 만들어 놓고 LAPM을 설치하지 않는 건 말도 안되는 일이라... Omap4-extras를 포기했습니다. ㅠㅠ

아아.. 드디어 긴 삽질이 끝났군요. ㅠㅠ

그럼 좋은 하루 되세요 ^^

우분투(Ubuntu)에서 새로운 리파지토리 추가가 필요해서 "apt-add-repository"를 입력했더니 "command not found" 오류가 발생했습니다. ㅠㅠ (요즘 이런류의 오류를 많이 겪는 듯한...) 그래서 처음엔 오타가 났나 했는데... 아무리봐도 오타는 아니었습니다.

그래서 구글신께 또 여쭤봤더니 다음과 같이 답변을 해주시더군요. 결론은 "python-software-properties"를 설치해야 한다는 겁니다. ^^;;; 그것 참... 이상하네요. 이게 왜 기본 패키지에 안들어있는지 잘 모르겠다는... ^^;;;

sudo apt-get update 
sudo apt-get install python-software-properties
sudo apt-get install software-properties-common

그럼 좋은 하루 되세요 ^^

예전에 계획한 일이 있어 판다보드(PandaBoard)를 다시 꺼내 들었는데요, 우분투 12.04 서버 버전을 깔고 싶어 튜토리얼 대로 진행을 했습니다만.... 역시나 문제가 발생했습니다. ㅠㅠ 바로 Uboot 문제인데요, 판다보드 ES 버전 보드의 램이 엘피다(ELPIDA) 사 제품으로 교체되면서 다음처럼 제대로 인식이 안되는 문제가 발생했습니다.

OMAP4460 ES2.0
SDRAM: identified size not same as expected size identified: 0 expected: 40000000

구글링해보니 이 문제를 해결하기 위해서는 결국 Uboot의 소스코드 중 omap4_common.h 파일의 다음 부분을 수정해야 한다는 걸 알게됬는데요... 사실 Uboot를 다시 빌드하는 것도 귀찮고 이걸 위해 호스트 PC에 우분투 개발 환경을 설정하는 것 또한 부담이라 다른 사람이 빌드해 놓은 걸 찾아봤습니다. ^^;;;

// 아래 부분을 주석처리해서 기능을 제거해야 함
// #define CONFIG_SYS_EMIF_PRECALCULATED_TIMING_REGS

그랬더니~!! SVT 사이트에서 해당 부분을 수정하고 빌드한 boot 이미지를 찾을 수 있었습니다. 사이트에서 압축 파일을 통째로 다운받아 압축을 풀면 boot 디렉토리에서 MLO, u-boot.bin, uimage 파일을 확인할 수 있는데요, 이 파일을 우분투 이미지 다운로드 사이트에서 다운로드한 OMAP4 버전 Prebuild 이미지에 덮어쓰면 정상적으로 부팅이 됩니다.

판다보드에 우분투 설치에 대한 내용은 softswagen 사이트에서 자세히 볼 수 있습니다. 참 자세히 설명해줘서 따라하는데 큰 무리는 없었던 것 같아요(그 Uboot 문제로 부팅 안되는 문제만 빼면... 쿨럭..;;;)

어휴... 이걸 몰라서 하루종일 삽질했네요. ^^;;;

그럼 좋은 하루 되세요. ^^


MLO


u-boot.bin


uImage


+ Recent posts