@@ -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 );
468484 if (IS_ERR (pol )) {
485+ mutex_unlock (& selinux_state .policy_mutex );
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+ mutex_unlock (& selinux_state .policy_mutex );
473491 db = & pol -> policydb ;
474492
475493 cursor .cur = payload ;
@@ -508,21 +526,34 @@ int handle_sepolicy(void __user *user_data, u64 data_len)
508526 ret = apply_one_sepolicy_cmd (db , & header , args );
509527 if (ret < 0 ) {
510528 pr_err ("sepol: cmd #%u failed, cmd=%u subcmd=%u.\n" , cmd_index , header .cmd , header .subcmd );
529+ if (header .cmd == KSU_SEPOLICY_CMD_CLONE_TYPE )
530+ goto out_drop_new_policy ;
511531 } else {
512532 success_cmd_count ++ ;
513533 }
514534 cmd_index ++ ;
515535 }
516536
537+ mutex_lock (& selinux_state .policy_mutex );
538+ old_pol = rcu_dereference_protected (selinux_state .policy , lockdep_is_held (& selinux_state .policy_mutex ));
539+ if (old_pol != locked_old_pol ) {
540+ ret = - EAGAIN ;
541+ pr_err ("sepol: policy changed during offline patch, retry required.\n" );
542+ goto out_drop_new_policy_locked ;
543+ }
544+
517545 rcu_assign_pointer (selinux_state .policy , pol );
518546 synchronize_rcu ();
519547 ksu_destroy_sepolicy (old_pol );
520548
521549 reset_avc_cache ();
550+ pr_info ("sepol: policy publish complete, success_cmd_count=%d\n" , success_cmd_count );
522551 ret = success_cmd_count ;
523552 goto out_unlock ;
524553
525554out_drop_new_policy :
555+ mutex_lock (& selinux_state .policy_mutex );
556+ out_drop_new_policy_locked :
526557 ksu_destroy_sepolicy (pol );
527558out_unlock :
528559 mutex_unlock (& selinux_state .policy_mutex );
0 commit comments