@@ -155,7 +155,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
*
* Returns: new permission mapping
*/
-static u32 map_old_perms(u32 old)
+u32 map_old_perms(u32 old)
{
u32 new = old & 0xf;
if (old & MAY_READ)
@@ -186,6 +186,8 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
aa_free_domain_entries(&rules->trans);
}
+u32 map_old_perms(u32 old);
+
#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
/* from namei.c */
@@ -22,5 +22,6 @@ int aa_getprocattr(struct aa_profile *profile, char **string);
int aa_setprocattr_changehat(char *args, size_t size, int test);
int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
int aa_setprocattr_permipc(char *fqname);
+int aa_setprocattr_perm(char *fqname, size_t size);
#endif /* __AA_PROCATTR_H */
@@ -559,10 +559,6 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
args[size] = '\0';
}
- /* task can only write its own attributes */
- if (current != task)
- return -EACCES;
-
args = value;
args = strim(args);
command = strsep(&args, " ");
@@ -575,12 +571,18 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
arg_size = size - (args - (char *) value);
if (strcmp(name, "current") == 0) {
if (strcmp(command, "changehat") == 0) {
+ /* task can only write its own attributes */
+ if (current != task)
+ return -EACCES;
error = aa_setprocattr_changehat(args, arg_size,
!AA_DO_TEST);
} else if (strcmp(command, "permhat") == 0) {
error = aa_setprocattr_changehat(args, arg_size,
AA_DO_TEST);
} else if (strcmp(command, "changeprofile") == 0) {
+ /* task can only write its own attributes */
+ if (current != task)
+ return -EACCES;
error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
!AA_DO_TEST);
} else if (strcmp(command, "permprofile") == 0) {
@@ -588,6 +590,8 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
AA_DO_TEST);
} else if (strcmp(command, "permipc") == 0) {
error = aa_setprocattr_permipc(args);
+ } else if (strcmp(command, "perm") == 0) {
+ error = aa_setprocattr_perm(args, arg_size);
} else {
struct common_audit_data sa;
COMMON_AUDIT_DATA_INIT(&sa, NONE);
@@ -168,3 +168,37 @@ int aa_setprocattr_permipc(char *fqname)
/* TODO: add ipc permission querying */
return -ENOTSUPP;
}
+
+/**
+ * aa_setprocattr_perm - generic perm test can be used to determine transition
+ * @args: args from writting to /proc/<pid>/attr/current (NOT NULL)
+ * @size: size of the args
+ */
+int aa_setprocattr_perm(char *args, size_t size)
+{
+ struct aa_profile *profile;
+ char *permstr, *val = args;
+ u32 mask, perms;
+ unsigned int state;
+
+ if (!args)
+ return -EINVAL;
+ permstr = strsep(&val, " ");
+ if (!val)
+ return -EINVAL;
+ mask = simple_strtoul(permstr, NULL, 0);
+ size -= val - args;
+
+ profile = aa_current_profile();
+ if (profile->policy) {
+ state = aa_dfa_match_len(profile->policy, profile->policy_start,
+ args, size);
+ perms = map_old_perms(dfa_user_allow(profile->policy, state));
+ } else
+ perms = 0;
+
+ if (mask & ~perms)
+ return -EACCES;
+
+ return 0;
+}
The generic perm query allow userspace (if it has sufficient permissions) to query what permissions are being enforced. Also while only the current task may set its security context, allow any task with sufficient perms to query if the security context could be set. Signed-off-by: John Johansen <john.johansen@canonical.com> --- security/apparmor/file.c | 2 +- security/apparmor/include/file.h | 2 ++ security/apparmor/include/procattr.h | 1 + security/apparmor/lsm.c | 12 ++++++++---- security/apparmor/procattr.c | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 5 deletions(-)