bobuhiro11's diary

LSMについて調べてみた.

05 Jun 2013
[LSM]

LSMとは

LSM(Linux Security Module)とは,kernel2.6から実装されたセキュリティフレームワーク.SELinuxやTOMOYO Linuxでも使われていて,チェックが必要な箇所でフックがおこり,登録されたコールバック関数が呼び出される.

インターフェースの外から

サンプルを書いてたんですけど,上手くいかなかったので,コピペはやめたほうがいいです.
/* bobulsm.c */

static int bobulsm_inode_mkdir(struct inode *inode, struct dentry *dentry,
			   umode_t mask)
{
	printk("bobulsm: inode_mkdir called.\n");

  /* Return 0 if permission is granted. */
	return -EPERM;
}

static struct security_operations bobulsm_ops = {
	.name = "bobulsm",
	.inode_mkdir = bobulsm_inode_mkdir,
};

static int __init bobulsm_init(void){
	if (register_security(&bobulsm_ops))
		panic("bobulsm: Occurred an error at register_security(&bobuhiro11lsm_ops).\n");
	else
		printk("bobulsm: registered surely.\n");
	return 0;
}

security_initcall(bobulsm_init);

MODULE_DESCRIPTION("BOBULSM");
security_operations構造体に,イベントが発生した時にやらせたい関数を登録します.ここでは,ディレクトリの作成時に,呼び出されるように,inode_mkdirメンバにbobulsm_inode_mkdirを登録しました.これで,ディレクトリ作成時に,bobulsm_inode_mkdirが呼ばれるはずです.
cd linux-3.8.8/security
 wget http://bobuhiro11.net/wordpress/wp-content/uploads/2013/06/bobulsm.tar
 tar xvf bobulsm.tar
 rm bobulsm.tar
そのあとは,『Linux Security Modulesを作りたい』こちらに詳しく書いてあるので,参考にしました.これで上手くいくはずだったんですけど,どうも動いてくれない(泣).dmesgには,このように出力されてます.なにか手掛かりを教えてくれると喜びます.
[    0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-3.8.8 root=UUID=b5af552c-3516-48dc-8175-b7ce91be3e60 ro security=bobulsm crashkernel=384M-2G:64M,2G-:128M quiet splash vt.handoff=7

インターフェースの内から 

kernelの中身です.
/*
 *
 * include/linux/security.h
 * security_operations構造体は,イベント発生時に呼び出すコールバック関数を
 * 登録するための構造体です.
 * LSMを使うときは,この構造体のインスタンスを作って,いろいろ登録してやると
 * 良さそうです.
 *
 */
struct security_operations {
          char name[SECURITY_NAME_MAX + 1];
   
          int (*ptrace_access_check) (struct task_struct *child, unsigned int mode);
          int (*ptrace_traceme) (struct task_struct *parent);
          int (*capget) (struct task_struct *target,
                             kernel_cap_t *effective,
                             kernel_cap_t *inheritable, kernel_cap_t *permitted);
       ...
          void (*audit_rule_free) (void *lsmrule);
#endif /* CONFIG_AUDIT */
};


/*
 *
 * security/security.h
 * デフォルトのopsです.
 *
 */
static struct security_operations *security_ops;
static struct security_operations default_security_ops = {
          .name   = "default",
};

/*
 *
 * include/linux/init.h
 * LSM自身の初期化の関数群の始まりと終わりを示す.
 */
typedef int (*initcall_t)(void);
extern initcall_t __security_initcall_start[], __security_initcall_end[];

/*
 *
 * security/security.c
 * LSMの実際の初期化関数です.
 *
 * 『security_init() -> security_fixup_ops() -> set_to_cap_if_null()』
 * opsの中にまだ登録されていないコールバックがあれば,
 * デフォルトで上書きする.
 *
 * 『security_init() -> do_security_initcalls()』
 * __security_initcall_startと__security_initcall_endで
 * 囲まれた初期化関数群を実行する.
 *
 */
int __init security_init(void)
{
  printk(KERN_INFO "Security Framework initialized\n");

  security_fixup_ops(&default_security_ops);
  security_ops = &default_security_ops;
  do_security_initcalls();

  return 0;
}

/*
 *
 * security/security.c
 *
 */
#define set_to_cap_if_null(ops, function)             \
  do {                                                \
    if (!ops->function) {                             \
      ops->function = cap_##function;                 \
      pr_debug("Had to override the " #function       \
          " security operation with the default.\n"); \
    }                                                 \
  } while (0)

void __init security_fixup_ops(struct security_operations *ops)
{
  set_to_cap_if_null(ops, ptrace_access_check);
  set_to_cap_if_null(ops, ptrace_traceme);
  set_to_cap_if_null(ops, capget);
  set_to_cap_if_null(ops, capset);
  ...
}

static void __init do_security_initcalls(void)
{
  initcall_t *call;
  call = __security_initcall_start;
  while (call < __security_initcall_end) {
    (*call) ();
    call++;
  }
}

/*
 *
 * security/security.c
 * 外部から引数で与えられたopsをverify()でチェックして登録する.
 *
 */
int __init register_security(struct security_operations *ops)
{
  if (verify(ops)) {
    printk(KERN_DEBUG "%s could not verify "
        "security_operations structure.\n", __func__);
    return -EINVAL;
  }

  if (security_ops != &default_security_ops)
    return -EAGAIN;

  security_ops = ops;

  return 0;
}

/*
 *
 * security/security.c
 * 引数で与えられたopsで正しいかチェックする.
 * security_fixup_ops()を使って,opsの中で未定義のコールバックがあれば,
 * デフォルトでうめる.
 *
 */
static inline int __init verify(struct security_operations *ops)
{
  /* verify the security_operations structure exists */
  if (!ops)
    return -EINVAL;
  security_fixup_ops(ops);
  return 0;
}
動かないサンプルで申し訳ありません. 参考 Linux Security Modulesを作りたい Introduction to Linux Security Modules (LSM) Android雑記

comments powered by Disqus < gnu globalでコードリーティング LSMについて調べてみた.(続き) >