summaryrefslogtreecommitdiff
path: root/security/smack
diff options
context:
space:
mode:
Diffstat (limited to 'security/smack')
-rw-r--r--security/smack/smack.h17
-rw-r--r--security/smack/smack_access.c96
-rw-r--r--security/smack/smack_lsm.c290
-rw-r--r--security/smack/smack_netfilter.c4
-rw-r--r--security/smack/smackfs.c4
5 files changed, 288 insertions, 123 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h
index bf6a6ed3946c..9b9eb262fe33 100644
--- a/security/smack/smack.h
+++ b/security/smack/smack.h
@@ -276,6 +276,20 @@ struct smk_audit_info {
};
/*
+ * Initialization
+ */
+#if defined(CONFIG_SECURITY_SMACK_NETFILTER)
+int smack_nf_ip_init(void);
+#else
+static inline int smack_nf_ip_init(void)
+{
+ return 0;
+}
+#endif
+int init_smk_fs(void);
+int smack_initcall(void);
+
+/*
* These functions are in smack_access.c
*/
int smk_access_entry(char *, char *, struct list_head *);
@@ -286,9 +300,12 @@ int smk_tskacc(struct task_smack *, struct smack_known *,
int smk_curacc(struct smack_known *, u32, struct smk_audit_info *);
int smack_str_from_perm(char *string, int access);
struct smack_known *smack_from_secid(const u32);
+int smk_parse_label_len(const char *string, int len);
char *smk_parse_smack(const char *string, int len);
int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int);
struct smack_known *smk_import_entry(const char *, int);
+struct smack_known *smk_import_valid_label(const char *label, int label_len,
+ gfp_t gfp);
void smk_insert_entry(struct smack_known *skp);
struct smack_known *smk_find_entry(const char *);
bool smack_privileged(int cap);
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c
index 2e4a0cb22782..fc507dcc7ea5 100644
--- a/security/smack/smack_access.c
+++ b/security/smack/smack_access.c
@@ -443,19 +443,19 @@ struct smack_known *smk_find_entry(const char *string)
}
/**
- * smk_parse_smack - parse smack label from a text string
- * @string: a text string that might contain a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
+ * smk_parse_label_len - calculate the length of the starting segment
+ * in the string that constitutes a valid smack label
+ * @string: a text string that might contain a Smack label at the beginning
+ * @len: the maximum size to look into, may be zero if string is null-terminated
*
- * Returns a pointer to the clean label or an error code.
+ * Returns the length of the segment (0 < L < SMK_LONGLABEL) or an error code.
*/
-char *smk_parse_smack(const char *string, int len)
+int smk_parse_label_len(const char *string, int len)
{
- char *smack;
int i;
- if (len <= 0)
- len = strlen(string) + 1;
+ if (len <= 0 || len > SMK_LONGLABEL)
+ len = SMK_LONGLABEL;
/*
* Reserve a leading '-' as an indicator that
@@ -463,7 +463,7 @@ char *smk_parse_smack(const char *string, int len)
* including /smack/cipso and /smack/cipso2
*/
if (string[0] == '-')
- return ERR_PTR(-EINVAL);
+ return -EINVAL;
for (i = 0; i < len; i++)
if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' ||
@@ -471,6 +471,25 @@ char *smk_parse_smack(const char *string, int len)
break;
if (i == 0 || i >= SMK_LONGLABEL)
+ return -EINVAL;
+
+ return i;
+}
+
+/**
+ * smk_parse_smack - copy the starting segment in the string
+ * that constitutes a valid smack label
+ * @string: a text string that might contain a Smack label at the beginning
+ * @len: the maximum size to look into, may be zero if string is null-terminated
+ *
+ * Returns a pointer to the copy of the label or an error code.
+ */
+char *smk_parse_smack(const char *string, int len)
+{
+ char *smack;
+ int i = smk_parse_label_len(string, len);
+
+ if (i < 0)
return ERR_PTR(-EINVAL);
smack = kstrndup(string, i, GFP_NOFS);
@@ -554,31 +573,26 @@ int smack_populate_secattr(struct smack_known *skp)
}
/**
- * smk_import_entry - import a label, return the list entry
- * @string: a text string that might be a Smack label
- * @len: the maximum size, or zero if it is NULL terminated.
+ * smk_import_valid_allocated_label - import a label, return the list entry
+ * @smack: a text string that is a valid Smack label and may be kfree()ed.
+ * It is consumed: either becomes a part of the entry or kfree'ed.
+ * @gfp: Allocation type
*
- * Returns a pointer to the entry in the label list that
- * matches the passed string, adding it if necessary,
- * or an error code.
+ * Returns: see description of smk_import_entry()
*/
-struct smack_known *smk_import_entry(const char *string, int len)
+static struct smack_known *
+smk_import_allocated_label(char *smack, gfp_t gfp)
{
struct smack_known *skp;
- char *smack;
int rc;
- smack = smk_parse_smack(string, len);
- if (IS_ERR(smack))
- return ERR_CAST(smack);
-
mutex_lock(&smack_known_lock);
skp = smk_find_entry(smack);
if (skp != NULL)
goto freeout;
- skp = kzalloc(sizeof(*skp), GFP_NOFS);
+ skp = kzalloc(sizeof(*skp), gfp);
if (skp == NULL) {
skp = ERR_PTR(-ENOMEM);
goto freeout;
@@ -609,6 +623,44 @@ unlockout:
}
/**
+ * smk_import_entry - import a label, return the list entry
+ * @string: a text string that might contain a Smack label at the beginning
+ * @len: the maximum size to look into, may be zero if string is null-terminated
+ *
+ * Returns a pointer to the entry in the label list that
+ * matches the passed string, adding it if necessary,
+ * or an error code.
+ */
+struct smack_known *smk_import_entry(const char *string, int len)
+{
+ char *smack = smk_parse_smack(string, len);
+
+ if (IS_ERR(smack))
+ return ERR_CAST(smack);
+
+ return smk_import_allocated_label(smack, GFP_NOFS);
+}
+
+/**
+ * smk_import_valid_label - import a label, return the list entry
+ * @label: a text string that is a valid Smack label, not null-terminated
+ * @label_len: the length of the text string in the @label
+ * @gfp: the GFP mask used for allocating memory for the @label text string copy
+ *
+ * Return: see description of smk_import_entry()
+ */
+struct smack_known *
+smk_import_valid_label(const char *label, int label_len, gfp_t gfp)
+{
+ char *smack = kstrndup(label, label_len, gfp);
+
+ if (!smack)
+ return ERR_PTR(-ENOMEM);
+
+ return smk_import_allocated_label(smack, gfp);
+}
+
+/**
* smack_from_secid - find the Smack label associated with a secid
* @secid: an integer that might be associated with a Smack label
*
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index af986587841d..a0bd4919a9d9 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -963,6 +963,42 @@ static int smack_inode_alloc_security(struct inode *inode)
}
/**
+ * smk_rule_transmutes - does access rule for (subject,object) contain 't'?
+ * @subject: a pointer to the subject's Smack label entry
+ * @object: a pointer to the object's Smack label entry
+ */
+static bool
+smk_rule_transmutes(struct smack_known *subject,
+ const struct smack_known *object)
+{
+ int may;
+
+ rcu_read_lock();
+ may = smk_access_entry(subject->smk_known, object->smk_known,
+ &subject->smk_rules);
+ rcu_read_unlock();
+ return (may > 0) && (may & MAY_TRANSMUTE);
+}
+
+static int
+xattr_dupval(struct xattr *xattrs, int *xattr_count,
+ const char *name, const void *value, unsigned int vallen)
+{
+ struct xattr * const xattr = lsm_get_xattr_slot(xattrs, xattr_count);
+
+ if (!xattr)
+ return 0;
+
+ xattr->value = kmemdup(value, vallen, GFP_NOFS);
+ if (!xattr->value)
+ return -ENOMEM;
+
+ xattr->value_len = vallen;
+ xattr->name = name;
+ return 0;
+}
+
+/**
* smack_inode_init_security - copy out the smack from an inode
* @inode: the newly created inode
* @dir: containing directory object
@@ -977,23 +1013,30 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
struct xattr *xattrs, int *xattr_count)
{
struct task_smack *tsp = smack_cred(current_cred());
- struct inode_smack *issp = smack_inode(inode);
- struct smack_known *skp = smk_of_task(tsp);
- struct smack_known *isp = smk_of_inode(inode);
+ struct inode_smack * const issp = smack_inode(inode);
struct smack_known *dsp = smk_of_inode(dir);
- struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
- int may;
+ int rc = 0;
+ int transflag = 0;
+ bool trans_cred;
+ bool trans_rule;
/*
+ * UNIX domain sockets use lower level socket data. Let
+ * UDS inode have fixed * label to keep smack_inode_permission() calm
+ * when called from unix_find_bsd()
+ */
+ if (S_ISSOCK(inode->i_mode)) {
+ /* forced label, no need to save to xattrs */
+ issp->smk_inode = &smack_known_star;
+ goto instant_inode;
+ }
+ /*
* If equal, transmuting already occurred in
* smack_dentry_create_files_as(). No need to check again.
*/
- if (tsp->smk_task != tsp->smk_transmuted) {
- rcu_read_lock();
- may = smk_access_entry(skp->smk_known, dsp->smk_known,
- &skp->smk_rules);
- rcu_read_unlock();
- }
+ trans_cred = (tsp->smk_task == tsp->smk_transmuted);
+ if (!trans_cred)
+ trans_rule = smk_rule_transmutes(smk_of_task(tsp), dsp);
/*
* In addition to having smk_task equal to smk_transmuted,
@@ -1001,47 +1044,38 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
* requests transmutation then by all means transmute.
* Mark the inode as changed.
*/
- if ((tsp->smk_task == tsp->smk_transmuted) ||
- (may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
- smk_inode_transmutable(dir))) {
- struct xattr *xattr_transmute;
-
+ if (trans_cred || (trans_rule && smk_inode_transmutable(dir))) {
/*
* The caller of smack_dentry_create_files_as()
* should have overridden the current cred, so the
* inode label was already set correctly in
* smack_inode_alloc_security().
*/
- if (tsp->smk_task != tsp->smk_transmuted)
- isp = issp->smk_inode = dsp;
-
- issp->smk_flags |= SMK_INODE_TRANSMUTE;
- xattr_transmute = lsm_get_xattr_slot(xattrs,
- xattr_count);
- if (xattr_transmute) {
- xattr_transmute->value = kmemdup(TRANS_TRUE,
- TRANS_TRUE_SIZE,
- GFP_NOFS);
- if (!xattr_transmute->value)
- return -ENOMEM;
+ if (!trans_cred)
+ issp->smk_inode = dsp;
- xattr_transmute->value_len = TRANS_TRUE_SIZE;
- xattr_transmute->name = XATTR_SMACK_TRANSMUTE;
+ if (S_ISDIR(inode->i_mode)) {
+ transflag = SMK_INODE_TRANSMUTE;
+
+ if (xattr_dupval(xattrs, xattr_count,
+ XATTR_SMACK_TRANSMUTE,
+ TRANS_TRUE,
+ TRANS_TRUE_SIZE
+ ))
+ rc = -ENOMEM;
}
}
- issp->smk_flags |= SMK_INODE_INSTANT;
-
- if (xattr) {
- xattr->value = kstrdup(isp->smk_known, GFP_NOFS);
- if (!xattr->value)
- return -ENOMEM;
-
- xattr->value_len = strlen(isp->smk_known);
- xattr->name = XATTR_SMACK_SUFFIX;
- }
-
- return 0;
+ if (rc == 0)
+ if (xattr_dupval(xattrs, xattr_count,
+ XATTR_SMACK_SUFFIX,
+ issp->smk_inode->smk_known,
+ strlen(issp->smk_inode->smk_known)
+ ))
+ rc = -ENOMEM;
+instant_inode:
+ issp->smk_flags |= (SMK_INODE_INSTANT | transflag);
+ return rc;
}
/**
@@ -1315,13 +1349,23 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
int check_import = 0;
int check_star = 0;
int rc = 0;
+ umode_t const i_mode = d_backing_inode(dentry)->i_mode;
/*
* Check label validity here so import won't fail in post_setxattr
*/
- if (strcmp(name, XATTR_NAME_SMACK) == 0 ||
- strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
- strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
+ if (strcmp(name, XATTR_NAME_SMACK) == 0) {
+ /*
+ * UDS inode has fixed label
+ */
+ if (S_ISSOCK(i_mode)) {
+ rc = -EINVAL;
+ } else {
+ check_priv = 1;
+ check_import = 1;
+ }
+ } else if (strcmp(name, XATTR_NAME_SMACKIPIN) == 0 ||
+ strcmp(name, XATTR_NAME_SMACKIPOUT) == 0) {
check_priv = 1;
check_import = 1;
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0 ||
@@ -1331,7 +1375,7 @@ static int smack_inode_setxattr(struct mnt_idmap *idmap,
check_star = 1;
} else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) {
check_priv = 1;
- if (!S_ISDIR(d_backing_inode(dentry)->i_mode) ||
+ if (!S_ISDIR(i_mode) ||
size != TRANS_TRUE_SIZE ||
strncmp(value, TRANS_TRUE, TRANS_TRUE_SIZE) != 0)
rc = -EINVAL;
@@ -1462,12 +1506,15 @@ static int smack_inode_removexattr(struct mnt_idmap *idmap,
* Don't do anything special for these.
* XATTR_NAME_SMACKIPIN
* XATTR_NAME_SMACKIPOUT
+ * XATTR_NAME_SMACK if S_ISSOCK (UDS inode has fixed label)
*/
if (strcmp(name, XATTR_NAME_SMACK) == 0) {
- struct super_block *sbp = dentry->d_sb;
- struct superblock_smack *sbsp = smack_superblock(sbp);
+ if (!S_ISSOCK(d_backing_inode(dentry)->i_mode)) {
+ struct super_block *sbp = dentry->d_sb;
+ struct superblock_smack *sbsp = smack_superblock(sbp);
- isp->smk_inode = sbsp->smk_default;
+ isp->smk_inode = sbsp->smk_default;
+ }
} else if (strcmp(name, XATTR_NAME_SMACKEXEC) == 0)
isp->smk_task = NULL;
else if (strcmp(name, XATTR_NAME_SMACKMMAP) == 0)
@@ -3585,7 +3632,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
*/
/*
- * UNIX domain sockets use lower level socket data.
+ * UDS inode has fixed label (*)
*/
if (S_ISSOCK(inode->i_mode)) {
final = &smack_known_star;
@@ -3663,7 +3710,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* @attr: which attribute to fetch
* @ctx: buffer to receive the result
* @size: available size in, actual size out
- * @flags: unused
+ * @flags: reserved, currently zero
*
* Fill the passed user space @ctx with the details of the requested
* attribute.
@@ -3724,47 +3771,55 @@ static int smack_getprocattr(struct task_struct *p, const char *name, char **val
* Sets the Smack value of the task. Only setting self
* is permitted and only with privilege
*
- * Returns the length of the smack label or an error code
+ * Returns zero on success or an error code
*/
-static int do_setattr(u64 attr, void *value, size_t size)
+static int do_setattr(unsigned int attr, void *value, size_t size)
{
struct task_smack *tsp = smack_cred(current_cred());
struct cred *new;
struct smack_known *skp;
- struct smack_known_list_elem *sklep;
- int rc;
-
- if (!smack_privileged(CAP_MAC_ADMIN) && list_empty(&tsp->smk_relabel))
- return -EPERM;
+ int label_len;
+ /*
+ * let unprivileged user validate input, check permissions later
+ */
if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
return -EINVAL;
- if (attr != LSM_ATTR_CURRENT)
- return -EOPNOTSUPP;
-
- skp = smk_import_entry(value, size);
- if (IS_ERR(skp))
- return PTR_ERR(skp);
+ label_len = smk_parse_label_len(value, size);
+ if (label_len < 0 || label_len != size)
+ return -EINVAL;
/*
* No process is ever allowed the web ("@") label
* and the star ("*") label.
*/
- if (skp == &smack_known_web || skp == &smack_known_star)
- return -EINVAL;
+ if (label_len == 1 /* '@', '*' */) {
+ const char c = *(const char *)value;
+
+ if (c == *smack_known_web.smk_known ||
+ c == *smack_known_star.smk_known)
+ return -EPERM;
+ }
if (!smack_privileged(CAP_MAC_ADMIN)) {
- rc = -EPERM;
- list_for_each_entry(sklep, &tsp->smk_relabel, list)
- if (sklep->smk_label == skp) {
- rc = 0;
- break;
- }
- if (rc)
- return rc;
+ const struct smack_known_list_elem *sklep;
+ list_for_each_entry(sklep, &tsp->smk_relabel, list) {
+ const char *cp = sklep->smk_label->smk_known;
+
+ if (strlen(cp) == label_len &&
+ strncmp(cp, value, label_len) == 0)
+ goto in_relabel;
+ }
+ return -EPERM;
+in_relabel:
+ ;
}
+ skp = smk_import_valid_label(value, label_len, GFP_KERNEL);
+ if (IS_ERR(skp))
+ return PTR_ERR(skp);
+
new = prepare_creds();
if (new == NULL)
return -ENOMEM;
@@ -3777,7 +3832,7 @@ static int do_setattr(u64 attr, void *value, size_t size)
smk_destroy_label_list(&tsp->smk_relabel);
commit_creds(new);
- return size;
+ return 0;
}
/**
@@ -3785,7 +3840,7 @@ static int do_setattr(u64 attr, void *value, size_t size)
* @attr: which attribute to set
* @ctx: buffer containing the data
* @size: size of @ctx
- * @flags: unused
+ * @flags: reserved, must be zero
*
* Fill the passed user space @ctx with the details of the requested
* attribute.
@@ -3795,12 +3850,26 @@ static int do_setattr(u64 attr, void *value, size_t size)
static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
u32 size, u32 flags)
{
- int rc;
+ if (attr != LSM_ATTR_CURRENT)
+ return -EOPNOTSUPP;
- rc = do_setattr(attr, ctx->ctx, ctx->ctx_len);
- if (rc > 0)
- return 0;
- return rc;
+ if (ctx->flags)
+ return -EINVAL;
+ /*
+ * string must have \0 terminator, included in ctx->ctx
+ * (see description of struct lsm_ctx)
+ */
+ if (ctx->ctx_len == 0)
+ return -EINVAL;
+
+ if (ctx->ctx[ctx->ctx_len - 1] != '\0')
+ return -EINVAL;
+ /*
+ * other do_setattr() caller, smack_setprocattr(),
+ * does not count \0 into size, so
+ * decreasing length by 1 to accommodate the divergence.
+ */
+ return do_setattr(attr, ctx->ctx, ctx->ctx_len - 1);
}
/**
@@ -3812,15 +3881,39 @@ static int smack_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
* Sets the Smack value of the task. Only setting self
* is permitted and only with privilege
*
- * Returns the length of the smack label or an error code
+ * Returns the size of the input value or an error code
*/
static int smack_setprocattr(const char *name, void *value, size_t size)
{
- int attr = lsm_name_to_attr(name);
+ size_t realsize = size;
+ unsigned int attr = lsm_name_to_attr(name);
- if (attr != LSM_ATTR_UNDEF)
- return do_setattr(attr, value, size);
- return -EINVAL;
+ switch (attr) {
+ case LSM_ATTR_UNDEF: return -EINVAL;
+ default: return -EOPNOTSUPP;
+ case LSM_ATTR_CURRENT:
+ ;
+ }
+
+ /*
+ * The value for the "current" attribute is the label
+ * followed by one of the 4 trailers: none, \0, \n, \n\0
+ *
+ * I.e. following inputs are accepted as 3-characters long label "foo":
+ *
+ * "foo" (3 characters)
+ * "foo\0" (4 characters)
+ * "foo\n" (4 characters)
+ * "foo\n\0" (5 characters)
+ */
+
+ if (realsize && (((const char *)value)[realsize - 1] == '\0'))
+ --realsize;
+
+ if (realsize && (((const char *)value)[realsize - 1] == '\n'))
+ --realsize;
+
+ return do_setattr(attr, value, realsize) ? : size;
}
/**
@@ -4850,6 +4943,11 @@ static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
{
+ /*
+ * UDS inode has fixed label. Ignore nfs label.
+ */
+ if (S_ISSOCK(inode->i_mode))
+ return 0;
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx,
ctxlen, 0);
}
@@ -4915,7 +5013,6 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
struct task_smack *otsp = smack_cred(old);
struct task_smack *ntsp = smack_cred(new);
struct inode_smack *isp;
- int may;
/*
* Use the process credential unless all of
@@ -4929,18 +5026,12 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode,
isp = smack_inode(d_inode(dentry->d_parent));
if (isp->smk_flags & SMK_INODE_TRANSMUTE) {
- rcu_read_lock();
- may = smk_access_entry(otsp->smk_task->smk_known,
- isp->smk_inode->smk_known,
- &otsp->smk_task->smk_rules);
- rcu_read_unlock();
-
/*
* If the directory is transmuting and the rule
* providing access is transmuting use the containing
* directory label instead of the process label.
*/
- if (may > 0 && (may & MAY_TRANSMUTE)) {
+ if (smk_rule_transmutes(otsp->smk_task, isp->smk_inode)) {
ntsp->smk_task = isp->smk_inode;
ntsp->smk_transmuted = ntsp->smk_task;
}
@@ -5275,13 +5366,22 @@ static __init int smack_init(void)
return 0;
}
+int __init smack_initcall(void)
+{
+ int rc_fs = init_smk_fs();
+ int rc_nf = smack_nf_ip_init();
+
+ return rc_fs ? rc_fs : rc_nf;
+}
+
/*
* Smack requires early initialization in order to label
* all processes and objects when they are created.
*/
DEFINE_LSM(smack) = {
- .name = "smack",
+ .id = &smack_lsmid,
.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
.blobs = &smack_blob_sizes,
.init = smack_init,
+ .initcall_device = smack_initcall,
};
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index 8fd747b3653a..17ba578b1308 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -68,7 +68,7 @@ static struct pernet_operations smack_net_ops = {
.exit = smack_nf_unregister,
};
-static int __init smack_nf_ip_init(void)
+int __init smack_nf_ip_init(void)
{
if (smack_enabled == 0)
return 0;
@@ -76,5 +76,3 @@ static int __init smack_nf_ip_init(void)
printk(KERN_DEBUG "Smack: Registering netfilter hooks\n");
return register_pernet_subsys(&smack_net_ops);
}
-
-__initcall(smack_nf_ip_init);
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index b1e5e62f5cbd..405ace6db109 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -2978,7 +2978,7 @@ static struct vfsmount *smackfs_mount;
* Returns true if we were not chosen on boot or if
* we were chosen and filesystem registration succeeded.
*/
-static int __init init_smk_fs(void)
+int __init init_smk_fs(void)
{
int err;
int rc;
@@ -3021,5 +3021,3 @@ static int __init init_smk_fs(void)
return err;
}
-
-__initcall(init_smk_fs);