@@ -255,6 +255,8 @@ static int sepol_expected_argc(u32 cmd)
255255 return 4 ;
256256 case KSU_SEPOLICY_CMD_GENFSCON :
257257 return 3 ;
258+ case KSU_SEPOLICY_CMD_CLONE_TYPE :
259+ return 2 ;
258260 default :
259261 return - EINVAL ;
260262 }
@@ -423,6 +425,20 @@ static int apply_one_sepolicy_cmd(struct policydb *db, const struct sepol_data *
423425 }
424426 return 0 ;
425427
428+ case KSU_SEPOLICY_CMD_CLONE_TYPE :
429+ ret = sepol_require_not_all (args [0 ], "src" );
430+ if (ret < 0 )
431+ return ret ;
432+ ret = sepol_require_not_all (args [1 ], "dst" );
433+ if (ret < 0 )
434+ return ret ;
435+
436+ if (!ksu_clone_type (db , args [0 ], args [1 ])) {
437+ pr_err ("sepol: clone_type failed.\n" );
438+ return - EINVAL ;
439+ }
440+ return 0 ;
441+
426442 default :
427443 pr_err ("sepol: unknown cmd: %d\n" , header -> cmd );
428444 return - EINVAL ;
@@ -432,6 +448,7 @@ static int apply_one_sepolicy_cmd(struct policydb *db, const struct sepol_data *
432448int handle_sepolicy (void __user * user_data , u64 data_len )
433449{
434450 struct selinux_policy * pol , * old_pol ;
451+ struct selinux_policy * locked_old_pol ;
435452 struct policydb * db ;
436453 struct sepol_batch_cursor cursor ;
437454 u8 * payload ;
@@ -462,14 +479,15 @@ int handle_sepolicy(void __user *user_data, u64 data_len)
462479 }
463480
464481 mutex_lock (& selinux_state .policy_mutex );
465-
466- old_pol = selinux_state . policy ;
467- pol = ksu_dup_sepolicy ( rcu_dereference_protected ( old_pol , lockdep_is_held ( & selinux_state .policy_mutex )) );
482+ locked_old_pol = rcu_dereference_protected ( selinux_state . policy , lockdep_is_held ( & selinux_state . policy_mutex ));
483+ pol = ksu_dup_sepolicy ( locked_old_pol ) ;
484+ mutex_unlock ( & selinux_state .policy_mutex );
468485 if (IS_ERR (pol )) {
469486 ret = PTR_ERR (pol );
470487 pr_err ("ksu_dup_sepolicy err: %d\n" , ret );
471- goto out_unlock ;
488+ goto out_free ;
472489 }
490+ pr_info ("sepol: duplicated policy ready, payload_len=%llu\n" , data_len );
473491 db = & pol -> policydb ;
474492
475493 cursor .cur = payload ;
@@ -505,24 +523,40 @@ int handle_sepolicy(void __user *user_data, u64 data_len)
505523 }
506524 }
507525
526+ pr_info ("sepol: begin cmd #%u cmd=%u subcmd=%u\n" , cmd_index , header .cmd , header .subcmd );
508527 ret = apply_one_sepolicy_cmd (db , & header , args );
509528 if (ret < 0 ) {
510529 pr_err ("sepol: cmd #%u failed, cmd=%u subcmd=%u.\n" , cmd_index , header .cmd , header .subcmd );
530+ if (header .cmd == KSU_SEPOLICY_CMD_CLONE_TYPE )
531+ goto out_drop_new_policy ;
511532 } else {
512533 success_cmd_count ++ ;
534+ pr_info ("sepol: end cmd #%u cmd=%u subcmd=%u\n" , cmd_index , header .cmd , header .subcmd );
513535 }
514536 cmd_index ++ ;
515537 }
516538
539+ mutex_lock (& selinux_state .policy_mutex );
540+ old_pol = rcu_dereference_protected (selinux_state .policy , lockdep_is_held (& selinux_state .policy_mutex ));
541+ if (old_pol != locked_old_pol ) {
542+ ret = - EAGAIN ;
543+ pr_err ("sepol: policy changed during offline patch, retry required.\n" );
544+ goto out_drop_new_policy_locked ;
545+ }
546+
517547 rcu_assign_pointer (selinux_state .policy , pol );
548+ pr_info ("sepol: publishing new policy\n" );
518549 synchronize_rcu ();
519550 ksu_destroy_sepolicy (old_pol );
520551
521552 reset_avc_cache ();
553+ pr_info ("sepol: policy publish complete, success_cmd_count=%d\n" , success_cmd_count );
522554 ret = success_cmd_count ;
523555 goto out_unlock ;
524556
525557out_drop_new_policy :
558+ mutex_lock (& selinux_state .policy_mutex );
559+ out_drop_new_policy_locked :
526560 ksu_destroy_sepolicy (pol );
527561out_unlock :
528562 mutex_unlock (& selinux_state .policy_mutex );
0 commit comments