新聞中心
Linux操作系統(tǒng)作為一種開源的操作系統(tǒng),大家可能都很熟悉了。實(shí)際上,Linux操作系統(tǒng)在服務(wù)器領(lǐng)域的應(yīng)用廣泛,它提供了強(qiáng)大的網(wǎng)絡(luò)功能和高效的文件系統(tǒng),它的性能和安全性也備受贊譽(yù)。但是作為一名Linux開發(fā)者,對于PID和TID的概念的理解是十分必要的。在此,我們將深入Linux,來一探究竟:PID和TID到底是什么?

成都創(chuàng)新互聯(lián)長期為成百上千家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為古塔企業(yè)提供專業(yè)的網(wǎng)站制作、成都網(wǎng)站制作,古塔網(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。
一、什么是PID和TID?
PID是進(jìn)程號的縮寫,它是一個唯一的數(shù)字,用于標(biāo)識Linux操作系統(tǒng)的進(jìn)程。每個進(jìn)程都有一個PID,它由內(nèi)核動態(tài)分配,以便Linux操作系統(tǒng)可以區(qū)分不同的進(jìn)程并在進(jìn)程終止時清理它所使用的資源。當(dāng)一個進(jìn)程被創(chuàng)建時,它會被分配一個新的PID,而當(dāng)一個進(jìn)程終止時,它的PID就會被釋放,從而被系統(tǒng)重新使用。
TID是線程ID的縮寫,它是一個數(shù)字,用于標(biāo)識Linux操作系統(tǒng)的線程。在Linux中,線程被視為一種特殊的進(jìn)程,每個線程都有一個唯一的TID。因?yàn)長inux支持多線程,所以我們需要一種機(jī)制來區(qū)分不同的線程。每個線程都具有與其關(guān)聯(lián)的進(jìn)程的PID,并具有其自己的TID,以便操作系統(tǒng)可以在多個線程之間進(jìn)行調(diào)度。
二、PID和TID的關(guān)系
每個進(jìn)程都有一個唯一的PID,但在Linux操作系統(tǒng)中,一個進(jìn)程可以有多個線程。這些線程共享相同的進(jìn)程上下文,并使用相同的系統(tǒng)資源。因此,在Linux中,進(jìn)程和線程之間并沒有嚴(yán)格的區(qū)別,它們可以被視為同一種實(shí)體。所以,我們在使用Linux操作系統(tǒng)時,需要理解PID和TID之間的關(guān)系。
在Linux中,每個線程都由一個進(jìn)程創(chuàng)建。當(dāng)一個進(jìn)程創(chuàng)建一個線程時,該線程會繼承其父進(jìn)程的PID,并被分配一個新的TID。這種機(jī)制使得Linux在多線程運(yùn)行時能夠更加靈活地對線程進(jìn)行調(diào)度,同時也便于我們在進(jìn)程和線程之間切換。
三、PID和TID的應(yīng)用
在Linux的日常開發(fā)和維護(hù)中,PID和TID是必不可少的概念。不僅是操作系統(tǒng)內(nèi)核會使用它們,而且許多進(jìn)程和線程管理工具也會用到它們。
我們可以使用PID和TID來查看進(jìn)程和線程的狀態(tài)。通過指定PID或TID,我們可以查看該進(jìn)程或線程的CPU使用率、內(nèi)存使用情況以及其他有關(guān)它的信息。
我們可以使用PID和TID來控制進(jìn)程和線程的行為。通過指定PID或TID,我們可以向進(jìn)程或線程發(fā)送信號,并控制它們的行為。例如,我們可以使用kill命令向進(jìn)程發(fā)送SIGTERM信號,以請求它終止運(yùn)行?;蛘呶覀兛梢允褂胮thread_kill命令向線程發(fā)送自定義信號,以通知它完成某個任務(wù)。
我們可以使用PID和TID來進(jìn)行調(diào)試和故障排除。通過指定PID或TID,我們可以使用調(diào)試工具對該進(jìn)程或線程進(jìn)行調(diào)試,以快速診斷和解決問題。例如,在使用gdb進(jìn)行調(diào)試時,我們可以通過指定進(jìn)程的PID或線程的TID來設(shè)置斷點(diǎn)和觀察變量。
四、
在Linux操作系統(tǒng)中,PID和TID是非常重要的概念。PID用于標(biāo)識進(jìn)程,而TID用于標(biāo)識線程。每個進(jìn)程都有一個唯一的PID,但一個進(jìn)程可以有多個線程,它們是由該進(jìn)程創(chuàng)建的,并共享相同的進(jìn)程上下文。
在日常開發(fā)和維護(hù)中,PID和TID是必不可少的。我們可以使用它們來查看進(jìn)程和線程的狀態(tài)、控制它們的行為以及進(jìn)行調(diào)試和故障排除。因此,在使用Linux操作系統(tǒng)時,了解和掌握PID和TID的概念是至關(guān)重要的。
相關(guān)問題拓展閱讀:
- Linux里面cpu占用太高排查思路是什么?
- ulibc怎么實(shí)現(xiàn)backtrace
- Linux 權(quán)能綜述
Linux里面cpu占用太高排查思路是什么?
可以通過top命令來缺蠢查看占用cpu的軟件看是否掘扮瞎有僵尸進(jìn)程在占用cpu如果可判空以通過kill殺死無用的進(jìn)程!
思路就是top查看是什么進(jìn)程占用高,一般是應(yīng)胡答配用或者數(shù)據(jù)庫,應(yīng)用方褲指面可以看看運(yùn)行吐出日志是否有報錯信息,查netstat連接舉敬應(yīng)用端口的會話是不是有異常,數(shù)據(jù)庫進(jìn)程高,可以使用自帶的檢查命令后臺看是否有執(zhí)行很久的sql事務(wù),鎖等待頻繁,報錯日志等,找到問題針對性的優(yōu)化,一步一步解決。
方法一
之一步:使用
top命令,然后按shift+p按照CPU排序
找到占用CPU過高的進(jìn)程的pid
第二步:使用
top -H -p
找到進(jìn)程中消耗資源更高的線程的id
第三步:使用
echo ‘obase=16;’悉則 | bc或者printf “%x\n”
將線程id轉(zhuǎn)換為16進(jìn)制(字母要小寫)
bc是linux的計(jì)算器命令
第四步:執(zhí)行
jstack |grep -A 10 ”
查看線程狀態(tài)信息
方法鄭空二
之一步:使用
top命令,然后按shift+p按照CPU排序
找到占用CPU過高的進(jìn)程
第二步:使用
ps -mp pid -o THREAD,tid,time | sort -rn
獲取線程信息,并找到占用CPU高的線程
第三步:使用
echo ‘obase=16;’ | bc或者printf “%x\n”
將需要的線程ID轉(zhuǎn)換為16進(jìn)制格式
第四步:使喊陸瞎用
jstack pid |grep tid -A 30
ulibc怎么實(shí)現(xiàn)backtrace
首先,讓我們看一看AndroidLog的格式。下面這段log是以所謂的long格式打印出來的。從前面Logcat的介紹中可以知道,long格式會把時間,標(biāo)簽等作為單獨(dú)的一行顯示。
Start procnet.coollet.infzmreader:umengService_v1 for service
net.coollet.infzmreader/com.umeng.message.
UmengService:pid=21745 uid=10039 gids={50039, 3003, 1015,1028}
Turning on JNI app bug workarounds fortarget SDK version 8…
onCreate()
我們以之一行為例:12-09 是日期,21:39:35.510是時間396是進(jìn)程號,416是線程號;I代表log優(yōu)先級,ActivityManager是log標(biāo)簽。
在應(yīng)用開發(fā)中,這些信息的作用可能不是很大。但是在系統(tǒng)開發(fā)中,這些都是很重要的輔助信息。開發(fā)工程師分析的log很多都是由測試工程師抓取的,所以可能有些log根本就不是當(dāng)時出錯的log。如果出現(xiàn)這種情況,無論你怎么分析都不太可螞含余能得出正確的結(jié)論。如何能更大限度的避免這種情況呢?筆者就要求測試工程師報bug時必須填上bug發(fā)生的時間。這樣結(jié)合log里的時間戳信息就能大致判斷是否是發(fā)生錯誤時的log。而且根據(jù)測試工程師提供的bug發(fā)生時間點(diǎn),開發(fā)工程師可以在長長的log信息中快速的定位錯誤的位置,縮小分析的范圍。
同時我們也要注意,時間信息在log分析中可能被錯誤的使用。例如:在分析多線程相關(guān)的問題時,我們有時需要根據(jù)兩段不同線程中l(wèi)og語句執(zhí)行的先后順序來判斷錯誤發(fā)生的原因,但是我們不能以兩段log在log文件中出現(xiàn)的先后做為判斷的條件,這是因?yàn)樵谛《螘r間內(nèi)兩個線程輸出log的先后是隨機(jī)的,log打印的先后順序并不完全等同于執(zhí)行的順序。那么我們是否能以log的時間戳來判斷呢?同樣是不可以,因?yàn)檫@個時間戳實(shí)際上是系統(tǒng)打印輸出log時的時間,并不是調(diào)用log函數(shù)時的時間。遇到這種情況唯一的辦法是在輸出log前,調(diào)用系統(tǒng)時間函數(shù)獲取當(dāng)時時間,然后再通過log信息打印輸出。這樣雖然麻煩一點(diǎn),但是只有這樣取得的時間才是可靠的,才能做為我們判斷的依據(jù)。
另外一種誤用log中時間戳的情況是用它來分析程序的性能。一個有多年工作經(jīng)驗(yàn)的工程師拿著他的性能分析結(jié)果給筆者看,但是悶滾筆者對這份和實(shí)際情況相差很遠(yuǎn)的報告表示懷疑,于是詢問這位工程師是如何得出結(jié)論的。他的回答讓筆者很驚訝,他計(jì)算所采用的數(shù)據(jù)就是log信息前面的時間戳。前面我們已經(jīng)講過,log前面時間戳和調(diào)用log函數(shù)的時間并不老兆相同,這是由于系統(tǒng)緩沖log信息引起的,而且這兩個時間的時間差并不固定。所以用log信息前附帶的時間戳來計(jì)算兩段log間代碼的性能會有比較大的誤差。正確的方法還是上面提到的:在程序中獲取系統(tǒng)時間然后打印輸出,利用我們打印的時間來計(jì)算所花費(fèi)的時間。
了解了時間,我們再談?wù)勥M(jìn)程Id和線程Id,它們也是分析log時很重要的依據(jù)。我們看到的log文件,不同進(jìn)程的log信息實(shí)際上是混雜在一起輸出的,這給我們分析log帶來了很大的麻煩。有時即使是一個函數(shù)內(nèi)的兩條相鄰的log,也會出現(xiàn)不同進(jìn)程的log交替輸出的情況,也就是A進(jìn)程的之一條log后面跟著的是B進(jìn)程的第二條log,對于這樣的組合如果不細(xì)心分析,就很容易得出錯誤的結(jié)論。這時一定要仔細(xì)看log前面的進(jìn)程Id,把相同Id的log放到一起看。
不同進(jìn)程的log有這樣的問題,不同的線程輸出的log當(dāng)然也存在著相同的問題。Logcat加上-vthread就能打印出線程Id。但是有一點(diǎn)也要引起注意,就是Android的線程Id和我們平時所講的Linux線程Id并不完全等同。首先,在Android系統(tǒng)中,C++層使用的Linux獲取線程Id的函數(shù)gettid()是不能得到線程Id的,調(diào)用gettid()實(shí)際上返回的是進(jìn)程Id。作為替代,我們可以調(diào)用pthread_self()得到一個唯一的值來標(biāo)示當(dāng)前的native線程。Android也提供了一個函數(shù)androidGetThreaId()來獲取線程Id,這個函數(shù)實(shí)際上就是在調(diào)用pthread_self函數(shù)。但是在Java層線程Id又是另外一個值,Java層的線程Id是通過調(diào)用Thread的getId方法得到的,這個方法的返回值實(shí)際上來自Android在每個進(jìn)程的java層中維護(hù)的一個全局變量,所以這個值和C++層所獲得的值并不相同。這也是我們分析log時要注意的問題,如果是Java層線程Id,一般值會比較小,幾百左右;如果是C++層的線程,值會比較大。在前里面的log樣本中,就能很容易的看出,之一條log是Jave層輸出的log,第二條是native層輸出的。明白了這些,我們在分析log時就不要看見兩段log前面的線程Id不相同就得出是兩個不同線程log的簡單結(jié)論,還要注意Jave層和native層的區(qū)別,這樣才能防止被誤導(dǎo)。
AndroidLog的優(yōu)先級在打印輸出時會被轉(zhuǎn)換成V,I,D,W,E等簡單的字符標(biāo)記。在做系統(tǒng)log分析時,我們很難把一個log文件從頭看到尾,都是利用搜索工具來查找出錯的標(biāo)記。比如搜索“E/”來看看有沒有指示錯誤的log。所以如果參與系統(tǒng)開發(fā)的每個工程師都能遵守Android定義的優(yōu)先級含義來輸出log,這會讓我們繁重的log分析工作變得相對輕松些。
Android比較常見的嚴(yán)重問題有兩大類,一是程序發(fā)生崩潰;二是產(chǎn)生了ANR。程序崩潰和ANR既可能發(fā)生在java層,也可能發(fā)生在native層。如果問題發(fā)生在java層,出錯的原因一般比較容易定位。如果是native層的問題,在很多情況下,解決問題就不是那么的容易了。我們先看一個java層的崩潰例子:
I/ActivityManager( 396): Start proccom.test.crash for activity com.test.crash/.MainActivity:
pid=1760 uid=10065 gids={50065, 1028}
D/AndroidRuntime( 1760): Shutting downVM
W/dalvikvm( 1760): threadid=1: threadexiting with uncaught exception(group=0x40c38930)
E/AndroidRuntime( 1760): FATALEXCEPTION: main
E/AndroidRuntime( 1760):java.lang.RuntimeException: Unable to start activityComponentInfo
{com.test.crash/com.test.crash.MainActivity}:java.lang.NullPointerException
E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)
E/AndroidRuntime( 1760): atandroid.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)
E/AndroidRuntime( 1760): atandroid.app.ActivityThread.access$600(ActivityThread.java:141)
E/AndroidRuntime( 1760): atandroid.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
E/AndroidRuntime( 1760): atandroid.os.Handler.dispatchMessage(Handler.java:99)
E/AndroidRuntime( 1760): atandroid.os.Looper.loop(Looper.java:137)
E/AndroidRuntime( 1760): atandroid.app.ActivityThread.main(ActivityThread.java:5050)
E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invokeNative(NativeMethod)
E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invoke(Method.java:511)
E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:793)
E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
E/AndroidRuntime( 1760): atdalvik.system.NativeStart.main(NativeMethod)
E/AndroidRuntime( 1760): Caused by:java.lang.NullPointerException
E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.setViewText(MainActivity.java:29)
E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.onCreate(MainActivity.java:17)
E/AndroidRuntime( 1760): atandroid.app.Activity.performCreate(Activity.java:5104)
E/AndroidRuntime( 1760): atandroid.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
E/AndroidRuntime( 1760): … 11more
I/Process ( 1760): Sending signal.PID: 1760 SIG: 9
W/ActivityManager( 396): Force finishing activitycom.test.crash/.MainActivity
Jave層的代碼發(fā)生crash問題時,系統(tǒng)往往會打印出很詳細(xì)的出錯信息。比如上面這個例子,不但給出了出錯的原因,還有出錯的文件和行數(shù)。根據(jù)這些信息,我們會很容易的定位問題所在。native層的crash雖然也有棧log信息輸出,但是就不那么容易看懂了。下面我們再看一個native層crash的例子:
F/libc ( 2102): Fatal signal 11 (SIGSEGV) at 0x(code=1), thread2102 (testapp)
D/dalvikvm(26630):GC_FOR_ALLOC freed 604K, 11% free 11980K/13368K, paused 36ms, total36ms
I/dalvikvm-heap(26630):Grow heap (frag case) to 11.831MB forbyteallocation
D/dalvikvm(26630):GC_FOR_ALLOC freed 1K, 11% free 12023K/13472K, paused 34ms, total34ms
I/DEBUG ( 127):***************************
I/DEBUG ( 127):Build fingerprint:
‘Android/full_maguro/maguro:4.2.2/JDQ39/eng.liuchao..202355:userdebug/test-keys’
I/DEBUG ( 127):Revision: ‘9’
I/DEBUG ( 127):pid: 2102, tid: 2102, name: testapp >>>./testapp >>./testapp
從這一行我們可以知道crash進(jìn)程的pid和tid,前文我們已經(jīng)提到過,Android調(diào)用gettid函數(shù)得到的實(shí)際是進(jìn)程Id號,所以這里的pid和tid相同。知道進(jìn)程號后我們可以往前翻翻log,看看該進(jìn)程最后一次打印的log是什么,這樣能縮小一點(diǎn)范圍。
接下來內(nèi)容是進(jìn)程名和啟動參數(shù)。再接下來的一行比較重要了,它告訴了我們從系統(tǒng)角度看,出錯的原因:
signal 11 (SIGSEGV), code 1(SEGV_MAPERR), fault addr
signal11是Linux定義的信號之一,含義是Invalidmemory reference,無效的內(nèi)存引用。加上后面的“faultaddr”我們基本可以判定這是一個空指針導(dǎo)致的crash。當(dāng)然這是筆者為了講解而特地制造的一個Crash的例子,比較容易判斷,大部分實(shí)際的例子可能就沒有那么容易了。
再接下來的log打印出了cpu的所有寄存器的信息和堆棧的信息,這里面最重要的是從堆棧中得到的backtrace信息:
I/DEBUG ( 127):backtrace:
I/DEBUG ( 127): #00 pce /system/bin/testapp
I/DEBUG ( 127): #01 pcb /system/bin/testapp
I/DEBUG ( 127): #02 pcf /system/lib/libc.so (__libc_init+38)
I/DEBUG ( 127): #03 pc/system/bin/testapp
因?yàn)閷?shí)際的運(yùn)行系統(tǒng)里沒有符號信息,所以打印出的log里看不出文件名和行數(shù)。這就需要我們借助編譯時留下的符號信息表來翻譯了。Android提供了一個工具可以來做這種翻譯工作:arm-eabi-addr2line,位于prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin目錄下。用法很簡單:
#./arm-eabi-addr2line -f -eout/target/product/hammerhead/symbols/system/bin/testapp0xe
參數(shù)-f表示打印函數(shù)名;參數(shù)-e表示帶符號表的模塊路徑;最后是要轉(zhuǎn)換的地址。這條命令在筆者的編譯環(huán)境中得到的結(jié)果是:
memcpy /home/rd/compile/android-4.4_r1.2/bionic/libc/include/string.h:108
剩余三個地址翻譯如下:
main /home/rd/compile/android-4.4_r1.2/packages/apps/testapp/app_main.cpp:38
out_vformat /home/rd/compile/android-4.4_r1.2/bionic/libc/bionic/libc_logging.cpp:361
_start libgcc2.c:0
利用這些信息我們很快就能定位問題了。不過這樣手動一條一條的翻譯比較麻煩,筆者使用的是從網(wǎng)上找到的一個腳本,可以一次翻譯所有的行,有需要的讀者可以在網(wǎng)上找一找。
Linux 權(quán)能綜述
為了執(zhí)行權(quán)限檢查,傳統(tǒng)的 UNIX 實(shí)現(xiàn)區(qū)分兩種類型的進(jìn)程:特權(quán)進(jìn)程(其有效用戶 ID 為0,稱為超級用戶或 root),和非特權(quán)用戶(其有效 UID 非0)。特權(quán)進(jìn)程繞過所有的內(nèi)核權(quán)限檢查,而非特權(quán)進(jìn)程受基于進(jìn)程的認(rèn)證信息(通常是:有效 UID,世斗有效 GID,仿彎和補(bǔ)充組列表)的完整權(quán)限檢查的支配。
自內(nèi)核 2.2 版本開始,Linux 將傳統(tǒng)上與超級用戶關(guān)聯(lián)的特權(quán)分為幾個單元,稱為 capabilities (權(quán)能),它們可以被獨(dú)立的搜大磨啟用或禁用。權(quán)能是每個線程的屬性。
下面的列表展示了 Linux 上實(shí)現(xiàn)的權(quán)能,以及每種權(quán)能允許的操作或行為:
權(quán)能的完整實(shí)現(xiàn)需要:
在內(nèi)核 2.6.24 之前,只有前兩個要求能夠滿足;自內(nèi)核 2.6.24 開始,所有三個要求都能滿足。
每個線程具有三個包含零個或多個上面的權(quán)能的權(quán)能:
A child created via fork(2) inherits copies of its parent’s capability sets. See below for a discussion of the treatment of capabilities during execve(2).
Using capset(2), a thread may manipulate its own capability sets (see below).
Since Linux 3.2, the file /proc/sys/kernel/cap_last_cap exposes the numerical value of the highest capability supported by the running kernel; this can be used to determine the highest bit that may be set in a capability set.
Since kernel 2.6.24, the kernel supports associating capability sets with an executable file using setcap(8). The file capability sets are stored in an extended attribute (see setxattr(2)) named security.capability. Writing to this extended attribute requires the CAP_SETFCAP capability. The file capability sets, in conjunction with the capability sets of the thread, determine the capabilities of a thread after an execve(2).
The three file capability sets are:
During an execve(2), the kernel calculates the new capabilities of the process using the following algorithm:
其中:
A privileged file is one that has capabilities or has the set-user-ID or set-group-ID bit set.
In order to provide an all-powerful root using capability sets, during an execve(2):
The upshot of the above rules, combined with the capabilities transformations described above, is that when a process execve(2)s a set-user-ID-root program, or when a process with an effective UID of 0 execve(2)s a program, it gains all capabilities in its permitted and effective capability sets, except those masked out by the capability bounding set. This provides semantics that are the same as those provided by traditional UNIX systems.
The capability bounding set is a security mechani that can be used to limit the capabilities that can be gained during an execve(2). The bounding set is used in the following ways:
Note that the bounding set masks the file permitted capabilities, but not the inherited capabilities. If a thread maintains a capability in its inherited set that is not in its bounding set, then it can still gain that capability in its permitted set by executing a file that has the capability in its inherited set.
Depending on the kernel version, the capability bounding set is either a system-wide attribute, or a per-process attribute.
In kernels before 2.6.25, the capability bounding set is a system-wide attribute that affects all threads on the system. The bounding set is accessible via the file /proc/sys/kernel/cap-bound. (Confusingly, this bit mask parameter is expressed as a signed decimal number in /proc/sys/kernel/capbound.)
Only the init process may set capabilities in the capability bounding set; other than that, the superuser (more precisely: programs with the CAP_SYS_MODULE capability) may only clear capabilities from this set.
On a standard system the capability bounding set always masks out the CAP_SETPCAP capability. To remove this restriction (dangerous!), modify the definition of CAP_INIT_EFF_SET in include/linux/capability.h and rebuild the kernel.
The system-wide capability bounding set feature was added to Linux starting with kernel version 2.2.11.
From Linux 2.6.25, the capability bounding set is a per-thread attribute. (There is no longer a systemwide capability bounding set.)
The bounding set is inherited at fork(2) from the thread’s parent, and is preserved across an execve(2).
A thread may remove capabilities from its capability bounding set using the prctl(2) PR_CAPBSET_DROP operation, provided it has the CAP_SETPCAP capability. Once a capability has been dropped from the bounding set, it cannot be restored to that set. A thread can determine if a capability is in its bounding set using the prctl(2) PR_CAPBSET_READ operation.
Removing capabilities from the bounding set is supported only if file capabilities are compiled into the kernel. In kernels before Linux 2.6.33, file capabilities were an optional feature configurable via the CONFIG_SECURITY_FILE_CAPABILITIES option. Since Linux 2.6.33, the configuration option has been removed and file capabilities are always part of the kernel. When file capabilities are compiled into the kernel, the init process (the ancestor of all processes) begins with a full bounding set. If file capabilities are not compiled into the kernel, then init begins with a full bounding set minus CAP_SETPCAP, because this capability has a different meaning when there are no file capabilities.
Removing a capability from the bounding set does not remove it from the thread’s inherited set. However it does prevent the capability from being added back into the thread’s inherited set in the future.
To preserve the traditional semantics for transitions between 0 and nonzero user IDs, the kernel makes the following changes to a thread’s capability sets on changes to the thread’s real, effective, saved set, and filesystem user IDs (using setuid(2), setresuid(2), or similar):
If a thread that has a 0 value for one or more of its user IDs wants to prevent its permitted capability set being cleared when it resets all of its user IDs to nonzero values, it can do so using the prctl(2) PR_SET_KEEPCAPS operation or the SECBIT_KEEP_CAPS securebits flag described below.
A thread can retrieve and change its capability sets using the capget(2) and capset(2) system calls. However, the use of cap_get_proc(3) and cap_set_proc(3), both provided in the libcap package, is preferred for this purpose. The following rules govern changes to the thread capability sets:
Starting with kernel 2.6.26, and with a kernel in which file capabilities are enabled, Linux implements a set of per-thread securebits flags that can be used to disable special handling of capabilities for UID 0 (root). These flags are as follows:
Each of the above “base” flags has a companion “l(fā)ocked” flag. Setting any of the “l(fā)ocked” flags is irreversible, and has the effect of preventing further changes to the corresponding “base” flag. The locked flags are: SECBIT_KEEP_CAPS_LOCKED, SECBIT_NO_SETUID_FIXUP_LOCKED, SECBIT_NOROOT_LOCKED, and SECBIT_NO_CAP_AMBIENT_RAISE.
The securebits flags can be modified and retrieved using the prctl(2) PR_SET_SECUREBITS and PR_GET_SECUREBITS operations. The CAP_SETPCAP capability is required to modify the flags.
The securebits flags are inherited by child processes. During an execve(2), all of the flags are preserved, except SECBIT_KEEP_CAPS which is always cleared.
An application can use the following call to lock itself, and all of its descendants, into an environment where the only way of gaining capabilities is by executing a program with associated file capabilities:
For a discussion of the interaction of capabilities and user namespaces, see user_namespaces(7).
No standards govern capabilities, but the Linux capability implementation is based on the withdrawn POSIX.1e draft standard; see
.
From kernel 2.5.27 to kernel 2.6.26, capabilities were an optional kernel component, and can be enabled/disabled via the CONFIG_SECURITY_CAPABILITIES kernel configuration option.
The /proc/PID/task/TID/status file can be used to view the capability sets of a thread. The /proc/PID/status file shows the capability sets of a process’s main thread. Before Linux 3.8, nonexistent capabilities were shown as being enabled (1) in these sets. Since Linux 3.8, all nonexistent capabilities (above CAP_LAST_CAP) are shown as disabled (0).
The libcap package provides a suite of routines for setting and getting capabilities that is more comfortable and less likely to change than the interface provided by capset(2) and capget(2). This package also provides the setcap(8) and getcap(8) programs. It can be found at
.
Before kernel 2.6.24, and from kernel 2.6.24 to kernel 2.6.32 if file capabilities are not enabled, a thread with the CAP_SETPCAP capability can manipulate the capabilities of threads other than itself. However, this is only theoretically possible, since no thread ever has CAP_SETPCAP in either of these cases:
capsh(1), setpriv(1), prctl(2), setfsuid(2), cap_clear(3), cap_copy_ext(3), cap_from_text(3), cap_get_file(3), cap_get_proc(3), cap_init(3), capgetp(3), capsetp(3), libcap(3), credentials(7), user_namespaces(7), pthreads(7), getcap(8), setcap(8)
include/linux/capability.h in the Linux kernel source tree
This page is part of release 4.04 of the Linux man-pages project. A description of the project, information about reporting bugs, and the latest version of this page, can be found at
.
關(guān)于linux pid和tid的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都創(chuàng)新互聯(lián)科技有限公司,是一家專注于互聯(lián)網(wǎng)、IDC服務(wù)、應(yīng)用軟件開發(fā)、網(wǎng)站建設(shè)推廣的公司,為客戶提供互聯(lián)網(wǎng)基礎(chǔ)服務(wù)!
創(chuàng)新互聯(lián)(www.cdcxhl.com)提供簡單好用,價格厚道的香港/美國云服務(wù)器和獨(dú)立服務(wù)器。創(chuàng)新互聯(lián)成都老牌IDC服務(wù)商,專注四川成都IDC機(jī)房服務(wù)器托管/機(jī)柜租用。為您精選優(yōu)質(zhì)idc數(shù)據(jù)中心機(jī)房租用、服務(wù)器托管、機(jī)柜租賃、大帶寬租用,可選線路電信、移動、聯(lián)通等。
當(dāng)前標(biāo)題:深入Linux:理解PID和TID的概念(linuxpid和tid)
分享鏈接:http://www.dlmjj.cn/article/dphoesg.html


咨詢
建站咨詢
